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