From be462dc662c6b3688516c43aff4fdb56db8ef07b Mon Sep 17 00:00:00 2001 From: jmanczak Date: Thu, 30 Apr 2026 22:01:28 +0200 Subject: [PATCH] actually do db readwrites this time --- src/config.rs | 27 +++++++++++++++++++++++++++ src/main.rs | 4 +++- src/web/pages/conf.rs | 31 +++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index 103c7a4..302f843 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,6 +23,33 @@ impl MnemoConf { pub fn new() -> Self { MnemoConf::default() } + pub async fn load(conn: &mut sqlx::PgConnection) -> Result { + let row: Option = + sqlx::query_scalar("SELECT config FROM mnemoconf LIMIT 1") + .fetch_optional(&mut *conn) + .await?; + + Ok(match row { + Some(val) => serde_json::from_value(val).unwrap_or_default(), + None => { + let conf = MnemoConf::default(); + conf.save(conn).await?; + conf + } + }) + } + + pub async fn save(&self, conn: &mut sqlx::PgConnection) -> Result<(), sqlx::Error> { + let val = serde_json::to_value(self).unwrap(); + sqlx::query("DELETE FROM mnemoconf") + .execute(&mut *conn) + .await?; + sqlx::query("INSERT INTO mnemoconf (config) VALUES ($1)") + .bind(val) + .execute(&mut *conn) + .await?; + Ok(()) + } } impl Default for MnemoConf { fn default() -> Self { diff --git a/src/main.rs b/src/main.rs index 6ac2507..2430e0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,9 @@ async fn main() -> Result<(), Box> { let pool = config::init_pool().await?; sqlx::migrate!("src/database/migrations").run(&pool).await?; log::info!("Migrations applied successfully."); - let conf = Arc::new(RwLock::new(MnemoConf::new())); + let conf = Arc::new(RwLock::new( + MnemoConf::load(&mut *pool.acquire().await?).await?, + )); users::auth::init_password_dummies(); users::setup::initialise_reserved_users_if_needed(&pool).await?; diff --git a/src/web/pages/conf.rs b/src/web/pages/conf.rs index edd49ff..d0d117f 100644 --- a/src/web/pages/conf.rs +++ b/src/web/pages/conf.rs @@ -27,10 +27,21 @@ pub async fn page( ) -> Result { let mut conn = state.pool.acquire().await?; let u = match User::authenticate(&mut *conn, req.headers()).await? { - Some(u) => Some(u), + Some(u) => u, None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()), }; + if !u + .has_permission(&mut *conn, Permission::ConfigureInstance) + .await? + { + return Ok(( + StatusCode::FORBIDDEN, + "You do not have permission to view this page.", + ) + .into_response()); + } + let (current_name, current_webhook) = { let conf = state.conf.read().await; let current_name = conf.instance_name.clone(); @@ -45,7 +56,7 @@ pub async fn page( Ok(base( "Instance Config | Mnemosyne", html!( - (nav(u.as_ref(), req.uri().path())) + (nav(Some(&u), req.uri().path())) div class="max-w-4xl mx-auto px-2" { div class="mx-auto max-w-4xl my-4 mb-8" { @@ -143,18 +154,25 @@ pub async fn change_name( return Ok((StatusCode::BAD_REQUEST, "Instance name cannot be empty.").into_response()); } + let new_name = form.instance_name.trim().to_string(); + LogEntry::new( &mut tx, u, LogAction::ChangeInstanceName { old: state.conf.read().await.instance_name.clone(), - new: form.instance_name.trim().to_string(), + new: new_name.clone(), }, ) .await?; + let mut new_conf = state.conf.read().await.clone(); + new_conf.instance_name = new_name.clone(); + new_conf.save(&mut tx).await?; + tx.commit().await?; - state.conf.write().await.instance_name = form.instance_name.trim().to_string(); + + state.conf.write().await.instance_name = new_name; Ok(Redirect::to("/instance-config").into_response()) } @@ -203,7 +221,12 @@ pub async fn change_webhook( ) .await?; + let mut new_conf = state.conf.read().await.clone(); + new_conf.discord_webhook = new_webhook.clone(); + new_conf.save(&mut tx).await?; + tx.commit().await?; + state.conf.write().await.discord_webhook = new_webhook; Ok(Redirect::to("/instance-config").into_response()) }