Skip to main content

asana_cli/api/
sections.rs

1//! High level section operations built on the core API client.
2
3use crate::api::{SingleResponse, api_delete, api_post, api_put};
4use crate::{
5    api::{ApiClient, ApiError},
6    models::{
7        AddTaskToSectionData, AddTaskToSectionRequest, Section, SectionCreateRequest,
8        SectionUpdateRequest, Task,
9    },
10};
11use futures_util::{StreamExt, pin_mut};
12
13/// Retrieve sections for a project.
14///
15/// # Errors
16///
17/// Returns an error if the API request fails, if deserialization fails, or if the response is invalid.
18pub async fn list_sections(
19    client: &ApiClient,
20    project_gid: &str,
21) -> Result<Vec<Section>, ApiError> {
22    let stream = client.paginate_with_limit::<Section>(
23        &format!("/projects/{project_gid}/sections"),
24        Vec::new(),
25        None,
26    );
27    pin_mut!(stream);
28
29    let mut sections = Vec::new();
30    while let Some(page) = stream.next().await {
31        let mut page = page?;
32        sections.append(&mut page);
33    }
34
35    Ok(sections)
36}
37
38/// Retrieve a single section by gid.
39///
40/// # Errors
41///
42/// Returns an error if the API request fails, if deserialization fails, or if the response is invalid.
43pub async fn get_section(
44    client: &ApiClient,
45    section_gid: &str,
46    fields: Vec<String>,
47) -> Result<Section, ApiError> {
48    let mut query = Vec::new();
49    if !fields.is_empty() {
50        query.push(("opt_fields".into(), fields.join(",")));
51    }
52
53    let response: SingleResponse<Section> = client
54        .get_json_with_pairs(&format!("/sections/{section_gid}"), query)
55        .await?;
56    Ok(response.data)
57}
58
59/// Create a section in a project.
60///
61/// # Errors
62///
63/// Returns an error if the API request fails, if deserialization fails, or if the response is invalid.
64pub async fn create_section(
65    client: &ApiClient,
66    project_gid: &str,
67    request: SectionCreateRequest,
68) -> Result<Section, ApiError> {
69    api_post(
70        client,
71        &format!("/projects/{project_gid}/sections"),
72        &request,
73    )
74    .await
75}
76
77/// Update a section.
78///
79/// # Errors
80///
81/// Returns an error if the API request fails or the response is invalid.
82pub async fn update_section(
83    client: &ApiClient,
84    section_gid: &str,
85    request: SectionUpdateRequest,
86) -> Result<Section, ApiError> {
87    api_put(client, &format!("/sections/{section_gid}"), &request).await
88}
89
90/// Delete a section.
91///
92/// # Errors
93///
94/// Returns an error if the API request fails.
95pub async fn delete_section(client: &ApiClient, section_gid: &str) -> Result<(), ApiError> {
96    api_delete(client, &format!("/sections/{section_gid}")).await
97}
98
99/// Get tasks within a section (board view only).
100///
101/// # Errors
102///
103/// Returns an error if the API request fails, if deserialization fails, or if the response is invalid.
104pub async fn get_section_tasks(
105    client: &ApiClient,
106    section_gid: &str,
107    fields: Vec<String>,
108) -> Result<Vec<Task>, ApiError> {
109    let mut query = Vec::new();
110    if !fields.is_empty() {
111        query.push(("opt_fields".into(), fields.join(",")));
112    }
113
114    let stream =
115        client.paginate_with_limit::<Task>(&format!("/sections/{section_gid}/tasks"), query, None);
116    pin_mut!(stream);
117
118    let mut tasks = Vec::new();
119    while let Some(page) = stream.next().await {
120        let mut page = page?;
121        tasks.append(&mut page);
122    }
123
124    Ok(tasks)
125}
126
127/// Add a task to a section.
128///
129/// This will remove the task from other sections of the project.
130/// The task will be inserted at the top of the section unless
131/// `insert_before` or `insert_after` is specified.
132///
133/// # Errors
134///
135/// Returns an error if the API request fails or if the response is invalid.
136pub async fn add_task_to_section(
137    client: &ApiClient,
138    section_gid: &str,
139    task_gid: String,
140    insert_before: Option<String>,
141    insert_after: Option<String>,
142) -> Result<(), ApiError> {
143    let request = AddTaskToSectionRequest {
144        data: AddTaskToSectionData {
145            task: task_gid,
146            insert_before,
147            insert_after,
148        },
149    };
150
151    client
152        .post_void(&format!("/sections/{section_gid}/addTask"), &request)
153        .await
154}