use anyhow::{Result, anyhow};
use clap::Args;
use systemprompt_identifiers::SessionId;
use systemprompt_runtime::AppContext;
use systemprompt_users::{UserAdminService, UserService};
use crate::CliConfig;
use crate::commands::admin::users::types::SessionEndOutput;
use crate::shared::CommandResult;
#[derive(Debug, Args)]
pub struct EndArgs {
#[arg(
value_name = "SESSION_ID",
help = "Session ID to end (optional if using --user --all)"
)]
pub session: Option<String>,
#[arg(
long,
help = "User identifier (ID, email, or username) to end sessions for"
)]
pub user: Option<String>,
#[arg(
long,
help = "End all sessions for the specified user (requires --user)"
)]
pub all: bool,
#[arg(short = 'y', long)]
pub yes: bool,
}
pub async fn execute(
args: EndArgs,
_config: &CliConfig,
) -> Result<CommandResult<SessionEndOutput>> {
if !args.yes {
return Err(anyhow!(
"This will end user session(s). Use --yes to confirm."
));
}
let ctx = AppContext::new().await?;
let user_service = UserService::new(ctx.db_pool())?;
let admin_service = UserAdminService::new(user_service.clone());
if args.all {
let user_identifier = args
.user
.ok_or_else(|| anyhow!("--user is required when using --all"))?;
let user = admin_service
.find_user(&user_identifier)
.await?
.ok_or_else(|| anyhow!("User not found: {}", user_identifier))?;
let count = user_service.end_all_sessions(&user.id).await?;
let output = SessionEndOutput {
ended: vec![format!("all sessions for user '{}'", user.name)],
count,
message: format!("{} session(s) ended for user '{}'", count, user.name),
};
return Ok(CommandResult::text(output).with_title("Sessions Ended"));
}
let session_id_str = args.session.ok_or_else(|| {
anyhow!("Session ID is required (or use --user --all to end all sessions for a user)")
})?;
let session_id = SessionId::new(&session_id_str);
let ended = user_service.end_session(&session_id).await?;
let output = SessionEndOutput {
ended: if ended {
vec![session_id_str.clone()]
} else {
vec![]
},
count: u64::from(ended),
message: if ended {
format!("Session '{}' ended successfully", session_id_str)
} else {
format!(
"Session '{}' was not found or already ended",
session_id_str
)
},
};
Ok(CommandResult::text(output).with_title("Sessions Ended"))
}