diff --git a/plume-cli/Cargo.toml b/plume-cli/Cargo.toml index 3d5ddae..3a96ce4 100644 --- a/plume-cli/Cargo.toml +++ b/plume-cli/Cargo.toml @@ -10,6 +10,7 @@ path = "src/main.rs" [dependencies] clap = "2.32" dotenv = "0.13" +rpassword = "2.0" [dependencies.diesel] features = ["postgres", "r2d2", "chrono"] diff --git a/plume-cli/src/main.rs b/plume-cli/src/main.rs index 2dc97b4..be012fc 100644 --- a/plume-cli/src/main.rs +++ b/plume-cli/src/main.rs @@ -2,6 +2,7 @@ extern crate clap; extern crate diesel; extern crate dotenv; extern crate plume_models; +extern crate rpassword; use clap::App; use diesel::{Connection, PgConnection}; @@ -9,13 +10,15 @@ use std::io::{self, prelude::*}; use plume_models::DB_URL; mod instance; +mod users; fn main() { let mut app = App::new("Plume CLI") .bin_name("plm") .version("0.2.0") .about("Collection of tools to manage your Plume instance.") - .subcommand(instance::command()); + .subcommand(instance::command()) + .subcommand(users::command()); let matches = app.clone().get_matches(); dotenv::dotenv().ok(); @@ -23,6 +26,7 @@ fn main() { match matches.subcommand() { ("instance", Some(args)) => instance::run(args, &conn.expect("Couldn't connect to the database.")), + ("users", Some(args)) => users::run(args, &conn.expect("Couldn't connect to the database.")), _ => app.print_help().unwrap() }; } diff --git a/plume-cli/src/users.rs b/plume-cli/src/users.rs new file mode 100644 index 0000000..b3bcee1 --- /dev/null +++ b/plume-cli/src/users.rs @@ -0,0 +1,77 @@ +use clap::{Arg, ArgMatches, App, SubCommand}; +use diesel::PgConnection; + +use rpassword; +use std::io::{self, Write}; +use plume_models::{ + users::*, +}; + +pub fn command<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("users") + .about("Manage users") + .subcommand(SubCommand::with_name("new") + .arg(Arg::with_name("name") + .short("n") + .long("name") + .alias("username") + .takes_value(true) + .help("The username of the new user") + ).arg(Arg::with_name("display-name") + .short("N") + .long("display-name") + .takes_value(true) + .help("The display name of the new user") + ).arg(Arg::with_name("biography") + .short("b") + .long("bio") + .alias("biography") + .takes_value(true) + .help("The biography of the new user") + ).arg(Arg::with_name("email") + .short("e") + .long("email") + .takes_value(true) + .help("Email address of the new user") + ).arg(Arg::with_name("password") + .short("p") + .long("password") + .takes_value(true) + .help("The password of the new user") + ).arg(Arg::with_name("admin") + .short("a") + .long("admin") + .help("Makes the user an administrator of the instance") + ).about("Create a new user on this instance")) +} + +pub fn run<'a>(args: &ArgMatches<'a>, conn: &PgConnection) { + let conn = conn; + match args.subcommand() { + ("new", Some(x)) => new(x, conn), + _ => println!("Unknwon subcommand"), + } +} + +fn new<'a>(args: &ArgMatches<'a>, conn: &PgConnection) { + let username = args.value_of("name").map(String::from).unwrap_or_else(|| super::ask_for("Username")); + let display_name = args.value_of("display-name").map(String::from).unwrap_or_else(|| super::ask_for("Display name")); + let admin = args.is_present("admin"); + let bio = args.value_of("biography").unwrap_or("").to_string(); + let email = args.value_of("email").map(String::from).unwrap_or_else(|| super::ask_for("Email address")); + let password = args.value_of("password").map(String::from).unwrap_or_else(|| { + print!("Password: "); + io::stdout().flush().expect("Couldn't flush STDOUT"); + rpassword::read_password().expect("Couldn't read your password.") + }); + + NewUser::new_local( + conn, + username, + display_name, + admin, + bio, + email, + User::hash_pass(password), + ).update_boxes(conn); +}