1use crate::client::RestClient;
12use crate::error::Result;
13use serde::{Deserialize, Serialize};
14use serde_json::Value;
15use std::collections::BTreeMap;
16use typed_builder::TypedBuilder;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20#[non_exhaustive]
21pub struct User {
22 pub uid: u32,
24 pub email: String,
26 pub name: Option<String>,
28 pub role: String,
30 pub status: Option<String>,
32 pub auth_method: Option<String>,
34 pub certificate_subject_line: Option<String>,
36 pub password_issue_date: Option<String>,
38 pub email_alerts: Option<bool>,
40 pub role_uids: Option<Vec<u32>>,
42 pub bdbs: Option<Vec<u32>>,
44 pub alert_audit_db_conns: Option<bool>,
46 pub alert_bdb_backup: Option<bool>,
48 pub alert_bdb_crdt_src_syncer: Option<bool>,
50 pub password_expiration_duration: Option<u32>,
52 pub last_login: Option<u64>,
54 #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
56 pub additional_fields: BTreeMap<String, Value>,
57}
58
59#[derive(Debug, Serialize, TypedBuilder)]
75pub struct CreateUserRequest {
76 #[builder(setter(into))]
78 pub email: String,
79 #[builder(setter(into))]
81 pub password: String,
82 #[serde(skip_serializing_if = "Option::is_none")]
85 #[builder(default, setter(into, strip_option))]
86 pub role: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 #[builder(default, setter(into, strip_option))]
90 pub name: Option<String>,
91 #[serde(skip_serializing_if = "Option::is_none")]
93 #[builder(default, setter(strip_option))]
94 pub email_alerts: Option<bool>,
95 #[serde(skip_serializing_if = "Option::is_none")]
97 #[builder(default, setter(strip_option))]
98 pub bdbs_email_alerts: Option<Vec<String>>,
99 #[serde(skip_serializing_if = "Option::is_none")]
102 #[builder(default, setter(strip_option))]
103 pub role_uids: Option<Vec<u32>>,
104 #[serde(skip_serializing_if = "Option::is_none")]
106 #[builder(default, setter(into, strip_option))]
107 pub auth_method: Option<String>,
108}
109
110#[derive(Debug, Serialize, TypedBuilder)]
123pub struct UpdateUserRequest {
124 #[serde(skip_serializing_if = "Option::is_none")]
126 #[builder(default, setter(into, strip_option))]
127 pub password: Option<String>,
128 #[serde(skip_serializing_if = "Option::is_none")]
130 #[builder(default, setter(into, strip_option))]
131 pub role: Option<String>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 #[builder(default, setter(into, strip_option))]
135 pub email: Option<String>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 #[builder(default, setter(into, strip_option))]
139 pub name: Option<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 #[builder(default, setter(strip_option))]
143 pub email_alerts: Option<bool>,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 #[builder(default, setter(strip_option))]
147 pub bdbs_email_alerts: Option<Vec<String>>,
148 #[serde(skip_serializing_if = "Option::is_none")]
150 #[builder(default, setter(strip_option))]
151 pub role_uids: Option<Vec<u32>>,
152 #[serde(skip_serializing_if = "Option::is_none")]
154 #[builder(default, setter(into, strip_option))]
155 pub auth_method: Option<String>,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct Role {
161 pub uid: u32,
163 pub name: String,
165 pub management: Option<String>,
167 pub data_access: Option<String>,
169}
170
171pub struct UserHandler {
173 client: RestClient,
174}
175
176pub type UsersHandler = UserHandler;
178
179impl UserHandler {
180 pub fn new(client: RestClient) -> Self {
182 UserHandler { client }
183 }
184
185 pub async fn list(&self) -> Result<Vec<User>> {
187 self.client.get("/v1/users").await
188 }
189
190 pub async fn get(&self, uid: u32) -> Result<User> {
192 self.client.get(&format!("/v1/users/{}", uid)).await
193 }
194
195 pub async fn create(&self, request: CreateUserRequest) -> Result<User> {
197 let has_role = request
198 .role
199 .as_deref()
200 .map(|role| !role.trim().is_empty())
201 .unwrap_or(false);
202 let has_role_uids = request
203 .role_uids
204 .as_ref()
205 .map(|role_uids| !role_uids.is_empty())
206 .unwrap_or(false);
207
208 if has_role == has_role_uids {
209 return Err(crate::error::RestError::ValidationError(
210 "CreateUserRequest must include exactly one of role or role_uids".to_string(),
211 ));
212 }
213
214 self.client.post("/v1/users", &request).await
215 }
216
217 pub async fn update(&self, uid: u32, request: UpdateUserRequest) -> Result<User> {
219 self.client
220 .put(&format!("/v1/users/{}", uid), &request)
221 .await
222 }
223
224 pub async fn delete(&self, uid: u32) -> Result<()> {
226 self.client.delete(&format!("/v1/users/{}", uid)).await
227 }
228
229 pub async fn permissions(&self) -> Result<Value> {
231 self.client.get("/v1/users/permissions").await
232 }
233
234 pub async fn permission_detail(&self, perm: &str) -> Result<Value> {
236 self.client
237 .get(&format!("/v1/users/permissions/{}", perm))
238 .await
239 }
240
241 pub async fn authorize(&self, body: AuthRequest) -> Result<AuthResponse> {
243 self.client.post("/v1/users/authorize", &body).await
244 }
245
246 pub async fn password_set(&self, body: PasswordSet) -> Result<()> {
248 self.client.post_action("/v1/users/password", &body).await
249 }
250
251 pub async fn password_update(&self, body: PasswordUpdate) -> Result<()> {
253 self.client.put("/v1/users/password", &body).await
254 }
255
256 pub async fn password_delete(&self) -> Result<()> {
258 self.client.delete("/v1/users/password").await
259 }
260
261 pub async fn refresh_jwt(&self, body: JwtRefreshRequest) -> Result<JwtRefreshResponse> {
263 self.client.post("/v1/users/refresh_jwt", &body).await
264 }
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct AuthRequest {
270 pub email: String,
272 pub password: String,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct AuthResponse {
279 pub jwt: String,
281 #[serde(skip_serializing_if = "Option::is_none")]
283 pub expires_at: Option<String>,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct PasswordSet {
289 pub email: String,
291 pub password: String,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct PasswordUpdate {
298 #[serde(skip_serializing_if = "Option::is_none")]
300 pub current_password: Option<String>,
301 pub new_password: String,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct JwtRefreshRequest {
308 pub jwt: String,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
314pub struct JwtRefreshResponse {
315 pub jwt: String,
317 #[serde(skip_serializing_if = "Option::is_none")]
319 pub expires_at: Option<String>,
320}
321
322pub struct RoleHandler {
324 client: RestClient,
325}
326
327impl RoleHandler {
328 pub fn new(client: RestClient) -> Self {
330 RoleHandler { client }
331 }
332
333 pub async fn list(&self) -> Result<Vec<Role>> {
335 self.client.get("/v1/roles").await
336 }
337
338 pub async fn get(&self, uid: u32) -> Result<Role> {
340 self.client.get(&format!("/v1/roles/{}", uid)).await
341 }
342}