1use chrono::{DateTime, Utc};
2use rmcp::schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use utoipa::ToSchema;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
7#[serde(rename_all = "snake_case")]
8pub enum Visibility {
9 Public,
10 Private,
11}
12
13impl Visibility {
14 pub fn as_str(self) -> &'static str {
15 match self {
16 Self::Public => "public",
17 Self::Private => "private",
18 }
19 }
20}
21
22impl std::str::FromStr for Visibility {
23 type Err = anyhow::Error;
24
25 fn from_str(value: &str) -> Result<Self, Self::Err> {
26 match value {
27 "public" => Ok(Self::Public),
28 "private" => Ok(Self::Private),
29 other => Err(anyhow::anyhow!("unsupported visibility: {other}")),
30 }
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
35#[serde(rename_all = "snake_case")]
36pub enum MembershipRole {
37 Owner,
38 Maintainer,
39 Viewer,
40}
41
42impl MembershipRole {
43 pub fn as_str(self) -> &'static str {
44 match self {
45 Self::Owner => "owner",
46 Self::Maintainer => "maintainer",
47 Self::Viewer => "viewer",
48 }
49 }
50
51 pub fn rank(self) -> i16 {
52 match self {
53 Self::Viewer => 1,
54 Self::Maintainer => 2,
55 Self::Owner => 3,
56 }
57 }
58}
59
60impl std::str::FromStr for MembershipRole {
61 type Err = anyhow::Error;
62
63 fn from_str(value: &str) -> Result<Self, Self::Err> {
64 match value {
65 "owner" => Ok(Self::Owner),
66 "maintainer" => Ok(Self::Maintainer),
67 "viewer" => Ok(Self::Viewer),
68 other => Err(anyhow::anyhow!("unsupported membership role: {other}")),
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
74#[serde(rename_all = "snake_case")]
75pub enum GroupKind {
76 Personal,
77 Shared,
78}
79
80impl GroupKind {
81 pub fn as_str(self) -> &'static str {
82 match self {
83 Self::Personal => "personal",
84 Self::Shared => "shared",
85 }
86 }
87}
88
89impl std::str::FromStr for GroupKind {
90 type Err = anyhow::Error;
91
92 fn from_str(value: &str) -> Result<Self, Self::Err> {
93 match value {
94 "personal" => Ok(Self::Personal),
95 "shared" => Ok(Self::Shared),
96 other => Err(anyhow::anyhow!("unsupported group kind: {other}")),
97 }
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
102pub struct GroupResponse {
103 pub group_id: i64,
104 pub group_key: String,
105 #[serde(default, skip_serializing_if = "Option::is_none")]
106 pub parent_group_key: Option<String>,
107 pub name: String,
108 pub visibility: Visibility,
109 pub kind: GroupKind,
110 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub current_role: Option<MembershipRole>,
112 pub created_at: DateTime<Utc>,
113 pub updated_at: DateTime<Utc>,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
117pub struct ProjectResponse {
118 pub project_id: i64,
119 pub group_key: String,
120 pub project_key: String,
121 pub name: String,
122 pub visibility: Visibility,
123 #[serde(default, skip_serializing_if = "Option::is_none")]
124 pub current_role: Option<MembershipRole>,
125 pub created_at: DateTime<Utc>,
126 pub updated_at: DateTime<Utc>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
130pub struct GroupMemberResponse {
131 pub user_id: i64,
132 pub login_name: String,
133 pub display_name: String,
134 pub role: MembershipRole,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
138pub struct ProjectMemberResponse {
139 pub user_id: i64,
140 pub login_name: String,
141 pub display_name: String,
142 pub role: MembershipRole,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
146pub struct UserDirectoryEntryResponse {
147 pub user_id: i64,
148 pub login_name: String,
149 pub display_name: String,
150}