Skip to main content

uptrakit_web_api_types/
users.rs

1use crate::permissions::Permission;
2use crate::validation::{Validate, ValidationError};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// A user with their assigned roles and resolved permissions.
7#[derive(Serialize, Deserialize, Clone)]
8#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
9pub struct UserWithRolesResponse {
10    pub id: Uuid,
11    pub email: String,
12    pub first_name: String,
13    pub last_name: String,
14    pub is_active: bool,
15    pub roles: Vec<UserRoleSummary>,
16    pub permissions: Vec<Permission>,
17}
18
19/// Summary of a role assigned to a user.
20#[derive(Serialize, Deserialize, Clone)]
21#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
22pub struct UserRoleSummary {
23    pub id: Uuid,
24    pub name: String,
25}
26
27/// Request to replace a user's roles.
28#[derive(Serialize, Deserialize)]
29#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
30pub struct UpdateUserRolesRequest {
31    /// List of role IDs to assign. Replaces all existing role assignments.
32    pub role_ids: Vec<Uuid>,
33}
34
35impl Validate for UpdateUserRolesRequest {
36    fn validate(&self) -> Result<(), ValidationError> {
37        if self.role_ids.is_empty() {
38            return Err(ValidationError {
39                field: "role_ids",
40                message: "at least one role must be assigned".to_string(),
41            });
42        }
43        if self.role_ids.len() > 20 {
44            return Err(ValidationError {
45                field: "role_ids",
46                message: "cannot assign more than 20 roles".to_string(),
47            });
48        }
49        Ok(())
50    }
51}
52
53/// Request to activate or deactivate a user.
54#[derive(Serialize, Deserialize)]
55#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
56pub struct UpdateUserActiveRequest {
57    pub is_active: bool,
58}
59
60/// Request to apply an access preset to a user.
61#[derive(Serialize, Deserialize)]
62#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
63pub struct ApplyPresetRequest {
64    /// The access preset name to apply.
65    pub preset: String,
66}
67
68impl Validate for ApplyPresetRequest {
69    fn validate(&self) -> Result<(), ValidationError> {
70        if self.preset.is_empty() {
71            return Err(ValidationError {
72                field: "preset",
73                message: "preset name must not be empty".to_string(),
74            });
75        }
76        Ok(())
77    }
78}