uptrakit_web_api_types/
users.rs1use crate::validation::{Validate, ValidationError};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Serialize, Deserialize, Clone)]
7#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
8pub struct UserWithRolesResponse {
9 pub id: Uuid,
10 pub email: String,
11 pub first_name: String,
12 pub last_name: String,
13 pub is_active: bool,
14 pub roles: Vec<UserRoleSummary>,
15}
16
17#[derive(Serialize, Deserialize, Clone)]
19#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
20pub struct UserRoleSummary {
21 pub id: Uuid,
22 pub name: String,
23}
24
25#[derive(Serialize, Deserialize)]
27#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
28pub struct UpdateUserRolesRequest {
29 pub role_ids: Vec<Uuid>,
31}
32
33impl Validate for UpdateUserRolesRequest {
34 fn validate(&self) -> Result<(), ValidationError> {
35 if self.role_ids.is_empty() {
36 return Err(ValidationError {
37 field: "role_ids",
38 message: "at least one role must be assigned".to_string(),
39 });
40 }
41 if self.role_ids.len() > 20 {
42 return Err(ValidationError {
43 field: "role_ids",
44 message: "cannot assign more than 20 roles".to_string(),
45 });
46 }
47 Ok(())
48 }
49}
50
51#[derive(Serialize, Deserialize)]
53#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
54pub struct UpdateUserActiveRequest {
55 pub is_active: bool,
56}
57
58impl Validate for UpdateUserActiveRequest {
59 fn validate(&self) -> Result<(), ValidationError> {
60 Ok(())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 #![expect(
68 clippy::assertions_on_result_states,
69 reason = "test assertions — is_ok/is_err provides readable failure messages"
70 )]
71 use super::*;
72
73 #[test]
74 fn update_user_active_validate_is_ok() {
75 assert!(
76 UpdateUserActiveRequest { is_active: false }
77 .validate()
78 .is_ok()
79 );
80 }
81}