From 09d782b6a51820a3c5b61e41b3e40ec2ccb87dfb Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Fri, 29 Aug 2025 15:03:05 +0200 Subject: [PATCH] feat(otter): add link to users page in navbar for admins --- CHANGELOG.md | 1 + otter/src/server/web/mod.rs | 6 ++++-- otter/src/server/web/sessions.rs | 4 +++- otter/src/server/web/users.rs | 2 +- otter/src/web/page.rs | 20 +++++++++++++++++++- otter/src/web/templates/base.html | 3 +++ 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 179b144..1529316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Ability for an account to be an admin * CLI command to toggle admin status of users +* Admin user management page ## [0.3.0](https://git.rustybever.be/Chewing_Bever/otter/src/tag/0.3.0) diff --git a/otter/src/server/web/mod.rs b/otter/src/server/web/mod.rs index ab67b9a..06e9713 100644 --- a/otter/src/server/web/mod.rs +++ b/otter/src/server/web/mod.rs @@ -73,10 +73,12 @@ async fn get_index( headers: HeaderMap, jar: CookieJar, ) -> AppResult>> { - let authenticated = auth::extract_session(ctx.clone(), &jar).await?.is_some(); + let user = auth::extract_session(ctx.clone(), &jar) + .await? + .map(|session| session.user); Ok(View::Index .page(&headers) - .authenticated(authenticated) + .user(user.as_ref()) .response(&ctx.tera)) } diff --git a/otter/src/server/web/sessions.rs b/otter/src/server/web/sessions.rs index 4c7aa4c..f60a09a 100644 --- a/otter/src/server/web/sessions.rs +++ b/otter/src/server/web/sessions.rs @@ -30,6 +30,8 @@ pub async fn get_sessions( Query(page): Query, ) -> AppResult>> { let next_page = page.next_page(); + let admin = session.user.admin; + let sessions = tokio::task::spawn_blocking(move || { ctx.store .user(&session.user) @@ -44,7 +46,7 @@ pub async fn get_sessions( Ok(View::Sessions(sessions, session.id, next_page_query) .page(&headers) .headers(&headers) - .authenticated(true) + .authenticated(true, admin) .response(&ctx.tera)) } diff --git a/otter/src/server/web/users.rs b/otter/src/server/web/users.rs index c719076..c6d5a5b 100644 --- a/otter/src/server/web/users.rs +++ b/otter/src/server/web/users.rs @@ -68,7 +68,7 @@ async fn get_users( Ok(View::Users(users, user_id, next_page_query) .page(&headers) .headers(&headers) - .authenticated(true) + .authenticated(true, true) .response(&ctx.tera)) } diff --git a/otter/src/web/page.rs b/otter/src/web/page.rs index e7f7f6b..2cf5a4b 100644 --- a/otter/src/web/page.rs +++ b/otter/src/web/page.rs @@ -11,6 +11,7 @@ pub struct Page { template: T, wrap_with_base: bool, authenticated: bool, + admin: bool, } impl Template for Page { @@ -25,6 +26,7 @@ impl Template for Page { let mut ctx = tera::Context::new(); ctx.insert("inner", &inner); ctx.insert("authenticated", &self.authenticated); + ctx.insert("admin", &self.admin); tera.render(super::BASE_TEMPLATE, &ctx) } else { @@ -39,6 +41,7 @@ impl Page { template, wrap_with_base: false, authenticated: false, + admin: false, } } @@ -54,8 +57,23 @@ impl Page { self } - pub fn authenticated(mut self, authenticated: bool) -> Self { + /// Set the view's authentication level + pub fn authenticated(mut self, authenticated: bool, admin: bool) -> Self { self.authenticated = authenticated; + self.admin = admin; + + self + } + + /// Utility function to derive authentication level from a given user + pub fn user(mut self, user: Option<&gpodder::User>) -> Self { + if let Some(user) = user { + self.authenticated = true; + self.admin = user.admin; + } else { + self.authenticated = false; + self.admin = false; + } self } diff --git a/otter/src/web/templates/base.html b/otter/src/web/templates/base.html index c60df08..d1ea814 100644 --- a/otter/src/web/templates/base.html +++ b/otter/src/web/templates/base.html @@ -23,6 +23,9 @@ a:hover {