wekan-cli 2.0.0

Agent-first, human-friendly command-line client for Wekan
Documentation
use crate::client::{
    ClientError, WekanClient, datetime::validate_response_date, transport::decode_success,
};
use reqwest::header::ACCEPT;
use secrecy::{ExposeSecret, SecretString};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(
    deny_unknown_fields,
    rename_all(deserialize = "camelCase", serialize = "snake_case")
)]
pub struct DeletedAttachment {
    pub attachment_id: String,
    pub attachment_name: String,
    pub attachment_type: String,
    pub board_id: String,
    pub swimlane_id: Option<String>,
    pub list_id: Option<String>,
    pub card_id: Option<String>,
    pub deleted_at: String,
    pub deleted_by: Option<String>,
    pub delete_batch_id: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(
    deny_unknown_fields,
    rename_all(deserialize = "camelCase", serialize = "snake_case")
)]
pub struct SoftDeleteAttachmentResponse {
    pub deleted: bool,
    pub batch_id: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct RestoreAttachmentResponse {
    pub restored: bool,
}

impl WekanClient {
    pub async fn deleted_board_attachments(
        &self,
        board: &str,
        token: &SecretString,
    ) -> Result<Vec<DeletedAttachment>, ClientError> {
        let mut endpoint = self.board_endpoint(board, Some("attachments"))?;
        endpoint
            .path_segments_mut()
            .expect("HTTP URL supports path segments")
            .push("deleted");
        let body = self
            .execute_success_request(
                self.http
                    .get(endpoint)
                    .header(ACCEPT, "application/json")
                    .bearer_auth(token.expose_secret()),
            )
            .await?;
        let attachments: Vec<DeletedAttachment> =
            decode_success(&body, "deleted board attachments", true)?;
        for attachment in &attachments {
            if attachment.board_id != board || attachment.attachment_id.trim().is_empty() {
                return Err(super::protocol(
                    "the deleted attachment did not match the requested board",
                ));
            }
            validate_response_date(&attachment.deleted_at)
                .map_err(|()| super::protocol("the deleted attachment timestamp is invalid"))?;
        }
        Ok(attachments)
    }
    pub async fn soft_delete_board_attachment(
        &self,
        board: &str,
        attachment: &str,
        token: &SecretString,
    ) -> Result<SoftDeleteAttachmentResponse, ClientError> {
        let mut endpoint = self.board_endpoint(board, Some("attachments"))?;
        endpoint
            .path_segments_mut()
            .expect("HTTP URL supports path segments")
            .push(attachment);
        let body = self
            .execute_success_request(
                self.http
                    .delete(endpoint)
                    .header(ACCEPT, "application/json")
                    .bearer_auth(token.expose_secret()),
            )
            .await?;
        decode_success(&body, "board attachment deletion", true)
    }
    pub async fn restore_board_attachment(
        &self,
        board: &str,
        attachment: &str,
        token: &SecretString,
    ) -> Result<RestoreAttachmentResponse, ClientError> {
        let mut endpoint = self.board_endpoint(board, Some("attachments"))?;
        endpoint
            .path_segments_mut()
            .expect("HTTP URL supports path segments")
            .extend([attachment, "restore"]);
        let body = self
            .execute_success_request(
                self.http
                    .post(endpoint)
                    .header(ACCEPT, "application/json")
                    .bearer_auth(token.expose_secret()),
            )
            .await?;
        decode_success(&body, "board attachment restore", true)
    }
}