systemprompt_users/services/user/
mod.rs1mod archive;
22mod bulk;
23mod merge;
24mod provider;
25
26use std::fmt;
27use std::sync::Arc;
28use systemprompt_identifiers::{SessionId, UserId};
29use systemprompt_traits::DynOwnerReassignment;
30
31use crate::error::Result;
32use crate::models::{User, UserActivity, UserRole, UserSession, UserStatus, UserWithSessions};
33use crate::repository::{PurgeCount, UpdateUserParams, UserRepository};
34
35#[derive(Clone)]
36pub struct UserService {
37 pub(super) repository: Arc<UserRepository>,
38 pub(super) owner_reassignments: Arc<[DynOwnerReassignment]>,
39}
40
41impl fmt::Debug for UserService {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 let domains: Vec<&str> = self
44 .owner_reassignments
45 .iter()
46 .map(|reassignment| reassignment.domain())
47 .collect();
48 f.debug_struct("UserService")
49 .field("repository", &self.repository)
50 .field("owner_reassignments", &domains)
51 .finish()
52 }
53}
54
55impl UserService {
56 pub fn new(repository: Arc<UserRepository>) -> Self {
57 Self {
58 repository,
59 owner_reassignments: Arc::from([]),
60 }
61 }
62
63 #[must_use]
64 pub fn with_owner_reassignments(mut self, reassignments: Vec<DynOwnerReassignment>) -> Self {
65 self.owner_reassignments = Arc::from(reassignments);
66 self
67 }
68
69 pub async fn find_by_id(&self, id: &UserId) -> Result<Option<User>> {
70 self.repository.find_by_id(id).await
71 }
72
73 pub async fn find_by_email(&self, email: &str) -> Result<Option<User>> {
74 self.repository.find_by_email(email).await
75 }
76
77 pub async fn find_by_name(&self, name: &str) -> Result<Option<User>> {
78 self.repository.find_by_name(name).await
79 }
80
81 pub async fn list_by_role(&self, role: UserRole) -> Result<Vec<User>> {
82 self.repository.list_by_role(role).await
83 }
84
85 pub async fn find_first_user(&self) -> Result<Option<User>> {
86 self.repository.find_first_user().await
87 }
88
89 pub async fn find_first_admin(&self) -> Result<Option<User>> {
90 self.repository.find_first_admin().await
91 }
92
93 pub async fn find_authenticated_user(&self, user_id: &UserId) -> Result<Option<User>> {
94 self.repository.find_authenticated_user(user_id).await
95 }
96
97 pub async fn find_with_sessions(&self, user_id: &UserId) -> Result<Option<UserWithSessions>> {
98 self.repository.find_with_sessions(user_id).await
99 }
100
101 pub async fn get_activity(&self, user_id: &UserId) -> Result<UserActivity> {
102 self.repository.get_activity(user_id).await
103 }
104
105 pub async fn list(&self, limit: i64, offset: i64) -> Result<Vec<User>> {
106 self.repository.list(limit, offset).await
107 }
108
109 pub async fn list_including_anonymous(&self, limit: i64, offset: i64) -> Result<Vec<User>> {
110 self.repository
111 .list_including_anonymous(limit, offset)
112 .await
113 }
114
115 pub async fn list_all(&self) -> Result<Vec<User>> {
116 self.repository.list_all().await
117 }
118
119 pub async fn search(&self, query: &str, limit: i64) -> Result<Vec<User>> {
120 self.repository.search(query, limit).await
121 }
122
123 pub async fn search_including_anonymous(&self, query: &str, limit: i64) -> Result<Vec<User>> {
124 self.repository
125 .search_including_anonymous(query, limit)
126 .await
127 }
128
129 pub async fn count(&self) -> Result<i64> {
130 self.repository.count().await
131 }
132
133 pub async fn count_including_anonymous(&self) -> Result<i64> {
134 self.repository.count_including_anonymous().await
135 }
136
137 pub async fn is_temporary_anonymous(&self, id: &UserId) -> Result<bool> {
138 self.repository.is_temporary_anonymous(id).await
139 }
140
141 pub async fn list_non_anonymous_with_sessions(
142 &self,
143 limit: i64,
144 ) -> Result<Vec<UserWithSessions>> {
145 self.repository
146 .list_non_anonymous_with_sessions(limit)
147 .await
148 }
149
150 pub async fn list_sessions(&self, user_id: &UserId) -> Result<Vec<UserSession>> {
151 self.repository.list_sessions(user_id).await
152 }
153
154 pub async fn list_active_sessions(&self, user_id: &UserId) -> Result<Vec<UserSession>> {
155 self.repository.list_active_sessions(user_id).await
156 }
157
158 pub async fn list_recent_sessions(
159 &self,
160 user_id: &UserId,
161 limit: i64,
162 ) -> Result<Vec<UserSession>> {
163 self.repository.list_recent_sessions(user_id, limit).await
164 }
165
166 pub async fn session_exists(&self, session_id: &SessionId) -> Result<bool> {
167 self.repository.session_exists(session_id).await
168 }
169
170 pub async fn end_session(&self, session_id: &SessionId) -> Result<bool> {
171 self.repository.end_session(session_id).await
172 }
173
174 pub async fn end_all_sessions(&self, user_id: &UserId) -> Result<u64> {
175 self.repository.end_all_sessions(user_id).await
176 }
177
178 pub async fn create(
179 &self,
180 name: &str,
181 email: &str,
182 full_name: Option<&str>,
183 display_name: Option<&str>,
184 ) -> Result<User> {
185 self.repository
186 .create(name, email, full_name, display_name)
187 .await
188 }
189
190 pub async fn create_if_absent(
191 &self,
192 name: &str,
193 email: &str,
194 full_name: Option<&str>,
195 display_name: Option<&str>,
196 ) -> Result<Option<User>> {
197 self.repository
198 .create_if_absent(name, email, full_name, display_name)
199 .await
200 }
201
202 pub async fn create_anonymous(&self, fingerprint: &str) -> Result<User> {
203 self.repository.create_anonymous(fingerprint).await
204 }
205
206 pub async fn find_or_create_federated(
207 &self,
208 issuer: &str,
209 external_sub: &str,
210 claims: &systemprompt_traits::FederatedIdentityClaims,
211 ) -> Result<User> {
212 self.repository
213 .find_or_create_federated(issuer, external_sub, claims)
214 .await
215 }
216
217 pub async fn update_email(&self, id: &UserId, email: &str) -> Result<User> {
218 self.repository.update_email(id, email).await
219 }
220
221 pub async fn update_full_name(&self, id: &UserId, full_name: &str) -> Result<User> {
222 self.repository.update_full_name(id, full_name).await
223 }
224
225 pub async fn update_status(&self, id: &UserId, status: UserStatus) -> Result<User> {
226 self.repository.update_status(id, status).await
227 }
228
229 pub async fn update_email_verified(&self, id: &UserId, verified: bool) -> Result<User> {
230 self.repository.update_email_verified(id, verified).await
231 }
232
233 pub async fn update_display_name(&self, id: &UserId, display_name: &str) -> Result<User> {
234 self.repository.update_display_name(id, display_name).await
235 }
236
237 pub async fn update_all_fields(
238 &self,
239 id: &UserId,
240 params: UpdateUserParams<'_>,
241 ) -> Result<User> {
242 self.repository.update_all_fields(id, params).await
243 }
244
245 pub async fn assign_roles(&self, id: &UserId, roles: &[String]) -> Result<User> {
246 self.repository.assign_roles(id, roles).await
247 }
248
249 pub async fn delete(&self, id: &UserId) -> Result<Vec<PurgeCount>> {
250 self.repository.delete(id).await
251 }
252
253 pub async fn purge_preview(&self, id: &UserId) -> Result<Vec<PurgeCount>> {
254 self.repository.purge_preview(id).await
255 }
256
257 pub async fn cleanup_old_anonymous(&self, days: i32) -> Result<u64> {
258 self.repository.cleanup_old_anonymous(days).await
259 }
260
261 pub async fn count_old_anonymous(&self, days: i32) -> Result<i64> {
262 self.repository.count_old_anonymous(days).await
263 }
264}