use std::{cmp::Ordering, fmt::Display, ops::DerefMut}; use super::{activity::ActivityBuilder, user::AdminUser}; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; #[derive(FromRow, Serialize, Clone, Deserialize, Debug)] pub struct Role { pub(crate) id: i64, pub(crate) name: String, pub(crate) formatted_name: Option, pub(crate) desc: Option, pub(crate) hide_in_lists: bool, pub(crate) cluster: Option, } // Implement PartialEq to compare roles based only on id impl PartialEq for Role { fn eq(&self, other: &Self) -> bool { self.id == other.id } } // Implement Eq to indicate that equality is reflexive impl Eq for Role {} // Implement PartialOrd if you need to sort or compare roles impl PartialOrd for Role { fn partial_cmp(&self, other: &Self) -> Option { Some(self.id.cmp(&other.id)) } } // Implement Ord if you need total ordering (for sorting) impl Ord for Role { fn cmp(&self, other: &Self) -> Ordering { self.id.cmp(&other.id) } } impl Display for Role { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(formatted_name) = &self.formatted_name { write!(f, "{}", formatted_name) } else { write!(f, "{}", self.name) } } } impl Role { pub async fn all(db: &SqlitePool) -> Vec { sqlx::query_as!( Role, "SELECT id, name, formatted_name, desc, hide_in_lists, cluster FROM role" ) .fetch_all(db) .await .unwrap() } pub async fn all_cluster(db: &SqlitePool, cluster: &str) -> Vec { sqlx::query_as!( Role, r#"SELECT id, CASE WHEN formatted_name IS NOT NULL AND formatted_name != '' THEN formatted_name ELSE name END AS "name!: String", '' as formatted_name, desc, hide_in_lists, cluster FROM role WHERE cluster = ?"#, cluster ) .fetch_all(db) .await .unwrap() } pub async fn find_by_id(db: &SqlitePool, name: i32) -> Option { sqlx::query_as!( Self, " SELECT id, name, formatted_name, desc, hide_in_lists, cluster FROM role WHERE id like ? ", name ) .fetch_one(db) .await .ok() } pub async fn find_by_id_tx(db: &mut Transaction<'_, Sqlite>, name: i32) -> Option { sqlx::query_as!( Self, " SELECT id, name, formatted_name, desc, hide_in_lists, cluster FROM role WHERE id like ? ", name ) .fetch_one(db.deref_mut()) .await .ok() } pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option { sqlx::query_as!( Self, " SELECT id, name, formatted_name, desc, hide_in_lists, cluster FROM role WHERE name like ? ", name ) .fetch_one(db) .await .ok() } pub async fn find_by_name_tx(db: &mut Transaction<'_, Sqlite>, name: &str) -> Option { sqlx::query_as!( Self, " SELECT id, name, formatted_name, desc, hide_in_lists, cluster FROM role WHERE name like ? ", name ) .fetch_one(db.deref_mut()) .await .ok() } pub async fn update( &self, db: &SqlitePool, updated_by: &AdminUser, formatted_name: &str, desc: &str, ) -> Result<(), String> { sqlx::query!( "UPDATE role SET formatted_name=?, desc=? WHERE id=?", formatted_name, desc, self.id ) .execute(db) .await .map_err(|e| e.to_string())?; ActivityBuilder::new(&format!( "{updated_by} hat Rolle {self} von {self:#?} auf FORMATTED_NAME={formatted_name}, DESC={desc} aktualisiert." )).role(self).save(db).await; Ok(()) } pub async fn names_from_role(&self, db: &SqlitePool) -> Vec { let query = format!( "SELECT u.name FROM user u JOIN user_role ur ON u.id = ur.user_id JOIN role r ON ur.role_id = r.id WHERE r.id = {} AND deleted=0;", self.id ); sqlx::query_scalar(&query).fetch_all(db).await.unwrap() } pub async fn mails_from_role(&self, db: &SqlitePool) -> Vec { let query = format!( "SELECT u.mail FROM user u JOIN user_role ur ON u.id = ur.user_id JOIN role r ON ur.role_id = r.id WHERE r.id = {} AND deleted=0;", self.id ); sqlx::query_scalar(&query).fetch_all(db).await.unwrap() } }