Files
chatapp/backend/src/cli.rs
T
zxq5 bda1ef251a full backend rewrite.
calling this v0.4.0
2026-04-06 00:57:23 +01:00

97 lines
2.9 KiB
Rust

use clap::{Parser, Subcommand};
use sqlx::postgres::PgPoolOptions;
use std::time::Duration;
use std::sync::Arc;
use crate::repo::user_repo::UserRepository;
use crate::repo::space_repo::SpaceRepository;
use crate::repo::channel_repo::ChannelRepository;
use crate::repo::{UserRepo, SpaceRepo, ChannelRepo};
use argon2::{
password_hash::{PasswordHasher, SaltString},
Argon2,
};
use rand::rngs::OsRng;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand)]
pub enum Commands {
/// First-time setup for the server
Setup {
/// Admin username
#[arg(short, long)]
username: String,
/// Admin password
#[arg(short, long)]
password: String,
/// Default space name
#[arg(short, long, default_value = "Default Space")]
space: String,
/// Default channel name
#[arg(short, long, default_value = "general")]
channel: String,
},
}
pub async fn handle_cli() -> bool {
let cli = Cli::parse();
match cli.command {
Some(Commands::Setup { username, password, space, channel }) => {
if let Err(e) = run_setup(username, password, space, channel).await {
eprintln!("Setup failed: {}", e);
std::process::exit(1);
}
println!("Setup completed successfully!");
true
}
None => false,
}
}
async fn run_setup(username: String, password: String, space_name: String, channel_name: String) -> Result<(), Box<dyn std::error::Error>> {
dotenv::dotenv().ok();
let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = PgPoolOptions::new()
.max_connections(1)
.acquire_timeout(Duration::from_secs(5))
.connect(&db_url)
.await?;
let user_repo = UserRepository::new(pool.clone());
let space_repo = SpaceRepository::new(pool.clone());
let channel_repo = ChannelRepository::new(pool.clone());
// 1. Create admin user
println!("Creating admin user: {}...", username);
let argon2 = Argon2::default();
let salt = SaltString::generate(&mut OsRng);
let passhash = argon2
.hash_password(password.as_bytes(), &salt)
.map_err(|e| e.to_string())?
.to_string();
let user_id = user_repo.new_user("admin@localhost", &username, &passhash).await?;
user_repo.set_role(user_id, "admin").await?;
// 2. Create default space
println!("Creating default space: {}...", space_name);
let space_id = space_repo.create(&space_name, Some("Default space created during setup"), user_id).await?;
// 3. Create default channel
println!("Creating default channel: {}...", channel_name);
channel_repo.create(&channel_name, Some("Default channel"), space_id).await?;
Ok(())
}