openlark_workflow/v2/task/subtask/
create.rs1use crate::common::{api_endpoints::TaskApiV2, api_utils::*};
6use openlark_core::{
7 SDKResult,
8 api::{ApiRequest, ApiResponseTrait, ResponseFormat},
9 config::Config,
10 validate_required,
11};
12use serde::{Deserialize, Serialize};
13use std::sync::Arc;
14
15#[derive(Debug, Clone, Serialize, Default)]
17pub struct CreateSubtaskBody {
18 pub summary: String,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub description: Option<String>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub assignee: Option<String>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub due: Option<String>,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub completed_at: Option<String>,
36}
37
38#[derive(Debug, Clone, Deserialize)]
40pub struct CreateSubtaskResponse {
41 pub task_guid: String,
43
44 pub summary: String,
46
47 #[serde(default)]
49 pub description: Option<String>,
50
51 pub status: String,
53
54 pub parent_task_guid: String,
56
57 pub created_at: String,
59
60 pub updated_at: String,
62}
63
64#[derive(Debug, Clone)]
66pub struct CreateSubtaskRequest {
67 config: Arc<Config>,
69 task_guid: String,
71 body: CreateSubtaskBody,
73}
74
75impl CreateSubtaskRequest {
76 pub fn new(config: Arc<Config>, task_guid: impl Into<String>) -> Self {
78 Self {
79 config,
80 task_guid: task_guid.into(),
81 body: CreateSubtaskBody::default(),
82 }
83 }
84
85 pub fn summary(mut self, summary: impl Into<String>) -> Self {
87 self.body.summary = summary.into();
88 self
89 }
90
91 pub fn description(mut self, description: impl Into<String>) -> Self {
93 self.body.description = Some(description.into());
94 self
95 }
96
97 pub fn assignee(mut self, assignee: impl Into<String>) -> Self {
99 self.body.assignee = Some(assignee.into());
100 self
101 }
102
103 pub fn due(mut self, due: impl Into<String>) -> Self {
105 self.body.due = Some(due.into());
106 self
107 }
108
109 pub fn completed_at(mut self, completed_at: impl Into<String>) -> Self {
111 self.body.completed_at = Some(completed_at.into());
112 self
113 }
114
115 pub async fn execute(self) -> SDKResult<CreateSubtaskResponse> {
117 self.execute_with_options(openlark_core::req_option::RequestOption::default())
118 .await
119 }
120
121 pub async fn execute_with_options(
123 self,
124 option: openlark_core::req_option::RequestOption,
125 ) -> SDKResult<CreateSubtaskResponse> {
126 validate_required!(self.body.summary.trim(), "子任务标题不能为空");
128 validate_required!(self.task_guid.trim(), "父任务 GUID 不能为空");
129
130 let api_endpoint = TaskApiV2::SubtaskCreate(self.task_guid.clone());
131 let mut request = ApiRequest::<CreateSubtaskResponse>::post(api_endpoint.to_url());
132
133 let request_body = &self.body;
134 request = request.body(serialize_params(request_body, "创建子任务")?);
135
136 let response =
137 openlark_core::http::Transport::request(request, &self.config, Some(option)).await?;
138 extract_response_data(response, "创建子任务")
139 }
140}
141
142impl ApiResponseTrait for CreateSubtaskResponse {
143 fn data_format() -> ResponseFormat {
144 ResponseFormat::Data
145 }
146}
147
148#[cfg(test)]
149#[allow(unused_imports)]
150mod tests {
151 use std::sync::Arc;
152
153 use super::*;
154
155 #[test]
156 fn test_create_subtask_builder() {
157 let config = Arc::new(
158 openlark_core::config::Config::builder()
159 .app_id("test")
160 .app_secret("test")
161 .build(),
162 );
163
164 let request = CreateSubtaskRequest::new(config, "parent_task_123")
165 .summary("测试子任务")
166 .description("子任务描述")
167 .assignee("user_123");
168
169 assert_eq!(request.task_guid, "parent_task_123");
170 assert_eq!(request.body.summary, "测试子任务");
171 assert_eq!(request.body.description, Some("子任务描述".to_string()));
172 assert_eq!(request.body.assignee, Some("user_123".to_string()));
173 }
174
175 #[test]
176 fn test_subtask_api_v2_url() {
177 let endpoint = TaskApiV2::SubtaskCreate("task_123".to_string());
178 assert_eq!(
179 endpoint.to_url(),
180 "/open-apis/task/v2/tasks/task_123/subtasks"
181 );
182 }
183}