1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct ClickUpUser {
14 pub id: u64,
15 pub username: String,
16 #[serde(default)]
17 pub email: Option<String>,
18 #[serde(default, rename = "profilePicture")]
19 pub profile_picture: Option<String>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct ClickUpTask {
28 pub id: String,
29 #[serde(default)]
30 pub custom_id: Option<String>,
31 pub name: String,
32 #[serde(default)]
33 pub description: Option<String>,
34 #[serde(default)]
35 pub text_content: Option<String>,
36 pub status: ClickUpStatus,
37 #[serde(default)]
38 pub priority: Option<ClickUpPriority>,
39 #[serde(default)]
40 pub tags: Vec<ClickUpTag>,
41 #[serde(default)]
42 pub assignees: Vec<ClickUpUser>,
43 #[serde(default)]
44 pub creator: Option<ClickUpUser>,
45 pub url: String,
46 #[serde(default)]
47 pub date_created: Option<String>,
48 #[serde(default)]
49 pub date_updated: Option<String>,
50 #[serde(default)]
51 pub parent: Option<String>,
52 #[serde(default)]
53 pub subtasks: Option<Vec<ClickUpTask>>,
54 #[serde(default)]
57 pub dependencies: Option<Vec<serde_json::Value>>,
58 #[serde(default)]
60 pub linked_tasks: Option<Vec<ClickUpLinkedTask>>,
61 #[serde(default)]
66 pub attachments: Vec<ClickUpAttachment>,
67 #[serde(default)]
73 pub custom_fields: Vec<ClickUpCustomField>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct ClickUpCustomField {
79 pub id: String,
80 #[serde(default)]
81 pub name: Option<String>,
82 #[serde(default, rename = "type")]
85 pub field_type: Option<String>,
86 #[serde(default)]
89 pub value: Option<serde_json::Value>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ClickUpAttachment {
95 pub id: String,
96 #[serde(default)]
97 pub title: Option<String>,
98 #[serde(default)]
100 pub url: Option<String>,
101 #[serde(default)]
103 pub size: Option<serde_json::Value>,
104 #[serde(default)]
106 pub extension: Option<String>,
107 #[serde(default)]
108 pub mimetype: Option<String>,
109 #[serde(default)]
111 pub date: Option<String>,
112 #[serde(default)]
114 pub user: Option<ClickUpUser>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct ClickUpStatus {
120 pub status: String,
121 #[serde(default, rename = "type")]
122 pub status_type: Option<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct ClickUpPriority {
128 pub id: String,
129 pub priority: String,
130 #[serde(default)]
131 pub color: Option<String>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct ClickUpTag {
136 pub name: String,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct ClickUpLinkedTask {
142 pub task_id: String,
143 pub link_id: String,
144 #[serde(default)]
146 pub link_type: Option<String>,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ClickUpTaskList {
156 pub tasks: Vec<ClickUpTask>,
157}
158
159#[derive(Debug, Clone, Deserialize)]
166pub struct ClickUpTeamsResponse {
167 #[serde(default)]
168 pub teams: Vec<ClickUpTeam>,
169}
170
171#[derive(Debug, Clone, Deserialize)]
172pub struct ClickUpTeam {
173 pub id: String,
174 #[serde(default)]
175 pub members: Vec<ClickUpTeamMember>,
176}
177
178#[derive(Debug, Clone, Deserialize)]
179pub struct ClickUpTeamMember {
180 pub user: ClickUpUser,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct ClickUpComment {
189 pub id: String,
190 pub comment_text: String,
191 #[serde(default)]
192 pub user: Option<ClickUpUser>,
193 #[serde(default)]
194 pub date: Option<String>,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct ClickUpCommentList {
200 pub comments: Vec<ClickUpComment>,
201}
202
203#[derive(Debug, Clone, Deserialize)]
209pub struct ClickUpListStatus {
210 pub status: String,
211 #[serde(default, rename = "type")]
212 pub status_type: Option<String>,
213 #[serde(default)]
214 pub color: Option<String>,
215 #[serde(default)]
216 pub orderindex: Option<u32>,
217}
218
219#[derive(Debug, Clone, Deserialize)]
221pub struct ClickUpListInfo {
222 pub statuses: Vec<ClickUpListStatus>,
223}
224
225#[derive(Debug, Clone, Deserialize)]
227pub struct ClickUpDependencyResponse {
228 #[serde(default)]
229 pub dependency: Option<serde_json::Value>,
230}
231
232#[derive(Debug, Clone, Deserialize)]
234pub struct ClickUpLinkResponse {
235 #[serde(default)]
236 pub link: Option<serde_json::Value>,
237}
238
239#[derive(Debug, Clone, Serialize)]
244pub struct CreateTaskRequest {
245 pub name: String,
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub description: Option<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub markdown_content: Option<String>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub parent: Option<String>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub status: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub priority: Option<u8>,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub tags: Option<Vec<String>>,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub assignees: Option<Vec<u64>>,
260}
261
262#[derive(Debug, Clone, Serialize, Default)]
263pub struct UpdateTaskRequest {
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub name: Option<String>,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 pub description: Option<String>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub markdown_content: Option<String>,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub status: Option<String>,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub priority: Option<u8>,
274 #[serde(skip_serializing_if = "Option::is_none")]
275 pub parent: Option<String>,
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub tags: Option<Vec<String>>,
278 #[serde(skip_serializing_if = "Option::is_none")]
283 pub assignees: Option<AssigneeDiff>,
284}
285
286#[derive(Debug, Clone, Default, Serialize)]
289pub struct AssigneeDiff {
290 #[serde(skip_serializing_if = "Vec::is_empty")]
291 pub add: Vec<u64>,
292 #[serde(skip_serializing_if = "Vec::is_empty")]
293 pub rem: Vec<u64>,
294}
295
296#[derive(Debug, Clone, Serialize)]
297pub struct CreateCommentRequest {
298 pub comment_text: String,
299}
300
301#[derive(Debug, Clone, Deserialize)]
304pub struct CreateCommentResponse {
305 #[serde(deserialize_with = "value_to_string")]
306 pub id: String,
307 #[serde(default, deserialize_with = "option_value_to_string")]
308 pub date: Option<String>,
309}
310
311fn value_to_string<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
313where
314 D: serde::Deserializer<'de>,
315{
316 let value = serde_json::Value::deserialize(deserializer)?;
317 match value {
318 serde_json::Value::String(s) => Ok(s),
319 serde_json::Value::Number(n) => Ok(n.to_string()),
320 other => Ok(other.to_string()),
321 }
322}
323
324fn option_value_to_string<'de, D>(deserializer: D) -> std::result::Result<Option<String>, D::Error>
326where
327 D: serde::Deserializer<'de>,
328{
329 let value = Option::<serde_json::Value>::deserialize(deserializer)?;
330 Ok(value.map(|v| match v {
331 serde_json::Value::String(s) => s,
332 serde_json::Value::Number(n) => n.to_string(),
333 other => other.to_string(),
334 }))
335}