Skip to main content

wekan_cli/commands/
cards.rs

1mod archive;
2mod bulk;
3mod create;
4mod delete;
5mod find_by_custom_field;
6mod get;
7mod labels;
8mod list;
9mod membership;
10mod restore;
11mod set_custom_field;
12mod update;
13
14#[cfg(test)]
15mod tests;
16
17use clap::{Args, Subcommand};
18
19use crate::{
20    client::WekanClientFactory,
21    command_result::{CardMembershipKind, CommandSuccess},
22    credentials::CredentialStore,
23    error::AppError,
24    input::ConfirmationProvider,
25};
26
27#[derive(Debug, Args)]
28pub struct CardArgs {
29    #[command(subcommand)]
30    pub command: CardCommand,
31}
32
33#[derive(Debug, Subcommand)]
34pub enum CardCommand {
35    /// Create, delete, or merge labels on up to 500 cards per request.
36    Bulk(bulk::BulkArgs),
37    /// List the label IDs stored on a card.
38    Label(labels::LabelArgs),
39    /// List or merge individual card members.
40    Member(membership::MembershipArgs),
41    /// List or merge individual card assignees.
42    Assignee(membership::MembershipArgs),
43    /// List the cards returned by Wekan for a board list.
44    List(list::ListArgs),
45
46    /// Show one card by board, list, and card ID.
47    Get(get::GetArgs),
48
49    /// Assign an existing custom-field entry on an active card.
50    SetCustomField(set_custom_field::SetCustomFieldArgs),
51    /// Find active cards using Wekan's string custom-field query.
52    FindByCustomField(find_by_custom_field::FindByCustomFieldArgs),
53    /// Create a card in a board list.
54    Create(Box<create::CreateArgs>),
55
56    /// Update one or more editable card fields.
57    Update(Box<update::UpdateArgs>),
58
59    /// Archive an active card and its child cards.
60    Archive(archive::ArchiveArgs),
61
62    /// Restore an archived card and its child cards.
63    Restore(restore::RestoreArgs),
64
65    /// Permanently delete a card and its child resources.
66    Delete(delete::DeleteArgs),
67}
68
69pub(crate) async fn dispatch(
70    command: CardCommand,
71    client_factory: &WekanClientFactory,
72    credential_store: &dyn CredentialStore,
73    confirmation: &dyn ConfirmationProvider,
74) -> Result<CommandSuccess, AppError> {
75    match command {
76        CardCommand::Bulk(args) => {
77            bulk::dispatch(args.command, client_factory, credential_store, confirmation).await
78        }
79        CardCommand::Label(args) => {
80            labels::dispatch(args.command, client_factory, credential_store).await
81        }
82        CardCommand::Member(args) => {
83            membership::dispatch(
84                args.command,
85                CardMembershipKind::Member,
86                client_factory,
87                credential_store,
88            )
89            .await
90        }
91        CardCommand::Assignee(args) => {
92            membership::dispatch(
93                args.command,
94                CardMembershipKind::Assignee,
95                client_factory,
96                credential_store,
97            )
98            .await
99        }
100        CardCommand::List(args) => list::execute(args, client_factory, credential_store).await,
101        CardCommand::Get(args) => get::execute(args, client_factory, credential_store).await,
102        CardCommand::SetCustomField(args) => {
103            set_custom_field::execute(args, client_factory, credential_store).await
104        }
105        CardCommand::FindByCustomField(args) => {
106            find_by_custom_field::execute(args, client_factory, credential_store).await
107        }
108        CardCommand::Create(args) => create::execute(*args, client_factory, credential_store).await,
109        CardCommand::Update(args) => update::execute(*args, client_factory, credential_store).await,
110        CardCommand::Archive(args) => {
111            archive::execute(args, client_factory, credential_store).await
112        }
113        CardCommand::Restore(args) => {
114            restore::execute(args, client_factory, credential_store).await
115        }
116        CardCommand::Delete(args) => {
117            delete::execute(args, client_factory, credential_store, confirmation).await
118        }
119    }
120}
121
122fn non_empty(value: &str) -> Result<String, String> {
123    trimmed_non_empty(value)
124}
125
126fn trimmed_non_empty(value: &str) -> Result<String, String> {
127    let value = value.trim();
128    if value.is_empty() {
129        Err("value must not be empty or whitespace".to_owned())
130    } else {
131        Ok(value.to_owned())
132    }
133}
134
135fn date_input(value: &str) -> Result<crate::client::cards::CardDateInput, String> {
136    use crate::client::cards::CardDateInput;
137    Ok(match value.trim().parse::<serde_json::Number>() {
138        Ok(number) => CardDateInput::EpochMilliseconds(number),
139        Err(_) => CardDateInput::Text(value.to_owned()),
140    })
141}