1mod archive;
2mod bot_runs;
3mod bulk;
4mod copy;
5mod count;
6mod create;
7mod delete;
8mod export;
9mod find_by_custom_field;
10mod get;
11mod import_ics;
12mod labels;
13mod list;
14mod membership;
15mod restore;
16mod set_custom_field;
17mod update;
18
19#[cfg(test)]
20mod tests;
21
22use clap::{Args, Subcommand};
23
24use crate::{
25 client::WekanClientFactory,
26 command_result::{CardMembershipKind, CommandSuccess},
27 credentials::CredentialStore,
28 error::AppError,
29 input::ConfirmationProvider,
30};
31
32#[derive(Debug, Args)]
33pub struct CardArgs {
34 #[command(subcommand)]
35 pub command: CardCommand,
36}
37
38#[derive(Debug, Subcommand)]
39pub enum CardCommand {
40 BotRun(bot_runs::BotRunArgs),
41 ImportIcs(import_ics::ImportIcsArgs),
43 Export(export::ExportArgs),
45 Count(count::CountArgs),
47 Copy(copy::CopyArgs),
49 Bulk(bulk::BulkArgs),
51 Label(labels::LabelArgs),
53 Member(membership::MembershipArgs),
55 Assignee(membership::MembershipArgs),
57 List(list::ListArgs),
59
60 Get(get::GetArgs),
62
63 SetCustomField(set_custom_field::SetCustomFieldArgs),
65 FindByCustomField(find_by_custom_field::FindByCustomFieldArgs),
67 Create(Box<create::CreateArgs>),
69
70 Update(Box<update::UpdateArgs>),
72
73 Archive(archive::ArchiveArgs),
75
76 Restore(restore::RestoreArgs),
78
79 Delete(delete::DeleteArgs),
81}
82
83pub(crate) async fn dispatch(
84 command: CardCommand,
85 client_factory: &WekanClientFactory,
86 credential_store: &dyn CredentialStore,
87 confirmation: &dyn ConfirmationProvider,
88) -> Result<CommandSuccess, AppError> {
89 match command {
90 CardCommand::BotRun(args) => {
91 bot_runs::dispatch(args.command, client_factory, credential_store).await
92 }
93 CardCommand::ImportIcs(args) => {
94 import_ics::execute(args, client_factory, credential_store).await
95 }
96 CardCommand::Export(args) => export::execute(args, client_factory, credential_store).await,
97 CardCommand::Count(args) => count::execute(args, client_factory, credential_store).await,
98 CardCommand::Copy(args) => copy::execute(args, client_factory, credential_store).await,
99 CardCommand::Bulk(args) => {
100 bulk::dispatch(args.command, client_factory, credential_store, confirmation).await
101 }
102 CardCommand::Label(args) => {
103 labels::dispatch(args.command, client_factory, credential_store).await
104 }
105 CardCommand::Member(args) => {
106 membership::dispatch(
107 args.command,
108 CardMembershipKind::Member,
109 client_factory,
110 credential_store,
111 )
112 .await
113 }
114 CardCommand::Assignee(args) => {
115 membership::dispatch(
116 args.command,
117 CardMembershipKind::Assignee,
118 client_factory,
119 credential_store,
120 )
121 .await
122 }
123 CardCommand::List(args) => list::execute(args, client_factory, credential_store).await,
124 CardCommand::Get(args) => get::execute(args, client_factory, credential_store).await,
125 CardCommand::SetCustomField(args) => {
126 set_custom_field::execute(args, client_factory, credential_store).await
127 }
128 CardCommand::FindByCustomField(args) => {
129 find_by_custom_field::execute(args, client_factory, credential_store).await
130 }
131 CardCommand::Create(args) => create::execute(*args, client_factory, credential_store).await,
132 CardCommand::Update(args) => update::execute(*args, client_factory, credential_store).await,
133 CardCommand::Archive(args) => {
134 archive::execute(args, client_factory, credential_store).await
135 }
136 CardCommand::Restore(args) => {
137 restore::execute(args, client_factory, credential_store).await
138 }
139 CardCommand::Delete(args) => {
140 delete::execute(args, client_factory, credential_store, confirmation).await
141 }
142 }
143}
144
145fn non_empty(value: &str) -> Result<String, String> {
146 trimmed_non_empty(value)
147}
148
149fn trimmed_non_empty(value: &str) -> Result<String, String> {
150 let value = value.trim();
151 if value.is_empty() {
152 Err("value must not be empty or whitespace".to_owned())
153 } else {
154 Ok(value.to_owned())
155 }
156}
157
158fn date_input(value: &str) -> Result<crate::client::cards::CardDateInput, String> {
159 use crate::client::cards::CardDateInput;
160 Ok(match value.trim().parse::<serde_json::Number>() {
161 Ok(number) => CardDateInput::EpochMilliseconds(number),
162 Err(_) => CardDateInput::Text(value.to_owned()),
163 })
164}