Add favicon
This commit is contained in:
parent
a590d7e1e9
commit
b2572ebfe5
9 changed files with 73 additions and 22 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
|
@ -1905,7 +1905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"rand_core 0.9.2",
|
"rand_core 0.9.3",
|
||||||
"zerocopy 0.8.21",
|
"zerocopy 0.8.21",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1926,7 +1926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core 0.9.2",
|
"rand_core 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1940,12 +1940,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.9.2"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a509b1a2ffbe92afab0e55c8fd99dea1c280e8171bd2d88682bb20bc41cbc2c"
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.1",
|
"getrandom 0.3.1",
|
||||||
"zerocopy 0.8.21",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1962,7 +1961,7 @@ dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"lettre",
|
"lettre",
|
||||||
"rand 0.9.0",
|
"rand 0.9.0",
|
||||||
"rand_core 0.9.2",
|
"rand_core 0.9.3",
|
||||||
"rinja",
|
"rinja",
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -2813,9 +2812,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.26.1"
|
version = "0.26.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
|
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,11 @@ As root:
|
||||||
2. Enabled it: #> systemctl enable recipes
|
2. Enabled it: #> systemctl enable recipes
|
||||||
3. Launch it: #> systemctl start recipes
|
3. Launch it: #> systemctl start recipes
|
||||||
|
|
||||||
|
## Cross compile for Raspberry PI on Windows
|
||||||
|
|
||||||
|
* $> https://gnutoolchains.com/raspberry/
|
||||||
|
* https://gnutoolchains.com/raspberry64/
|
||||||
|
|
||||||
# Useful URLs
|
# Useful URLs
|
||||||
|
|
||||||
* Rust patterns : https://github.com/rust-unofficial/patterns
|
* Rust patterns : https://github.com/rust-unofficial/patterns
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{Duration, prelude::*};
|
||||||
use rand::distr::{Alphanumeric, SampleString};
|
use rand::distr::{Alphanumeric, SampleString};
|
||||||
use sqlx::Sqlite;
|
use sqlx::Sqlite;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
use argon2::{
|
use argon2::{
|
||||||
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
|
||||||
Argon2,
|
Argon2,
|
||||||
|
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn get_argon2<'k>() -> Argon2<'k> {
|
fn get_argon2<'k>() -> Argon2<'k> {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,10 @@ use chrono::prelude::*;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tower_http::{services::ServeDir, trace::TraceLayer};
|
use tower_http::{
|
||||||
|
services::{ServeDir, ServeFile},
|
||||||
|
trace::TraceLayer,
|
||||||
|
};
|
||||||
use tracing::{Level, event};
|
use tracing::{Level, event};
|
||||||
|
|
||||||
use data::{db, model};
|
use data::{db, model};
|
||||||
|
|
@ -85,7 +88,7 @@ async fn main() {
|
||||||
.with_max_level(TRACING_LEVEL)
|
.with_max_level(TRACING_LEVEL)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
if process_args().await {
|
if !process_args().await {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,22 +257,22 @@ async fn main() {
|
||||||
"/user/edit",
|
"/user/edit",
|
||||||
get(services::user::edit_user_get).post(services::user::edit_user_post),
|
get(services::user::edit_user_get).post(services::user::edit_user_post),
|
||||||
)
|
)
|
||||||
|
.nest("/fragments", fragments_routes)
|
||||||
.route_layer(middleware::from_fn(services::ron_error_to_html));
|
.route_layer(middleware::from_fn(services::ron_error_to_html));
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.merge(html_routes)
|
.merge(html_routes)
|
||||||
.nest("/fragments", fragments_routes)
|
|
||||||
.nest("/ron-api", ron_api_routes)
|
.nest("/ron-api", ron_api_routes)
|
||||||
.fallback(services::not_found)
|
.fallback(services::not_found)
|
||||||
.layer(TraceLayer::new_for_http())
|
|
||||||
// FIXME: Should be 'route_layer' but it doesn't work for 'fallback(..)'.
|
|
||||||
.layer(middleware::from_fn(translation))
|
.layer(middleware::from_fn(translation))
|
||||||
.layer(middleware::from_fn_with_state(
|
.layer(middleware::from_fn_with_state(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
user_authentication,
|
user_authentication,
|
||||||
))
|
))
|
||||||
.nest_service("/static", ServeDir::new("static"))
|
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
|
.nest_service("/favicon.ico", ServeFile::new("static/favicon.ico"))
|
||||||
|
.nest_service("/static", ServeDir::new("static"))
|
||||||
|
.layer(TraceLayer::new_for_http())
|
||||||
.into_make_service_with_connect_info::<SocketAddr>();
|
.into_make_service_with_connect_info::<SocketAddr>();
|
||||||
|
|
||||||
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
||||||
|
|
@ -291,11 +294,53 @@ async fn user_authentication(
|
||||||
Ok(next.run(req).await)
|
Ok(next.run(req).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The language of the current HTTP request is defined in the current order:
|
||||||
|
/// - Extraction from the url: like in '/fr/recipe/view/42' (Not yet implemented).
|
||||||
|
/// - Get from the user database record.
|
||||||
|
/// - Get from the cookie.
|
||||||
|
/// - Get from the HTTP header `accept-language`.
|
||||||
|
/// - Set as `translation::DEFAULT_LANGUAGE_CODE`.
|
||||||
async fn translation(
|
async fn translation(
|
||||||
Extension(user): Extension<Option<model::User>>,
|
Extension(user): Extension<Option<model::User>>,
|
||||||
mut req: Request,
|
mut req: Request,
|
||||||
next: Next,
|
next: Next,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
|
// Here we are extracting the language from the url then rewriting it.
|
||||||
|
// For example:
|
||||||
|
// "/fr/recipe/view/1"
|
||||||
|
// lang = "fr" and uri rewritten as = "/recipe/view/1"
|
||||||
|
// Disable because it doesn't work at this level, see:
|
||||||
|
// https://docs.rs/axum/latest/axum/middleware/index.html#rewriting-request-uri-in-middleware
|
||||||
|
|
||||||
|
// let lang_and_new_uri = 'lang_from_uri: {
|
||||||
|
// if let Some(path_query) = req.uri().path_and_query() {
|
||||||
|
// event!(Level::INFO, "path: {:?}", path_query.path());
|
||||||
|
// let mut parts = path_query.path().split('/');
|
||||||
|
// let _ = parts.next(); // Empty part due to the first '/'.
|
||||||
|
// if let Some(lang) = parts.next() {
|
||||||
|
// let available_codes = translation::available_codes();
|
||||||
|
// if available_codes.contains(&lang) {
|
||||||
|
// let mut rest: String = String::from("");
|
||||||
|
// for part in parts {
|
||||||
|
// rest.push('/');
|
||||||
|
// rest.push_str(part);
|
||||||
|
// }
|
||||||
|
// // let uri_builder = Uri::builder()
|
||||||
|
// if let Ok(new_uri) = rest.parse::<Uri>() {
|
||||||
|
// event!(Level::INFO, "path rewrite: {:?}", new_uri.path());
|
||||||
|
// break 'lang_from_uri Some((lang.to_string(), new_uri));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// None
|
||||||
|
// };
|
||||||
|
// let language = if let Some((lang, uri)) = lang_and_new_uri {
|
||||||
|
// *req.uri_mut() = uri; // Replace the URI without the language.
|
||||||
|
// event!(Level::INFO, "URI: {:?}", req.uri());
|
||||||
|
// lang
|
||||||
|
// } else
|
||||||
|
|
||||||
let language = if let Some(user) = user {
|
let language = if let Some(user) = user {
|
||||||
user.lang
|
user.lang
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -370,6 +415,7 @@ struct Args {
|
||||||
dbtest: bool,
|
dbtest: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the server can be started.
|
||||||
async fn process_args() -> bool {
|
async fn process_args() -> bool {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
|
|
@ -418,8 +464,8 @@ async fn process_args() -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
body, debug_handler,
|
body, debug_handler,
|
||||||
extract::{Extension, Request, State},
|
extract::{Extension, Request, State},
|
||||||
http::{header, StatusCode},
|
http::{StatusCode, header},
|
||||||
middleware::Next,
|
middleware::Next,
|
||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
};
|
};
|
||||||
use rinja::Template;
|
use rinja::Template;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Result,
|
||||||
data::{db, model},
|
data::{db, model},
|
||||||
html_templates::*,
|
html_templates::*,
|
||||||
ron_utils, translation, Result,
|
ron_utils, translation,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod fragments;
|
pub mod fragments;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use ron::de::from_reader;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use strum::EnumCount;
|
use strum::EnumCount;
|
||||||
use strum_macros::EnumCount;
|
use strum_macros::EnumCount;
|
||||||
use tracing::{event, Level};
|
use tracing::{Level, event};
|
||||||
|
|
||||||
use crate::consts;
|
use crate::consts;
|
||||||
|
|
||||||
|
|
|
||||||
BIN
backend/static/favicon.ico
Normal file
BIN
backend/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -1,5 +1,5 @@
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use ron::ser::{to_string_pretty, PrettyConfig};
|
use ron::ser::{PrettyConfig, to_string_pretty};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue