use clap::Args;
use crate::{
client::{
CreateUserRequest, WekanClientFactory,
users::{PasswordDigestError, UserPassword},
},
command_result::{CommandSuccess, UserCreateSuccess},
commands::authenticated::AuthenticatedContext,
credentials::{CredentialStore, SecretInputProvider},
error::AppError,
redaction::Redactor,
};
use super::map_client_error;
#[derive(Debug, Args)]
pub struct CreateArgs {
#[arg(long, default_value = "")]
pub username: String,
#[arg(long, default_value = "")]
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> {
if args.username.is_empty() && args.email.is_empty() {
return Err(AppError::invalid_input(
"provide a nonempty --username or --email; no request was sent",
));
}
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());
let created = 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"))?;
Ok(CommandSuccess::UserCreated(UserCreateSuccess {
username: args.username,
email: args.email,
user_id: created.user_id,
}))
}