Skip to main content

systemprompt_users/services/
admin_service.rs

1use systemprompt_identifiers::UserId;
2
3use crate::error::Result;
4use crate::models::{User, UserRole};
5use crate::UserService;
6
7#[derive(Debug)]
8pub struct UserAdminService {
9    user_service: UserService,
10}
11
12impl UserAdminService {
13    pub const fn new(user_service: UserService) -> Self {
14        Self { user_service }
15    }
16
17    pub async fn find_user(&self, identifier: &str) -> Result<Option<User>> {
18        if uuid::Uuid::parse_str(identifier).is_ok() {
19            let user_id = UserId::new(identifier);
20            if let Some(user) = self.user_service.find_by_id(&user_id).await? {
21                return Ok(Some(user));
22            }
23        }
24
25        if identifier.contains('@') {
26            return self.user_service.find_by_email(identifier).await;
27        }
28
29        self.user_service.find_by_name(identifier).await
30    }
31
32    pub async fn promote_to_admin(&self, user_identifier: &str) -> Result<PromoteResult> {
33        let user = self.find_user(user_identifier).await?;
34        let admin_role = UserRole::Admin.as_str().to_string();
35        let user_role = UserRole::User.as_str().to_string();
36
37        match user {
38            Some(u) => {
39                let current_roles = u.roles.clone();
40
41                if current_roles.contains(&admin_role) {
42                    return Ok(PromoteResult::AlreadyAdmin(u));
43                }
44
45                let mut new_roles = current_roles;
46                if !new_roles.contains(&admin_role) {
47                    new_roles.push(admin_role);
48                }
49                if !new_roles.contains(&user_role) {
50                    new_roles.push(user_role);
51                }
52
53                let updated = self.user_service.assign_roles(&u.id, &new_roles).await?;
54                Ok(PromoteResult::Promoted(updated, new_roles))
55            },
56            None => Ok(PromoteResult::UserNotFound),
57        }
58    }
59
60    pub async fn demote_from_admin(&self, user_identifier: &str) -> Result<DemoteResult> {
61        let user = self.find_user(user_identifier).await?;
62        let admin_role = UserRole::Admin.as_str();
63        let user_role = UserRole::User.as_str().to_string();
64
65        match user {
66            Some(u) => {
67                let current_roles = u.roles.clone();
68
69                if !current_roles.contains(&admin_role.to_string()) {
70                    return Ok(DemoteResult::NotAdmin(u));
71                }
72
73                let new_roles: Vec<String> = current_roles
74                    .into_iter()
75                    .filter(|r| r != admin_role)
76                    .collect();
77
78                let mut final_roles = new_roles;
79                if !final_roles.contains(&user_role) {
80                    final_roles.push(user_role);
81                }
82
83                let updated = self.user_service.assign_roles(&u.id, &final_roles).await?;
84                Ok(DemoteResult::Demoted(updated, final_roles))
85            },
86            None => Ok(DemoteResult::UserNotFound),
87        }
88    }
89}
90
91#[derive(Debug)]
92pub enum PromoteResult {
93    Promoted(User, Vec<String>),
94    AlreadyAdmin(User),
95    UserNotFound,
96}
97
98#[derive(Debug)]
99pub enum DemoteResult {
100    Demoted(User, Vec<String>),
101    NotAdmin(User),
102    UserNotFound,
103}