mysqladm/client/commands/
create_user.rs

1use clap::Parser;
2use dialoguer::Confirm;
3use futures_util::SinkExt;
4use tokio_stream::StreamExt;
5
6use crate::{
7    client::commands::{erroneous_server_response, read_password_from_stdin_with_double_check},
8    core::{
9        protocol::{
10            ClientToServerMessageStream, Request, Response, print_create_users_output_status,
11            print_create_users_output_status_json, print_set_password_output_status,
12        },
13        types::MySQLUser,
14    },
15};
16
17#[derive(Parser, Debug, Clone)]
18pub struct CreateUserArgs {
19    #[arg(num_args = 1..)]
20    username: Vec<MySQLUser>,
21
22    /// Do not ask for a password, leave it unset
23    #[clap(long)]
24    no_password: bool,
25
26    /// Print the information as JSON
27    ///
28    /// Note that this implies `--no-password`, since the command will become non-interactive.
29    #[arg(short, long)]
30    json: bool,
31}
32
33pub async fn create_users(
34    args: CreateUserArgs,
35    mut server_connection: ClientToServerMessageStream,
36) -> anyhow::Result<()> {
37    if args.username.is_empty() {
38        anyhow::bail!("No usernames provided");
39    }
40
41    let message = Request::CreateUsers(args.username.to_owned());
42    if let Err(err) = server_connection.send(message).await {
43        server_connection.close().await.ok();
44        anyhow::bail!(anyhow::Error::from(err).context("Failed to communicate with server"));
45    }
46
47    let result = match server_connection.next().await {
48        Some(Ok(Response::CreateUsers(result))) => result,
49        response => return erroneous_server_response(response),
50    };
51
52    if args.json {
53        print_create_users_output_status_json(&result);
54    } else {
55        print_create_users_output_status(&result);
56
57        let successfully_created_users = result
58            .iter()
59            .filter_map(|(username, result)| result.as_ref().ok().map(|_| username))
60            .collect::<Vec<_>>();
61
62        for username in successfully_created_users {
63            if !args.no_password
64                && Confirm::new()
65                    .with_prompt(format!(
66                        "Do you want to set a password for user '{}'?",
67                        username
68                    ))
69                    .default(false)
70                    .interact()?
71            {
72                let password = read_password_from_stdin_with_double_check(username)?;
73                let message = Request::PasswdUser((username.to_owned(), password));
74
75                if let Err(err) = server_connection.send(message).await {
76                    server_connection.close().await.ok();
77                    anyhow::bail!(err);
78                }
79
80                match server_connection.next().await {
81                    Some(Ok(Response::SetUserPassword(result))) => {
82                        print_set_password_output_status(&result, username)
83                    }
84                    response => return erroneous_server_response(response),
85                }
86
87                println!();
88            }
89        }
90    }
91
92    server_connection.send(Request::Exit).await?;
93
94    Ok(())
95}