use std::io::Write;
use sqlx::Database;
use crate::manage_interactive;
use crate::tenancy::error::TenancyError;
use crate::tenancy::operators::{self as ops, Outcome};
use crate::tenancy::pools::TenantPools;
fn explain(e: ops::OperatorError) -> TenancyError {
match e {
ops::OperatorError::Driver(d) => TenancyError::from(d),
other => TenancyError::Validation(other.to_string()),
}
}
pub(super) async fn list_operators<W: Write + Send, DB: Database>(
pools: &TenantPools<DB>,
args: &[String],
w: &mut W,
) -> Result<(), TenancyError>
where
crate::sql::Pool: From<sqlx::Pool<DB>>,
{
super::args::no_args(args, "list-operators")?;
let rows = ops::list(&pools.registry_pool()).await.map_err(explain)?;
if rows.is_empty() {
writeln!(w, "(no operators — create one with `create-operator`)")?;
return Ok(());
}
writeln!(w, "{:<32} {:<8} created_at", "username", "active")?;
writeln!(w, "{}", "-".repeat(64))?;
for o in &rows {
writeln!(
w,
"{:<32} {:<8} {}",
o.username,
o.active,
o.created_at.format("%Y-%m-%d %H:%M:%SZ"),
)?;
}
let active = rows.iter().filter(|o| o.active).count();
writeln!(w, "\n{} operator(s), {active} active", rows.len())?;
Ok(())
}
pub(super) async fn set_operator_active<W: Write + Send, DB: Database>(
pools: &TenantPools<DB>,
args: &[String],
w: &mut W,
) -> Result<(), TenancyError>
where
crate::sql::Pool: From<sqlx::Pool<DB>>,
{
let parsed = super::args::parse(
args,
&super::args::Spec {
verb: "set-operator-active",
usage: "set-operator-active <username> --on|--off",
switches: &["--on", "--off"],
valued: &[],
max_positionals: 1,
},
)?;
let active = parsed.on_off()?;
let username = match parsed.positional(0) {
Some(u) => u.clone(),
None => manage_interactive::ask("Operator username: ")
.map_err(TenancyError::Io)?
.ok_or_else(|| {
TenancyError::Validation("set-operator-active requires a username".into())
})?,
};
let active = active.ok_or_else(|| {
TenancyError::Validation("set-operator-active requires --on or --off".into())
})?;
let registry = pools.registry_pool();
let mut target = ops::by_username(®istry, &username)
.await
.map_err(explain)?;
match ops::set_active(®istry, &mut target, active, None)
.await
.map_err(explain)?
{
Outcome::AlreadySo => writeln!(
w,
"`{username}` was already {}",
if active { "active" } else { "inactive" }
)?,
Outcome::Changed => writeln!(
w,
"{} `{username}`",
if active { "activated" } else { "deactivated" }
)?,
}
Ok(())
}