use clap::Args;
use crate::{
client::{
CreateUserRequest, WekanClientFactory,
users::{PasswordDigestError, UserPassword},
},
command_result::{CommandSuccess, UserCreateSuccess, UserCreateWarning},
commands::authenticated::AuthenticatedContext,
credentials::{CredentialStore, SecretInputProvider},
error::AppError,
redaction::Redactor,
};
use super::{map_client_error, non_empty};
#[derive(Debug, Args)]
pub struct CreateArgs {
#[arg(long, value_parser = non_empty)]
pub username: String,
#[arg(long, value_parser = non_empty)]
pub email: String,
#[arg(long)]
pub password_stdin: bool,
#[arg(long, conflicts_with_all = ["password_stdin", "password_digest_stdin"])]
pub password_raw_stdin: bool,
#[arg(long, conflicts_with_all = ["password_stdin", "password_raw_stdin"])]
pub password_digest_stdin: bool,
}
pub(super) async fn execute(
args: CreateArgs,
client_factory: &WekanClientFactory,
credential_store: &dyn CredentialStore,
secret_input: &dyn SecretInputProvider,
) -> Result<CommandSuccess, AppError> {
let context = AuthenticatedContext::load(client_factory, credential_store)?;
let password = if args.password_digest_stdin {
UserPassword::from_digest_json(&secret_input.read_raw_secret()?).map_err(|error| {
AppError::invalid_input(match error {
PasswordDigestError::InvalidObject => {
"expected a SHA-256 password digest object on stdin"
}
PasswordDigestError::InvalidDigest => {
"expected a 64-character digest with algorithm sha-256"
}
})
})?
} else if args.password_raw_stdin {
UserPassword::Plaintext(secret_input.read_raw_secret()?)
} else {
UserPassword::Plaintext(secret_input.read_new_account_password(args.password_stdin)?)
};
let redactor = Redactor::with_secret(context.record().token()).and_secret(password.secret());
context
.client()
.create_user(
&CreateUserRequest {
username: args.username.clone(),
email: args.email.clone(),
password: password.clone(),
},
context.record().token(),
)
.await
.map_err(|error| map_client_error(error, &redactor, "user creation", true))?;
Ok(CommandSuccess::UserCreated(UserCreateSuccess {
created: true,
username: args.username,
email: args.email,
user_id: None,
warning: Some(UserCreateWarning::UserIdUnavailableInWekanV1106),
}))
}