Skip to main content

wekan_cli/commands/
cards.rs

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