full backend rewrite.
calling this v0.4.0
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
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(())
|
||||
}
|
||||
Reference in New Issue
Block a user