Skip to main content

wekan_cli/client/cards/
archival.rs

1use reqwest::header::ACCEPT;
2use secrecy::{ExposeSecret, SecretString};
3use serde::Deserialize;
4
5use super::{
6    ClientError, WekanClient, decode_success, protocol_error, require_non_empty, validate_date_time,
7};
8
9#[derive(Clone, Debug, Eq, PartialEq)]
10pub struct ArchiveCardResult {
11    pub card_id: String,
12    pub archived: bool,
13    pub archived_at: String,
14}
15
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct RestoreCardResult {
18    pub card_id: String,
19    pub archived: bool,
20}
21
22#[derive(Deserialize)]
23#[serde(deny_unknown_fields, rename_all = "camelCase")]
24struct ArchiveResponse {
25    #[serde(rename = "_id")]
26    card_id: String,
27    archived: bool,
28    archived_at: String,
29}
30
31#[derive(Deserialize)]
32#[serde(deny_unknown_fields)]
33struct RestoreResponse {
34    #[serde(rename = "_id")]
35    card_id: String,
36    archived: bool,
37}
38
39impl WekanClient {
40    pub async fn archive_card(
41        &self,
42        board_id: &str,
43        list_id: &str,
44        card_id: &str,
45        token: &SecretString,
46    ) -> Result<ArchiveCardResult, ClientError> {
47        let body = self
48            .execute_success_request(
49                self.http
50                    .post(self.card_action_endpoint(board_id, list_id, card_id, "archive")?)
51                    .header(ACCEPT, "application/json")
52                    .bearer_auth(token.expose_secret()),
53            )
54            .await?;
55        let response: ArchiveResponse = decode_success(&body, "card archive", true)?;
56        validate_state_response(
57            &response.card_id,
58            card_id,
59            response.archived,
60            true,
61            "card archive",
62        )?;
63        validate_date_time(&response.archived_at, "archivedAt", "card archive")?;
64        Ok(ArchiveCardResult {
65            card_id: response.card_id,
66            archived: response.archived,
67            archived_at: response.archived_at,
68        })
69    }
70
71    pub async fn restore_card(
72        &self,
73        board_id: &str,
74        list_id: &str,
75        card_id: &str,
76        token: &SecretString,
77    ) -> Result<RestoreCardResult, ClientError> {
78        let body = self
79            .execute_success_request(
80                self.http
81                    .post(self.card_action_endpoint(board_id, list_id, card_id, "unarchive")?)
82                    .header(ACCEPT, "application/json")
83                    .bearer_auth(token.expose_secret()),
84            )
85            .await?;
86        let response: RestoreResponse = decode_success(&body, "card restore", true)?;
87        validate_state_response(
88            &response.card_id,
89            card_id,
90            response.archived,
91            false,
92            "card restore",
93        )?;
94        Ok(RestoreCardResult {
95            card_id: response.card_id,
96            archived: response.archived,
97        })
98    }
99
100    fn card_action_endpoint(
101        &self,
102        board_id: &str,
103        list_id: &str,
104        card_id: &str,
105        action: &str,
106    ) -> Result<reqwest::Url, ClientError> {
107        let mut endpoint = self.card_endpoint(board_id, list_id, Some(card_id))?;
108        endpoint
109            .path_segments_mut()
110            .map_err(|()| ClientError::Protocol {
111                diagnostic: None,
112                message: "could not add the action to the card endpoint".to_owned(),
113                success_status_received: false,
114            })?
115            .push(action);
116        Ok(endpoint)
117    }
118}
119
120fn validate_state_response(
121    actual_id: &str,
122    requested_id: &str,
123    archived: bool,
124    expected_archived: bool,
125    operation: &str,
126) -> Result<(), ClientError> {
127    require_non_empty(actual_id, operation, "card id")?;
128    if actual_id != requested_id {
129        return Err(protocol_error(format!(
130            "the {operation} response reported a different card ID than requested"
131        )));
132    }
133    if archived != expected_archived {
134        return Err(protocol_error(format!(
135            "the {operation} response contained an unexpected archived state"
136        )));
137    }
138    Ok(())
139}