frontend: Only show logout button when logged in

This commit is contained in:
Lennart
2025-11-04 15:33:13 +01:00
parent 53c6e3b1f4
commit 3a10a695f5
7 changed files with 62 additions and 7 deletions

View File

@@ -14,9 +14,11 @@
<header> <header>
<a class="logo" href="/frontend/user">RustiCal</a> <a class="logo" href="/frontend/user">RustiCal</a>
{% block header_center %}{% endblock %} {% block header_center %}{% endblock %}
<form method="POST" action="/frontend/logout" class="logout_form"> {% if self.get_user().is_some() %}
<button type="submit">Log out</button> <form method="POST" action="/frontend/logout" class="logout_form">
</form> <button type="submit">Log out</button>
</form>
{% endif %}
</header> </header>
{% endblock %} {% endblock %}
<div id="app"> <div id="app">

View File

@@ -2,7 +2,7 @@ use super::{
NextcloudFlow, NextcloudFlows, NextcloudLoginPoll, NextcloudLoginResponse, NextcloudFlow, NextcloudFlows, NextcloudLoginPoll, NextcloudLoginResponse,
NextcloudSuccessResponse, NextcloudSuccessResponse,
}; };
use crate::routes::app_token::generate_app_token; use crate::{pages::DefaultLayoutData, routes::app_token::generate_app_token};
use askama::Template; use askama::Template;
use axum::{ use axum::{
Extension, Form, Json, Extension, Form, Json,
@@ -100,6 +100,12 @@ struct NextcloudLoginPage {
app_name: String, app_name: String,
} }
impl DefaultLayoutData for NextcloudLoginPage {
fn get_user(&self) -> Option<&Principal> {
None
}
}
#[instrument(skip(state))] #[instrument(skip(state))]
pub async fn get_nextcloud_flow( pub async fn get_nextcloud_flow(
Extension(state): Extension<Arc<NextcloudFlows>>, Extension(state): Extension<Arc<NextcloudFlows>>,
@@ -130,6 +136,13 @@ pub struct NextcloudAuthorizeForm {
#[template(path = "pages/nextcloud_login/success.html")] #[template(path = "pages/nextcloud_login/success.html")]
struct NextcloudLoginSuccessPage { struct NextcloudLoginSuccessPage {
app_name: String, app_name: String,
user: Principal,
}
impl DefaultLayoutData for NextcloudLoginSuccessPage {
fn get_user(&self) -> Option<&Principal> {
Some(&self.user)
}
} }
#[instrument(skip(state))] #[instrument(skip(state))]
@@ -150,6 +163,7 @@ pub async fn post_nextcloud_flow(
Ok(Html( Ok(Html(
NextcloudLoginSuccessPage { NextcloudLoginSuccessPage {
app_name: flow.app_name.clone(), app_name: flow.app_name.clone(),
user,
} }
.render() .render()
.unwrap(), .unwrap(),

View File

@@ -1 +1,8 @@
use rustical_store::auth::Principal;
pub mod user; pub mod user;
/// Required by the base layout
pub trait DefaultLayoutData {
fn get_user(&self) -> Option<&Principal>;
}

View File

@@ -2,6 +2,8 @@ use askama::Template;
use askama_web::WebTemplate; use askama_web::WebTemplate;
use rustical_store::auth::Principal; use rustical_store::auth::Principal;
use crate::pages::DefaultLayoutData;
pub trait Section: Template { pub trait Section: Template {
fn name() -> &'static str; fn name() -> &'static str;
} }
@@ -12,3 +14,9 @@ pub struct UserPage<S: Section> {
pub user: Principal, pub user: Principal,
pub section: S, pub section: S,
} }
impl<S: Section> DefaultLayoutData for UserPage<S> {
fn get_user(&self) -> Option<&Principal> {
Some(&self.user)
}
}

View File

@@ -12,10 +12,19 @@ use headers::Referer;
use http::StatusCode; use http::StatusCode;
use rustical_store::{Addressbook, AddressbookStore, auth::Principal}; use rustical_store::{Addressbook, AddressbookStore, auth::Principal};
use crate::pages::DefaultLayoutData;
#[derive(Template, WebTemplate)] #[derive(Template, WebTemplate)]
#[template(path = "pages/addressbook.html")] #[template(path = "pages/addressbook.html")]
struct AddressbookPage { struct AddressbookPage {
addressbook: Addressbook, addressbook: Addressbook,
user: Principal,
}
impl DefaultLayoutData for AddressbookPage {
fn get_user(&self) -> Option<&Principal> {
Some(&self.user)
}
} }
pub async fn route_addressbook<AS: AddressbookStore>( pub async fn route_addressbook<AS: AddressbookStore>(
@@ -28,6 +37,7 @@ pub async fn route_addressbook<AS: AddressbookStore>(
} }
Ok(AddressbookPage { Ok(AddressbookPage {
addressbook: store.get_addressbook(&owner, &addrbook_id, true).await?, addressbook: store.get_addressbook(&owner, &addrbook_id, true).await?,
user,
} }
.into_response()) .into_response())
} }

View File

@@ -1,5 +1,4 @@
use std::sync::Arc; use crate::pages::DefaultLayoutData;
use askama::Template; use askama::Template;
use askama_web::WebTemplate; use askama_web::WebTemplate;
use axum::{ use axum::{
@@ -11,11 +10,19 @@ use axum_extra::TypedHeader;
use headers::Referer; use headers::Referer;
use http::StatusCode; use http::StatusCode;
use rustical_store::{Calendar, CalendarStore, auth::Principal}; use rustical_store::{Calendar, CalendarStore, auth::Principal};
use std::sync::Arc;
#[derive(Template, WebTemplate)] #[derive(Template, WebTemplate)]
#[template(path = "pages/calendar.html")] #[template(path = "pages/calendar.html")]
struct CalendarPage { struct CalendarPage {
calendar: Calendar, calendar: Calendar,
user: Principal,
}
impl DefaultLayoutData for CalendarPage {
fn get_user(&self) -> Option<&Principal> {
Some(&self.user)
}
} }
pub async fn route_calendar<C: CalendarStore>( pub async fn route_calendar<C: CalendarStore>(
@@ -28,6 +35,7 @@ pub async fn route_calendar<C: CalendarStore>(
} }
Ok(CalendarPage { Ok(CalendarPage {
calendar: store.get_calendar(&owner, &cal_id, true).await?, calendar: store.get_calendar(&owner, &cal_id, true).await?,
user,
} }
.into_response()) .into_response())
} }

View File

@@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{FrontendConfig, OidcConfig}; use crate::{FrontendConfig, OidcConfig, pages::DefaultLayoutData};
use askama::Template; use askama::Template;
use askama_web::WebTemplate; use askama_web::WebTemplate;
use axum::{ use axum::{
@@ -24,6 +24,12 @@ struct LoginPage<'a> {
allow_password_login: bool, allow_password_login: bool,
} }
impl DefaultLayoutData for LoginPage<'_> {
fn get_user(&self) -> Option<&rustical_store::auth::Principal> {
None
}
}
struct OidcProviderData<'a> { struct OidcProviderData<'a> {
pub name: &'a str, pub name: &'a str,
pub redirect_url: String, pub redirect_url: String,