2025-03-25 18:18:33 -04:00
use super ::* ;
use crate ::cache ::Cache ;
use crate ::model ::{ Error , Result , auth ::Notification , auth ::User , permissions ::FinePermission } ;
2025-04-03 15:07:57 -04:00
use crate ::{ auto_method , execute , get , query_row , query_rows , params } ;
2025-03-25 18:18:33 -04:00
#[ cfg(feature = " sqlite " ) ]
use rusqlite ::Row ;
#[ cfg(feature = " postgres " ) ]
use tokio_postgres ::Row ;
impl DataManager {
2025-03-25 21:19:55 -04:00
/// Get a [`Notification`] from an SQL row.
2025-03-25 18:18:33 -04:00
pub ( crate ) fn get_notification_from_row (
#[ cfg(feature = " sqlite " ) ] x : & Row < '_ > ,
#[ cfg(feature = " postgres " ) ] x : & Row ,
) -> Notification {
Notification {
2025-04-03 13:52:29 -04:00
id : get ! ( x ->0 ( i64 ) ) as usize ,
created : get ! ( x ->1 ( i64 ) ) as usize ,
2025-03-25 18:18:33 -04:00
title : get ! ( x ->2 ( String ) ) ,
content : get ! ( x ->3 ( String ) ) ,
2025-04-03 13:52:29 -04:00
owner : get ! ( x ->4 ( i64 ) ) as usize ,
2025-04-10 18:16:52 -04:00
read : get ! ( x ->5 ( i32 ) ) as i8 = = 1 ,
2025-03-25 18:18:33 -04:00
}
}
auto_method! ( get_notification_by_id ( ) @ get_notification_from_row -> " SELECT * FROM notifications WHERE id = $1 " - - name = " notification " - - returns = Notification - - cache - key - tmpl = " atto.notification:{} " ) ;
2025-03-27 18:10:47 -04:00
/// Get all notifications by `owner`.
2025-03-25 18:18:33 -04:00
pub async fn get_notifications_by_owner ( & self , owner : usize ) -> Result < Vec < Notification > > {
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = query_rows! (
& conn ,
2025-04-01 15:03:56 -04:00
" SELECT * FROM notifications WHERE owner = $1 ORDER BY created DESC " ,
2025-04-03 13:52:29 -04:00
& [ & ( owner as i64 ) ] ,
2025-03-25 18:18:33 -04:00
| x | { Self ::get_notification_from_row ( x ) }
) ;
if res . is_err ( ) {
2025-03-25 21:19:55 -04:00
return Err ( Error ::GeneralNotFound ( " notification " . to_string ( ) ) ) ;
2025-03-25 18:18:33 -04:00
}
Ok ( res . unwrap ( ) )
}
/// Create a new notification in the database.
///
/// # Arguments
2025-04-12 22:25:54 -04:00
/// * `data` - a mock [`Notification`] object to insert
2025-03-25 18:18:33 -04:00
pub async fn create_notification ( & self , data : Notification ) -> Result < ( ) > {
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = execute! (
& conn ,
2025-03-29 23:51:13 -04:00
" INSERT INTO notifications VALUES ($1, $2, $3, $4, $5, $6) " ,
2025-04-03 15:07:57 -04:00
params! [
& ( data . id as i64 ) ,
& ( data . created as i64 ) ,
& data . title ,
& data . content ,
& ( data . owner as i64 ) ,
2025-04-10 18:16:52 -04:00
& { if data . read { 1 } else { 0 } }
2025-03-25 18:18:33 -04:00
]
) ;
if let Err ( e ) = res {
return Err ( Error ::DatabaseError ( e . to_string ( ) ) ) ;
}
// incr notification count
self . incr_user_notifications ( data . owner ) . await . unwrap ( ) ;
// return
Ok ( ( ) )
}
2025-03-29 23:51:13 -04:00
pub async fn delete_notification ( & self , id : usize , user : & User ) -> Result < ( ) > {
2025-03-25 18:18:33 -04:00
let notification = self . get_notification_by_id ( id ) . await ? ;
2025-04-12 22:25:54 -04:00
if user . id ! = notification . owner
& & ! user . permissions . check ( FinePermission ::MANAGE_NOTIFICATIONS )
{
2025-04-10 18:16:52 -04:00
return Err ( Error ::NotAllowed ) ;
2025-03-25 18:18:33 -04:00
}
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = execute! (
& conn ,
2025-03-30 22:26:20 -04:00
" DELETE FROM notifications WHERE id = $1 " ,
2025-04-03 15:07:57 -04:00
& [ & ( id as i64 ) ]
2025-03-25 18:18:33 -04:00
) ;
if let Err ( e ) = res {
return Err ( Error ::DatabaseError ( e . to_string ( ) ) ) ;
}
self . 2. remove ( format! ( " atto.notification: {} " , id ) ) . await ;
// decr notification count
2025-03-30 22:26:20 -04:00
if ! notification . read {
self . decr_user_notifications ( notification . owner )
. await
. unwrap ( ) ;
}
2025-03-25 18:18:33 -04:00
// return
Ok ( ( ) )
}
2025-03-29 23:51:13 -04:00
pub async fn delete_all_notifications ( & self , user : & User ) -> Result < ( ) > {
let notifications = self . get_notifications_by_owner ( user . id ) . await ? ;
for notification in notifications {
2025-04-12 22:25:54 -04:00
if user . id ! = notification . owner
& & ! user . permissions . check ( FinePermission ::MANAGE_NOTIFICATIONS )
{
2025-04-10 18:16:52 -04:00
return Err ( Error ::NotAllowed ) ;
2025-03-29 23:51:13 -04:00
}
self . delete_notification ( notification . id , user ) . await ?
}
Ok ( ( ) )
}
pub async fn update_notification_read (
& self ,
id : usize ,
new_read : bool ,
user : & User ,
) -> Result < ( ) > {
let y = self . get_notification_by_id ( id ) . await ? ;
2025-04-10 18:16:52 -04:00
if y . owner ! = user . id & & ! user . permissions . check ( FinePermission ::MANAGE_NOTIFICATIONS ) {
return Err ( Error ::NotAllowed ) ;
2025-03-29 23:51:13 -04:00
}
// ...
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = execute! (
& conn ,
" UPDATE notifications SET read = $1 WHERE id = $2 " ,
2025-04-10 18:16:52 -04:00
params! [ & { if new_read { 1 } else { 0 } } , & ( id as i64 ) ]
2025-03-29 23:51:13 -04:00
) ;
if let Err ( e ) = res {
return Err ( Error ::DatabaseError ( e . to_string ( ) ) ) ;
}
self . 2. remove ( format! ( " atto.notification: {} " , id ) ) . await ;
2025-04-10 18:16:52 -04:00
if ( y . read ) & & ( ! new_read ) {
2025-03-29 23:51:13 -04:00
self . incr_user_notifications ( user . id ) . await ? ;
2025-04-10 18:16:52 -04:00
} else if ( ! y . read ) & & ( new_read ) {
2025-03-29 23:51:13 -04:00
self . decr_user_notifications ( user . id ) . await ? ;
}
Ok ( ( ) )
}
2025-03-25 18:18:33 -04:00
}