Skip to main content

wekan_cli/client/cards/
reads.rs

1use reqwest::header::ACCEPT;
2use secrecy::{ExposeSecret, SecretString};
3use serde::{Deserialize, Serialize};
4use serde_json::Number;
5
6use super::{
7    CardDocument, ClientError, WekanClient, require_non_empty, validate_card_document,
8    validate_optional_date_time, validate_optional_id,
9};
10use crate::client::transport::decode_success;
11
12#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
13#[serde(
14    deny_unknown_fields,
15    rename_all(deserialize = "camelCase", serialize = "snake_case")
16)]
17pub struct SwimlaneCardSummary {
18    #[serde(rename(deserialize = "_id", serialize = "card_id"))]
19    pub card_id: String,
20    pub title: Option<String>,
21    pub description: Option<String>,
22    pub list_id: Option<String>,
23    pub received_at: Option<String>,
24    pub start_at: Option<String>,
25    pub due_at: Option<String>,
26    pub end_at: Option<String>,
27    pub assignees: Option<Vec<Option<String>>>,
28    pub sort: Option<Number>,
29}
30
31#[derive(Deserialize)]
32#[serde(deny_unknown_fields)]
33struct BoardCardCount {
34    board_cards_count: u64,
35}
36
37#[derive(Deserialize)]
38#[serde(deny_unknown_fields)]
39struct ListCardCount {
40    list_cards_count: u64,
41}
42
43impl WekanClient {
44    pub async fn board_card_count(
45        &self,
46        board_id: &str,
47        token: &SecretString,
48    ) -> Result<u64, ClientError> {
49        let body = self
50            .execute_success_request(
51                self.http
52                    .get(self.board_endpoint(board_id, Some("cards_count"))?)
53                    .header(ACCEPT, "application/json")
54                    .bearer_auth(token.expose_secret()),
55            )
56            .await?;
57        let count: BoardCardCount = decode_success(&body, "board card count", true)?;
58        Ok(count.board_cards_count)
59    }
60
61    pub async fn list_card_count(
62        &self,
63        board_id: &str,
64        list_id: &str,
65        token: &SecretString,
66    ) -> Result<u64, ClientError> {
67        let mut endpoint = self.list_endpoint(board_id, Some(list_id))?;
68        endpoint
69            .path_segments_mut()
70            .expect("HTTP endpoint")
71            .push("cards_count");
72        let body = self
73            .execute_success_request(
74                self.http
75                    .get(endpoint)
76                    .header(ACCEPT, "application/json")
77                    .bearer_auth(token.expose_secret()),
78            )
79            .await?;
80        let count: ListCardCount = decode_success(&body, "list card count", true)?;
81        Ok(count.list_cards_count)
82    }
83
84    pub async fn card_by_id(
85        &self,
86        card_id: &str,
87        token: &SecretString,
88    ) -> Result<CardDocument, ClientError> {
89        let mut endpoint = self
90            .server()
91            .join("api/cards")
92            .map_err(|_| super::protocol_error("could not build the card endpoint".into()))?;
93        endpoint
94            .path_segments_mut()
95            .expect("HTTP endpoint")
96            .push(card_id);
97        let body = self
98            .execute_success_request(
99                self.http
100                    .get(endpoint)
101                    .header(ACCEPT, "application/json")
102                    .bearer_auth(token.expose_secret()),
103            )
104            .await?;
105        validate_card_document(decode_success(&body, "card lookup by ID", true)?)
106    }
107
108    pub async fn swimlane_cards(
109        &self,
110        board_id: &str,
111        swimlane_id: &str,
112        token: &SecretString,
113    ) -> Result<Vec<SwimlaneCardSummary>, ClientError> {
114        let mut endpoint = self.swimlane_endpoint(board_id, Some(swimlane_id))?;
115        endpoint
116            .path_segments_mut()
117            .expect("HTTP endpoint")
118            .push("cards");
119        let body = self
120            .execute_success_request(
121                self.http
122                    .get(endpoint)
123                    .header(ACCEPT, "application/json")
124                    .bearer_auth(token.expose_secret()),
125            )
126            .await?;
127        let cards: Vec<SwimlaneCardSummary> =
128            decode_success(&body, "swimlane card collection", true)?;
129        for card in &cards {
130            require_non_empty(&card.card_id, "swimlane card collection", "card id")?;
131            validate_optional_id(
132                card.list_id.as_deref(),
133                "swimlane card collection",
134                "list id",
135            )?;
136            for id in card.assignees.iter().flatten().flatten() {
137                require_non_empty(id, "swimlane card collection", "assignee id")?;
138            }
139            for (field, value) in [
140                ("receivedAt", &card.received_at),
141                ("startAt", &card.start_at),
142                ("dueAt", &card.due_at),
143                ("endAt", &card.end_at),
144            ] {
145                validate_optional_date_time(value.as_deref(), field, "swimlane card collection")?;
146            }
147        }
148        Ok(cards)
149    }
150}