feat(admin): create and list users commands

This commit is contained in:
Matthieu Bessat 2024-12-03 13:20:33 +01:00
parent 8d20cab18f
commit a0de3b287b
19 changed files with 314 additions and 30 deletions

View file

@ -2,10 +2,17 @@
name = "admin_cli"
edition = "2021"
[dependencies]
anyhow = { workspace = true }
fully_pub = { workspace = true }
[[bin]]
name = "minauthator-admin"
path = "src/main.rs"
[dependencies]
anyhow = { workspace = true }
thiserror = { workspace = true }
fully_pub = { workspace = true }
argh = { workspace = true }
tokio = { workspace = true }
log = { workspace = true }
env_logger = { workspace = true }
kernel = { path = "../kernel" }

View file

@ -0,0 +1 @@
pub mod users;

View file

@ -0,0 +1,115 @@
use anyhow::{Context, Result};
use argh::FromArgs;
use fully_pub::fully_pub;
use kernel::{context::KernelContext, models::user::User, repositories::users::get_users};
use log::info;
#[fully_pub]
#[derive(FromArgs, PartialEq, Debug)]
#[argh(
subcommand, name = "create",
description = "Create user in DB."
)]
struct CreateUserCommand {
/// aka login, username
#[argh(option)]
handle: String,
/// displayed name (eg. first name and last name)
#[argh(option)]
full_name: Option<String>,
/// use to identify and prove user identity
/// formated as specified in RFC 2821, RFC 3696
#[argh(option)]
email: String,
/// if true, create an invitation token
#[argh(switch)]
invite: bool
}
#[fully_pub]
#[derive(FromArgs, PartialEq, Debug)]
#[argh(
subcommand, name = "delete",
description = "Delete user in DB."
)]
struct DeleteUserCommand {
/// delete by user Uuid
#[argh(option)]
id: String
}
#[fully_pub]
#[derive(FromArgs, PartialEq, Debug)]
#[argh(
subcommand, name = "list",
description = "List users in DB."
)]
struct ListUsersCommand {
/// how many users to return
#[argh(option)]
limit: Option<usize>,
}
#[fully_pub]
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum UsersSubCommands {
Create(CreateUserCommand),
List(ListUsersCommand),
Delete(DeleteUserCommand),
}
#[fully_pub]
#[derive(FromArgs, PartialEq, Debug)]
#[argh(
subcommand, name = "users",
description = "Manage instance users."
)]
struct UsersCommand {
#[argh(subcommand)]
nested: UsersSubCommands,
}
pub async fn list_users(cmd: ListUsersCommand, ctx: KernelContext) -> Result<()> {
for user in get_users(&ctx.storage).await? {
println!(
"{0: <36} | [{1:<8}] | {2: <15} | {3: <25}",
user.id, user.status, user.handle, user.email.unwrap_or("()".to_string())
);
}
Ok(())
}
pub async fn create_user(cmd: CreateUserCommand, ctx: KernelContext) -> Result<()> {
let mut user = User::new(cmd.handle);
user.email = Some(cmd.email);
user.full_name = cmd.full_name;
if cmd.invite {
user.invite();
println!("Generated invite code: {}", user.reset_password_token.as_ref().unwrap());
}
let _res = kernel::actions::users::create_user(ctx, user).await?;
info!("Created user.");
if cmd.invite {
// TODO: Send invitation email
info!("Not sending invitation email.");
}
Ok(())
}
pub async fn delete_user(cmd: DeleteUserCommand, ctx: KernelContext) -> Result<()> {
todo!()
}
pub async fn handle_command_tree(cmd: UsersCommand, ctx: KernelContext) -> Result<()> {
match cmd.nested {
UsersSubCommands::List(sc) => list_users(sc, ctx).await,
UsersSubCommands::Create(sc) => create_user(sc, ctx).await,
UsersSubCommands::Delete(sc) => delete_user(sc, ctx).await
}
}

View file

@ -1,6 +1,49 @@
use anyhow::Result;
use argh::FromArgs;
use anyhow::{Context, Result};
use commands::users;
use kernel::context::{get_kernel_context, StartKernelConfig};
use log::info;
fn main() -> Result<()> {
println!("Starting minauthator admin CLI");
Ok(())
pub mod commands;
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum SubCommands {
Users(users::UsersCommand),
}
#[derive(FromArgs, PartialEq, Debug)]
/// Minauthator admin top level
struct AdminCliTopLevelCommand {
#[argh(subcommand)]
nested: SubCommands,
/// path to YAML config file to use to configure this instance
#[argh(option)]
config: Option<String>,
/// path to the Sqlite3 DB file to use
#[argh(option)]
database: Option<String>,
/// path to the static assets dir
#[argh(option)]
static_assets: Option<String>,
}
/// handle CLI arguments to run admin CLI
#[tokio::main]
pub async fn main() -> Result<()> {
info!("Starting minauth");
let command_input: AdminCliTopLevelCommand = argh::from_env();
let ctx = get_kernel_context(StartKernelConfig {
config_path: command_input.config.clone(),
database_path: command_input.database.clone()
}).await.context("Getting kernel context")?;
match command_input.nested {
SubCommands::Users(sc) => {
users::handle_command_tree(sc, ctx).await
}
}
}