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 Current(current::CurrentArgs),
40
41 Cards(cards::CardsArgs),
43
44 List(list::ListArgs),
46
47 Get(get::GetArgs),
49
50 Create(create::CreateArgs),
52
53 Boards(boards::BoardsArgs),
55
56 TakeOwnership(take_ownership::TakeOwnershipArgs),
58
59 DisableLogin(disable_login::DisableLoginArgs),
61
62 EnableLogin(enable_login::EnableLoginArgs),
64
65 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}