Skip to main content

context69_contracts/
namespace.rs

1use chrono::{DateTime, Utc};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use utoipa::{IntoParams, ToSchema};
5
6use crate::Pagination;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
9#[serde(rename_all = "snake_case")]
10pub enum Visibility {
11    Public,
12    Private,
13}
14
15impl Visibility {
16    pub fn as_str(self) -> &'static str {
17        match self {
18            Self::Public => "public",
19            Self::Private => "private",
20        }
21    }
22}
23
24impl std::str::FromStr for Visibility {
25    type Err = anyhow::Error;
26
27    fn from_str(value: &str) -> Result<Self, Self::Err> {
28        match value {
29            "public" => Ok(Self::Public),
30            "private" => Ok(Self::Private),
31            other => Err(anyhow::anyhow!("unsupported visibility: {other}")),
32        }
33    }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
37#[serde(rename_all = "snake_case")]
38pub enum MembershipRole {
39    Owner,
40    Maintainer,
41    Viewer,
42}
43
44impl MembershipRole {
45    pub fn as_str(self) -> &'static str {
46        match self {
47            Self::Owner => "owner",
48            Self::Maintainer => "maintainer",
49            Self::Viewer => "viewer",
50        }
51    }
52
53    pub fn rank(self) -> i16 {
54        match self {
55            Self::Viewer => 1,
56            Self::Maintainer => 2,
57            Self::Owner => 3,
58        }
59    }
60}
61
62impl std::str::FromStr for MembershipRole {
63    type Err = anyhow::Error;
64
65    fn from_str(value: &str) -> Result<Self, Self::Err> {
66        match value {
67            "owner" => Ok(Self::Owner),
68            "maintainer" => Ok(Self::Maintainer),
69            "viewer" => Ok(Self::Viewer),
70            other => Err(anyhow::anyhow!("unsupported membership role: {other}")),
71        }
72    }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
76#[serde(rename_all = "snake_case")]
77pub enum GroupKind {
78    Personal,
79    Shared,
80}
81
82impl GroupKind {
83    pub fn as_str(self) -> &'static str {
84        match self {
85            Self::Personal => "personal",
86            Self::Shared => "shared",
87        }
88    }
89}
90
91impl std::str::FromStr for GroupKind {
92    type Err = anyhow::Error;
93
94    fn from_str(value: &str) -> Result<Self, Self::Err> {
95        match value {
96            "personal" => Ok(Self::Personal),
97            "shared" => Ok(Self::Shared),
98            other => Err(anyhow::anyhow!("unsupported group kind: {other}")),
99        }
100    }
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
104pub struct CreateGroupRequest {
105    #[serde(default, skip_serializing_if = "Option::is_none")]
106    pub parent_group_path: Option<String>,
107    pub group_key: String,
108    pub name: String,
109    pub visibility: Visibility,
110    #[serde(default)]
111    pub kind: Option<GroupKind>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
115pub struct UpdateGroupRequest {
116    #[serde(default, skip_serializing_if = "Option::is_none")]
117    pub name: Option<String>,
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub visibility: Option<Visibility>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
123pub struct MoveGroupRequest {
124    #[serde(default, skip_serializing_if = "Option::is_none")]
125    pub target_parent_group_path: Option<String>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
129pub struct UpsertMembershipRequest {
130    pub login_name: String,
131    pub role: MembershipRole,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
135pub struct GroupResponse {
136    pub group_id: i64,
137    pub group_key: String,
138    #[serde(default, skip_serializing_if = "Option::is_none")]
139    pub group_path: Option<String>,
140    #[serde(default, skip_serializing_if = "Option::is_none")]
141    pub parent_group_path: Option<String>,
142    pub name: String,
143    pub visibility: Visibility,
144    pub kind: GroupKind,
145    #[serde(default, skip_serializing_if = "Option::is_none")]
146    pub current_role: Option<MembershipRole>,
147    pub created_at: DateTime<Utc>,
148    pub updated_at: DateTime<Utc>,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
152pub struct GroupMemberResponse {
153    pub user_id: i64,
154    pub login_name: String,
155    pub display_name: String,
156    pub role: MembershipRole,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
160pub struct UserDirectoryEntryResponse {
161    pub user_id: i64,
162    pub login_name: String,
163    pub display_name: String,
164}
165
166fn default_page() -> u32 {
167    1
168}
169fn default_page_size() -> u32 {
170    50
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize, IntoParams, ToSchema)]
174#[into_params(parameter_in = Query)]
175pub struct NamespacePageQuery {
176    #[serde(default = "default_page")]
177    pub page: u32,
178    #[serde(default = "default_page_size")]
179    pub page_size: u32,
180    #[serde(default)]
181    pub query: Option<String>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
185pub struct GroupPageResponse {
186    pub items: Vec<GroupResponse>,
187    pub pagination: Pagination,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
191pub struct GroupMemberPageResponse {
192    pub items: Vec<GroupMemberResponse>,
193    pub pagination: Pagination,
194}
195
196#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
197#[into_params(parameter_in = Query)]
198pub struct GroupSearchQuery {
199    #[serde(default)]
200    pub query: String,
201    #[serde(default = "default_search_limit")]
202    pub limit: u32,
203}
204
205const fn default_search_limit() -> u32 {
206    20
207}