use serde::Serialize;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize)]
pub struct CreateTaskRequest {
pub data: CreateTaskData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct CreateTaskData {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub projects: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub assignee: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub due_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completed: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_fields: Option<HashMap<String, serde_json::Value>>,
}
impl CreateTaskData {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn workspace(mut self, workspace: impl Into<String>) -> Self {
self.workspace = Some(workspace.into());
self
}
pub fn projects(mut self, projects: Vec<String>) -> Self {
self.projects = Some(projects);
self
}
pub fn assignee(mut self, assignee: impl Into<String>) -> Self {
self.assignee = Some(assignee.into());
self
}
pub fn due_on(mut self, due_on: impl Into<String>) -> Self {
self.due_on = Some(due_on.into());
self
}
pub fn start_on(mut self, start_on: impl Into<String>) -> Self {
self.start_on = Some(start_on.into());
self
}
pub fn notes(mut self, notes: impl Into<String>) -> Self {
self.notes = Some(notes.into());
self
}
pub fn html_notes(mut self, html_notes: impl Into<String>) -> Self {
self.html_notes = Some(html_notes.into());
self
}
pub fn completed(mut self, completed: bool) -> Self {
self.completed = Some(completed);
self
}
pub fn custom_fields(mut self, custom_fields: HashMap<String, serde_json::Value>) -> Self {
self.custom_fields = Some(custom_fields);
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateTaskRequest {
pub data: UpdateTaskData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdateTaskData {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub assignee: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub due_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completed: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_fields: Option<HashMap<String, serde_json::Value>>,
}
impl UpdateTaskData {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn assignee(mut self, assignee: impl Into<String>) -> Self {
self.assignee = Some(assignee.into());
self
}
pub fn due_on(mut self, due_on: impl Into<String>) -> Self {
self.due_on = Some(due_on.into());
self
}
pub fn start_on(mut self, start_on: impl Into<String>) -> Self {
self.start_on = Some(start_on.into());
self
}
pub fn notes(mut self, notes: impl Into<String>) -> Self {
self.notes = Some(notes.into());
self
}
pub fn html_notes(mut self, html_notes: impl Into<String>) -> Self {
self.html_notes = Some(html_notes.into());
self
}
pub fn completed(mut self, completed: bool) -> Self {
self.completed = Some(completed);
self
}
pub fn custom_fields(mut self, custom_fields: HashMap<String, serde_json::Value>) -> Self {
self.custom_fields = Some(custom_fields);
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct AddProjectRequest {
pub data: AddProjectData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddProjectData {
pub project: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub section: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_after: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveProjectRequest {
pub data: RemoveProjectData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveProjectData {
pub project: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddTagRequest {
pub data: AddTagData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddTagData {
pub tag: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveTagRequest {
pub data: RemoveTagData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveTagData {
pub tag: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct SetParentRequest {
pub data: SetParentData,
}
#[derive(Debug, Clone, Serialize)]
pub struct SetParentData {
pub parent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_after: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddDependenciesRequest {
pub data: AddDependenciesData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddDependenciesData {
pub dependencies: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveDependenciesRequest {
pub data: RemoveDependenciesData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveDependenciesData {
pub dependencies: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddDependentsRequest {
pub data: AddDependentsData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddDependentsData {
pub dependents: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveDependentsRequest {
pub data: RemoveDependentsData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveDependentsData {
pub dependents: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddFollowersRequest {
pub data: AddFollowersData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddFollowersData {
pub followers: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveFollowersRequest {
pub data: RemoveFollowersData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveFollowersData {
pub followers: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateProjectRequest {
pub data: CreateProjectData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct CreateProjectData {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub team: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub due_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_view: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub privacy_setting: Option<String>,
}
impl CreateProjectData {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn workspace(mut self, workspace: impl Into<String>) -> Self {
self.workspace = Some(workspace.into());
self
}
pub fn team(mut self, team: impl Into<String>) -> Self {
self.team = Some(team.into());
self
}
pub fn color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn notes(mut self, notes: impl Into<String>) -> Self {
self.notes = Some(notes.into());
self
}
pub fn html_notes(mut self, html_notes: impl Into<String>) -> Self {
self.html_notes = Some(html_notes.into());
self
}
pub fn due_on(mut self, due_on: impl Into<String>) -> Self {
self.due_on = Some(due_on.into());
self
}
pub fn start_on(mut self, start_on: impl Into<String>) -> Self {
self.start_on = Some(start_on.into());
self
}
pub fn default_view(mut self, default_view: impl Into<String>) -> Self {
self.default_view = Some(default_view.into());
self
}
pub fn privacy_setting(mut self, privacy_setting: impl Into<String>) -> Self {
self.privacy_setting = Some(privacy_setting.into());
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateProjectRequest {
pub data: UpdateProjectData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdateProjectData {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_notes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub due_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub archived: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub privacy_setting: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_fields: Option<HashMap<String, serde_json::Value>>,
}
impl UpdateProjectData {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn notes(mut self, notes: impl Into<String>) -> Self {
self.notes = Some(notes.into());
self
}
pub fn html_notes(mut self, html_notes: impl Into<String>) -> Self {
self.html_notes = Some(html_notes.into());
self
}
pub fn due_on(mut self, due_on: impl Into<String>) -> Self {
self.due_on = Some(due_on.into());
self
}
pub fn start_on(mut self, start_on: impl Into<String>) -> Self {
self.start_on = Some(start_on.into());
self
}
pub fn archived(mut self, archived: bool) -> Self {
self.archived = Some(archived);
self
}
pub fn privacy_setting(mut self, privacy_setting: impl Into<String>) -> Self {
self.privacy_setting = Some(privacy_setting.into());
self
}
pub fn custom_fields(mut self, custom_fields: HashMap<String, serde_json::Value>) -> Self {
self.custom_fields = Some(custom_fields);
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct InstantiateProjectRequest {
pub data: InstantiateProjectData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct InstantiateProjectData {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub team: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub public: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub requested_dates: Option<Vec<DateVariable>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub requested_roles: Option<Vec<RoleAssignment>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct DateVariable {
pub gid: String,
pub value: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct RoleAssignment {
pub gid: String,
pub value: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddMembersRequest {
pub data: AddMembersData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddMembersData {
pub members: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveMembersRequest {
pub data: RemoveMembersData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveMembersData {
pub members: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreatePortfolioRequest {
pub data: CreatePortfolioData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct CreatePortfolioData {
pub name: String,
pub workspace: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub public: Option<bool>,
}
impl CreatePortfolioData {
pub fn new(name: impl Into<String>, workspace: impl Into<String>) -> Self {
Self {
name: name.into(),
workspace: workspace.into(),
..Default::default()
}
}
pub fn color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn public(mut self, public: bool) -> Self {
self.public = Some(public);
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdatePortfolioRequest {
pub data: UpdatePortfolioData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdatePortfolioData {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub public: Option<bool>,
}
impl UpdatePortfolioData {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn public(mut self, public: bool) -> Self {
self.public = Some(public);
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct AddItemRequest {
pub data: AddItemData,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddItemData {
pub item: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_after: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveItemRequest {
pub data: RemoveItemData,
}
#[derive(Debug, Clone, Serialize)]
pub struct RemoveItemData {
pub item: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateSectionRequest {
pub data: CreateSectionData,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateSectionData {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_after: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateSectionRequest {
pub data: UpdateSectionData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdateSectionData {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateStatusUpdateRequest {
pub data: CreateStatusUpdateData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct CreateStatusUpdateData {
pub parent: String,
pub status_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_text: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateStatusUpdateRequest {
pub data: UpdateStatusUpdateData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdateStatusUpdateData {
#[serde(skip_serializing_if = "Option::is_none")]
pub status_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_text: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateCommentRequest {
pub data: CreateCommentData,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateCommentData {
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_text: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateStoryRequest {
pub data: UpdateStoryData,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateStoryData {
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub html_text: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateTagRequest {
pub data: CreateTagData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct CreateTagData {
pub name: String,
pub workspace: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateTagRequest {
pub data: UpdateTagData,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdateTagData {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
}
#[derive(Debug, Clone, serde::Deserialize, Serialize)]
pub struct Job {
pub gid: String,
pub resource_type: String,
pub status: String,
pub new_project: Option<JobProject>,
}
#[derive(Debug, Clone, serde::Deserialize, Serialize)]
pub struct JobProject {
pub gid: String,
pub name: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_task_request_serialization() {
let request = CreateTaskRequest {
data: CreateTaskData {
name: Some("Test Task".to_string()),
workspace: Some("ws123".to_string()),
..Default::default()
},
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"name\":\"Test Task\""));
assert!(json.contains("\"workspace\":\"ws123\""));
}
#[test]
fn test_update_task_request_skips_none() {
let request = UpdateTaskRequest {
data: UpdateTaskData {
name: Some("Updated".to_string()),
..Default::default()
},
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"name\":\"Updated\""));
assert!(!json.contains("assignee"));
assert!(!json.contains("due_on"));
}
#[test]
fn test_add_project_request_serialization() {
let request = AddProjectRequest {
data: AddProjectData {
project: "proj123".to_string(),
section: Some("sect456".to_string()),
insert_before: None,
insert_after: None,
},
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"project\":\"proj123\""));
assert!(json.contains("\"section\":\"sect456\""));
}
#[test]
fn test_instantiate_project_request() {
let request = InstantiateProjectRequest {
data: InstantiateProjectData {
name: "New Project".to_string(),
team: Some("team123".to_string()),
requested_dates: Some(vec![DateVariable {
gid: "date1".to_string(),
value: "2024-12-31".to_string(),
}]),
..Default::default()
},
};
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"name\":\"New Project\""));
assert!(json.contains("\"requested_dates\""));
}
}