Add a toggle between dark and light theme
This commit is contained in:
parent
d22617538e
commit
559ed139aa
34 changed files with 640 additions and 469 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use askama::Template;
|
||||
|
||||
use crate::{
|
||||
Context,
|
||||
data::model,
|
||||
translation::{self, Sentence, Tr},
|
||||
};
|
||||
|
|
@ -20,8 +21,7 @@ impl Recipes {
|
|||
#[derive(Template)]
|
||||
#[template(path = "home.html")]
|
||||
pub struct HomeTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub recipes: Recipes,
|
||||
}
|
||||
|
|
@ -29,8 +29,7 @@ pub struct HomeTemplate {
|
|||
#[derive(Template)]
|
||||
#[template(path = "message.html")]
|
||||
pub struct MessageTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub message: &'a str,
|
||||
pub as_code: bool, // Display the message in <pre> markup.
|
||||
|
|
@ -39,8 +38,11 @@ pub struct MessageTemplate<'a> {
|
|||
impl<'a> MessageTemplate<'a> {
|
||||
pub fn new(message: &'a str, tr: Tr) -> MessageTemplate<'a> {
|
||||
MessageTemplate {
|
||||
user: None,
|
||||
tr,
|
||||
context: Context {
|
||||
user: None,
|
||||
tr,
|
||||
dark_theme: false,
|
||||
},
|
||||
message,
|
||||
as_code: false,
|
||||
}
|
||||
|
|
@ -52,8 +54,11 @@ impl<'a> MessageTemplate<'a> {
|
|||
user: Option<model::User>,
|
||||
) -> MessageTemplate<'a> {
|
||||
MessageTemplate {
|
||||
user,
|
||||
tr,
|
||||
context: Context {
|
||||
user,
|
||||
tr,
|
||||
dark_theme: false,
|
||||
},
|
||||
message,
|
||||
as_code: false,
|
||||
}
|
||||
|
|
@ -63,8 +68,7 @@ impl<'a> MessageTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "sign_up_form.html")]
|
||||
pub struct SignUpFormTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub email: String,
|
||||
pub message: &'a str,
|
||||
|
|
@ -75,8 +79,7 @@ pub struct SignUpFormTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "sign_in_form.html")]
|
||||
pub struct SignInFormTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub email: &'a str,
|
||||
pub message: &'a str,
|
||||
|
|
@ -85,8 +88,7 @@ pub struct SignInFormTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "ask_reset_password.html")]
|
||||
pub struct AskResetPasswordTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub email: &'a str,
|
||||
pub message: &'a str,
|
||||
|
|
@ -96,8 +98,7 @@ pub struct AskResetPasswordTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "reset_password.html")]
|
||||
pub struct ResetPasswordTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub reset_token: &'a str,
|
||||
pub message: &'a str,
|
||||
|
|
@ -107,8 +108,7 @@ pub struct ResetPasswordTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "profile.html")]
|
||||
pub struct ProfileTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub username: &'a str,
|
||||
pub email: &'a str,
|
||||
|
|
@ -121,8 +121,7 @@ pub struct ProfileTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "recipe_view.html")]
|
||||
pub struct RecipeViewTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub recipes: Recipes,
|
||||
|
||||
|
|
@ -132,8 +131,7 @@ pub struct RecipeViewTemplate {
|
|||
#[derive(Template)]
|
||||
#[template(path = "recipe_edit.html")]
|
||||
pub struct RecipeEditTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub recipes: Recipes,
|
||||
|
||||
|
|
@ -143,7 +141,7 @@ pub struct RecipeEditTemplate {
|
|||
#[derive(Template)]
|
||||
#[template(path = "recipes_list_fragment.html")]
|
||||
pub struct RecipesListFragmentTemplate {
|
||||
pub tr: Tr,
|
||||
pub context: Context,
|
||||
|
||||
pub recipes: Recipes,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,13 @@ const TRACING_LEVEL: tracing::Level = tracing::Level::DEBUG;
|
|||
#[cfg(not(debug_assertions))]
|
||||
const TRACING_LEVEL: tracing::Level = tracing::Level::INFO;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Context {
|
||||
pub user: Option<model::User>,
|
||||
pub tr: Tr,
|
||||
pub dark_theme: bool,
|
||||
}
|
||||
|
||||
// TODO: Should main returns 'Result'?
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
@ -294,11 +301,7 @@ async fn main() {
|
|||
.merge(html_routes)
|
||||
.nest("/ron-api", ron_api_routes)
|
||||
.fallback(services::not_found)
|
||||
.layer(middleware::from_fn(translation))
|
||||
.layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
user_authentication,
|
||||
))
|
||||
.layer(middleware::from_fn_with_state(state.clone(), context))
|
||||
.with_state(state)
|
||||
.nest_service("/favicon.ico", ServeFile::new("static/favicon.ico"))
|
||||
.nest_service("/static", ServeDir::new("static"))
|
||||
|
|
@ -321,19 +324,6 @@ async fn main() {
|
|||
event!(Level::INFO, "Recipes stopped");
|
||||
}
|
||||
|
||||
async fn user_authentication(
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
State(connection): State<db::Connection>,
|
||||
mut req: Request,
|
||||
next: Next,
|
||||
) -> Result<Response> {
|
||||
let jar = CookieJar::from_headers(req.headers());
|
||||
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(req.headers(), addr);
|
||||
let user = get_current_user(connection, &jar, &client_ip, &client_user_agent).await;
|
||||
req.extensions_mut().insert(user);
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Lang(Option<String>);
|
||||
|
||||
|
|
@ -384,16 +374,21 @@ fn url_rewriting(mut req: Request) -> Request {
|
|||
/// - Get from the cookie.
|
||||
/// - Get from the HTTP header `accept-language`.
|
||||
/// - Set as `translation::DEFAULT_LANGUAGE_CODE`.
|
||||
async fn translation(
|
||||
Extension(lang): Extension<Lang>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
async fn context(
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(lang_from_url): Extension<Lang>,
|
||||
mut req: Request,
|
||||
next: Next,
|
||||
) -> Result<Response> {
|
||||
let language = if let Some(lang) = lang.0 {
|
||||
let jar = CookieJar::from_headers(req.headers());
|
||||
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(req.headers(), addr);
|
||||
let user = get_current_user(connection, &jar, &client_ip, &client_user_agent).await;
|
||||
|
||||
let language = if let Some(lang) = lang_from_url.0 {
|
||||
lang
|
||||
} else if let Some(user) = user {
|
||||
user.lang
|
||||
} else if let Some(ref user) = user {
|
||||
user.lang.clone()
|
||||
} else {
|
||||
let available_codes = translation::available_codes();
|
||||
let jar = CookieJar::from_headers(req.headers());
|
||||
|
|
@ -420,7 +415,17 @@ async fn translation(
|
|||
|
||||
let tr = Tr::new(&language);
|
||||
|
||||
req.extensions_mut().insert(tr);
|
||||
let dark_theme = match jar.get(common::consts::COOKIE_DARK_THEME) {
|
||||
Some(dark_theme_cookie) => dark_theme_cookie.value().parse().unwrap_or_default(),
|
||||
None => false,
|
||||
};
|
||||
|
||||
req.extensions_mut().insert(Context {
|
||||
user,
|
||||
tr,
|
||||
dark_theme,
|
||||
});
|
||||
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,7 @@ use axum::{
|
|||
use serde::Deserialize;
|
||||
// use tracing::{event, Level};
|
||||
|
||||
use crate::{
|
||||
Result,
|
||||
data::{db, model},
|
||||
html_templates::*,
|
||||
translation,
|
||||
};
|
||||
use crate::{Context, Result, data::db, html_templates::*};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CurrentRecipeId {
|
||||
|
|
@ -23,14 +18,16 @@ pub struct CurrentRecipeId {
|
|||
pub async fn recipes_list_fragments(
|
||||
State(connection): State<db::Connection>,
|
||||
current_recipe: Query<CurrentRecipeId>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
let recipes = Recipes {
|
||||
published: connection
|
||||
.get_all_published_recipe_titles(tr.current_lang_code(), user.as_ref().map(|u| u.id))
|
||||
.get_all_published_recipe_titles(
|
||||
context.tr.current_lang_code(),
|
||||
context.user.as_ref().map(|u| u.id),
|
||||
)
|
||||
.await?,
|
||||
unpublished: if let Some(user) = user.as_ref() {
|
||||
unpublished: if let Some(user) = context.user.as_ref() {
|
||||
connection
|
||||
.get_all_unpublished_recipe_titles(user.id)
|
||||
.await?
|
||||
|
|
@ -39,5 +36,7 @@ pub async fn recipes_list_fragments(
|
|||
},
|
||||
current_id: current_recipe.current_recipe_id,
|
||||
};
|
||||
Ok(Html(RecipesListFragmentTemplate { tr, recipes }.render()?))
|
||||
Ok(Html(
|
||||
RecipesListFragmentTemplate { context, recipes }.render()?,
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,7 @@ use axum::{
|
|||
response::{Html, IntoResponse, Response},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Result,
|
||||
data::{db, model},
|
||||
html_templates::*,
|
||||
ron_utils, translation,
|
||||
};
|
||||
use crate::{Context, Result, data::db, html_templates::*, ron_utils};
|
||||
|
||||
pub mod fragments;
|
||||
pub mod recipe;
|
||||
|
|
@ -21,7 +16,7 @@ pub mod user;
|
|||
|
||||
// Will embed RON error in HTML page.
|
||||
pub async fn ron_error_to_html(
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
req: Request,
|
||||
next: Next,
|
||||
) -> Result<Response> {
|
||||
|
|
@ -35,10 +30,9 @@ pub async fn ron_error_to_html(
|
|||
};
|
||||
return Ok(Html(
|
||||
MessageTemplate {
|
||||
user: None,
|
||||
context,
|
||||
message: &message,
|
||||
as_code: true,
|
||||
tr,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -54,14 +48,16 @@ pub async fn ron_error_to_html(
|
|||
#[debug_handler]
|
||||
pub async fn home_page(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
let recipes = Recipes {
|
||||
published: connection
|
||||
.get_all_published_recipe_titles(tr.current_lang_code(), user.as_ref().map(|u| u.id))
|
||||
.get_all_published_recipe_titles(
|
||||
context.tr.current_lang_code(),
|
||||
context.user.as_ref().map(|u| u.id),
|
||||
)
|
||||
.await?,
|
||||
unpublished: if let Some(user) = user.as_ref() {
|
||||
unpublished: if let Some(user) = context.user.as_ref() {
|
||||
connection
|
||||
.get_all_unpublished_recipe_titles(user.id)
|
||||
.await?
|
||||
|
|
@ -71,18 +67,15 @@ pub async fn home_page(
|
|||
current_id: None,
|
||||
};
|
||||
|
||||
Ok(Html(HomeTemplate { user, recipes, tr }.render()?))
|
||||
Ok(Html(HomeTemplate { context, recipes }.render()?))
|
||||
}
|
||||
|
||||
///// 404 /////
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn not_found(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
pub async fn not_found(Extension(context): Extension<Context>) -> Result<impl IntoResponse> {
|
||||
Ok((
|
||||
StatusCode::NOT_FOUND,
|
||||
Html(MessageTemplate::new_with_user("404: Not found", tr, user).render()?),
|
||||
Html(MessageTemplate::new_with_user("404: Not found", context.tr, context.user).render()?),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,44 +7,48 @@ use axum::{
|
|||
// use tracing::{event, Level};
|
||||
|
||||
use crate::{
|
||||
Result,
|
||||
Context, Result,
|
||||
data::{db, model},
|
||||
html_templates::*,
|
||||
translation::{self, Sentence},
|
||||
translation::Sentence,
|
||||
};
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn create(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
) -> Result<Response> {
|
||||
if let Some(user) = user {
|
||||
if let Some(user) = context.user {
|
||||
let recipe_id = connection.create_recipe(user.id).await?;
|
||||
Ok(Redirect::to(&format!(
|
||||
"/{}/recipe/edit/{}",
|
||||
tr.current_lang_code(),
|
||||
context.tr.current_lang_code(),
|
||||
recipe_id
|
||||
))
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(Html(MessageTemplate::new(tr.t(Sentence::NotLoggedIn), tr).render()?).into_response())
|
||||
Ok(
|
||||
Html(MessageTemplate::new(context.tr.t(Sentence::NotLoggedIn), context.tr).render()?)
|
||||
.into_response(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn edit(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Path(recipe_id): Path<i64>,
|
||||
) -> Result<Response> {
|
||||
if let Some(user) = user {
|
||||
if let Some(ref user) = context.user {
|
||||
if let Some(recipe) = connection.get_recipe(recipe_id, false).await? {
|
||||
if model::can_user_edit_recipe(&user, &recipe) {
|
||||
let recipes = Recipes {
|
||||
published: connection
|
||||
.get_all_published_recipe_titles(tr.current_lang_code(), Some(user.id))
|
||||
.get_all_published_recipe_titles(
|
||||
context.tr.current_lang_code(),
|
||||
Some(user.id),
|
||||
)
|
||||
.await?,
|
||||
unpublished: connection
|
||||
.get_all_unpublished_recipe_titles(user.id)
|
||||
|
|
@ -54,8 +58,7 @@ pub async fn edit(
|
|||
|
||||
Ok(Html(
|
||||
RecipeEditTemplate {
|
||||
user: Some(user),
|
||||
tr,
|
||||
context,
|
||||
recipes,
|
||||
recipe,
|
||||
}
|
||||
|
|
@ -63,42 +66,48 @@ pub async fn edit(
|
|||
)
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(
|
||||
Html(
|
||||
MessageTemplate::new(tr.t(Sentence::RecipeNotAllowedToEdit), tr)
|
||||
.render()?,
|
||||
Ok(Html(
|
||||
MessageTemplate::new(
|
||||
context.tr.t(Sentence::RecipeNotAllowedToEdit),
|
||||
context.tr,
|
||||
)
|
||||
.into_response(),
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
} else {
|
||||
Ok(
|
||||
Html(MessageTemplate::new(tr.t(Sentence::RecipeNotFound), tr).render()?)
|
||||
.into_response(),
|
||||
Ok(Html(
|
||||
MessageTemplate::new(context.tr.t(Sentence::RecipeNotFound), context.tr)
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
} else {
|
||||
Ok(Html(MessageTemplate::new(tr.t(Sentence::NotLoggedIn), tr).render()?).into_response())
|
||||
Ok(
|
||||
Html(MessageTemplate::new(context.tr.t(Sentence::NotLoggedIn), context.tr).render()?)
|
||||
.into_response(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn view(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Path(recipe_id): Path<i64>,
|
||||
) -> Result<Response> {
|
||||
match connection.get_recipe(recipe_id, true).await? {
|
||||
Some(recipe) => {
|
||||
if !recipe.is_published
|
||||
&& (user.is_none() || recipe.user_id != user.as_ref().unwrap().id)
|
||||
&& (context.user.is_none() || recipe.user_id != context.user.as_ref().unwrap().id)
|
||||
{
|
||||
return Ok(Html(
|
||||
MessageTemplate::new_with_user(
|
||||
&tr.tp(Sentence::RecipeNotAllowedToView, &[Box::new(recipe_id)]),
|
||||
tr,
|
||||
user,
|
||||
&context
|
||||
.tr
|
||||
.tp(Sentence::RecipeNotAllowedToView, &[Box::new(recipe_id)]),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -108,11 +117,11 @@ pub async fn view(
|
|||
let recipes = Recipes {
|
||||
published: connection
|
||||
.get_all_published_recipe_titles(
|
||||
tr.current_lang_code(),
|
||||
user.as_ref().map(|u| u.id),
|
||||
context.tr.current_lang_code(),
|
||||
context.user.as_ref().map(|u| u.id),
|
||||
)
|
||||
.await?,
|
||||
unpublished: if let Some(user) = user.as_ref() {
|
||||
unpublished: if let Some(user) = context.user.as_ref() {
|
||||
connection
|
||||
.get_all_unpublished_recipe_titles(user.id)
|
||||
.await?
|
||||
|
|
@ -124,8 +133,7 @@ pub async fn view(
|
|||
|
||||
Ok(Html(
|
||||
RecipeViewTemplate {
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
recipes,
|
||||
recipe,
|
||||
}
|
||||
|
|
@ -134,7 +142,12 @@ pub async fn view(
|
|||
.into_response())
|
||||
}
|
||||
None => Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::RecipeNotFound), tr, user).render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::RecipeNotFound),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response()),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use axum_extra::extract::Query;
|
|||
// use tracing::{event, Level};
|
||||
|
||||
use crate::{
|
||||
Context,
|
||||
data::{self, db},
|
||||
model,
|
||||
ron_extractor::ExtractRon,
|
||||
ron_utils::{ron_error, ron_response_ok},
|
||||
};
|
||||
|
|
@ -19,10 +19,10 @@ use super::rights::*;
|
|||
#[debug_handler]
|
||||
pub async fn get_scheduled_recipes(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
date_range: Query<common::ron_api::DateRange>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
if let Some(user) = user {
|
||||
if let Some(user) = context.user {
|
||||
Ok(ron_response_ok(common::ron_api::ScheduledRecipes {
|
||||
recipes: connection
|
||||
.get_scheduled_recipes(user.id, date_range.start_date, date_range.end_date)
|
||||
|
|
@ -50,11 +50,11 @@ impl From<data::db::recipe::AddScheduledRecipeResult> for common::ron_api::Sched
|
|||
#[debug_handler]
|
||||
pub async fn schedule_recipe(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<common::ron_api::ScheduleRecipe>,
|
||||
) -> Result<Response> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
if let Some(user) = user {
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
if let Some(user) = context.user {
|
||||
connection
|
||||
.add_scheduled_recipe(
|
||||
user.id,
|
||||
|
|
@ -76,11 +76,11 @@ pub async fn schedule_recipe(
|
|||
#[debug_handler]
|
||||
pub async fn rm_scheduled_recipe(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<common::ron_api::RemoveScheduledRecipe>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
if let Some(user) = user {
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
if let Some(user) = context.user {
|
||||
connection
|
||||
.rm_scheduled_recipe(
|
||||
user.id,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use axum::{
|
|||
use axum_extra::extract::cookie::{Cookie, CookieJar};
|
||||
// use tracing::{event, Level};
|
||||
|
||||
use crate::{consts, data::db, model, ron_extractor::ExtractRon, ron_utils::ron_error};
|
||||
use crate::{Context, consts, data::db, model, ron_extractor::ExtractRon, ron_utils::ron_error};
|
||||
|
||||
pub mod calendar;
|
||||
pub mod recipe;
|
||||
|
|
@ -19,12 +19,12 @@ const NOT_AUTHORIZED_MESSAGE: &str = "Action not authorized";
|
|||
#[debug_handler]
|
||||
pub async fn set_lang(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
headers: HeaderMap,
|
||||
ExtractRon(ron): ExtractRon<common::ron_api::SetLang>,
|
||||
) -> Result<(CookieJar, StatusCode)> {
|
||||
let mut jar = CookieJar::from_headers(&headers);
|
||||
if let Some(user) = user {
|
||||
if let Some(user) = context.user {
|
||||
connection.set_user_lang(user.id, &ron.lang).await?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use axum_extra::extract::Query;
|
|||
use common::ron_api;
|
||||
// use tracing::{event, Level};
|
||||
|
||||
use crate::{data::db, model, ron_extractor::ExtractRon, ron_utils::ron_response_ok};
|
||||
use crate::{Context, data::db, model, ron_extractor::ExtractRon, ron_utils::ron_response_ok};
|
||||
|
||||
use super::rights::*;
|
||||
|
||||
|
|
@ -27,10 +27,10 @@ pub async fn get_titles(
|
|||
#[debug_handler]
|
||||
pub async fn set_title(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeTitle>,
|
||||
) -> Result<StatusCode> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_title(ron.recipe_id, &ron.title)
|
||||
.await?;
|
||||
|
|
@ -40,10 +40,10 @@ pub async fn set_title(
|
|||
#[debug_handler]
|
||||
pub async fn set_description(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeDescription>,
|
||||
) -> Result<StatusCode> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_description(ron.recipe_id, &ron.description)
|
||||
.await?;
|
||||
|
|
@ -53,10 +53,10 @@ pub async fn set_description(
|
|||
#[debug_handler]
|
||||
pub async fn set_servings(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeServings>,
|
||||
) -> Result<StatusCode> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_servings(ron.recipe_id, ron.servings)
|
||||
.await?;
|
||||
|
|
@ -66,10 +66,10 @@ pub async fn set_servings(
|
|||
#[debug_handler]
|
||||
pub async fn set_estimated_time(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeEstimatedTime>,
|
||||
) -> Result<StatusCode> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_estimated_time(ron.recipe_id, ron.estimated_time)
|
||||
.await?;
|
||||
|
|
@ -90,10 +90,10 @@ pub async fn get_tags(
|
|||
#[debug_handler]
|
||||
pub async fn add_tags(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Tags>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.add_recipe_tags(
|
||||
ron.recipe_id,
|
||||
|
|
@ -109,10 +109,10 @@ pub async fn add_tags(
|
|||
#[debug_handler]
|
||||
pub async fn rm_tags(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Tags>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection.rm_recipe_tags(ron.recipe_id, &ron.tags).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -120,10 +120,10 @@ pub async fn rm_tags(
|
|||
#[debug_handler]
|
||||
pub async fn set_difficulty(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeDifficulty>,
|
||||
) -> Result<StatusCode> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_difficulty(ron.recipe_id, ron.difficulty)
|
||||
.await?;
|
||||
|
|
@ -133,7 +133,7 @@ pub async fn set_difficulty(
|
|||
#[debug_handler]
|
||||
pub async fn set_language(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeLanguage>,
|
||||
) -> Result<StatusCode> {
|
||||
if !crate::translation::available_codes()
|
||||
|
|
@ -144,7 +144,7 @@ pub async fn set_language(
|
|||
return Ok(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_language(ron.recipe_id, &ron.lang)
|
||||
.await?;
|
||||
|
|
@ -154,10 +154,10 @@ pub async fn set_language(
|
|||
#[debug_handler]
|
||||
pub async fn set_is_published(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetIsPublished>,
|
||||
) -> Result<StatusCode> {
|
||||
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||
connection
|
||||
.set_recipe_is_published(ron.recipe_id, ron.is_published)
|
||||
.await?;
|
||||
|
|
@ -167,10 +167,10 @@ pub async fn set_is_published(
|
|||
#[debug_handler]
|
||||
pub async fn rm(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.id).await?;
|
||||
connection.rm_recipe(ron.id).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -231,10 +231,10 @@ pub async fn get_groups(
|
|||
#[debug_handler]
|
||||
pub async fn add_group(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe(&connection, &context.user, ron.id).await?;
|
||||
let id = connection.add_recipe_group(ron.id).await?;
|
||||
|
||||
Ok(ron_response_ok(ron_api::Id { id }))
|
||||
|
|
@ -243,10 +243,10 @@ pub async fn add_group(
|
|||
#[debug_handler]
|
||||
pub async fn rm_group(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_group(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe_group(&connection, &context.user, ron.id).await?;
|
||||
connection.rm_recipe_group(ron.id).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -254,10 +254,10 @@ pub async fn rm_group(
|
|||
#[debug_handler]
|
||||
pub async fn set_group_name(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetGroupName>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_group(&connection, &user, ron.group_id).await?;
|
||||
check_user_rights_recipe_group(&connection, &context.user, ron.group_id).await?;
|
||||
connection.set_group_name(ron.group_id, &ron.name).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -265,10 +265,10 @@ pub async fn set_group_name(
|
|||
#[debug_handler]
|
||||
pub async fn set_group_comment(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetGroupComment>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_group(&connection, &user, ron.group_id).await?;
|
||||
check_user_rights_recipe_group(&connection, &context.user, ron.group_id).await?;
|
||||
connection
|
||||
.set_group_comment(ron.group_id, &ron.comment)
|
||||
.await?;
|
||||
|
|
@ -278,10 +278,10 @@ pub async fn set_group_comment(
|
|||
#[debug_handler]
|
||||
pub async fn set_groups_order(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Ids>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_groups(&connection, &user, &ron.ids).await?;
|
||||
check_user_rights_recipe_groups(&connection, &context.user, &ron.ids).await?;
|
||||
connection.set_groups_order(&ron.ids).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -289,10 +289,10 @@ pub async fn set_groups_order(
|
|||
#[debug_handler]
|
||||
pub async fn add_step(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_group(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe_group(&connection, &context.user, ron.id).await?;
|
||||
let id = connection.add_recipe_step(ron.id).await?;
|
||||
|
||||
Ok(ron_response_ok(ron_api::Id { id }))
|
||||
|
|
@ -301,10 +301,10 @@ pub async fn add_step(
|
|||
#[debug_handler]
|
||||
pub async fn rm_step(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_step(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe_step(&connection, &context.user, ron.id).await?;
|
||||
connection.rm_recipe_step(ron.id).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -312,10 +312,10 @@ pub async fn rm_step(
|
|||
#[debug_handler]
|
||||
pub async fn set_step_action(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetStepAction>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_step(&connection, &user, ron.step_id).await?;
|
||||
check_user_rights_recipe_step(&connection, &context.user, ron.step_id).await?;
|
||||
connection.set_step_action(ron.step_id, &ron.action).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -323,10 +323,10 @@ pub async fn set_step_action(
|
|||
#[debug_handler]
|
||||
pub async fn set_steps_order(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Ids>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_steps(&connection, &user, &ron.ids).await?;
|
||||
check_user_rights_recipe_steps(&connection, &context.user, &ron.ids).await?;
|
||||
connection.set_steps_order(&ron.ids).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -334,10 +334,10 @@ pub async fn set_steps_order(
|
|||
#[debug_handler]
|
||||
pub async fn add_ingredient(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_step(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe_step(&connection, &context.user, ron.id).await?;
|
||||
let id = connection.add_recipe_ingredient(ron.id).await?;
|
||||
Ok(ron_response_ok(ron_api::Id { id }))
|
||||
}
|
||||
|
|
@ -345,10 +345,10 @@ pub async fn add_ingredient(
|
|||
#[debug_handler]
|
||||
pub async fn rm_ingredient(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Id>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_ingredient(&connection, &user, ron.id).await?;
|
||||
check_user_rights_recipe_ingredient(&connection, &context.user, ron.id).await?;
|
||||
connection.rm_recipe_ingredient(ron.id).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
@ -356,10 +356,10 @@ pub async fn rm_ingredient(
|
|||
#[debug_handler]
|
||||
pub async fn set_ingredient_name(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetIngredientName>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_ingredient(&connection, &user, ron.ingredient_id).await?;
|
||||
check_user_rights_recipe_ingredient(&connection, &context.user, ron.ingredient_id).await?;
|
||||
connection
|
||||
.set_ingredient_name(ron.ingredient_id, &ron.name)
|
||||
.await?;
|
||||
|
|
@ -369,10 +369,10 @@ pub async fn set_ingredient_name(
|
|||
#[debug_handler]
|
||||
pub async fn set_ingredient_comment(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetIngredientComment>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_ingredient(&connection, &user, ron.ingredient_id).await?;
|
||||
check_user_rights_recipe_ingredient(&connection, &context.user, ron.ingredient_id).await?;
|
||||
connection
|
||||
.set_ingredient_comment(ron.ingredient_id, &ron.comment)
|
||||
.await?;
|
||||
|
|
@ -382,10 +382,10 @@ pub async fn set_ingredient_comment(
|
|||
#[debug_handler]
|
||||
pub async fn set_ingredient_quantity(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetIngredientQuantity>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_ingredient(&connection, &user, ron.ingredient_id).await?;
|
||||
check_user_rights_recipe_ingredient(&connection, &context.user, ron.ingredient_id).await?;
|
||||
connection
|
||||
.set_ingredient_quantity(ron.ingredient_id, ron.quantity)
|
||||
.await?;
|
||||
|
|
@ -395,10 +395,10 @@ pub async fn set_ingredient_quantity(
|
|||
#[debug_handler]
|
||||
pub async fn set_ingredient_unit(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::SetIngredientUnit>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_ingredient(&connection, &user, ron.ingredient_id).await?;
|
||||
check_user_rights_recipe_ingredient(&connection, &context.user, ron.ingredient_id).await?;
|
||||
connection
|
||||
.set_ingredient_unit(ron.ingredient_id, &ron.unit)
|
||||
.await?;
|
||||
|
|
@ -408,10 +408,10 @@ pub async fn set_ingredient_unit(
|
|||
#[debug_handler]
|
||||
pub async fn set_ingredients_order(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Ids>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_ingredients(&connection, &user, &ron.ids).await?;
|
||||
check_user_rights_recipe_ingredients(&connection, &context.user, &ron.ids).await?;
|
||||
connection.set_ingredients_order(&ron.ids).await?;
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use axum::{
|
|||
use common::ron_api;
|
||||
|
||||
use crate::{
|
||||
Context,
|
||||
data::db,
|
||||
model,
|
||||
ron_extractor::ExtractRon,
|
||||
|
|
@ -33,9 +34,9 @@ impl From<model::ShoppingListItem> for common::ron_api::ShoppingListItem {
|
|||
#[debug_handler]
|
||||
pub async fn get(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
if let Some(user) = user {
|
||||
if let Some(user) = context.user {
|
||||
Ok(ron_response_ok(
|
||||
connection
|
||||
.get_shopping_list(user.id)
|
||||
|
|
@ -55,10 +56,10 @@ pub async fn get(
|
|||
#[debug_handler]
|
||||
pub async fn set_entry_checked(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(context): Extension<Context>,
|
||||
ExtractRon(ron): ExtractRon<ron_api::Value<bool>>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_shopping_list_entry(&connection, &user, ron.id).await?;
|
||||
check_user_rights_shopping_list_entry(&connection, &context.user, ron.id).await?;
|
||||
Ok(ron_response_ok(
|
||||
connection.set_entry_checked(ron.id, ron.value).await?,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use axum::{
|
|||
};
|
||||
use axum_extra::extract::{
|
||||
Host, Query,
|
||||
cookie::{Cookie, CookieJar},
|
||||
cookie::{self, Cookie, CookieJar},
|
||||
};
|
||||
use chrono::Duration;
|
||||
use lettre::Address;
|
||||
|
|
@ -19,14 +19,8 @@ use serde::Deserialize;
|
|||
use tracing::{Level, event};
|
||||
|
||||
use crate::{
|
||||
AppState, Result,
|
||||
config::Config,
|
||||
consts,
|
||||
data::{db, model},
|
||||
email,
|
||||
html_templates::*,
|
||||
translation::{self, Sentence},
|
||||
utils,
|
||||
AppState, Context, Result, config::Config, consts, data::db, email, html_templates::*,
|
||||
translation::Sentence, utils,
|
||||
};
|
||||
|
||||
/// SIGN UP ///
|
||||
|
|
@ -34,14 +28,12 @@ use crate::{
|
|||
#[debug_handler]
|
||||
pub async fn sign_up_get(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
) -> Result<Response> {
|
||||
if connection.get_new_user_registration_enabled().await? {
|
||||
Ok(Html(
|
||||
SignUpFormTemplate {
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
email: String::new(),
|
||||
message: "",
|
||||
message_email: "",
|
||||
|
|
@ -51,10 +43,15 @@ pub async fn sign_up_get(
|
|||
)
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(
|
||||
Html(MessageTemplate::new_with_user(tr.t(Sentence::SignUpClosed), tr, user).render()?)
|
||||
.into_response(),
|
||||
Ok(Html(
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::SignUpClosed),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,40 +76,37 @@ pub async fn sign_up_post(
|
|||
Host(host): Host,
|
||||
State(connection): State<db::Connection>,
|
||||
State(config): State<Config>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Form(form_data): Form<SignUpFormData>,
|
||||
) -> Result<Response> {
|
||||
fn error_response(
|
||||
error: SignUpError,
|
||||
form_data: &SignUpFormData,
|
||||
user: Option<model::User>,
|
||||
tr: translation::Tr,
|
||||
context: Context,
|
||||
) -> Result<Response> {
|
||||
let invalid_password_mess = &tr.tp(
|
||||
let invalid_password_mess = &context.tr.tp(
|
||||
Sentence::InvalidPassword,
|
||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||
);
|
||||
Ok(Html(
|
||||
SignUpFormTemplate {
|
||||
user,
|
||||
email: form_data.email.clone(),
|
||||
message_email: match error {
|
||||
SignUpError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
||||
SignUpError::InvalidEmail => context.tr.t(Sentence::InvalidEmail),
|
||||
_ => "",
|
||||
},
|
||||
message_password: match error {
|
||||
SignUpError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
||||
SignUpError::PasswordsNotEqual => context.tr.t(Sentence::PasswordDontMatch),
|
||||
SignUpError::InvalidPassword => invalid_password_mess,
|
||||
_ => "",
|
||||
},
|
||||
message: match error {
|
||||
SignUpError::UserAlreadyExists => tr.t(Sentence::EmailAlreadyTaken),
|
||||
SignUpError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||
SignUpError::UnableSendEmail => tr.t(Sentence::UnableToSendEmail),
|
||||
SignUpError::UserAlreadyExists => context.tr.t(Sentence::EmailAlreadyTaken),
|
||||
SignUpError::DatabaseError => context.tr.t(Sentence::DatabaseError),
|
||||
SignUpError::UnableSendEmail => context.tr.t(Sentence::UnableToSendEmail),
|
||||
_ => "",
|
||||
},
|
||||
tr,
|
||||
context,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -121,24 +115,29 @@ pub async fn sign_up_post(
|
|||
|
||||
if !connection.get_new_user_registration_enabled().await? {
|
||||
return Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::SignUpClosed), tr, user).render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::SignUpClosed),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response());
|
||||
}
|
||||
|
||||
// Validation of email and password.
|
||||
if form_data.email.parse::<Address>().is_err() {
|
||||
return error_response(SignUpError::InvalidEmail, &form_data, user, tr);
|
||||
return error_response(SignUpError::InvalidEmail, &form_data, context);
|
||||
}
|
||||
|
||||
if form_data.password_1 != form_data.password_2 {
|
||||
return error_response(SignUpError::PasswordsNotEqual, &form_data, user, tr);
|
||||
return error_response(SignUpError::PasswordsNotEqual, &form_data, context);
|
||||
}
|
||||
|
||||
if let common::utils::PasswordValidation::TooShort =
|
||||
common::utils::validate_password(&form_data.password_1)
|
||||
{
|
||||
return error_response(SignUpError::InvalidPassword, &form_data, user, tr);
|
||||
return error_response(SignUpError::InvalidPassword, &form_data, context);
|
||||
}
|
||||
|
||||
match connection
|
||||
|
|
@ -146,14 +145,14 @@ pub async fn sign_up_post(
|
|||
.await
|
||||
{
|
||||
Ok(db::user::SignUpResult::UserAlreadyExists) => {
|
||||
error_response(SignUpError::UserAlreadyExists, &form_data, user, tr)
|
||||
error_response(SignUpError::UserAlreadyExists, &form_data, context)
|
||||
}
|
||||
Ok(db::user::SignUpResult::UserCreatedWaitingForValidation(token)) => {
|
||||
let url = utils::get_url_from_host(&host);
|
||||
let email = form_data.email.clone();
|
||||
match email::send_email(
|
||||
&email,
|
||||
&tr.tp(
|
||||
&context.tr.tp(
|
||||
Sentence::SignUpFollowEmailLink,
|
||||
&[Box::new(format!(
|
||||
"{}/validation?validation_token={}",
|
||||
|
|
@ -167,19 +166,23 @@ pub async fn sign_up_post(
|
|||
.await
|
||||
{
|
||||
Ok(()) => Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::SignUpEmailSent), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::SignUpEmailSent),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response()),
|
||||
Err(_) => {
|
||||
// error!("Email validation error: {}", error); // TODO: log
|
||||
error_response(SignUpError::UnableSendEmail, &form_data, user, tr)
|
||||
error_response(SignUpError::UnableSendEmail, &form_data, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// error!("Signup database error: {}", error); // TODO: log
|
||||
error_response(SignUpError::DatabaseError, &form_data, user, tr)
|
||||
error_response(SignUpError::DatabaseError, &form_data, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -187,21 +190,20 @@ pub async fn sign_up_post(
|
|||
#[debug_handler]
|
||||
pub async fn sign_up_validation(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
Query(query): Query<HashMap<String, String>>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<(CookieJar, impl IntoResponse)> {
|
||||
let mut jar = CookieJar::from_headers(&headers);
|
||||
if user.is_some() {
|
||||
if context.user.is_some() {
|
||||
return Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::ValidationUserAlreadyExists),
|
||||
tr,
|
||||
user,
|
||||
context.tr.t(Sentence::ValidationUserAlreadyExists),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
|
|
@ -221,15 +223,16 @@ pub async fn sign_up_validation(
|
|||
.await?
|
||||
{
|
||||
db::user::ValidationResult::Ok(token, user_id) => {
|
||||
let cookie = Cookie::new(consts::COOKIE_AUTH_TOKEN_NAME, token);
|
||||
let cookie = Cookie::build((consts::COOKIE_AUTH_TOKEN_NAME, token))
|
||||
.same_site(cookie::SameSite::Strict);
|
||||
jar = jar.add(cookie);
|
||||
let user = connection.load_user(user_id).await?;
|
||||
Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::SignUpEmailValidationSuccess),
|
||||
tr,
|
||||
context.tr.t(Sentence::SignUpEmailValidationSuccess),
|
||||
context.tr,
|
||||
user,
|
||||
)
|
||||
.render()?,
|
||||
|
|
@ -240,9 +243,9 @@ pub async fn sign_up_validation(
|
|||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::SignUpValidationExpired),
|
||||
tr,
|
||||
user,
|
||||
context.tr.t(Sentence::SignUpValidationExpired),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
|
|
@ -251,9 +254,9 @@ pub async fn sign_up_validation(
|
|||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::SignUpValidationErrorTryAgain),
|
||||
tr,
|
||||
user,
|
||||
context.tr.t(Sentence::SignUpValidationErrorTryAgain),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
|
|
@ -263,8 +266,12 @@ pub async fn sign_up_validation(
|
|||
None => Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::ValidationError), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::ValidationError),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
)),
|
||||
}
|
||||
|
|
@ -273,14 +280,10 @@ pub async fn sign_up_validation(
|
|||
/// SIGN IN ///
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn sign_in_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
pub async fn sign_in_get(Extension(context): Extension<Context>) -> Result<impl IntoResponse> {
|
||||
Ok(Html(
|
||||
SignInFormTemplate {
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
email: "",
|
||||
message: "",
|
||||
}
|
||||
|
|
@ -298,8 +301,7 @@ pub struct SignInFormData {
|
|||
pub async fn sign_in_post(
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
headers: HeaderMap,
|
||||
Form(form_data): Form<SignInFormData>,
|
||||
) -> Result<(CookieJar, Response)> {
|
||||
|
|
@ -319,10 +321,9 @@ pub async fn sign_in_post(
|
|||
jar,
|
||||
Html(
|
||||
SignInFormTemplate {
|
||||
user,
|
||||
email: &form_data.email,
|
||||
message: tr.t(Sentence::AccountMustBeValidatedFirst),
|
||||
tr,
|
||||
message: context.tr.t(Sentence::AccountMustBeValidatedFirst),
|
||||
context,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -332,20 +333,20 @@ pub async fn sign_in_post(
|
|||
jar,
|
||||
Html(
|
||||
SignInFormTemplate {
|
||||
user,
|
||||
email: &form_data.email,
|
||||
message: tr.t(Sentence::WrongEmailOrPassword),
|
||||
tr,
|
||||
message: context.tr.t(Sentence::WrongEmailOrPassword),
|
||||
context,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
.into_response(),
|
||||
)),
|
||||
db::user::SignInResult::Ok(token, _user_id) => {
|
||||
let cookie = Cookie::new(consts::COOKIE_AUTH_TOKEN_NAME, token);
|
||||
let cookie = Cookie::build((consts::COOKIE_AUTH_TOKEN_NAME, token))
|
||||
.same_site(cookie::SameSite::Strict);
|
||||
Ok((
|
||||
jar.add(cookie),
|
||||
Redirect::to(&format!("/{}/", tr.current_lang_code())).into_response(),
|
||||
Redirect::to(&format!("/{}/", context.tr.current_lang_code())).into_response(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -356,7 +357,7 @@ pub async fn sign_in_post(
|
|||
#[debug_handler]
|
||||
pub async fn sign_out(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
req: Request<Body>,
|
||||
) -> Result<(CookieJar, Redirect)> {
|
||||
let mut jar = CookieJar::from_headers(req.headers());
|
||||
|
|
@ -365,27 +366,30 @@ pub async fn sign_out(
|
|||
jar = jar.remove(consts::COOKIE_AUTH_TOKEN_NAME);
|
||||
connection.sign_out(&token).await?;
|
||||
}
|
||||
Ok((jar, Redirect::to(&format!("/{}/", tr.current_lang_code()))))
|
||||
Ok((
|
||||
jar,
|
||||
Redirect::to(&format!("/{}/", context.tr.current_lang_code())),
|
||||
))
|
||||
}
|
||||
|
||||
/// RESET PASSWORD ///
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn ask_reset_password_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
) -> Result<Response> {
|
||||
if user.is_some() {
|
||||
pub async fn ask_reset_password_get(Extension(context): Extension<Context>) -> Result<Response> {
|
||||
if context.user.is_some() {
|
||||
Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::AskResetAlreadyLoggedInError), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::AskResetAlreadyLoggedInError),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(Html(
|
||||
AskResetPasswordTemplate {
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
email: "",
|
||||
message: "",
|
||||
message_email: "",
|
||||
|
|
@ -414,36 +418,33 @@ pub async fn ask_reset_password_post(
|
|||
Host(host): Host,
|
||||
State(connection): State<db::Connection>,
|
||||
State(config): State<Config>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Form(form_data): Form<AskResetPasswordForm>,
|
||||
) -> Result<Response> {
|
||||
fn error_response(
|
||||
error: AskResetPasswordError,
|
||||
email: &str,
|
||||
user: Option<model::User>,
|
||||
tr: translation::Tr,
|
||||
context: Context,
|
||||
) -> Result<Response> {
|
||||
Ok(Html(
|
||||
AskResetPasswordTemplate {
|
||||
user,
|
||||
email,
|
||||
message_email: match error {
|
||||
AskResetPasswordError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
||||
AskResetPasswordError::InvalidEmail => context.tr.t(Sentence::InvalidEmail),
|
||||
_ => "",
|
||||
},
|
||||
message: match error {
|
||||
AskResetPasswordError::EmailAlreadyReset => {
|
||||
tr.t(Sentence::AskResetEmailAlreadyResetError)
|
||||
context.tr.t(Sentence::AskResetEmailAlreadyResetError)
|
||||
}
|
||||
AskResetPasswordError::EmailUnknown => tr.t(Sentence::EmailUnknown),
|
||||
AskResetPasswordError::EmailUnknown => context.tr.t(Sentence::EmailUnknown),
|
||||
AskResetPasswordError::UnableSendEmail => {
|
||||
tr.t(Sentence::UnableToSendResetEmail)
|
||||
context.tr.t(Sentence::UnableToSendResetEmail)
|
||||
}
|
||||
AskResetPasswordError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||
AskResetPasswordError::DatabaseError => context.tr.t(Sentence::DatabaseError),
|
||||
_ => "",
|
||||
},
|
||||
tr,
|
||||
context,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -455,8 +456,7 @@ pub async fn ask_reset_password_post(
|
|||
return error_response(
|
||||
AskResetPasswordError::InvalidEmail,
|
||||
&form_data.email,
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -470,20 +470,18 @@ pub async fn ask_reset_password_post(
|
|||
Ok(db::user::GetTokenResetPasswordResult::PasswordAlreadyReset) => error_response(
|
||||
AskResetPasswordError::EmailAlreadyReset,
|
||||
&form_data.email,
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
),
|
||||
Ok(db::user::GetTokenResetPasswordResult::EmailUnknown) => error_response(
|
||||
AskResetPasswordError::EmailUnknown,
|
||||
&form_data.email,
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
),
|
||||
Ok(db::user::GetTokenResetPasswordResult::Ok(token)) => {
|
||||
let url = utils::get_url_from_host(&host);
|
||||
match email::send_email(
|
||||
&form_data.email,
|
||||
&tr.tp(
|
||||
&context.tr.tp(
|
||||
Sentence::AskResetFollowEmailLink,
|
||||
&[Box::new(format!(
|
||||
"{}/reset_password?reset_token={}",
|
||||
|
|
@ -497,8 +495,12 @@ pub async fn ask_reset_password_post(
|
|||
.await
|
||||
{
|
||||
Ok(()) => Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::AskResetEmailSent), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::AskResetEmailSent),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response()),
|
||||
Err(_) => {
|
||||
|
|
@ -506,8 +508,7 @@ pub async fn ask_reset_password_post(
|
|||
error_response(
|
||||
AskResetPasswordError::UnableSendEmail,
|
||||
&form_data.email,
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -517,8 +518,7 @@ pub async fn ask_reset_password_post(
|
|||
error_response(
|
||||
AskResetPasswordError::DatabaseError,
|
||||
&form_data.email,
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -527,8 +527,7 @@ pub async fn ask_reset_password_post(
|
|||
#[debug_handler]
|
||||
pub async fn reset_password_get(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Query(query): Query<HashMap<String, String>>,
|
||||
) -> Result<Response> {
|
||||
if let Some(reset_token) = query.get("reset_token") {
|
||||
|
|
@ -542,8 +541,7 @@ pub async fn reset_password_get(
|
|||
{
|
||||
Ok(Html(
|
||||
ResetPasswordTemplate {
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
reset_token,
|
||||
message: "",
|
||||
message_password: "",
|
||||
|
|
@ -553,15 +551,23 @@ pub async fn reset_password_get(
|
|||
.into_response())
|
||||
} else {
|
||||
Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::AskResetTokenMissing), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::AskResetTokenMissing),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
} else {
|
||||
Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::AskResetTokenMissing), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::AskResetTokenMissing),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
|
|
@ -584,35 +590,36 @@ enum ResetPasswordError {
|
|||
#[debug_handler]
|
||||
pub async fn reset_password_post(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Form(form_data): Form<ResetPasswordForm>,
|
||||
) -> Result<Response> {
|
||||
fn error_response(
|
||||
error: ResetPasswordError,
|
||||
form_data: &ResetPasswordForm,
|
||||
user: Option<model::User>,
|
||||
tr: translation::Tr,
|
||||
context: Context,
|
||||
) -> Result<Response> {
|
||||
let reset_password_mess = &tr.tp(
|
||||
let reset_password_mess = &context.tr.tp(
|
||||
Sentence::InvalidPassword,
|
||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||
);
|
||||
Ok(Html(
|
||||
ResetPasswordTemplate {
|
||||
user,
|
||||
reset_token: &form_data.reset_token,
|
||||
message_password: match error {
|
||||
ResetPasswordError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
||||
ResetPasswordError::PasswordsNotEqual => {
|
||||
context.tr.t(Sentence::PasswordDontMatch)
|
||||
}
|
||||
ResetPasswordError::InvalidPassword => reset_password_mess,
|
||||
_ => "",
|
||||
},
|
||||
message: match error {
|
||||
ResetPasswordError::TokenExpired => tr.t(Sentence::AskResetTokenExpired),
|
||||
ResetPasswordError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||
ResetPasswordError::TokenExpired => {
|
||||
context.tr.t(Sentence::AskResetTokenExpired)
|
||||
}
|
||||
ResetPasswordError::DatabaseError => context.tr.t(Sentence::DatabaseError),
|
||||
_ => "",
|
||||
},
|
||||
tr,
|
||||
context,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -620,13 +627,13 @@ pub async fn reset_password_post(
|
|||
}
|
||||
|
||||
if form_data.password_1 != form_data.password_2 {
|
||||
return error_response(ResetPasswordError::PasswordsNotEqual, &form_data, user, tr);
|
||||
return error_response(ResetPasswordError::PasswordsNotEqual, &form_data, context);
|
||||
}
|
||||
|
||||
if let common::utils::PasswordValidation::TooShort =
|
||||
common::utils::validate_password(&form_data.password_1)
|
||||
{
|
||||
return error_response(ResetPasswordError::InvalidPassword, &form_data, user, tr);
|
||||
return error_response(ResetPasswordError::InvalidPassword, &form_data, context);
|
||||
}
|
||||
|
||||
match connection
|
||||
|
|
@ -638,24 +645,26 @@ pub async fn reset_password_post(
|
|||
.await
|
||||
{
|
||||
Ok(db::user::ResetPasswordResult::Ok) => Ok(Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::PasswordReset), tr, user).render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::PasswordReset),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
)
|
||||
.into_response()),
|
||||
Ok(db::user::ResetPasswordResult::ResetTokenExpired) => {
|
||||
error_response(ResetPasswordError::TokenExpired, &form_data, user, tr)
|
||||
error_response(ResetPasswordError::TokenExpired, &form_data, context)
|
||||
}
|
||||
Err(_) => error_response(ResetPasswordError::DatabaseError, &form_data, user, tr),
|
||||
Err(_) => error_response(ResetPasswordError::DatabaseError, &form_data, context),
|
||||
}
|
||||
}
|
||||
|
||||
/// EDIT PROFILE ///
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn edit_user_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
) -> Result<Response> {
|
||||
Ok(if let Some(user) = user {
|
||||
pub async fn edit_user_get(Extension(context): Extension<Context>) -> Result<Response> {
|
||||
Ok(if let Some(ref user) = context.user {
|
||||
Html(
|
||||
ProfileTemplate {
|
||||
username: &user.name,
|
||||
|
|
@ -664,14 +673,14 @@ pub async fn edit_user_get(
|
|||
message: "",
|
||||
message_email: "",
|
||||
message_password: "",
|
||||
user: Some(user.clone()),
|
||||
tr,
|
||||
context: context.clone(),
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
.into_response()
|
||||
} else {
|
||||
Html(MessageTemplate::new(tr.t(Sentence::NotLoggedIn), tr).render()?).into_response()
|
||||
Html(MessageTemplate::new(context.tr.t(Sentence::NotLoggedIn), context.tr).render()?)
|
||||
.into_response()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -699,43 +708,46 @@ pub async fn edit_user_post(
|
|||
Host(host): Host,
|
||||
State(connection): State<db::Connection>,
|
||||
State(config): State<Config>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
Form(form_data): Form<EditUserForm>,
|
||||
) -> Result<Response> {
|
||||
if let Some(user) = user {
|
||||
if let Some(ref user) = context.user {
|
||||
fn error_response(
|
||||
error: ProfileUpdateError,
|
||||
form_data: &EditUserForm,
|
||||
user: model::User,
|
||||
tr: translation::Tr,
|
||||
context: Context,
|
||||
) -> Result<Response> {
|
||||
let invalid_password_mess = &tr.tp(
|
||||
let invalid_password_mess = &context.tr.tp(
|
||||
Sentence::InvalidPassword,
|
||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||
);
|
||||
Ok(Html(
|
||||
ProfileTemplate {
|
||||
user: Some(user),
|
||||
username: &form_data.name,
|
||||
email: &form_data.email,
|
||||
default_servings: form_data.default_servings,
|
||||
message_email: match error {
|
||||
ProfileUpdateError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
||||
ProfileUpdateError::EmailAlreadyTaken => tr.t(Sentence::EmailAlreadyTaken),
|
||||
ProfileUpdateError::InvalidEmail => context.tr.t(Sentence::InvalidEmail),
|
||||
ProfileUpdateError::EmailAlreadyTaken => {
|
||||
context.tr.t(Sentence::EmailAlreadyTaken)
|
||||
}
|
||||
_ => "",
|
||||
},
|
||||
message_password: match error {
|
||||
ProfileUpdateError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
||||
ProfileUpdateError::PasswordsNotEqual => {
|
||||
context.tr.t(Sentence::PasswordDontMatch)
|
||||
}
|
||||
ProfileUpdateError::InvalidPassword => invalid_password_mess,
|
||||
_ => "",
|
||||
},
|
||||
message: match error {
|
||||
ProfileUpdateError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||
ProfileUpdateError::UnableSendEmail => tr.t(Sentence::UnableToSendEmail),
|
||||
ProfileUpdateError::DatabaseError => context.tr.t(Sentence::DatabaseError),
|
||||
ProfileUpdateError::UnableSendEmail => {
|
||||
context.tr.t(Sentence::UnableToSendEmail)
|
||||
}
|
||||
_ => "",
|
||||
},
|
||||
tr,
|
||||
context,
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
|
|
@ -743,17 +755,17 @@ pub async fn edit_user_post(
|
|||
}
|
||||
|
||||
if form_data.email.parse::<Address>().is_err() {
|
||||
return error_response(ProfileUpdateError::InvalidEmail, &form_data, user, tr);
|
||||
return error_response(ProfileUpdateError::InvalidEmail, &form_data, context);
|
||||
}
|
||||
|
||||
let new_password = if !form_data.password_1.is_empty() || !form_data.password_2.is_empty() {
|
||||
if form_data.password_1 != form_data.password_2 {
|
||||
return error_response(ProfileUpdateError::PasswordsNotEqual, &form_data, user, tr);
|
||||
return error_response(ProfileUpdateError::PasswordsNotEqual, &form_data, context);
|
||||
}
|
||||
if let common::utils::PasswordValidation::TooShort =
|
||||
common::utils::validate_password(&form_data.password_1)
|
||||
{
|
||||
return error_response(ProfileUpdateError::InvalidPassword, &form_data, user, tr);
|
||||
return error_response(ProfileUpdateError::InvalidPassword, &form_data, context);
|
||||
}
|
||||
Some(form_data.password_1.as_ref())
|
||||
} else {
|
||||
|
|
@ -774,14 +786,14 @@ pub async fn edit_user_post(
|
|||
.await
|
||||
{
|
||||
Ok(db::user::UpdateUserResult::EmailAlreadyTaken) => {
|
||||
return error_response(ProfileUpdateError::EmailAlreadyTaken, &form_data, user, tr);
|
||||
return error_response(ProfileUpdateError::EmailAlreadyTaken, &form_data, context);
|
||||
}
|
||||
Ok(db::user::UpdateUserResult::UserUpdatedWaitingForRevalidation(token)) => {
|
||||
let url = utils::get_url_from_host(&host);
|
||||
let email = form_data.email.clone();
|
||||
match email::send_email(
|
||||
&email,
|
||||
&tr.tp(
|
||||
&context.tr.tp(
|
||||
Sentence::ProfileFollowEmailLink,
|
||||
&[Box::new(format!(
|
||||
"{}/revalidation?validation_token={}",
|
||||
|
|
@ -795,24 +807,23 @@ pub async fn edit_user_post(
|
|||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
message = tr.t(Sentence::ProfileEmailSent);
|
||||
message = context.tr.t(Sentence::ProfileEmailSent);
|
||||
}
|
||||
Err(_) => {
|
||||
// error!("Email validation error: {}", error); // TODO: log
|
||||
return error_response(
|
||||
ProfileUpdateError::UnableSendEmail,
|
||||
&form_data,
|
||||
user,
|
||||
tr,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(db::user::UpdateUserResult::Ok) => {
|
||||
message = tr.t(Sentence::ProfileSaved);
|
||||
message = context.tr.t(Sentence::ProfileSaved);
|
||||
}
|
||||
Err(_) => {
|
||||
return error_response(ProfileUpdateError::DatabaseError, &form_data, user, tr);
|
||||
return error_response(ProfileUpdateError::DatabaseError, &form_data, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -821,41 +832,42 @@ pub async fn edit_user_post(
|
|||
|
||||
Ok(Html(
|
||||
ProfileTemplate {
|
||||
user,
|
||||
username: &form_data.name,
|
||||
email: &form_data.email,
|
||||
default_servings: form_data.default_servings,
|
||||
message,
|
||||
message_email: "",
|
||||
message_password: "",
|
||||
tr,
|
||||
context: Context { user, ..context },
|
||||
}
|
||||
.render()?,
|
||||
)
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(Html(MessageTemplate::new(tr.t(Sentence::NotLoggedIn), tr).render()?).into_response())
|
||||
Ok(
|
||||
Html(MessageTemplate::new(context.tr.t(Sentence::NotLoggedIn), context.tr).render()?)
|
||||
.into_response(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn email_revalidation(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
Extension(tr): Extension<translation::Tr>,
|
||||
Extension(context): Extension<Context>,
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
Query(query): Query<HashMap<String, String>>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<(CookieJar, impl IntoResponse)> {
|
||||
let mut jar = CookieJar::from_headers(&headers);
|
||||
if user.is_some() {
|
||||
if context.user.is_some() {
|
||||
return Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::ValidationUserAlreadyExists),
|
||||
tr,
|
||||
user,
|
||||
context.tr.t(Sentence::ValidationUserAlreadyExists),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
|
|
@ -875,15 +887,16 @@ pub async fn email_revalidation(
|
|||
.await?
|
||||
{
|
||||
db::user::ValidationResult::Ok(token, user_id) => {
|
||||
let cookie = Cookie::new(consts::COOKIE_AUTH_TOKEN_NAME, token);
|
||||
let cookie = Cookie::build((consts::COOKIE_AUTH_TOKEN_NAME, token))
|
||||
.same_site(cookie::SameSite::Strict);
|
||||
jar = jar.add(cookie);
|
||||
let user = connection.load_user(user_id).await?;
|
||||
Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::ValidationSuccessful),
|
||||
tr,
|
||||
context.tr.t(Sentence::ValidationSuccessful),
|
||||
context.tr,
|
||||
user,
|
||||
)
|
||||
.render()?,
|
||||
|
|
@ -893,17 +906,21 @@ pub async fn email_revalidation(
|
|||
db::user::ValidationResult::ValidationExpired => Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::ValidationExpired), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::ValidationExpired),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
)),
|
||||
db::user::ValidationResult::UnknownUser => Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(
|
||||
tr.t(Sentence::ValidationErrorTryToSignUpAgain),
|
||||
tr,
|
||||
user,
|
||||
context.tr.t(Sentence::ValidationErrorTryToSignUpAgain),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
|
|
@ -913,8 +930,12 @@ pub async fn email_revalidation(
|
|||
None => Ok((
|
||||
jar,
|
||||
Html(
|
||||
MessageTemplate::new_with_user(tr.t(Sentence::ValidationError), tr, user)
|
||||
.render()?,
|
||||
MessageTemplate::new_with_user(
|
||||
context.tr.t(Sentence::ValidationError),
|
||||
context.tr,
|
||||
context.user,
|
||||
)
|
||||
.render()?,
|
||||
),
|
||||
)),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ pub enum Sentence {
|
|||
|
||||
// Reset password page.
|
||||
LostPassword,
|
||||
AskResetChooseNewPassword,
|
||||
AskResetButton,
|
||||
AskResetAlreadyLoggedInError,
|
||||
AskResetEmailAlreadyResetError,
|
||||
|
|
@ -153,7 +154,7 @@ pub enum Sentence {
|
|||
pub const DEFAULT_LANGUAGE_CODE: &str = "en";
|
||||
pub const PLACEHOLDER_SUBSTITUTE: &str = "{}";
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Tr {
|
||||
lang: &'static Language,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue