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