2025-03-24 20:19:12 -04:00
use super ::* ;
use crate ::cache ::Cache ;
use crate ::model ::{
2025-03-27 18:10:47 -04:00
Error , Result , auth ::User , communities ::CommunityMembership ,
communities_permissions ::CommunityPermission , permissions ::FinePermission ,
2025-03-24 20:19:12 -04:00
} ;
2025-03-27 18:10:47 -04:00
use crate ::{ auto_method , execute , get , query_row , query_rows } ;
2025-03-24 20:19:12 -04:00
#[ cfg(feature = " sqlite " ) ]
use rusqlite ::Row ;
#[ cfg(feature = " postgres " ) ]
use tokio_postgres ::Row ;
impl DataManager {
/// Get a [`JournalEntry`] from an SQL row.
pub ( crate ) fn get_membership_from_row (
#[ cfg(feature = " sqlite " ) ] x : & Row < '_ > ,
#[ cfg(feature = " postgres " ) ] x : & Row ,
2025-03-27 18:10:47 -04:00
) -> CommunityMembership {
CommunityMembership {
2025-03-25 18:18:33 -04:00
id : get ! ( x ->0 ( i64 ) ) as usize ,
created : get ! ( x ->1 ( i64 ) ) as usize ,
owner : get ! ( x ->2 ( i64 ) ) as usize ,
2025-03-27 18:10:47 -04:00
community : get ! ( x ->3 ( i64 ) ) as usize ,
role : CommunityPermission ::from_bits ( get! ( x ->4 ( u32 ) ) ) . unwrap ( ) ,
2025-03-24 20:19:12 -04:00
}
}
2025-03-27 18:10:47 -04:00
auto_method! ( get_membership_by_id ( ) @ get_membership_from_row -> " SELECT * FROM memberships WHERE id = $1 " - - name = " journal membership " - - returns = CommunityMembership - - cache - key - tmpl = " atto.membership:{} " ) ;
2025-03-24 20:19:12 -04:00
2025-03-27 18:10:47 -04:00
/// Get a community membership by `owner` and `community`.
pub async fn get_membership_by_owner_community (
2025-03-24 20:19:12 -04:00
& self ,
owner : usize ,
2025-03-27 18:10:47 -04:00
community : usize ,
) -> Result < CommunityMembership > {
2025-03-24 20:19:12 -04:00
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = query_row! (
& conn ,
2025-03-27 18:10:47 -04:00
" SELECT * FROM memberships WHERE owner = $1 AND community = $2 " ,
& [ & ( owner as i64 ) , & ( community as i64 ) ] ,
2025-03-24 20:19:12 -04:00
| x | { Ok ( Self ::get_membership_from_row ( x ) ) }
) ;
if res . is_err ( ) {
2025-03-27 18:10:47 -04:00
return Err ( Error ::GeneralNotFound ( " community membership " . to_string ( ) ) ) ;
2025-03-24 20:19:12 -04:00
}
Ok ( res . unwrap ( ) )
}
2025-03-27 18:10:47 -04:00
/// Get all community memberships by `owner`.
pub async fn get_memberships_by_owner ( & self , owner : usize ) -> Result < Vec < CommunityMembership > > {
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = query_rows! (
& conn ,
" SELECT * FROM memberships WHERE owner = $1 " ,
& [ & ( owner as i64 ) ] ,
| x | { Self ::get_membership_from_row ( x ) }
) ;
if res . is_err ( ) {
return Err ( Error ::GeneralNotFound ( " community membership " . to_string ( ) ) ) ;
}
Ok ( res . unwrap ( ) )
}
/// Create a new community membership in the database.
2025-03-24 20:19:12 -04:00
///
/// # Arguments
2025-03-27 18:10:47 -04:00
/// * `data` - a mock [`CommunityMembership`] object to insert
pub async fn create_membership ( & self , data : CommunityMembership ) -> Result < ( ) > {
2025-03-24 20:19:12 -04:00
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = execute! (
& conn ,
" INSERT INTO memberships VALUES ($1, $2, $3, $4, $5 " ,
& [
& data . id . to_string ( ) . as_str ( ) ,
& data . created . to_string ( ) . as_str ( ) ,
& data . owner . to_string ( ) . as_str ( ) ,
2025-03-27 18:10:47 -04:00
& data . community . to_string ( ) . as_str ( ) ,
2025-03-24 20:19:12 -04:00
& ( data . role . bits ( ) ) . to_string ( ) . as_str ( ) ,
]
) ;
if let Err ( e ) = res {
return Err ( Error ::DatabaseError ( e . to_string ( ) ) ) ;
}
Ok ( ( ) )
}
2025-03-25 22:52:47 -04:00
/// Delete a membership given its `id`
pub async fn delete_membership ( & self , id : usize , user : User ) -> Result < ( ) > {
let y = self . get_membership_by_id ( id ) . await ? ;
if user . id ! = y . owner {
// pull other user's membership status
if let Ok ( z ) = self . get_membership_by_id ( user . id ) . await {
// somebody with MANAGE_ROLES _and_ a higher role number can remove us
2025-03-27 18:10:47 -04:00
if ( ! z . role . check ( CommunityPermission ::MANAGE_ROLES ) | ( z . role < y . role ) )
& & ! z . role . check ( CommunityPermission ::ADMINISTRATOR )
2025-03-25 22:52:47 -04:00
{
return Err ( Error ::NotAllowed ) ;
}
} else if ! user . permissions . check ( FinePermission ::MANAGE_MEMBERSHIPS ) {
return Err ( Error ::NotAllowed ) ;
}
}
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = execute! (
& conn ,
" DELETE FROM memberships WHERE id = $1 " ,
& [ & id . to_string ( ) ]
) ;
if let Err ( e ) = res {
return Err ( Error ::DatabaseError ( e . to_string ( ) ) ) ;
}
self . 2. remove ( format! ( " atto.membership: {} " , id ) ) . await ;
Ok ( ( ) )
}
/// Update a membership's role given its `id`
pub async fn update_membership_role (
& self ,
id : usize ,
2025-03-27 18:10:47 -04:00
new_role : CommunityPermission ,
2025-03-25 22:52:47 -04:00
) -> Result < ( ) > {
let conn = match self . connect ( ) . await {
Ok ( c ) = > c ,
Err ( e ) = > return Err ( Error ::DatabaseConnection ( e . to_string ( ) ) ) ,
} ;
let res = execute! (
& conn ,
" UPDATE memberships SET role = $1 WHERE id = $2 " ,
& [ & ( new_role . bits ( ) ) . to_string ( ) , & id . to_string ( ) ]
) ;
if let Err ( e ) = res {
return Err ( Error ::DatabaseError ( e . to_string ( ) ) ) ;
}
self . 2. remove ( format! ( " atto.membership: {} " , id ) ) . await ;
Ok ( ( ) )
}
2025-03-24 20:19:12 -04:00
}