Skip to main content

things_mcp/core/writer/operation/
mod.rs

1//! `Operation` — typed write operations, each capable of rendering itself
2//! as a single Things JSON URL operation element.
3
4pub mod add_project;
5pub mod add_todo;
6pub mod bulk;
7pub mod move_todo;
8pub mod status_change;
9pub mod update_project;
10pub mod update_todo;
11
12pub use add_project::AddProjectSpec;
13pub use add_todo::AddTodoSpec;
14pub use bulk::BulkRawSpec;
15pub use move_todo::MoveTodoSpec;
16pub use update_project::UpdateProjectSpec;
17pub use update_todo::UpdateTodoSpec;
18
19use serde::{Deserialize, Serialize};
20use serde_json::Value;
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub enum Operation {
24    AddTodo(AddTodoSpec),
25    AddProject(AddProjectSpec),
26    UpdateTodo(UpdateTodoSpec),
27    UpdateProject(UpdateProjectSpec),
28    CompleteTodo { id: String },
29    CancelTodo { id: String },
30    MoveTodo(MoveTodoSpec),
31    BulkRaw(BulkRawSpec),
32}
33
34impl Operation {
35    pub fn action_name(&self) -> &'static str {
36        match self {
37            Operation::AddTodo(_) => "add_todo",
38            Operation::AddProject(_) => "add_project",
39            Operation::UpdateTodo(_) => "update_todo",
40            Operation::UpdateProject(_) => "update_project",
41            Operation::CompleteTodo { .. } => "complete_todo",
42            Operation::CancelTodo { .. } => "cancel_todo",
43            Operation::MoveTodo(_) => "move_todo",
44            Operation::BulkRaw(_) => "bulk_json",
45        }
46    }
47
48    pub fn requires_auth_token(&self) -> bool {
49        match self {
50            Operation::AddTodo(_) => false,
51            Operation::AddProject(_) => false,
52            Operation::UpdateTodo(_) => true,
53            Operation::UpdateProject(_) => true,
54            Operation::CompleteTodo { .. } => true,
55            Operation::CancelTodo { .. } => true,
56            Operation::MoveTodo(_) => true,
57            // Conservative: bulk may carry update operations, and the chassis
58            // can't introspect the payload. Demand the token if present;
59            // the Writer's auth gate will only fire if no token is configured.
60            Operation::BulkRaw(_) => true,
61        }
62    }
63
64    pub fn render_json(&self) -> Value {
65        match self {
66            Operation::AddTodo(spec) => add_todo::render_add_todo(spec),
67            Operation::AddProject(spec) => add_project::render_add_project(spec),
68            Operation::UpdateTodo(spec) => update_todo::render_update_todo(spec),
69            Operation::UpdateProject(spec) => update_project::render_update_project(spec),
70            Operation::CompleteTodo { id } => status_change::render_complete_todo(id),
71            Operation::CancelTodo { id } => status_change::render_cancel_todo(id),
72            Operation::MoveTodo(spec) => move_todo::render_move_todo(spec),
73            Operation::BulkRaw(spec) => bulk::render_bulk_first(spec),
74        }
75    }
76
77    /// Returns the full batch as multiple JSON elements. For non-bulk variants,
78    /// this is a single-element vec wrapping `render_json()`. For `BulkRaw`,
79    /// the entire `operations` vec is returned. `build_url` uses this to
80    /// compose the URL's payload array.
81    pub fn render_batch(&self) -> Vec<Value> {
82        match self {
83            Operation::BulkRaw(spec) => spec.operations.clone(),
84            _ => vec![self.render_json()],
85        }
86    }
87}