From f6d4e7c55611b916b91befffef041b46f6d076df Mon Sep 17 00:00:00 2001 From: gabatxo1312 Date: Sat, 31 Jan 2026 00:05:53 +0100 Subject: [PATCH] Add Base Path --- BookForge.toml | 1 + src/lib.rs | 17 ++++++++++++----- src/routes/book.rs | 38 ++++++++++++++++++++++++++++++++------ src/routes/mod.rs | 1 + src/routes/template_ctx.rs | 14 ++++++++++++++ src/routes/user.rs | 29 +++++++++++++++++++++++------ src/state/config.rs | 6 ++++++ src/state/error.rs | 5 +++++ templates/base.html | 12 ++++++------ 9 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 src/routes/template_ctx.rs diff --git a/BookForge.toml b/BookForge.toml index 57033f1..0ac7cc8 100644 --- a/BookForge.toml +++ b/BookForge.toml @@ -1,5 +1,6 @@ database_path = "" locale = "fr" +base_url = "" [listener] port = 8000 diff --git a/src/lib.rs b/src/lib.rs index 9c1f01d..52757e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,11 +2,12 @@ use askama::Template; use askama_web::WebTemplate; use axum::{ Router, + extract::State, routing::{get, post}, }; use static_serve::embed_assets; -use crate::state::AppState; +use crate::{routes::template_ctx::TemplateCtx, state::AppState}; mod migrations; mod models; @@ -44,8 +45,14 @@ pub fn build_app(state: AppState) -> Router { #[derive(Template, WebTemplate)] #[template(path = "404.html")] -struct NotFoundTemplate {} - -pub async fn error_handler() -> impl axum::response::IntoResponse { - NotFoundTemplate {} +struct NotFoundTemplate { + pub ctx: TemplateCtx, +} + +pub async fn error_handler(State(state): State) -> impl axum::response::IntoResponse { + NotFoundTemplate { + ctx: TemplateCtx { + base_path: state.config.base_path, + }, + } } diff --git a/src/routes/book.rs b/src/routes/book.rs index 124a44f..1b1dbfc 100644 --- a/src/routes/book.rs +++ b/src/routes/book.rs @@ -13,7 +13,9 @@ use serde::Deserialize; use serde_with::{NoneAsEmptyString, serde_as}; use snafu::prelude::*; -use crate::{models::book::Model as BookModel, state::error::CSVSnafu}; +use crate::{ + models::book::Model as BookModel, routes::template_ctx::TemplateCtx, state::error::CSVSnafu, +}; use crate::{models::user::Model as UserModel, state::error::IOSnafu}; use crate::{ @@ -55,6 +57,7 @@ struct BookIndexTemplate { current_page: u64, total_page: u64, base_query: String, + ctx: TemplateCtx, } pub async fn index( @@ -73,7 +76,7 @@ pub async fn index( .context(UserSnafu)?; // Get all Book filtered with query - let books_paginate = BookOperator::new(state) + let books_paginate = BookOperator::new(state.clone()) .all_paginate(page, Some(query.clone())) .await .context(BookSnafu)?; @@ -127,6 +130,9 @@ pub async fn index( current_page: books_paginate.current_page, total_page: books_paginate.total_page, base_query, + ctx: TemplateCtx { + base_path: state.config.base_path, + }, }) } @@ -136,6 +142,7 @@ struct ShowBookTemplate { book: BookModel, owner: UserModel, current_holder: Option, + ctx: TemplateCtx, } pub async fn show( @@ -168,6 +175,9 @@ pub async fn show( book, owner, current_holder, + ctx: TemplateCtx { + base_path: state.config.base_path, + }, }) } @@ -200,14 +210,23 @@ pub async fn create( #[template(path = "books/new.html")] struct NewBookTemplate { users: Vec, + ctx: TemplateCtx, } pub async fn new( State(state): State, ) -> Result { - let users = UserOperator::new(state).all().await.context(UserSnafu)?; + let users = UserOperator::new(state.clone()) + .all() + .await + .context(UserSnafu)?; - Ok(NewBookTemplate { users }) + Ok(NewBookTemplate { + users, + ctx: TemplateCtx { + base_path: state.config.base_path, + }, + }) } #[derive(Template, WebTemplate)] @@ -215,6 +234,7 @@ pub async fn new( struct EditBookTemplate { users: Vec, book: BookModel, + ctx: TemplateCtx, } pub async fn edit( @@ -225,12 +245,18 @@ pub async fn edit( .all() .await .context(UserSnafu)?; - let book = BookOperator::new(state) + let book = BookOperator::new(state.clone()) .find_by_id(id) .await .context(BookSnafu)?; - Ok(EditBookTemplate { users, book }) + Ok(EditBookTemplate { + users, + book, + ctx: TemplateCtx { + base_path: state.config.base_path, + }, + }) } pub async fn update( diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 011ff79..b8d18ab 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,2 +1,3 @@ pub mod book; +pub mod template_ctx; pub mod user; diff --git a/src/routes/template_ctx.rs b/src/routes/template_ctx.rs new file mode 100644 index 0000000..43c09b6 --- /dev/null +++ b/src/routes/template_ctx.rs @@ -0,0 +1,14 @@ +#[derive(Clone)] +pub struct TemplateCtx { + pub base_path: String, +} + +impl TemplateCtx { + pub fn asset(&self, path: &str) -> String { + if self.base_path.is_empty() || self.base_path == "/" { + format!("/{}", path) + } else { + format!("{}/{}", self.base_path.trim_end_matches('/'), path) + } + } +} diff --git a/src/routes/user.rs b/src/routes/user.rs index e4458eb..d870ed7 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -16,6 +16,7 @@ use crate::{ book::BookOperator, user::{self, UserOperator}, }, + routes::template_ctx::TemplateCtx, state::{ AppState, error::{AppStateError, BookSnafu, UserSnafu}, @@ -27,6 +28,7 @@ use crate::{ struct UsersIndexTemplate { users_with_books_number: Vec, query: IndexQuery, + ctx: TemplateCtx, } pub struct UserWithBookNumber { @@ -86,6 +88,9 @@ pub async fn index( Ok(UsersIndexTemplate { users_with_books_number: result, query, + ctx: TemplateCtx { + base_path: state.config.base_path, + }, }) } @@ -135,24 +140,36 @@ pub async fn delete( #[template(path = "users/edit.html")] struct EditTemplate { user: user::Model, + ctx: TemplateCtx, } pub async fn edit( State(state): State, Path(id): Path, ) -> Result { - let user = UserOperator::new(state) + let user = UserOperator::new(state.clone()) .find_by_id(id) .await .context(UserSnafu)?; - Ok(EditTemplate { user }) + Ok(EditTemplate { + user, + ctx: TemplateCtx { + base_path: state.config.base_path, + }, + }) } #[derive(Template, WebTemplate)] #[template(path = "users/new.html")] -struct NewTemplate {} - -pub async fn new() -> impl axum::response::IntoResponse { - NewTemplate {} +struct NewTemplate { + ctx: TemplateCtx, +} + +pub async fn new(State(state): State) -> impl axum::response::IntoResponse { + NewTemplate { + ctx: TemplateCtx { + base_path: state.config.base_path, + }, + } } diff --git a/src/state/config.rs b/src/state/config.rs index 3686711..f137f8a 100644 --- a/src/state/config.rs +++ b/src/state/config.rs @@ -33,6 +33,7 @@ pub struct AppConfig { #[serde(default = "AppConfig::default_sqlite_path")] pub database_path: Utf8PathBuf, pub locale: String, + pub base_path: String, pub listener: Listener, } @@ -40,6 +41,7 @@ impl Default for AppConfig { fn default() -> Self { AppConfig { database_path: Self::default_sqlite_path(), + base_path: Self::default_base_path(), locale: Self::default_locale(), listener: Listener::default(), } @@ -98,6 +100,10 @@ impl AppConfig { "en".to_string() } + fn default_base_path() -> String { + "".to_string() + } + pub fn default_sqlite_path() -> Utf8PathBuf { Self::config_path().join("db.sqlite") } diff --git a/src/state/error.rs b/src/state/error.rs index 59d8232..3a9a1f4 100644 --- a/src/state/error.rs +++ b/src/state/error.rs @@ -6,6 +6,7 @@ use snafu::prelude::*; use crate::{ models::{book::BookError, user::UserError}, + routes::template_ctx::TemplateCtx, state::config::ConfigError, }; @@ -47,6 +48,7 @@ pub enum AppStateError { #[template(path = "error.html")] struct ErrorTemplate { state: AppStateErrorContext, + ctx: TemplateCtx, } struct AppStateErrorContext { @@ -66,6 +68,9 @@ impl IntoResponse for AppStateError { let error_context = AppStateErrorContext::from(self); ErrorTemplate { state: error_context, + ctx: TemplateCtx { + base_path: "".to_string(), + }, } .into_response() } diff --git a/templates/base.html b/templates/base.html index 8e7f371..dd8aa4f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,12 +4,12 @@ {% block title %}{{ t!("name") }}{% endblock %} - - + + - - + + {% block extra_head %}{% endblock extra_head %} @@ -26,7 +26,7 @@ {% endblock %} - - + +