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