use clap::{Parser, Subcommand};
use sea_orm::DatabaseConnection;
use std::sync::Arc;
use dms::{auth, config::{Config, create_db_connection}};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(name = "registration-token")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Create a new registration token
Create {
/// Email to restrict token to (optional)
#[arg(short, long)]
email: Option<String>,
/// Number of days until token expires
#[arg(short, long, default_value = "7")]
days: i64,
/// User ID (UUID) of the admin creating this token (optional)
#[arg(short, long)]
created_by: Option<uuid::Uuid>,
},
/// List all registration tokens
List,
/// Show detailed information about a token
Show {
/// Token to show
token: String,
},
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
tracing_subscriber::fmt::init();
let cli = Cli::parse();
// Load configuration
let config = Config::from_env()?;
let db = Arc::new(create_db_connection(&config.database_url).await?);
match cli.command {
Commands::Create { email, days, created_by } => {
create_token(&db, email, days, created_by).await?;
}
Commands::List => {
list_tokens(&db).await?;
}
Commands::Show { token } => {
show_token(&db, &token).await?;
}
}
Ok(())
}
async fn create_token(
db: &DatabaseConnection,
email: Option<String>,
days: i64,
created_by: Option<uuid::Uuid>,
) -> Result<(), Box<dyn std::error::Error>> {
let token = auth::create_registration_token(db, created_by, email.clone(), days).await?;
println!("✅ Registration token created successfully!");
println!();
println!("Token: {}", token.token);
println!("Email: {}", email.unwrap_or_else(|| "Any".to_string()));
println!("Expires: {}", token.expires_at);
println!("Created by: {}", created_by.map_or_else(|| "System".to_string(), |id| id.to_string()));
println!();
println!("🔗 Registration URL:");
println!(" http://localhost:3007/register?token={}", token.token);
Ok(())
}
async fn list_tokens(db: &DatabaseConnection) -> Result<(), Box<dyn std::error::Error>> {
use sea_orm::*;
use dms::entities::registration_tokens;
let tokens = registration_tokens::Entity::find()
.order_by_desc(registration_tokens::Column::CreatedAt)
.all(db)
.await?;
if tokens.is_empty() {
println!("No registration tokens found.");
return Ok(());
}
println!("Registration Tokens:");
println!("┌────────────────────────────────────────┬──────────────────┬──────────┬─────────────────────┐");
println!("│ Token │ Email │ Status │ Expires │");
println!("├────────────────────────────────────────┼──────────────────┼──────────┼─────────────────────┤");
for token in tokens {
let email = token.email.as_deref().unwrap_or("Any");
let status = if token.is_used {
"Used"
} else if token.expires_at < chrono::DateTime::<chrono::FixedOffset>::from(chrono::Utc::now()) {
"Expired"
} else {
"Active"
};
println!(
"│ {:<38} │ {:<16} │ {:<8} │ {:<19} │",
&token.token[..Ord::min(38, token.token.len())],
&email[..Ord::min(16, email.len())],
status,
token.expires_at.format("%Y-%m-%d %H:%M:%S")
);
}
println!("└────────────────────────────────────────┴──────────────────┴──────────┴─────────────────────┘");
Ok(())
}
async fn show_token(
db: &DatabaseConnection,
token: &str,
) -> Result<(), Box<dyn std::error::Error>> {
use sea_orm::*;
use dms::entities::registration_tokens;
let token_model = registration_tokens::Entity::find()
.filter(registration_tokens::Column::Token.eq(token))
.one(db)
.await?;
match token_model {
Some(token) => {
println!("Registration Token Details:");
println!();
println!("Token: {}", token.token);
println!("Email: {}", token.email.unwrap_or_else(|| "Any".to_string()));
println!("Status: {}", if token.is_used {
"Used"
} else if token.expires_at < chrono::DateTime::<chrono::FixedOffset>::from(chrono::Utc::now()) {
"Expired"
} else {
"Active"
});
println!("Created: {}", token.created_at);
println!("Expires: {}", token.expires_at);
println!("Created by: {}", token.created_by_user_id.map_or_else(|| "System".to_string(), |id| id.to_string()));
if token.is_used {
println!("Used by: {}", token.used_by_user_id.map_or_else(|| "Unknown".to_string(), |id| id.to_string()));
if let Some(used_at) = token.used_at {
println!("Used at: {}", used_at);
}
}
println!();
println!("🔗 Registration URL:");
println!(" http://localhost:3007/register?token={}", token.token);
}
None => {
println!("❌ Token not found: {}", token);
}
}
Ok(())
}
⭐
Log in to mark this repository.
6.0 KiB · text
History
8aa8e40