Add Base Path
This commit is contained in:
parent
4eb913e7a1
commit
f6d4e7c556
@ -1,5 +1,6 @@
|
|||||||
database_path = ""
|
database_path = ""
|
||||||
locale = "fr"
|
locale = "fr"
|
||||||
|
base_url = ""
|
||||||
|
|
||||||
[listener]
|
[listener]
|
||||||
port = 8000
|
port = 8000
|
||||||
|
|||||||
17
src/lib.rs
17
src/lib.rs
@ -2,11 +2,12 @@ use askama::Template;
|
|||||||
use askama_web::WebTemplate;
|
use askama_web::WebTemplate;
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
|
extract::State,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
use static_serve::embed_assets;
|
use static_serve::embed_assets;
|
||||||
|
|
||||||
use crate::state::AppState;
|
use crate::{routes::template_ctx::TemplateCtx, state::AppState};
|
||||||
|
|
||||||
mod migrations;
|
mod migrations;
|
||||||
mod models;
|
mod models;
|
||||||
@ -44,8 +45,14 @@ pub fn build_app(state: AppState) -> Router {
|
|||||||
|
|
||||||
#[derive(Template, WebTemplate)]
|
#[derive(Template, WebTemplate)]
|
||||||
#[template(path = "404.html")]
|
#[template(path = "404.html")]
|
||||||
struct NotFoundTemplate {}
|
struct NotFoundTemplate {
|
||||||
|
pub ctx: TemplateCtx,
|
||||||
pub async fn error_handler() -> impl axum::response::IntoResponse {
|
}
|
||||||
NotFoundTemplate {}
|
|
||||||
|
pub async fn error_handler(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
||||||
|
NotFoundTemplate {
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,9 @@ use serde::Deserialize;
|
|||||||
use serde_with::{NoneAsEmptyString, serde_as};
|
use serde_with::{NoneAsEmptyString, serde_as};
|
||||||
use snafu::prelude::*;
|
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::{models::user::Model as UserModel, state::error::IOSnafu};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -55,6 +57,7 @@ struct BookIndexTemplate {
|
|||||||
current_page: u64,
|
current_page: u64,
|
||||||
total_page: u64,
|
total_page: u64,
|
||||||
base_query: String,
|
base_query: String,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn index(
|
pub async fn index(
|
||||||
@ -73,7 +76,7 @@ pub async fn index(
|
|||||||
.context(UserSnafu)?;
|
.context(UserSnafu)?;
|
||||||
|
|
||||||
// Get all Book filtered with query
|
// 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()))
|
.all_paginate(page, Some(query.clone()))
|
||||||
.await
|
.await
|
||||||
.context(BookSnafu)?;
|
.context(BookSnafu)?;
|
||||||
@ -127,6 +130,9 @@ pub async fn index(
|
|||||||
current_page: books_paginate.current_page,
|
current_page: books_paginate.current_page,
|
||||||
total_page: books_paginate.total_page,
|
total_page: books_paginate.total_page,
|
||||||
base_query,
|
base_query,
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +142,7 @@ struct ShowBookTemplate {
|
|||||||
book: BookModel,
|
book: BookModel,
|
||||||
owner: UserModel,
|
owner: UserModel,
|
||||||
current_holder: Option<UserModel>,
|
current_holder: Option<UserModel>,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn show(
|
pub async fn show(
|
||||||
@ -168,6 +175,9 @@ pub async fn show(
|
|||||||
book,
|
book,
|
||||||
owner,
|
owner,
|
||||||
current_holder,
|
current_holder,
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,14 +210,23 @@ pub async fn create(
|
|||||||
#[template(path = "books/new.html")]
|
#[template(path = "books/new.html")]
|
||||||
struct NewBookTemplate {
|
struct NewBookTemplate {
|
||||||
users: Vec<UserModel>,
|
users: Vec<UserModel>,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
) -> 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)]
|
#[derive(Template, WebTemplate)]
|
||||||
@ -215,6 +234,7 @@ pub async fn new(
|
|||||||
struct EditBookTemplate {
|
struct EditBookTemplate {
|
||||||
users: Vec<UserModel>,
|
users: Vec<UserModel>,
|
||||||
book: BookModel,
|
book: BookModel,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit(
|
pub async fn edit(
|
||||||
@ -225,12 +245,18 @@ pub async fn edit(
|
|||||||
.all()
|
.all()
|
||||||
.await
|
.await
|
||||||
.context(UserSnafu)?;
|
.context(UserSnafu)?;
|
||||||
let book = BookOperator::new(state)
|
let book = BookOperator::new(state.clone())
|
||||||
.find_by_id(id)
|
.find_by_id(id)
|
||||||
.await
|
.await
|
||||||
.context(BookSnafu)?;
|
.context(BookSnafu)?;
|
||||||
|
|
||||||
Ok(EditBookTemplate { users, book })
|
Ok(EditBookTemplate {
|
||||||
|
users,
|
||||||
|
book,
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod book;
|
pub mod book;
|
||||||
|
pub mod template_ctx;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|||||||
14
src/routes/template_ctx.rs
Normal file
14
src/routes/template_ctx.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ use crate::{
|
|||||||
book::BookOperator,
|
book::BookOperator,
|
||||||
user::{self, UserOperator},
|
user::{self, UserOperator},
|
||||||
},
|
},
|
||||||
|
routes::template_ctx::TemplateCtx,
|
||||||
state::{
|
state::{
|
||||||
AppState,
|
AppState,
|
||||||
error::{AppStateError, BookSnafu, UserSnafu},
|
error::{AppStateError, BookSnafu, UserSnafu},
|
||||||
@ -27,6 +28,7 @@ use crate::{
|
|||||||
struct UsersIndexTemplate {
|
struct UsersIndexTemplate {
|
||||||
users_with_books_number: Vec<UserWithBookNumber>,
|
users_with_books_number: Vec<UserWithBookNumber>,
|
||||||
query: IndexQuery,
|
query: IndexQuery,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserWithBookNumber {
|
pub struct UserWithBookNumber {
|
||||||
@ -86,6 +88,9 @@ pub async fn index(
|
|||||||
Ok(UsersIndexTemplate {
|
Ok(UsersIndexTemplate {
|
||||||
users_with_books_number: result,
|
users_with_books_number: result,
|
||||||
query,
|
query,
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,24 +140,36 @@ pub async fn delete(
|
|||||||
#[template(path = "users/edit.html")]
|
#[template(path = "users/edit.html")]
|
||||||
struct EditTemplate {
|
struct EditTemplate {
|
||||||
user: user::Model,
|
user: user::Model,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit(
|
pub async fn edit(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
||||||
let user = UserOperator::new(state)
|
let user = UserOperator::new(state.clone())
|
||||||
.find_by_id(id)
|
.find_by_id(id)
|
||||||
.await
|
.await
|
||||||
.context(UserSnafu)?;
|
.context(UserSnafu)?;
|
||||||
|
|
||||||
Ok(EditTemplate { user })
|
Ok(EditTemplate {
|
||||||
|
user,
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template, WebTemplate)]
|
#[derive(Template, WebTemplate)]
|
||||||
#[template(path = "users/new.html")]
|
#[template(path = "users/new.html")]
|
||||||
struct NewTemplate {}
|
struct NewTemplate {
|
||||||
|
ctx: TemplateCtx,
|
||||||
pub async fn new() -> impl axum::response::IntoResponse {
|
}
|
||||||
NewTemplate {}
|
|
||||||
|
pub async fn new(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
||||||
|
NewTemplate {
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: state.config.base_path,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ pub struct AppConfig {
|
|||||||
#[serde(default = "AppConfig::default_sqlite_path")]
|
#[serde(default = "AppConfig::default_sqlite_path")]
|
||||||
pub database_path: Utf8PathBuf,
|
pub database_path: Utf8PathBuf,
|
||||||
pub locale: String,
|
pub locale: String,
|
||||||
|
pub base_path: String,
|
||||||
pub listener: Listener,
|
pub listener: Listener,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +41,7 @@ impl Default for AppConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
AppConfig {
|
AppConfig {
|
||||||
database_path: Self::default_sqlite_path(),
|
database_path: Self::default_sqlite_path(),
|
||||||
|
base_path: Self::default_base_path(),
|
||||||
locale: Self::default_locale(),
|
locale: Self::default_locale(),
|
||||||
listener: Listener::default(),
|
listener: Listener::default(),
|
||||||
}
|
}
|
||||||
@ -98,6 +100,10 @@ impl AppConfig {
|
|||||||
"en".to_string()
|
"en".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_base_path() -> String {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn default_sqlite_path() -> Utf8PathBuf {
|
pub fn default_sqlite_path() -> Utf8PathBuf {
|
||||||
Self::config_path().join("db.sqlite")
|
Self::config_path().join("db.sqlite")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use snafu::prelude::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{book::BookError, user::UserError},
|
models::{book::BookError, user::UserError},
|
||||||
|
routes::template_ctx::TemplateCtx,
|
||||||
state::config::ConfigError,
|
state::config::ConfigError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ pub enum AppStateError {
|
|||||||
#[template(path = "error.html")]
|
#[template(path = "error.html")]
|
||||||
struct ErrorTemplate {
|
struct ErrorTemplate {
|
||||||
state: AppStateErrorContext,
|
state: AppStateErrorContext,
|
||||||
|
ctx: TemplateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppStateErrorContext {
|
struct AppStateErrorContext {
|
||||||
@ -66,6 +68,9 @@ impl IntoResponse for AppStateError {
|
|||||||
let error_context = AppStateErrorContext::from(self);
|
let error_context = AppStateErrorContext::from(self);
|
||||||
ErrorTemplate {
|
ErrorTemplate {
|
||||||
state: error_context,
|
state: error_context,
|
||||||
|
ctx: TemplateCtx {
|
||||||
|
base_path: "".to_string(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,12 +4,12 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{% block title %}{{ t!("name") }}{% endblock %}</title>
|
<title>{% block title %}{{ t!("name") }}{% endblock %}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.css">
|
<link rel="stylesheet" href='{{ ctx.asset("assets/css/bootstrap.css") }}'>
|
||||||
<link rel="stylesheet" href="/assets/css/main.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="icon" type="image/png" sizes="32x32" href="/assets/images/favicon.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href="/assets/css/fork-awesome.min.css">
|
<link rel="stylesheet" href='{{ ctx.asset("assets/css/fork-awesome.min.css") }}'>
|
||||||
<link rel="icon" type="image/x-icon" href="/assets/images/favicon.ico">
|
<link rel="icon" type="image/x-icon" href='{{ ctx.asset("assets/images/favicon.ico") }}'>
|
||||||
{% block extra_head %}{% endblock extra_head %}
|
{% block extra_head %}{% endblock extra_head %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -26,7 +26,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src='{{ ctx.asset("assets/js/bootstrap.min.js") }}'></script>
|
||||||
<script src="/assets/js/script.js"></script>
|
<script src='{{ ctx.asset("assets/js/script.js") }}'></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user