Add Base Path

This commit is contained in:
gabatxo1312 2026-01-31 00:05:53 +01:00
parent 4eb913e7a1
commit f6d4e7c556
No known key found for this signature in database
9 changed files with 100 additions and 23 deletions

View File

@ -1,5 +1,6 @@
database_path = ""
locale = "fr"
base_url = ""
[listener]
port = 8000

View File

@ -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<AppState>) -> impl axum::response::IntoResponse {
NotFoundTemplate {
ctx: TemplateCtx {
base_path: state.config.base_path,
},
}
}

View File

@ -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<UserModel>,
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<UserModel>,
ctx: TemplateCtx,
}
pub async fn new(
State(state): State<AppState>,
) -> Result<impl axum::response::IntoResponse, AppStateError> {
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<UserModel>,
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(

View File

@ -1,2 +1,3 @@
pub mod book;
pub mod template_ctx;
pub mod user;

View File

@ -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)
}
}
}

View File

@ -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<UserWithBookNumber>,
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<AppState>,
Path(id): Path<i32>,
) -> Result<impl axum::response::IntoResponse, AppStateError> {
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<AppState>) -> impl axum::response::IntoResponse {
NewTemplate {
ctx: TemplateCtx {
base_path: state.config.base_path,
},
}
}

View File

@ -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")
}

View File

@ -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()
}

View File

@ -4,12 +4,12 @@
<meta charset="utf-8">
<title>{% block title %}{{ t!("name") }}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/assets/css/bootstrap.css">
<link rel="stylesheet" href="/assets/css/main.css">
<link rel="stylesheet" href='{{ ctx.asset("assets/css/bootstrap.css") }}'>
<link rel="stylesheet" href='{{ ctx.asset("assets/css/main.css") }}'>
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon.png">
<link rel="stylesheet" href="/assets/css/fork-awesome.min.css">
<link rel="icon" type="image/x-icon" href="/assets/images/favicon.ico">
<link rel="stylesheet" href='{{ ctx.asset("assets/css/fork-awesome.min.css") }}'>
<link rel="icon" type="image/x-icon" href='{{ ctx.asset("assets/images/favicon.ico") }}'>
{% block extra_head %}{% endblock extra_head %}
</head>
@ -26,7 +26,7 @@
{% endblock %}
</footer>
<script src="/assets/js/bootstrap.min.js"></script>
<script src="/assets/js/script.js"></script>
<script src='{{ ctx.asset("assets/js/bootstrap.min.js") }}'></script>
<script src='{{ ctx.asset("assets/js/script.js") }}'></script>
</body>
</html>