Skip to main content

systemprompt_users/services/user/
mod.rs

1mod provider;
2
3use std::collections::HashMap;
4use systemprompt_database::DbPool;
5use systemprompt_identifiers::{SessionId, UserId};
6
7use crate::error::Result;
8use crate::models::{
9    User, UserActivity, UserCountBreakdown, UserRole, UserSession, UserStats, UserStatus,
10    UserWithSessions,
11};
12use crate::repository::{MergeResult, UpdateUserParams, UserRepository};
13
14#[derive(Debug, Clone)]
15pub struct UserService {
16    repository: UserRepository,
17}
18
19impl UserService {
20    pub fn new(db: &DbPool) -> Result<Self> {
21        Ok(Self {
22            repository: UserRepository::new(db)?,
23        })
24    }
25
26    pub async fn find_by_id(&self, id: &UserId) -> Result<Option<User>> {
27        self.repository.find_by_id(id).await
28    }
29
30    pub async fn find_by_email(&self, email: &str) -> Result<Option<User>> {
31        self.repository.find_by_email(email).await
32    }
33
34    pub async fn find_by_name(&self, name: &str) -> Result<Option<User>> {
35        self.repository.find_by_name(name).await
36    }
37
38    pub async fn find_by_role(&self, role: UserRole) -> Result<Vec<User>> {
39        self.repository.find_by_role(role).await
40    }
41
42    pub async fn find_first_user(&self) -> Result<Option<User>> {
43        self.repository.find_first_user().await
44    }
45
46    pub async fn find_first_admin(&self) -> Result<Option<User>> {
47        self.repository.find_first_admin().await
48    }
49
50    pub async fn find_admin_owner(&self) -> Result<Option<User>> {
51        self.repository.find_admin_owner().await
52    }
53
54    pub async fn find_authenticated_user(&self, user_id: &UserId) -> Result<Option<User>> {
55        self.repository.find_authenticated_user(user_id).await
56    }
57
58    pub async fn find_with_sessions(&self, user_id: &UserId) -> Result<Option<UserWithSessions>> {
59        self.repository.find_with_sessions(user_id).await
60    }
61
62    pub async fn get_activity(&self, user_id: &UserId) -> Result<UserActivity> {
63        self.repository.get_activity(user_id).await
64    }
65
66    pub async fn list(&self, limit: i64, offset: i64) -> Result<Vec<User>> {
67        self.repository.list(limit, offset).await
68    }
69
70    pub async fn list_all(&self) -> Result<Vec<User>> {
71        self.repository.list_all().await
72    }
73
74    pub async fn search(&self, query: &str, limit: i64) -> Result<Vec<User>> {
75        self.repository.search(query, limit).await
76    }
77
78    pub async fn count(&self) -> Result<i64> {
79        self.repository.count().await
80    }
81
82    pub async fn is_temporary_anonymous(&self, id: &UserId) -> Result<bool> {
83        self.repository.is_temporary_anonymous(id).await
84    }
85
86    pub async fn list_non_anonymous_with_sessions(
87        &self,
88        limit: i64,
89    ) -> Result<Vec<UserWithSessions>> {
90        self.repository
91            .list_non_anonymous_with_sessions(limit)
92            .await
93    }
94
95    pub async fn list_sessions(&self, user_id: &UserId) -> Result<Vec<UserSession>> {
96        self.repository.list_sessions(user_id).await
97    }
98
99    pub async fn list_active_sessions(&self, user_id: &UserId) -> Result<Vec<UserSession>> {
100        self.repository.list_active_sessions(user_id).await
101    }
102
103    pub async fn list_recent_sessions(
104        &self,
105        user_id: &UserId,
106        limit: i64,
107    ) -> Result<Vec<UserSession>> {
108        self.repository.list_recent_sessions(user_id, limit).await
109    }
110
111    pub async fn session_exists(&self, session_id: &SessionId) -> Result<bool> {
112        self.repository.session_exists(session_id).await
113    }
114
115    pub async fn end_session(&self, session_id: &SessionId) -> Result<bool> {
116        self.repository.end_session(session_id).await
117    }
118
119    pub async fn end_all_sessions(&self, user_id: &UserId) -> Result<u64> {
120        self.repository.end_all_sessions(user_id).await
121    }
122
123    pub async fn create(
124        &self,
125        name: &str,
126        email: &str,
127        full_name: Option<&str>,
128        display_name: Option<&str>,
129    ) -> Result<User> {
130        self.repository
131            .create(name, email, full_name, display_name)
132            .await
133    }
134
135    pub async fn create_anonymous(&self, fingerprint: &str) -> Result<User> {
136        self.repository.create_anonymous(fingerprint).await
137    }
138
139    pub async fn find_or_create_federated(
140        &self,
141        issuer: &str,
142        external_sub: &str,
143        claims: &systemprompt_traits::FederatedIdentityClaims,
144    ) -> Result<User> {
145        self.repository
146            .find_or_create_federated(issuer, external_sub, claims)
147            .await
148    }
149
150    pub async fn update_email(&self, id: &UserId, email: &str) -> Result<User> {
151        self.repository.update_email(id, email).await
152    }
153
154    pub async fn update_full_name(&self, id: &UserId, full_name: &str) -> Result<User> {
155        self.repository.update_full_name(id, full_name).await
156    }
157
158    pub async fn update_status(&self, id: &UserId, status: UserStatus) -> Result<User> {
159        self.repository.update_status(id, status).await
160    }
161
162    pub async fn update_email_verified(&self, id: &UserId, verified: bool) -> Result<User> {
163        self.repository.update_email_verified(id, verified).await
164    }
165
166    pub async fn update_display_name(&self, id: &UserId, display_name: &str) -> Result<User> {
167        self.repository.update_display_name(id, display_name).await
168    }
169
170    pub async fn update_all_fields(
171        &self,
172        id: &UserId,
173        params: UpdateUserParams<'_>,
174    ) -> Result<User> {
175        self.repository.update_all_fields(id, params).await
176    }
177
178    pub async fn assign_roles(&self, id: &UserId, roles: &[String]) -> Result<User> {
179        self.repository.assign_roles(id, roles).await
180    }
181
182    pub async fn delete(&self, id: &UserId) -> Result<()> {
183        self.repository.delete(id).await
184    }
185
186    pub async fn cleanup_old_anonymous(&self, days: i32) -> Result<u64> {
187        self.repository.cleanup_old_anonymous(days).await
188    }
189
190    pub async fn count_with_breakdown(&self) -> Result<UserCountBreakdown> {
191        let total = self.repository.count().await?;
192        let by_status_vec = self.repository.count_by_status().await?;
193        let by_role_vec = self.repository.count_by_role().await?;
194
195        let by_status: HashMap<String, i64> = by_status_vec.into_iter().collect();
196        let by_role: HashMap<String, i64> = by_role_vec.into_iter().collect();
197
198        Ok(UserCountBreakdown {
199            total,
200            by_status,
201            by_role,
202        })
203    }
204
205    pub async fn get_stats(&self) -> Result<UserStats> {
206        self.repository.get_stats().await
207    }
208
209    pub async fn list_by_filter(
210        &self,
211        status: Option<&str>,
212        role: Option<&str>,
213        older_than_days: Option<i64>,
214        limit: i64,
215    ) -> Result<Vec<User>> {
216        self.repository
217            .list_by_filter(status, role, older_than_days, limit)
218            .await
219    }
220
221    pub async fn bulk_update_status(&self, user_ids: &[UserId], new_status: &str) -> Result<u64> {
222        self.repository
223            .bulk_update_status(user_ids, new_status)
224            .await
225    }
226
227    pub async fn bulk_delete(&self, user_ids: &[UserId]) -> Result<u64> {
228        self.repository.bulk_delete(user_ids).await
229    }
230
231    pub async fn merge_users(&self, source_id: &UserId, target_id: &UserId) -> Result<MergeResult> {
232        self.repository.merge_users(source_id, target_id).await
233    }
234}