only show instance config link for permitted users, make nav markup

component async
This commit is contained in:
2026-05-04 14:11:31 +02:00
parent 47cd13f734
commit f876ff3f00
14 changed files with 32 additions and 21 deletions

View File

@@ -1,6 +1,10 @@
use maud::{Markup, PreEscaped, html};
use sqlx::PgConnection;
use crate::{users::User, web::icons};
use crate::{
users::{User, permissions::Permission},
web::icons,
};
// (SHOWTEXT, LINK, ICON, REQUIRES_LOG_IN)
const LINKS: &[(&str, &str, &str, bool)] = &[
@@ -13,7 +17,12 @@ const LINKS: &[(&str, &str, &str, bool)] = &[
("Logs", "/logs", icons::CLIPBOARD_CLOCK, true),
];
pub fn nav(user: Option<&User>, uri: &str) -> Markup {
pub async fn nav(conn: &mut PgConnection, user: Option<&User>, uri: &str) -> Markup {
#[rustfmt::skip]
let show_instance_conf = match user {
Some(u) if u.has_permission(conn, Permission::ConfigureInstance).await.is_ok_and(|r| r) => true,
_ => false,
};
html!(
div class="flex items-center text-sm gap-4 border-b border-neutral-200/25 bg-neutral-200/5 px-4 py-2" {
a href="/dashboard" class="font-lora font-semibold hidden xs:block md:text-xl sm:mr-2" {"Mnemosyne"}
@@ -56,10 +65,12 @@ pub fn nav(user: Option<&User>, uri: &str) -> Markup {
div class="scale-[.7]" {(PreEscaped(icons::SETTINGS))}
p {"User Settings"}
}
div class="h-px w-full bg-neutral-200/15" {}
a href="/instance-config" class="px-4 py-2 flex items-center gap-2 hover:bg-neutral-200/10 font-lexend text-sm text-neutral-200 transition-colors" {
div class="scale-[.7]" {(PreEscaped(icons::SERVER))}
p {"Instance Config"}
@if show_instance_conf {
div class="h-px w-full bg-neutral-200/15" {}
a href="/instance-config" class="px-4 py-2 flex items-center gap-2 hover:bg-neutral-200/10 font-lexend text-sm text-neutral-200 transition-colors" {
div class="scale-[.7]" {(PreEscaped(icons::SERVER))}
p {"Instance Config"}
}
}
div class="h-px w-full bg-neutral-200/15" {}
form action="/api/auth/logout-form" method="post" {

View File

@@ -56,7 +56,7 @@ pub async fn page(
Ok(base(
"Instance Config | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="max-w-4xl mx-auto px-2" {
div class="mx-auto max-w-4xl my-4 mb-8" {

View File

@@ -51,7 +51,7 @@ pub async fn page(
Ok(base(
"Dashboard | Mnemosyne",
html!(
(nav(u.as_ref(), req.uri().path()))
(nav(&mut conn, u.as_ref(), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 mt-4 grid grid-cols-1 --sm:grid-cols-2 gap-4" {
div class="flex flex-col" {

View File

@@ -42,7 +42,7 @@ pub async fn page(
Ok(base(
"Logs | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut tx, Some(&u), req.uri().path()).await)
@if true {//let Ok(true) = u.has_permission(&mut *tx, Permission::BrowseServerLogs) {
div class="max-w-4xl mx-auto px-2" {

View File

@@ -17,7 +17,7 @@ pub async fn page(State(state): State<MnemoState>, req: Request) -> Result<Marku
Ok(base(
"Not Found | Mnemosyne",
html!(
(nav(u.as_ref(), req.uri().path()))
(nav(&mut conn, u.as_ref(), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 mt-8 mb-2" {
h1 class="text-4xl font-lora font-semibold mb-1" { "Not Found" }

View File

@@ -45,7 +45,7 @@ pub async fn page(
Ok(base(
"Persons | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 my-4" {
p class="flex items-center gap-2" {

View File

@@ -51,7 +51,7 @@ pub async fn page(
Ok(base(
&title,
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 my-4" {
@if let Ok(p) = p {

View File

@@ -60,7 +60,7 @@ pub async fn page(
Ok(base(
"Quotes | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="max-w-4xl mx-auto px-2" {
div class="my-4 flex justify-between" {

View File

@@ -40,7 +40,7 @@ pub async fn page(
Ok(base(
"Add Quote | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="max-w-4xl mx-auto px-2" {
div class="my-4 flex justify-between" {

View File

@@ -46,7 +46,7 @@ pub async fn page(
Ok(base(
"Tags | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 my-4" {
p class="flex items-center gap-2" {

View File

@@ -35,7 +35,7 @@ pub async fn page(
Ok(base(
"Users | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 my-4" {
p class="flex items-center gap-2" {

View File

@@ -36,7 +36,7 @@ pub async fn page(
Ok(base(
"Create User | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="mx-auto max-w-4xl px-2 my-4" {
p class="flex items-center gap-2" {

View File

@@ -33,7 +33,7 @@ pub async fn page(
return Ok(base(
"No such user | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut tx, Some(&u), req.uri().path()).await)
div class="mx-auto max-w-4xl mt-16 text-center" {
div class="text-6xl mb-4" { "?" }
p class="text-red-400 text-lg" { "No such user found." }
@@ -48,7 +48,7 @@ pub async fn page(
}
_ => {
return Ok(base("Error | Mnemosyne", html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut tx, Some(&u), req.uri().path()).await)
p class="text-red-400 text-center my-4" { "An error occurred while loading this profile." }
)).into_response());
}
@@ -70,7 +70,7 @@ pub async fn page(
Ok(base(
&format!("@{} | Mnemosyne", user.handle),
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut tx, Some(&u), req.uri().path()).await)
// banner
div class="relative w-full h-48 sm:h-56 md:h-64 bg-linear-to-b from-neutral-800 from-25% to-emerald-950 overflow-hidden" {

View File

@@ -32,7 +32,7 @@ pub async fn page(
Ok(base(
"User Settings | Mnemosyne",
html!(
(nav(Some(&u), req.uri().path()))
(nav(&mut conn, Some(&u), req.uri().path()).await)
div class="max-w-4xl mx-auto px-2" {
div class="mx-auto max-w-4xl my-4" {