use anyhow::{Result, bail};
use clap::Args;
use console::style;
use dialoguer::Confirm;
use opencode_cloud_core::docker::{
CONTAINER_NAME, DockerClient, delete_user, list_users, remove_persisted_user, user_exists,
};
use opencode_cloud_core::{load_config_or_default, save_config};
#[derive(Args)]
pub struct UserRemoveArgs {
pub username: String,
#[arg(long, short)]
pub force: bool,
}
const PROTECTED_USER: &str = "opencoder";
pub async fn cmd_user_remove(
client: &DockerClient,
args: &UserRemoveArgs,
quiet: bool,
_verbose: u8,
) -> Result<()> {
let username = &args.username;
if username == PROTECTED_USER {
bail!(
"Cannot remove '{PROTECTED_USER}' - this is a protected system user required for the container to function.\n\n\
To manage authentication users, use:\n \
occ user add <username>\n \
occ user remove <username>"
);
}
if !user_exists(client, CONTAINER_NAME, username).await? {
bail!("User '{username}' does not exist in the container");
}
let mut config = load_config_or_default()?;
let container_users = list_users(client, CONTAINER_NAME).await?;
let is_last_user = container_users.len() == 1;
if is_last_user && !args.force {
bail!(
"Cannot remove last user. Add another user first or use --force.\n\n\
To add a new user:\n \
occ user add <username>\n\n\
To force removal:\n \
occ user remove {username} --force"
);
}
if !args.force {
let confirm = Confirm::new()
.with_prompt(format!("Remove user '{username}'?"))
.default(false)
.interact()
.unwrap_or(false);
if !confirm {
if !quiet {
println!("Cancelled.");
}
return Ok(());
}
}
delete_user(client, CONTAINER_NAME, username).await?;
remove_persisted_user(client, CONTAINER_NAME, username).await?;
config.users.retain(|u| u != username);
save_config(&config)?;
if !quiet {
println!(
"{} User '{}' removed successfully",
style("Success:").green().bold(),
username
);
}
Ok(())
}