Skip to main content

systemprompt_users/services/user/
provider.rs

1//! `UserProvider` implementation over `UserService`.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use 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
92#[async_trait]
93impl RoleProvider for UserService {
94    async fn get_roles(&self, user_id: &UserId) -> AuthResult<Vec<String>> {
95        match Self::find_by_id(self, user_id).await {
96            Ok(Some(user)) => Ok(user.roles),
97            Ok(None) => Err(AuthProviderError::UserNotFound),
98            Err(e) => Err(AuthProviderError::Internal(e.to_string())),
99        }
100    }
101
102    async fn assign_role(&self, user_id: &UserId, role: &str) -> AuthResult<()> {
103        let user = match Self::find_by_id(self, user_id).await {
104            Ok(Some(u)) => u,
105            Ok(None) => return Err(AuthProviderError::UserNotFound),
106            Err(e) => return Err(AuthProviderError::Internal(e.to_string())),
107        };
108
109        let mut roles = user.roles;
110        let role_str = role.to_owned();
111        if !roles.contains(&role_str) {
112            roles.push(role_str);
113        }
114
115        Self::assign_roles(self, user_id, &roles)
116            .await
117            .map(|_| ())
118            .map_err(|e| AuthProviderError::Internal(e.to_string()))
119    }
120
121    async fn revoke_role(&self, user_id: &UserId, role: &str) -> AuthResult<()> {
122        let user = match Self::find_by_id(self, user_id).await {
123            Ok(Some(u)) => u,
124            Ok(None) => return Err(AuthProviderError::UserNotFound),
125            Err(e) => return Err(AuthProviderError::Internal(e.to_string())),
126        };
127
128        let roles: Vec<String> = user.roles.into_iter().filter(|r| r != role).collect();
129
130        Self::assign_roles(self, user_id, &roles)
131            .await
132            .map(|_| ())
133            .map_err(|e| AuthProviderError::Internal(e.to_string()))
134    }
135
136    async fn list_users_by_role(&self, role: &str) -> AuthResult<Vec<AuthUser>> {
137        let Ok(user_role) = UserRole::from_str(role) else {
138            return Ok(vec![]);
139        };
140
141        Self::find_by_role(self, user_role)
142            .await
143            .map(|users| users.into_iter().map(AuthUser::from).collect())
144            .map_err(|e| AuthProviderError::Internal(e.to_string()))
145    }
146}