use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpUser {
pub id: u64,
pub username: String,
#[serde(default)]
pub email: Option<String>,
#[serde(default, rename = "profilePicture")]
pub profile_picture: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpTask {
pub id: String,
#[serde(default)]
pub custom_id: Option<String>,
pub name: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub text_content: Option<String>,
pub status: ClickUpStatus,
#[serde(default)]
pub priority: Option<ClickUpPriority>,
#[serde(default)]
pub tags: Vec<ClickUpTag>,
#[serde(default)]
pub assignees: Vec<ClickUpUser>,
#[serde(default)]
pub creator: Option<ClickUpUser>,
pub url: String,
#[serde(default)]
pub date_created: Option<String>,
#[serde(default)]
pub date_updated: Option<String>,
#[serde(default)]
pub parent: Option<String>,
#[serde(default)]
pub subtasks: Option<Vec<ClickUpTask>>,
#[serde(default)]
pub dependencies: Option<Vec<serde_json::Value>>,
#[serde(default)]
pub linked_tasks: Option<Vec<ClickUpLinkedTask>>,
#[serde(default)]
pub attachments: Vec<ClickUpAttachment>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpAttachment {
pub id: String,
#[serde(default)]
pub title: Option<String>,
#[serde(default)]
pub url: Option<String>,
#[serde(default)]
pub size: Option<serde_json::Value>,
#[serde(default)]
pub extension: Option<String>,
#[serde(default)]
pub mimetype: Option<String>,
#[serde(default)]
pub date: Option<String>,
#[serde(default)]
pub user: Option<ClickUpUser>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpStatus {
pub status: String,
#[serde(default, rename = "type")]
pub status_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpPriority {
pub id: String,
pub priority: String,
#[serde(default)]
pub color: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpTag {
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpLinkedTask {
pub task_id: String,
pub link_id: String,
#[serde(default)]
pub link_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpTaskList {
pub tasks: Vec<ClickUpTask>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpComment {
pub id: String,
pub comment_text: String,
#[serde(default)]
pub user: Option<ClickUpUser>,
#[serde(default)]
pub date: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClickUpCommentList {
pub comments: Vec<ClickUpComment>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ClickUpListStatus {
pub status: String,
#[serde(default, rename = "type")]
pub status_type: Option<String>,
#[serde(default)]
pub color: Option<String>,
#[serde(default)]
pub orderindex: Option<u32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ClickUpListInfo {
pub statuses: Vec<ClickUpListStatus>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ClickUpDependencyResponse {
#[serde(default)]
pub dependency: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ClickUpLinkResponse {
#[serde(default)]
pub link: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateTaskRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub markdown_content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub assignees: Option<Vec<u64>>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateTaskRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub markdown_content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateCommentRequest {
pub comment_text: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateCommentResponse {
#[serde(deserialize_with = "value_to_string")]
pub id: String,
#[serde(default, deserialize_with = "option_value_to_string")]
pub date: Option<String>,
}
fn value_to_string<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = serde_json::Value::deserialize(deserializer)?;
match value {
serde_json::Value::String(s) => Ok(s),
serde_json::Value::Number(n) => Ok(n.to_string()),
other => Ok(other.to_string()),
}
}
fn option_value_to_string<'de, D>(deserializer: D) -> std::result::Result<Option<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = Option::<serde_json::Value>::deserialize(deserializer)?;
Ok(value.map(|v| match v {
serde_json::Value::String(s) => s,
serde_json::Value::Number(n) => n.to_string(),
other => other.to_string(),
}))
}