wekan_cli/commands/
attachments.rs1mod delete;
2mod download;
3mod get;
4mod list;
5#[cfg(test)]
6mod tests;
7mod transfer;
8mod upload;
9
10use crate::{
11 client::WekanClientFactory, command_result::CommandSuccess, credentials::CredentialStore,
12 error::AppError, input::ConfirmationProvider,
13};
14use clap::{Args, Subcommand};
15
16#[derive(Debug, Args)]
17pub struct AttachmentArgs {
18 #[command(subcommand)]
19 pub command: AttachmentCommand,
20}
21
22#[derive(Debug, Subcommand)]
23pub enum AttachmentCommand {
24 List(list::ListArgs),
26 Get(get::GetArgs),
28 Upload(upload::UploadArgs),
30 Download(download::DownloadArgs),
32 Copy(transfer::TransferArgs),
34 Move(transfer::TransferArgs),
36 Delete(delete::DeleteArgs),
38 UploadBackground(upload::BackgroundArgs),
40 DownloadBackground(download::BackgroundArgs),
42}
43
44impl AttachmentCommand {
45 pub(crate) fn validate_input(&self) -> Result<(), AppError> {
46 match self {
47 Self::Upload(a) => {
48 a.source.name()?;
49 }
50 Self::UploadBackground(a) => {
51 a.source.name()?;
52 }
53 _ => {}
54 }
55 Ok(())
56 }
57 pub(crate) fn download_destination(&self) -> Option<&download::DestinationArgs> {
58 match self {
59 Self::Download(a) => Some(&a.destination),
60 Self::DownloadBackground(a) => Some(&a.destination),
61 _ => None,
62 }
63 }
64}
65
66pub(crate) async fn dispatch(
67 command: AttachmentCommand,
68 factory: &WekanClientFactory,
69 store: &dyn CredentialStore,
70 confirmation: &dyn ConfirmationProvider,
71) -> Result<CommandSuccess, AppError> {
72 match command {
73 AttachmentCommand::List(a) => list::execute(a, factory, store).await,
74 AttachmentCommand::Get(a) => get::execute(a, factory, store).await,
75 AttachmentCommand::Upload(a) => upload::execute(a, factory, store).await,
76 AttachmentCommand::UploadBackground(a) => upload::background(a, factory, store).await,
77 AttachmentCommand::Download(a) => {
78 download::execute(Some(a.attachment_id), None, a.destination, factory, store).await
79 }
80 AttachmentCommand::DownloadBackground(a) => {
81 download::execute(None, Some(a.board_id), a.destination, factory, store).await
82 }
83 AttachmentCommand::Copy(a) => transfer::execute(a, false, factory, store).await,
84 AttachmentCommand::Move(a) => transfer::execute(a, true, factory, store).await,
85 AttachmentCommand::Delete(a) => delete::execute(a, factory, store, confirmation).await,
86 }
87}
88
89fn identifier(value: &str) -> Result<String, String> {
90 let value = crate::client::trim_javascript_whitespace(value);
91 if value.is_empty() || matches!(value, "." | "..") {
92 Err("ID must be nonblank and cannot be . or ..".to_owned())
93 } else {
94 Ok(value.to_owned())
95 }
96}
97
98fn file_error(operation: &str, path: &std::path::Path, error: std::io::Error) -> AppError {
99 AppError::new(
100 crate::error::ErrorCode::FileIoError,
101 format!(
102 "could not {operation} attachment file `{}`: {}",
103 crate::input::escape_terminal_text(&path.display().to_string()),
104 crate::input::escape_terminal_text(&error.to_string())
105 ),
106 crate::exit_code::StableExitCode::Transport,
107 )
108}