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 credentials::{CredentialStore, SecretInputProvider},
23 error::AppError,
24 input::ConfirmationProvider,
25};
26
27use super::client_error::map_client_error;
28
29#[derive(Debug, Args)]
30pub struct UserArgs {
31 #[command(subcommand)]
32 pub command: UserCommand,
33}
34
35#[derive(Debug, Subcommand)]
36pub enum UserCommand {
37 Current(current::CurrentArgs),
39
40 Cards(cards::CardsArgs),
42
43 List(list::ListArgs),
45
46 Get(get::GetArgs),
48
49 Create(create::CreateArgs),
51
52 Boards(boards::BoardsArgs),
54
55 TakeOwnership(take_ownership::TakeOwnershipArgs),
57
58 DisableLogin(disable_login::DisableLoginArgs),
60
61 EnableLogin(enable_login::EnableLoginArgs),
63
64 Delete(delete::DeleteArgs),
66}
67
68impl UserCommand {
69 pub(crate) fn validate(&self) -> Result<(), AppError> {
70 if let Self::Cards(args) = self {
71 cards::validate_range(args.from.as_deref(), args.to.as_deref())?;
72 }
73 Ok(())
74 }
75}
76
77pub(crate) async fn dispatch(
78 command: UserCommand,
79 client_factory: &WekanClientFactory,
80 credential_store: &dyn CredentialStore,
81 secret_input: &dyn SecretInputProvider,
82 confirmation: &dyn ConfirmationProvider,
83) -> Result<CommandSuccess, AppError> {
84 match command {
85 UserCommand::Current(args) => {
86 current::execute(args, client_factory, credential_store).await
87 }
88 UserCommand::Cards(args) => cards::execute(args, client_factory, credential_store).await,
89 UserCommand::List(args) => list::execute(args, client_factory, credential_store).await,
90 UserCommand::Get(args) => get::execute(args, client_factory, credential_store).await,
91 UserCommand::Create(args) => {
92 create::execute(args, client_factory, credential_store, secret_input).await
93 }
94 UserCommand::Boards(args) => boards::execute(args, client_factory, credential_store).await,
95 UserCommand::TakeOwnership(args) => {
96 take_ownership::execute(args, client_factory, credential_store, confirmation).await
97 }
98 UserCommand::DisableLogin(args) => {
99 disable_login::execute(args, client_factory, credential_store, confirmation).await
100 }
101 UserCommand::EnableLogin(args) => {
102 enable_login::execute(args, client_factory, credential_store).await
103 }
104 UserCommand::Delete(args) => {
105 delete::execute(args, client_factory, credential_store, confirmation).await
106 }
107 }
108}
109
110fn user_detail(user: UserRecord) -> UserDetail {
111 UserDetail {
112 user_id: user.user_id,
113 username: user.username,
114 full_name: user.profile.fullname,
115 emails: user
116 .emails
117 .into_iter()
118 .map(|email| UserEmail {
119 address: email.address,
120 verified: email.verified,
121 })
122 .collect(),
123 is_admin: user.is_admin,
124 login_disabled: user.login_disabled,
125 authentication_method: user.authentication_method,
126 created_at: user.created_at,
127 modified_at: user.modified_at,
128 last_connection_date: user.last_connection_date,
129 organizations: user
130 .orgs
131 .into_iter()
132 .map(|organization| UserOrganization {
133 organization_id: organization.org_id,
134 display_name: organization.org_display_name,
135 is_admin: organization.is_admin,
136 })
137 .collect(),
138 teams: user
139 .teams
140 .into_iter()
141 .map(|team| UserTeam {
142 team_id: team.team_id,
143 display_name: team.team_display_name,
144 })
145 .collect(),
146 boards: user
147 .boards
148 .into_iter()
149 .map(|board| UserBoardMembership {
150 board_id: board.board_id,
151 is_active: board.is_active,
152 is_admin: board.is_admin,
153 is_no_comments: board.is_no_comments,
154 is_comment_only: board.is_comment_only,
155 is_worker: board.is_worker,
156 is_normal_assigned_only: board.is_normal_assigned_only,
157 is_comment_assigned_only: board.is_comment_assigned_only,
158 is_read_only: board.is_read_only,
159 is_read_assigned_only: board.is_read_assigned_only,
160 })
161 .collect(),
162 }
163}
164
165fn non_empty(value: &str) -> Result<String, String> {
166 if value.is_empty() {
167 Err("value must not be empty".to_owned())
168 } else {
169 Ok(value.to_owned())
170 }
171}