Skip to main content

wekan_cli/commands/
cards.rs

1mod create;
2mod delete;
3mod get;
4mod list;
5mod update;
6
7#[cfg(test)]
8mod tests;
9
10use clap::{Args, Subcommand};
11use time::{OffsetDateTime, format_description::well_known::Rfc3339};
12
13use crate::{
14    client::WekanClientFactory, command_result::CommandSuccess, config::MissingProfileResolution,
15    credentials::CredentialStore, error::AppError, input::ConfirmationProvider,
16};
17
18#[derive(Debug, Args)]
19pub struct CardArgs {
20    #[command(subcommand)]
21    pub command: CardCommand,
22}
23
24#[derive(Debug, Subcommand)]
25pub enum CardCommand {
26    /// List the cards returned by Wekan for a board list.
27    List(list::ListArgs),
28
29    /// Show one card by board, list, and card ID.
30    Get(get::GetArgs),
31
32    /// Create a card in a board list.
33    Create(create::CreateArgs),
34
35    /// Update one or more editable card fields.
36    Update(update::UpdateArgs),
37
38    /// Permanently delete a card and its child resources.
39    Delete(delete::DeleteArgs),
40}
41
42impl CardCommand {
43    pub(crate) const fn missing_profile_resolution(&self) -> MissingProfileResolution {
44        MissingProfileResolution::Reject
45    }
46}
47
48pub(crate) async fn dispatch(
49    command: CardCommand,
50    client_factory: &WekanClientFactory,
51    credential_store: &dyn CredentialStore,
52    confirmation: &dyn ConfirmationProvider,
53) -> Result<CommandSuccess, AppError> {
54    match command {
55        CardCommand::List(args) => list::execute(args, client_factory, credential_store).await,
56        CardCommand::Get(args) => get::execute(args, client_factory, credential_store).await,
57        CardCommand::Create(args) => create::execute(args, client_factory, credential_store).await,
58        CardCommand::Update(args) => update::execute(args, client_factory, credential_store).await,
59        CardCommand::Delete(args) => {
60            delete::execute(args, client_factory, credential_store, confirmation).await
61        }
62    }
63}
64
65fn non_empty(value: &str) -> Result<String, String> {
66    trimmed_non_empty(value)
67}
68
69fn trimmed_non_empty(value: &str) -> Result<String, String> {
70    let value = value.trim();
71    if value.is_empty() {
72        Err("value must not be empty or whitespace".to_owned())
73    } else {
74        Ok(value.to_owned())
75    }
76}
77
78fn rfc3339(value: &str) -> Result<String, String> {
79    OffsetDateTime::parse(value, &Rfc3339)
80        .map(|_| value.to_owned())
81        .map_err(|_| "value must be an RFC3339 date-time".to_owned())
82}