//! CLI to bootstrap and inspect invite tokens — useful for creating the very
//! first invite before any user exists (there's no one to generate one from
//! the web UI yet).
use clap::{Parser, Subcommand};
use sea_orm::*;
use std::sync::Arc;
use fieri_eternal::auth;
use fieri_eternal::config::{create_db_connection, Config};
use fieri_eternal::entities::registration_tokens;
#[derive(Parser)]
#[command(name = "registration-token", about = "Manage invite (registration) tokens")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Create a new invite token
Create {
/// Restrict the token to this email (optional)
#[arg(short, long)]
email: Option<String>,
/// Days until the token expires
#[arg(short, long, default_value = "7")]
days: i64,
},
/// List all invite tokens
List,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();
let cli = Cli::parse();
let config = Config::from_env();
let db = Arc::new(create_db_connection(&config.database_url).await?);
match cli.command {
Commands::Create { email, days } => {
let token = auth::create_registration_token(&db, None, email.clone(), days).await?;
println!("Invite token created");
println!(" token: {}", token.token);
println!(" email: {}", email.unwrap_or_else(|| "any".to_string()));
println!(" expires: {}", token.expires_at);
println!();
println!("Registration URL:");
println!(" {}/register?token={}", public_base(&config), token.token);
}
Commands::List => {
let tokens = registration_tokens::Entity::find()
.order_by_desc(registration_tokens::Column::CreatedAt)
.all(db.as_ref())
.await?;
if tokens.is_empty() {
println!("No invite tokens.");
return Ok(());
}
for t in tokens {
let status = if t.is_used {
"used"
} else if t.expires_at < chrono::Utc::now() {
"expired"
} else {
"active"
};
println!(
"{:8} {:36} {}",
status,
t.token,
t.email.unwrap_or_else(|| "any".to_string())
);
}
}
}
Ok(())
}
/// Best-effort public base for the printed registration URL. Override with
/// `PUBLIC_URL`; otherwise derived from the bind address.
fn public_base(config: &Config) -> String {
config.public_url.clone().unwrap_or_else(|| format!("http://{}", config.bind_address))
}
neiam
/fieri-forever
the flavortown lunch engine
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
2.8 KiB · text
History
02765fe