Compare commits
No commits in common. "main" and "add-empty-state" have entirely different histories.
main
...
add-empty-
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1 @@
|
|||||||
/target
|
/target
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
database_path = ""
|
database_path = ""
|
||||||
locale = "fr"
|
locale = "fr"
|
||||||
base_url = ""
|
|
||||||
|
|
||||||
[listener]
|
[listener]
|
||||||
port = 8000
|
port = 8000
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
@ -1,13 +1,12 @@
|
|||||||
_version: 1
|
_version: 1
|
||||||
name: "BookForge"
|
name: "BookForge"
|
||||||
|
|
||||||
common:
|
common:
|
||||||
download: Download
|
download: Download
|
||||||
create: Create
|
create: Create
|
||||||
edit: Edit
|
edit: Edit
|
||||||
delete: Delete
|
delete: Delete
|
||||||
next: Next
|
next: Next
|
||||||
previous: Previous
|
previous: Prev
|
||||||
actions: Actions
|
actions: Actions
|
||||||
search: Search
|
search: Search
|
||||||
reset: Reset
|
reset: Reset
|
||||||
@ -16,77 +15,54 @@ common:
|
|||||||
close: Close
|
close: Close
|
||||||
confirmation: Confirmation
|
confirmation: Confirmation
|
||||||
are_you_sure: Are you sure?
|
are_you_sure: Are you sure?
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
toggle: Toggle navigation
|
toggle: Toggle navigation
|
||||||
books: Books
|
books: Books
|
||||||
users: Users
|
users: Users
|
||||||
|
|
||||||
theme:
|
theme:
|
||||||
light: Light
|
light: Light
|
||||||
dark: Dark
|
dark: Dark
|
||||||
|
|
||||||
user:
|
user:
|
||||||
attributes:
|
attributes:
|
||||||
name: Name
|
name: Name
|
||||||
owner_books: Owned books
|
owner_books: Owner books
|
||||||
borrowed_books: Borrowed books
|
borrowed_books: Borrowed books
|
||||||
|
|
||||||
index:
|
index:
|
||||||
title_tag: Users list | BookForge
|
|
||||||
title: All Users
|
title: All Users
|
||||||
button: Add a user
|
button: Add User
|
||||||
|
|
||||||
edit:
|
edit:
|
||||||
title_tag: Edit user | BookForge
|
|
||||||
title: Edit
|
title: Edit
|
||||||
button: Edit user
|
button: Edit user
|
||||||
|
|
||||||
new:
|
new:
|
||||||
title_tag: New user | BookForge
|
title: New User
|
||||||
title: New user
|
button: Create User
|
||||||
button: Create user
|
|
||||||
|
|
||||||
book:
|
book:
|
||||||
attributes:
|
attributes:
|
||||||
title: Title
|
title: Title
|
||||||
authors: Author(s)
|
authors: Author(s)
|
||||||
description: Description
|
description: Description
|
||||||
owner: Owner
|
owner: Owner
|
||||||
current_holder: Current holder
|
current_holder: Current Holder
|
||||||
comment: Comment
|
comment: Comment
|
||||||
|
|
||||||
index:
|
index:
|
||||||
title_tag: Books list | BookForge
|
|
||||||
title: All Books
|
title: All Books
|
||||||
|
|
||||||
new:
|
new:
|
||||||
title_tag: New book | BookForge
|
|
||||||
title: New Book
|
title: New Book
|
||||||
button: Create book
|
button: Create Book
|
||||||
button_short: Add book
|
button_short: Add book
|
||||||
|
|
||||||
edit:
|
edit:
|
||||||
title_tag: Edit book | BookForge
|
title: Edit Book
|
||||||
title: Edit book
|
button: Edit Book
|
||||||
button: Edit book
|
|
||||||
|
|
||||||
show:
|
show:
|
||||||
title_tag: Details | BookForge
|
book_details: Book Details
|
||||||
book_details: Book details
|
user_details: User Details
|
||||||
user_details: User details
|
more_informations: More Informations
|
||||||
more_informations: More information
|
|
||||||
|
|
||||||
footer:
|
footer:
|
||||||
message: Made with love & Fuck fascists!
|
message: Made with Love & Fuck a Fascist!
|
||||||
|
|
||||||
error:
|
error:
|
||||||
error_404:
|
error_404:
|
||||||
title_tag: Error 404 | BookForge
|
|
||||||
title: Oops ! This page does not exist
|
title: Oops ! This page does not exist
|
||||||
subtitle: 404 NOT FOUND
|
subtitle: 404 NOT FOUND
|
||||||
button: Back to home
|
button: Back to home
|
||||||
|
|
||||||
generic:
|
generic:
|
||||||
title_tag: Error | BookForge
|
|
||||||
title: Oops! An error occurred
|
title: Oops! An error occurred
|
||||||
|
|||||||
@ -28,17 +28,14 @@ user:
|
|||||||
owner_books: Livres possédés
|
owner_books: Livres possédés
|
||||||
borrowed_books: Livres empruntés
|
borrowed_books: Livres empruntés
|
||||||
index:
|
index:
|
||||||
title_tag: Liste des utilisateur.ice.s | BookForge
|
title: Tous les utilisateurs
|
||||||
title: Tous les utilisateur.ice.s
|
button: Ajouter un utilisateur
|
||||||
button: Ajouter un.e utilisateur.ice
|
|
||||||
edit:
|
edit:
|
||||||
title_tag: Modifier l'utilisateur.ice | BookForge
|
|
||||||
title: Modifier
|
title: Modifier
|
||||||
button: Modifier l'utilisateur.ice
|
button: Modifier l'utilisateur
|
||||||
new:
|
new:
|
||||||
title_tag: Nouvel utilisateur.ice | BookForge
|
title: Nouvel utilisateur
|
||||||
title: Nouvel utilisateur.ice
|
button: Créer l'utilisateur
|
||||||
button: Créer l'utilisateur.ice
|
|
||||||
book:
|
book:
|
||||||
attributes:
|
attributes:
|
||||||
title: Titre
|
title: Titre
|
||||||
@ -48,30 +45,24 @@ book:
|
|||||||
current_holder: Détenteur.ice actuel.le
|
current_holder: Détenteur.ice actuel.le
|
||||||
comment: Commentaire
|
comment: Commentaire
|
||||||
index:
|
index:
|
||||||
title_tag: Liste des livres | BookForge
|
|
||||||
title: Tous les livres
|
title: Tous les livres
|
||||||
new:
|
new:
|
||||||
title_tag: Nouveau livre | BookForge
|
|
||||||
title: Nouveau livre
|
title: Nouveau livre
|
||||||
button: Créer le livre
|
button: Créer le livre
|
||||||
button_short: Ajouter un livre
|
button_short: Ajouter un livre
|
||||||
edit:
|
edit:
|
||||||
title_tag: Modifier le livre | BookForge
|
|
||||||
title: Modifier le livre
|
title: Modifier le livre
|
||||||
button: Modifier le livre
|
button: Modifier le livre
|
||||||
show:
|
show:
|
||||||
title_tag: Details | BookForge
|
|
||||||
book_details: Détails du livre
|
book_details: Détails du livre
|
||||||
user_details: Détails de l'utilisateur.ice
|
user_details: Détails de l'utilisateur
|
||||||
more_informations: Plus d'informations
|
more_informations: Plus d'informations
|
||||||
footer:
|
footer:
|
||||||
message: Fait avec amour & Nique les fachos !
|
message: Fait avec amour & Nique les fachos !
|
||||||
error:
|
error:
|
||||||
error_404:
|
error_404:
|
||||||
title_tag: Erreur 404 | BookForge
|
|
||||||
title: Oups ! Cette page n'existe pas
|
title: Oups ! Cette page n'existe pas
|
||||||
subtitle: 404 NOT FOUND
|
subtitle: 404 NOT FOUND
|
||||||
button: Retour à l'accueil
|
button: Retour à l'accueil
|
||||||
generic:
|
generic:
|
||||||
title_tag: Erreur | BookForge
|
|
||||||
title: Oups ! Une erreur s'est produite
|
title: Oups ! Une erreur s'est produite
|
||||||
|
|||||||
14
src/lib.rs
14
src/lib.rs
@ -2,12 +2,10 @@ 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::routes::router::Router as InternalRouter;
|
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
|
|
||||||
mod migrations;
|
mod migrations;
|
||||||
@ -46,14 +44,8 @@ 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 router: InternalRouter,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn error_handler(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
pub async fn error_handler() -> impl axum::response::IntoResponse {
|
||||||
NotFoundTemplate {
|
NotFoundTemplate {}
|
||||||
router: InternalRouter {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ 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, routes::router::Router, state::error::CSVSnafu};
|
use crate::{models::book::Model as BookModel, 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,7 +55,6 @@ struct BookIndexTemplate {
|
|||||||
current_page: u64,
|
current_page: u64,
|
||||||
total_page: u64,
|
total_page: u64,
|
||||||
base_query: String,
|
base_query: String,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn index(
|
pub async fn index(
|
||||||
@ -74,7 +73,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.clone())
|
let books_paginate = BookOperator::new(state)
|
||||||
.all_paginate(page, Some(query.clone()))
|
.all_paginate(page, Some(query.clone()))
|
||||||
.await
|
.await
|
||||||
.context(BookSnafu)?;
|
.context(BookSnafu)?;
|
||||||
@ -128,9 +127,6 @@ 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,
|
||||||
router: Router {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +136,6 @@ struct ShowBookTemplate {
|
|||||||
book: BookModel,
|
book: BookModel,
|
||||||
owner: UserModel,
|
owner: UserModel,
|
||||||
current_holder: Option<UserModel>,
|
current_holder: Option<UserModel>,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn show(
|
pub async fn show(
|
||||||
@ -173,9 +168,6 @@ pub async fn show(
|
|||||||
book,
|
book,
|
||||||
owner,
|
owner,
|
||||||
current_holder,
|
current_holder,
|
||||||
router: Router {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,23 +200,14 @@ pub async fn create(
|
|||||||
#[template(path = "books/new.html")]
|
#[template(path = "books/new.html")]
|
||||||
struct NewBookTemplate {
|
struct NewBookTemplate {
|
||||||
users: Vec<UserModel>,
|
users: Vec<UserModel>,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.clone())
|
let users = UserOperator::new(state).all().await.context(UserSnafu)?;
|
||||||
.all()
|
|
||||||
.await
|
|
||||||
.context(UserSnafu)?;
|
|
||||||
|
|
||||||
Ok(NewBookTemplate {
|
Ok(NewBookTemplate { users })
|
||||||
users,
|
|
||||||
router: Router {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template, WebTemplate)]
|
#[derive(Template, WebTemplate)]
|
||||||
@ -232,7 +215,6 @@ pub async fn new(
|
|||||||
struct EditBookTemplate {
|
struct EditBookTemplate {
|
||||||
users: Vec<UserModel>,
|
users: Vec<UserModel>,
|
||||||
book: BookModel,
|
book: BookModel,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit(
|
pub async fn edit(
|
||||||
@ -243,18 +225,12 @@ pub async fn edit(
|
|||||||
.all()
|
.all()
|
||||||
.await
|
.await
|
||||||
.context(UserSnafu)?;
|
.context(UserSnafu)?;
|
||||||
let book = BookOperator::new(state.clone())
|
let book = BookOperator::new(state)
|
||||||
.find_by_id(id)
|
.find_by_id(id)
|
||||||
.await
|
.await
|
||||||
.context(BookSnafu)?;
|
.context(BookSnafu)?;
|
||||||
|
|
||||||
Ok(EditBookTemplate {
|
Ok(EditBookTemplate { users, book })
|
||||||
users,
|
|
||||||
book,
|
|
||||||
router: Router {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
pub mod book;
|
pub mod book;
|
||||||
pub mod router;
|
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|||||||
@ -1,54 +0,0 @@
|
|||||||
#[derive(Clone)]
|
|
||||||
pub struct Router {
|
|
||||||
pub base_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Router {
|
|
||||||
pub fn assets(&self, path: &str) -> String {
|
|
||||||
if self.base_path.is_empty() || self.base_path == "/" {
|
|
||||||
format!("/{}", path)
|
|
||||||
} else {
|
|
||||||
format!("{}/{}", self.base_path.trim_end_matches('/'), path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_path(&self) -> String {
|
|
||||||
format!("{}/", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BOOKS ROUTES
|
|
||||||
|
|
||||||
pub fn new_book_path(&self) -> String {
|
|
||||||
format!("{}/books/new", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_book_path(&self) -> String {
|
|
||||||
format!("{}/books", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_book_path(&self, id: &i32) -> String {
|
|
||||||
format!("{}/books/{}", &self.base_path, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn download_csv_book_path(&self) -> String {
|
|
||||||
format!("{}/books/download_csv", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// USERS
|
|
||||||
|
|
||||||
pub fn index_user_path(&self) -> String {
|
|
||||||
format!("{}/users", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_user_path(&self) -> String {
|
|
||||||
format!("{}/users/new", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_user_path(&self) -> String {
|
|
||||||
format!("{}/users", &self.base_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_user_path(&self, id: &i32) -> String {
|
|
||||||
format!("{}/users/{}", &self.base_path, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,7 +16,6 @@ use crate::{
|
|||||||
book::BookOperator,
|
book::BookOperator,
|
||||||
user::{self, UserOperator},
|
user::{self, UserOperator},
|
||||||
},
|
},
|
||||||
routes::router::Router,
|
|
||||||
state::{
|
state::{
|
||||||
AppState,
|
AppState,
|
||||||
error::{AppStateError, BookSnafu, UserSnafu},
|
error::{AppStateError, BookSnafu, UserSnafu},
|
||||||
@ -28,7 +27,6 @@ use crate::{
|
|||||||
struct UsersIndexTemplate {
|
struct UsersIndexTemplate {
|
||||||
users_with_books_number: Vec<UserWithBookNumber>,
|
users_with_books_number: Vec<UserWithBookNumber>,
|
||||||
query: IndexQuery,
|
query: IndexQuery,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserWithBookNumber {
|
pub struct UserWithBookNumber {
|
||||||
@ -88,9 +86,6 @@ pub async fn index(
|
|||||||
Ok(UsersIndexTemplate {
|
Ok(UsersIndexTemplate {
|
||||||
users_with_books_number: result,
|
users_with_books_number: result,
|
||||||
query,
|
query,
|
||||||
router: Router {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,36 +135,24 @@ pub async fn delete(
|
|||||||
#[template(path = "users/edit.html")]
|
#[template(path = "users/edit.html")]
|
||||||
struct EditTemplate {
|
struct EditTemplate {
|
||||||
user: user::Model,
|
user: user::Model,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.clone())
|
let user = UserOperator::new(state)
|
||||||
.find_by_id(id)
|
.find_by_id(id)
|
||||||
.await
|
.await
|
||||||
.context(UserSnafu)?;
|
.context(UserSnafu)?;
|
||||||
|
|
||||||
Ok(EditTemplate {
|
Ok(EditTemplate { user })
|
||||||
user,
|
|
||||||
router: Router {
|
|
||||||
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 {}
|
||||||
router: Router,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn new(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
pub async fn new() -> impl axum::response::IntoResponse {
|
||||||
NewTemplate {
|
NewTemplate {}
|
||||||
router: Router {
|
|
||||||
base_path: state.config.base_path,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@ 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +40,6 @@ 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(),
|
||||||
}
|
}
|
||||||
@ -100,10 +98,6 @@ 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,7 +6,6 @@ use snafu::prelude::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{book::BookError, user::UserError},
|
models::{book::BookError, user::UserError},
|
||||||
routes::router::Router,
|
|
||||||
state::config::ConfigError,
|
state::config::ConfigError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,7 +47,6 @@ pub enum AppStateError {
|
|||||||
#[template(path = "error.html")]
|
#[template(path = "error.html")]
|
||||||
struct ErrorTemplate {
|
struct ErrorTemplate {
|
||||||
state: AppStateErrorContext,
|
state: AppStateErrorContext,
|
||||||
router: Router,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppStateErrorContext {
|
struct AppStateErrorContext {
|
||||||
@ -68,9 +66,6 @@ impl IntoResponse for AppStateError {
|
|||||||
let error_context = AppStateErrorContext::from(self);
|
let error_context = AppStateErrorContext::from(self);
|
||||||
ErrorTemplate {
|
ErrorTemplate {
|
||||||
state: error_context,
|
state: error_context,
|
||||||
router: Router {
|
|
||||||
base_path: "".to_string(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,8 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("error.error_404.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="mt-4 text-center">
|
<div class="mt-4 text-center">
|
||||||
<h1>{{ t!("error.error_404.title") }}</h1>
|
<h1>{{ t!("error.error_404.title") }}</h1>
|
||||||
<h2 class="fst-italic">{{ t!("error.error_404.subtitle") }}</h2>
|
<h2 class="fst-italic">{{ t!("error.error_404.subtitle") }}</h2>
|
||||||
<a href="{{ router.root_path() }}" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
<a href="/" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -4,12 +4,11 @@
|
|||||||
<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='{{ router.assets("assets/css/bootstrap.css") }}'>
|
<link rel="stylesheet" href="/assets/css/bootstrap.css">
|
||||||
<link rel="stylesheet" href='{{ router.assets("assets/css/main.css") }}'>
|
<link rel="stylesheet" href="/assets/css/main.css">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon.png">
|
|
||||||
|
|
||||||
<link rel="stylesheet" href='{{ router.assets("assets/css/fork-awesome.min.css") }}'>
|
<link rel="stylesheet" href="/assets/css/fork-awesome.min.css">
|
||||||
<link rel="icon" type="image/x-icon" href='{{ router.assets("assets/images/favicon.png") }}'>
|
<link rel="icon" type="image/x-icon" href="/assets/images/favicon.ico">
|
||||||
{% block extra_head %}{% endblock extra_head %}
|
{% block extra_head %}{% endblock extra_head %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -26,7 +25,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src='{{ router.assets("assets/js/bootstrap.min.js") }}'></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src='{{ router.assets("assets/js/script.js") }}'></script>
|
<script src="/assets/js/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -2,15 +2,11 @@
|
|||||||
{% import "components/typography.html" as typography %}
|
{% import "components/typography.html" as typography %}
|
||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("book.edit.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{{ typography::heading(t!("book.edit.title")) }}
|
{{ typography::heading(t!("book.edit.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form method="post" action="{{ router.update_book_path(&book.id) }}">
|
<form method="post" action="/books/{{ book.id }}">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="title">{{ t!("book.attributes.title") }}</label>
|
<label class="form-label" for="title">{{ t!("book.attributes.title") }}</label>
|
||||||
<input type="text" name="title" class="form-control" value="{{ book.title }}" required>
|
<input type="text" name="title" class="form-control" value="{{ book.title }}" required>
|
||||||
|
|||||||
@ -3,15 +3,11 @@
|
|||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
{% import "components/inputs.html" as form_helpers %}
|
{% import "components/inputs.html" as form_helpers %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("book.new.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{{ typography::heading(t!("book.new.title")) }}
|
{{ typography::heading(t!("book.new.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form method="post" action="{{ router.create_book_path() }}">
|
<form method="post" action="/books">
|
||||||
{{ form_helpers::input("title", t!("book.attributes.title"), is_required = true, placeholder = "Ex: La Petite Dernière") }}
|
{{ form_helpers::input("title", t!("book.attributes.title"), is_required = true, placeholder = "Ex: La Petite Dernière") }}
|
||||||
{{ form_helpers::input("authors", t!("book.attributes.authors"), is_required = true, placeholder = "Ex: Fatima Daas") }}
|
{{ form_helpers::input("authors", t!("book.attributes.authors"), is_required = true, placeholder = "Ex: Fatima Daas") }}
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,12 @@
|
|||||||
{% import "components/fields.html" as fields %}
|
{% import "components/fields.html" as fields %}
|
||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("book.show.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{{ typography::book_heading(book.title, book, show = false) }}
|
{{ typography::book_heading(book.title, book, show = false) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<div class="">
|
<div class="mt-4">
|
||||||
<h5 class="fw-bold text-decoration-underline">{{ t!("book.show.book_details") }}</h5>
|
<h5 class="mt-4 fw-bold">{{ t!("book.show.book_details") }}</h5>
|
||||||
{{ fields::field(t!("book.attributes.title"), book.title) }}
|
{{ fields::field(t!("book.attributes.title"), book.title) }}
|
||||||
{{ fields::field(t!("book.attributes.authors"), book.authors) }}
|
{{ fields::field(t!("book.attributes.authors"), book.authors) }}
|
||||||
|
|
||||||
@ -24,7 +20,7 @@
|
|||||||
{{ fields::field(t!("book.attributes.description"), "-") }}
|
{{ fields::field(t!("book.attributes.description"), "-") }}
|
||||||
{% endmatch %}
|
{% endmatch %}
|
||||||
|
|
||||||
<h5 class="mt-50px fw-bold text-decoration-underline">{{ t!("book.show.user_details") }}</h5>
|
<h5 class="mt-50px fw-bold">{{ t!("book.show.user_details") }}</h5>
|
||||||
{{ fields::field(t!("book.attributes.owner"), owner.name) }}
|
{{ fields::field(t!("book.attributes.owner"), owner.name) }}
|
||||||
|
|
||||||
{% match current_holder %}
|
{% match current_holder %}
|
||||||
@ -35,7 +31,7 @@
|
|||||||
{% endmatch %}
|
{% endmatch %}
|
||||||
|
|
||||||
|
|
||||||
<h5 class="mt-50px fw-bold text-decoration-underline">{{ t!("book.show.more_informations") }}</h5>
|
<h5 class="mt-50px fw-bold">{{ t!("book.show.more_informations") }}</h5>
|
||||||
{% match book.comment %}
|
{% match book.comment %}
|
||||||
{% when Some with (comment) %}
|
{% when Some with (comment) %}
|
||||||
{{ fields::field(t!("book.attributes.comment"), comment) }}
|
{{ fields::field(t!("book.attributes.comment"), comment) }}
|
||||||
|
|||||||
@ -18,9 +18,9 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% if show %}
|
{% if show %}
|
||||||
<li><a class="dropdown-item" href="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}">{{ t!("common.show") }}</a></li>
|
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}">{{ t!("common.show") }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a class="dropdown-item" href="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}/edit">{{ t!("common.edit") }}</a></li>
|
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}/edit">{{ t!("common.edit") }}</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteUserModal{{ book.id }}">{{ t!("common.delete") }}</a>
|
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteUserModal{{ book.id }}">{{ t!("common.delete") }}</a>
|
||||||
</li>
|
</li>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t!("common.close") }}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t!("common.close") }}</button>
|
||||||
<form method="post" action="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}/delete" class="m-0">
|
<form method="post" action="/{{ sub_path }}/{{ book.id }}/delete" class="m-0">
|
||||||
<input class="btn btn-danger" type="submit" value='{{ t!("common.delete") }}'>
|
<input class="btn btn-danger" type="submit" value='{{ t!("common.delete") }}'>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("error.generic.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="mt-4 text-center">
|
<div class="mt-4 text-center">
|
||||||
<h1>{{ t!("error.generic.title") }}</h1>
|
<h1>{{ t!("error.generic.title") }}</h1>
|
||||||
@ -12,6 +7,6 @@
|
|||||||
<p>{{ error }}</p>
|
<p>{{ error }}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<a href="{{ router.root_path() }}" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
<a href="/" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -3,13 +3,9 @@
|
|||||||
{% import "components/dropdown.html" as dropdown %}
|
{% import "components/dropdown.html" as dropdown %}
|
||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("book.index.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% call typography::heading(t!("book.index.title")) %}
|
{% call typography::heading(t!("book.index.title")) %}
|
||||||
<a href="{{ router.download_csv_book_path() }}?{{ base_query }}" class="btn btn-info">
|
<a href="/books/download_csv?{{ base_query }}" class="btn btn-info">
|
||||||
<i class="fa fa-download me-2" aria-hidden="true"></i> {{ t!("common.download") }} (csv)
|
<i class="fa fa-download me-2" aria-hidden="true"></i> {{ t!("common.download") }} (csv)
|
||||||
</a>
|
</a>
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
@ -87,7 +83,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-1 d-flex align-items-end">
|
<div class="col-md-1 d-flex align-items-end">
|
||||||
<a href="{{ router.root_path() }}" class="btn btn-light">{{ t!("common.reset") }}</a>
|
<a href="/" class="btn btn-light">{{ t!("common.reset") }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -98,7 +94,7 @@
|
|||||||
<div class="d-flex flex-column align-items-center justify-content-center">
|
<div class="d-flex flex-column align-items-center justify-content-center">
|
||||||
<h2>{{ t!("common.no_result") }}</h2>
|
<h2>{{ t!("common.no_result") }}</h2>
|
||||||
|
|
||||||
<a class="btn btn-success text-white text-nowrap mt-3" href="{{ router.new_book_path() }}">
|
<a class="btn btn-success text-white text-nowrap mt-3" href="/books/new">
|
||||||
{{ t!("book.new.button_short") }}
|
{{ t!("book.new.button_short") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -142,19 +138,19 @@
|
|||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
<li class="page-item {% if current_page <= 1 %}disabled{% endif %}">
|
<li class="page-item {% if current_page <= 1 %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={% if current_page > 1 %}{{ current_page - 1 }}{% else %}1{% endif %}">{{ t!("common.previous") }}</a>
|
<a class="page-link" href="/?{{ base_query }}page={% if current_page > 1 %}{{ current_page - 1 }}{% else %}1{% endif %}">{{ t!("common.prev") }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% for page in 1..(total_page + 1) %}
|
{% for page in 1..(total_page + 1) %}
|
||||||
{% if page >= current_page - 1 && page <= current_page + 1 %}
|
{% if page >= current_page - 1 && page <= current_page + 1 %}
|
||||||
<li class="page-item {% if page == current_page %}active{% endif %}">
|
<li class="page-item {% if page == current_page %}active{% endif %}">
|
||||||
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={{ page }}">{{ page }}</a>
|
<a class="page-link" href="/?{{ base_query }}page={{ page }}">{{ page }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
|
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
|
||||||
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={{ current_page + 1 }}">{{ t!("common.next") }}</a>
|
<a class="page-link" href="/?{{ base_query }}page={{ current_page + 1 }}">{{ t!("common.next") }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<nav class="navbar navbar-expand-lg bg-body-tertiary fixed-top shadow">
|
<nav class="navbar navbar-expand-lg bg-body-tertiary fixed-top shadow">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="{{ router.root_path() }}">
|
<a class="navbar-brand" href="/">
|
||||||
{{ t!("name") }}
|
{{ t!("name") }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@ -12,10 +12,10 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav me-auto">
|
<ul class="navbar-nav me-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{{ router.root_path() }}">{{ t!("nav.books") }}</a>
|
<a class="nav-link" href="/">{{ t!("nav.books") }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{{ router.index_user_path() }}">{{ t!("nav.users") }}</a>
|
<a class="nav-link" href="/users">{{ t!("nav.users") }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="d-flex align-items-center gap-2 py-3">
|
<div class="d-flex align-items-center gap-2 py-3">
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<option value="dark">{{ t!("theme.dark") }}</option>
|
<option value="dark">{{ t!("theme.dark") }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<a class="btn btn-success text-white text-nowrap" href="{{ router.new_book_path() }}">
|
<a class="btn btn-success text-white text-nowrap" href="/books/new">
|
||||||
{{ t!("book.new.button_short") }}
|
{{ t!("book.new.button_short") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,17 +1,13 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% import "components/typography.html" as typography %}
|
{% import "components/typography.html" as typography %}
|
||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
{% import "components/inputs.html" as form_helpers %}
|
o{% import "components/inputs.html" as form_helpers %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("book.edit.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{{ typography::heading(t!("user.edit.title")) }}
|
{{ typography::heading(t!("user.edit.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form action="{{ router.update_user_path(&user.id) }}" method="post">
|
<form action="/users/{{ user.id }}" method="post">
|
||||||
<div class="row align-items-end">
|
<div class="row align-items-end">
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
{{ form_helpers::input("name", t!("user.attributes.name"), value = user.name, is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
{{ form_helpers::input("name", t!("user.attributes.name"), value = user.name, is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
||||||
|
|||||||
@ -4,13 +4,9 @@
|
|||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
{% import "components/inputs.html" as form_helpers %}
|
{% import "components/inputs.html" as form_helpers %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("user.index.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% call typography::heading(t!("user.index.title")) %}
|
{% call typography::heading(t!("user.index.title")) %}
|
||||||
<a class="btn-success btn" href="{{ router.new_user_path() }}">{{ t!("user.index.button") }}</a>
|
<a class="btn-success btn" href="/users/new">{{ t!("user.index.button") }}</a>
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
@ -42,7 +38,7 @@
|
|||||||
<div class="d-flex flex-column align-items-center justify-content-center">
|
<div class="d-flex flex-column align-items-center justify-content-center">
|
||||||
<h2>{{ t!("common.no_result") }}</h2>
|
<h2>{{ t!("common.no_result") }}</h2>
|
||||||
|
|
||||||
<a class="btn btn-success text-white text-nowrap mt-3" href="{{ router.new_user_path() }}">
|
<a class="btn btn-success text-white text-nowrap mt-3" href="//new">
|
||||||
{{ t!("user.index.button") }}
|
{{ t!("user.index.button") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,17 +1,13 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% import "components/typography.html" as typography %}
|
{% import "components/typography.html" as typography %}
|
||||||
{% import "components/cards.html" as cards %}
|
{% import "components/cards.html" as cards %}
|
||||||
{% import "components/inputs.html" as form_helpers %}
|
o{% import "components/inputs.html" as form_helpers %}
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{{ t!("user.new.title_tag") }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{{ typography::heading(t!("user.new.title")) }}
|
{{ typography::heading(t!("user.new.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form action="{{ router.create_user_path() }}" method="post">
|
<form action="/users" method="post">
|
||||||
<div class="row align-items-end">
|
<div class="row align-items-end">
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
{{ form_helpers::input("name", t!("user.attributes.name"), is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
{{ form_helpers::input("name", t!("user.attributes.name"), is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user