Skip to main content

asana_cli/models/
user.rs

1//! User-centric data structures consumed by the CLI.
2
3use super::{project::MemberPermission, workspace::WorkspaceReference};
4use serde::{Deserialize, Serialize};
5
6/// Lightweight user reference returned by Asana APIs.
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
8pub struct UserReference {
9    /// Globally unique identifier.
10    pub gid: String,
11    /// Human friendly display name.
12    #[serde(default)]
13    pub name: Option<String>,
14    /// Resource type reported by Asana.
15    #[serde(default)]
16    pub resource_type: Option<String>,
17    /// Optional primary email address when included in the response.
18    #[serde(default)]
19    pub email: Option<String>,
20}
21
22impl UserReference {
23    /// Convenience helper displaying either the name or email.
24    #[must_use]
25    pub fn label(&self) -> String {
26        self.name
27            .clone()
28            .or_else(|| self.email.clone())
29            .unwrap_or_else(|| self.gid.clone())
30    }
31}
32
33/// Identity payload used when specifying members in API requests.
34#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
35pub struct UserIdentity {
36    /// Accept both email addresses and gids per Asana API contract.
37    pub resource: String,
38    /// Optional role/permission hint.
39    #[serde(default)]
40    pub role: Option<MemberPermission>,
41}
42
43/// User photo URLs at different sizes.
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45#[serde(rename_all = "snake_case")]
46#[allow(
47    clippy::struct_field_names,
48    reason = "field names mirror the Asana API JSON keys; renaming to satisfy the lint would break serde mapping"
49)]
50pub struct UserPhoto {
51    /// 21x21 pixel image URL.
52    #[serde(rename = "image_21x21")]
53    #[serde(default)]
54    pub image_21x21: Option<String>,
55    /// 27x27 pixel image URL.
56    #[serde(rename = "image_27x27")]
57    #[serde(default)]
58    pub image_27x27: Option<String>,
59    /// 36x36 pixel image URL.
60    #[serde(rename = "image_36x36")]
61    #[serde(default)]
62    pub image_36x36: Option<String>,
63    /// 60x60 pixel image URL.
64    #[serde(rename = "image_60x60")]
65    #[serde(default)]
66    pub image_60x60: Option<String>,
67    /// 128x128 pixel image URL.
68    #[serde(rename = "image_128x128")]
69    #[serde(default)]
70    pub image_128x128: Option<String>,
71}
72
73/// Full user payload.
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
75#[serde(rename_all = "snake_case")]
76pub struct User {
77    /// Globally unique identifier.
78    pub gid: String,
79    /// User's name.
80    pub name: String,
81    /// Email address.
82    #[serde(default)]
83    pub email: Option<String>,
84    /// Resource type marker.
85    #[serde(default)]
86    pub resource_type: Option<String>,
87    /// Photo URLs.
88    #[serde(default)]
89    pub photo: Option<UserPhoto>,
90    /// Workspaces user is member of.
91    #[serde(default)]
92    pub workspaces: Vec<WorkspaceReference>,
93}
94
95/// Parameters for listing users in a workspace.
96#[derive(Debug, Clone)]
97pub struct UserListParams {
98    /// Workspace identifier.
99    pub workspace_gid: String,
100    /// Maximum number to fetch.
101    pub limit: Option<usize>,
102}