From 84dde9cc4b6d9f99b4b766347c631b9bbe38e2d3 Mon Sep 17 00:00:00 2001 From: jmanczak Date: Wed, 6 May 2026 02:24:05 +0200 Subject: [PATCH] require permission to delete quotes --- src/web/pages/quotes/id.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/web/pages/quotes/id.rs b/src/web/pages/quotes/id.rs index f2a33c1..9a123e8 100644 --- a/src/web/pages/quotes/id.rs +++ b/src/web/pages/quotes/id.rs @@ -3,6 +3,7 @@ use axum::{ http::HeaderMap, response::{IntoResponse, Redirect, Response}, }; +use http::StatusCode; use maud::{PreEscaped, html}; use uuid::Uuid; @@ -14,6 +15,7 @@ use crate::{ users::{ User, auth::{UserAuthRequired, UserAuthenticate}, + permissions::Permission, }, web::{ components::{nav::nav, quote::quote}, @@ -33,6 +35,9 @@ pub async fn page( None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()), }; let q = Quote::get_by_id(&mut conn, id).await; + let can_delete = u + .has_permission(&mut conn, Permission::DeleteQuotes) + .await?; Ok(base( "Add Quote | Mnemosyne", @@ -53,9 +58,11 @@ pub async fn page( span class="scale-[.75]" {(PreEscaped(icons::PEN))} "Edit" } - a href=(format!("/quotes/{id}/delete")) class="px-2 py-1 cursor-pointer border rounded flex flex-row gap-1 bg-pink-400/10 border-pink-400/25 hover:bg-pink-400/20 hover:border-pink-400/45" { - span class="scale-[.75]" {(PreEscaped(icons::TRASH))} - "Delete" + @if can_delete { + a href=(format!("/quotes/{id}/delete")) class="px-2 py-1 cursor-pointer border rounded flex flex-row gap-1 bg-pink-400/10 border-pink-400/25 hover:bg-pink-400/20 hover:border-pink-400/45" { + span class="scale-[.75]" {(PreEscaped(icons::TRASH))} + "Delete" + } } } } @else { @@ -126,6 +133,9 @@ pub async fn delete( ) -> Result { let mut tx = state.pool.begin().await?; let u = User::authenticate(&mut *tx, &headers).await?.required()?; + if !u.has_permission(&mut tx, Permission::DeleteQuotes).await? { + return Ok((StatusCode::FORBIDDEN, "No permission.").into_response()); + } let q = Quote::get_by_id(&mut *tx, id).await?; LogEntry::new(&mut *tx, u, LogAction::DeleteQuote { quote: q.clone() }).await?;