use std::str::FromStr; use crate::db::user::{add_user, get_user_by_name, get_user_count, DbUserRole}; use anyhow::{anyhow, Result}; use serde::Deserialize; use sqlx::SqlitePool; use tracing::info; const DEFAULT_TIMEZONE: i64 = -6 * 3600; #[derive(Debug, Deserialize)] struct BootstrapData { users: Vec, } #[derive(Debug, Deserialize)] struct BootstrapUser { name: String, role: String, tz_offset: Option, } pub async fn bootstrap_database(db: &SqlitePool) -> Result<()> { let bootstrap_str = match std::env::var("BOOTSTRAP_DATA") { Ok(s) => { info!("bootstrap data found, updating db: {}", s); s }, Err(_) => { info!("no Bootstrap data found"); return Ok(()); }, }; let data = ron::from_str::(&bootstrap_str)?; if db_needs_users(db).await? { for user in &data.users { let role = DbUserRole::try_from_str(&user.role).ok_or(anyhow!("invalid role {}", user.role))?; let tz = if let Some(tz) = &user.tz_offset { i64::from_str(&tz).unwrap_or(DEFAULT_TIMEZONE) } else { DEFAULT_TIMEZONE }; if get_user_by_name(db, &user.name).await?.is_none() { let new_id = add_user(db, &user.name, role, tz).await?; info!("bootstrap new user {}:{} ({})", new_id, user.name, user.role); } } } Ok(()) } async fn db_needs_users(db: &SqlitePool) -> Result { let count = get_user_count(&db).await?; Ok(count <= 0) }