Skip to main content

wekan_cli/commands/
users.rs

1mod boards;
2mod cards;
3mod create;
4mod current;
5mod delete;
6mod disable_login;
7mod enable_login;
8mod get;
9mod list;
10mod take_ownership;
11
12#[cfg(test)]
13mod tests;
14
15use clap::{Args, Subcommand};
16
17use crate::{
18    client::{UserRecord, WekanClientFactory},
19    command_result::{
20        CommandSuccess, UserBoardMembership, UserDetail, UserEmail, UserOrganization, UserTeam,
21    },
22    config::MissingProfileResolution,
23    credentials::{CredentialStore, SecretInputProvider},
24    error::AppError,
25    input::ConfirmationProvider,
26};
27
28use super::client_error::map_client_error;
29
30#[derive(Debug, Args)]
31pub struct UserArgs {
32    #[command(subcommand)]
33    pub command: UserCommand,
34}
35
36#[derive(Debug, Subcommand)]
37pub enum UserCommand {
38    /// Show the currently authenticated Wekan user.
39    Current(current::CurrentArgs),
40
41    /// List cards related to the currently authenticated user.
42    Cards(cards::CardsArgs),
43
44    /// List Wekan users (site admin only).
45    List(list::ListArgs),
46
47    /// Show a Wekan user by ID or username (site admin only).
48    Get(get::GetArgs),
49
50    /// Create a Wekan user (site admin only).
51    Create(create::CreateArgs),
52
53    /// List active boards visible for a user ID.
54    Boards(boards::BoardsArgs),
55
56    /// Transfer boards administered by a user to the current user.
57    TakeOwnership(take_ownership::TakeOwnershipArgs),
58
59    /// Disable a user's login and clear their sessions.
60    DisableLogin(disable_login::DisableLoginArgs),
61
62    /// Re-enable a user's login.
63    EnableLogin(enable_login::EnableLoginArgs),
64
65    /// Delete a Wekan user.
66    Delete(delete::DeleteArgs),
67}
68
69impl UserCommand {
70    pub(crate) const fn missing_profile_resolution(&self) -> MissingProfileResolution {
71        MissingProfileResolution::Reject
72    }
73
74    pub(crate) fn validate(&self) -> Result<(), AppError> {
75        if let Self::Cards(args) = self {
76            cards::validate_range(args.from.as_deref(), args.to.as_deref())?;
77        }
78        Ok(())
79    }
80}
81
82pub(crate) async fn dispatch(
83    command: UserCommand,
84    client_factory: &WekanClientFactory,
85    credential_store: &dyn CredentialStore,
86    secret_input: &dyn SecretInputProvider,
87    confirmation: &dyn ConfirmationProvider,
88) -> Result<CommandSuccess, AppError> {
89    match command {
90        UserCommand::Current(args) => {
91            current::execute(args, client_factory, credential_store).await
92        }
93        UserCommand::Cards(args) => cards::execute(args, client_factory, credential_store).await,
94        UserCommand::List(args) => list::execute(args, client_factory, credential_store).await,
95        UserCommand::Get(args) => get::execute(args, client_factory, credential_store).await,
96        UserCommand::Create(args) => {
97            create::execute(args, client_factory, credential_store, secret_input).await
98        }
99        UserCommand::Boards(args) => boards::execute(args, client_factory, credential_store).await,
100        UserCommand::TakeOwnership(args) => {
101            take_ownership::execute(args, client_factory, credential_store, confirmation).await
102        }
103        UserCommand::DisableLogin(args) => {
104            disable_login::execute(args, client_factory, credential_store, confirmation).await
105        }
106        UserCommand::EnableLogin(args) => {
107            enable_login::execute(args, client_factory, credential_store).await
108        }
109        UserCommand::Delete(args) => {
110            delete::execute(args, client_factory, credential_store, confirmation).await
111        }
112    }
113}
114
115fn user_detail(user: UserRecord) -> UserDetail {
116    UserDetail {
117        user_id: user.user_id,
118        username: user.username,
119        full_name: user.profile.fullname,
120        emails: user
121            .emails
122            .into_iter()
123            .map(|email| UserEmail {
124                address: email.address,
125                verified: email.verified,
126            })
127            .collect(),
128        is_admin: user.is_admin,
129        login_disabled: user.login_disabled,
130        authentication_method: user.authentication_method,
131        created_at: user.created_at,
132        modified_at: user.modified_at,
133        last_connection_date: user.last_connection_date,
134        organizations: user
135            .orgs
136            .into_iter()
137            .map(|organization| UserOrganization {
138                organization_id: organization.org_id,
139                display_name: organization.org_display_name,
140                is_admin: organization.is_admin,
141            })
142            .collect(),
143        teams: user
144            .teams
145            .into_iter()
146            .map(|team| UserTeam {
147                team_id: team.team_id,
148                display_name: team.team_display_name,
149            })
150            .collect(),
151        boards: user
152            .boards
153            .into_iter()
154            .map(|board| UserBoardMembership {
155                board_id: board.board_id,
156                is_active: board.is_active,
157                is_admin: board.is_admin,
158                is_no_comments: board.is_no_comments,
159                is_comment_only: board.is_comment_only,
160                is_worker: board.is_worker,
161                is_normal_assigned_only: board.is_normal_assigned_only,
162                is_comment_assigned_only: board.is_comment_assigned_only,
163                is_read_only: board.is_read_only,
164                is_read_assigned_only: board.is_read_assigned_only,
165            })
166            .collect(),
167    }
168}
169
170fn non_empty(value: &str) -> Result<String, String> {
171    if value.is_empty() {
172        Err("value must not be empty".to_owned())
173    } else {
174        Ok(value.to_owned())
175    }
176}