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}