systemprompt_users/services/user/
provider.rs1use std::str::FromStr;
7
8use async_trait::async_trait;
9use systemprompt_identifiers::UserId;
10use systemprompt_traits::auth::{
11 AuthProviderError, AuthResult, AuthUser, FederatedIdentityClaims, RoleProvider, UserProvider,
12};
13
14use super::UserService;
15use crate::models::{User, UserRole};
16
17impl From<User> for AuthUser {
18 fn from(user: User) -> Self {
19 let is_active = user.is_active();
20 Self {
21 id: user.id,
22 name: user.name,
23 email: user.email,
24 roles: user.roles,
25 is_active,
26 }
27 }
28}
29
30#[async_trait]
31impl UserProvider for UserService {
32 async fn find_by_id(&self, id: &UserId) -> AuthResult<Option<AuthUser>> {
33 self.find_by_id(id)
34 .await
35 .map(|opt| opt.map(AuthUser::from))
36 .map_err(|e| AuthProviderError::Internal(e.to_string()))
37 }
38
39 async fn find_by_email(&self, email: &str) -> AuthResult<Option<AuthUser>> {
40 Self::find_by_email(self, email)
41 .await
42 .map(|opt| opt.map(AuthUser::from))
43 .map_err(|e| AuthProviderError::Internal(e.to_string()))
44 }
45
46 async fn find_by_name(&self, name: &str) -> AuthResult<Option<AuthUser>> {
47 Self::find_by_name(self, name)
48 .await
49 .map(|opt| opt.map(AuthUser::from))
50 .map_err(|e| AuthProviderError::Internal(e.to_string()))
51 }
52
53 async fn create_user(
54 &self,
55 name: &str,
56 email: &str,
57 full_name: Option<&str>,
58 ) -> AuthResult<AuthUser> {
59 Self::create(self, name, email, full_name, full_name)
60 .await
61 .map(AuthUser::from)
62 .map_err(|e| AuthProviderError::Internal(e.to_string()))
63 }
64
65 async fn create_anonymous(&self, fingerprint: &str) -> AuthResult<AuthUser> {
66 Self::create_anonymous(self, fingerprint)
67 .await
68 .map(AuthUser::from)
69 .map_err(|e| AuthProviderError::Internal(e.to_string()))
70 }
71
72 async fn assign_roles(&self, user_id: &UserId, roles: &[String]) -> AuthResult<()> {
73 Self::assign_roles(self, user_id, roles)
74 .await
75 .map(|_| ())
76 .map_err(|e| AuthProviderError::Internal(e.to_string()))
77 }
78
79 async fn find_or_create_federated(
80 &self,
81 issuer: &str,
82 external_sub: &str,
83 claims: &FederatedIdentityClaims,
84 ) -> AuthResult<UserId> {
85 Self::find_or_create_federated(self, issuer, external_sub, claims)
86 .await
87 .map(|u| u.id)
88 .map_err(|e| AuthProviderError::Internal(e.to_string()))
89 }
90
91 async fn promote_anonymous(&self, source: &UserId, target: &UserId) -> AuthResult<u64> {
92 Self::promote_anonymous(self, source, target)
93 .await
94 .map(|result| result.total_rows)
95 .map_err(|e| AuthProviderError::Internal(e.to_string()))
96 }
97}
98
99#[async_trait]
100impl RoleProvider for UserService {
101 async fn get_roles(&self, user_id: &UserId) -> AuthResult<Vec<String>> {
102 match Self::find_by_id(self, user_id).await {
103 Ok(Some(user)) => Ok(user.roles),
104 Ok(None) => Err(AuthProviderError::UserNotFound),
105 Err(e) => Err(AuthProviderError::Internal(e.to_string())),
106 }
107 }
108
109 async fn assign_role(&self, user_id: &UserId, role: &str) -> AuthResult<()> {
110 let user = match Self::find_by_id(self, user_id).await {
111 Ok(Some(u)) => u,
112 Ok(None) => return Err(AuthProviderError::UserNotFound),
113 Err(e) => return Err(AuthProviderError::Internal(e.to_string())),
114 };
115
116 let mut roles = user.roles;
117 let role_str = role.to_owned();
118 if !roles.contains(&role_str) {
119 roles.push(role_str);
120 }
121
122 Self::assign_roles(self, user_id, &roles)
123 .await
124 .map(|_| ())
125 .map_err(|e| AuthProviderError::Internal(e.to_string()))
126 }
127
128 async fn revoke_role(&self, user_id: &UserId, role: &str) -> AuthResult<()> {
129 let user = match Self::find_by_id(self, user_id).await {
130 Ok(Some(u)) => u,
131 Ok(None) => return Err(AuthProviderError::UserNotFound),
132 Err(e) => return Err(AuthProviderError::Internal(e.to_string())),
133 };
134
135 let roles: Vec<String> = user.roles.into_iter().filter(|r| r != role).collect();
136
137 Self::assign_roles(self, user_id, &roles)
138 .await
139 .map(|_| ())
140 .map_err(|e| AuthProviderError::Internal(e.to_string()))
141 }
142
143 async fn list_users_by_role(&self, role: &str) -> AuthResult<Vec<AuthUser>> {
144 let Ok(user_role) = UserRole::from_str(role) else {
145 return Ok(vec![]);
146 };
147
148 Self::find_by_role(self, user_role)
149 .await
150 .map(|users| users.into_iter().map(AuthUser::from).collect())
151 .map_err(|e| AuthProviderError::Internal(e.to_string()))
152 }
153}