Skip to main content

wekan_cli/client/cards/
membership.rs

1use reqwest::{Method, header::ACCEPT};
2use secrecy::{ExposeSecret, SecretString};
3use serde::Deserialize;
4
5use super::{ClientError, WekanClient, require_non_empty, validate_ids};
6use crate::client::{boards::members::validate_id, transport::decode_success};
7
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
9#[serde(deny_unknown_fields)]
10pub struct CardMembershipResponse {
11    #[serde(rename = "_id")]
12    pub card_id: String,
13    pub members: Vec<String>,
14    pub assignees: Vec<String>,
15}
16
17impl WekanClient {
18    pub async fn add_card_member(
19        &self,
20        board: &str,
21        list: &str,
22        card: &str,
23        user: &str,
24        token: &SecretString,
25    ) -> Result<CardMembershipResponse, ClientError> {
26        self.change_card_membership((board, list, card), user, "members", Method::POST, token)
27            .await
28    }
29    pub async fn remove_card_member(
30        &self,
31        board: &str,
32        list: &str,
33        card: &str,
34        user: &str,
35        token: &SecretString,
36    ) -> Result<CardMembershipResponse, ClientError> {
37        self.change_card_membership((board, list, card), user, "members", Method::DELETE, token)
38            .await
39    }
40    pub async fn add_card_assignee(
41        &self,
42        board: &str,
43        list: &str,
44        card: &str,
45        user: &str,
46        token: &SecretString,
47    ) -> Result<CardMembershipResponse, ClientError> {
48        self.change_card_membership((board, list, card), user, "assignees", Method::POST, token)
49            .await
50    }
51    pub async fn remove_card_assignee(
52        &self,
53        board: &str,
54        list: &str,
55        card: &str,
56        user: &str,
57        token: &SecretString,
58    ) -> Result<CardMembershipResponse, ClientError> {
59        self.change_card_membership(
60            (board, list, card),
61            user,
62            "assignees",
63            Method::DELETE,
64            token,
65        )
66        .await
67    }
68
69    async fn change_card_membership(
70        &self,
71        (board, list, card): (&str, &str, &str),
72        user: &str,
73        field: &str,
74        method: Method,
75        token: &SecretString,
76    ) -> Result<CardMembershipResponse, ClientError> {
77        for id in [board, list, card, user] {
78            validate_id(id)?;
79        }
80        let mut endpoint = self.card_endpoint(board, list, Some(card))?;
81        endpoint
82            .path_segments_mut()
83            .expect("the server URL supports path segments")
84            .extend([field, user]);
85        let body = self
86            .execute_success_request(
87                self.http
88                    .request(method, endpoint)
89                    .header(ACCEPT, "application/json")
90                    .bearer_auth(token.expose_secret()),
91            )
92            .await?;
93        let response: CardMembershipResponse = decode_success(&body, "card membership", true)?;
94        require_non_empty(&response.card_id, "card membership", "card id")?;
95        validate_ids(&response.members, "card membership", "member id")?;
96        validate_ids(&response.assignees, "card membership", "assignee id")?;
97        if response.card_id != card {
98            return Err(ClientError::Protocol {
99                diagnostic: None,
100                message: "Wekan acknowledged a different membership card ID than requested".into(),
101                success_status_received: true,
102            });
103        }
104        Ok(response)
105    }
106}