Log errors in the user module
This commit is contained in:
parent
b0f0633338
commit
7b9df97a32
6 changed files with 199 additions and 118 deletions
|
|
@ -38,6 +38,8 @@ pub const COOKIE_LANG_NAME: &str = "lang";
|
||||||
/// (cookie authentication, password reset, validation token).
|
/// (cookie authentication, password reset, validation token).
|
||||||
pub const TOKEN_SIZE: usize = 32;
|
pub const TOKEN_SIZE: usize = 32;
|
||||||
|
|
||||||
|
pub const EMAIL_ADDRESS: &str = "recipes@recipes.gburri.org";
|
||||||
|
|
||||||
/// When sending a validation email,
|
/// When sending a validation email,
|
||||||
/// the server has this duration to wait for a response from the SMTP server.
|
/// the server has this duration to wait for a response from the SMTP server.
|
||||||
pub const SEND_EMAIL_TIMEOUT: Duration = Duration::from_secs(60);
|
pub const SEND_EMAIL_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use chrono::{Duration, prelude::*};
|
use chrono::{Duration, prelude::*};
|
||||||
use rand::distr::{Alphanumeric, SampleString};
|
use rand::distr::{Alphanumeric, SampleString};
|
||||||
use sqlx::Sqlite;
|
use sqlx::Sqlite;
|
||||||
|
use strum_macros::Display;
|
||||||
|
|
||||||
use super::{Connection, DBError, Result};
|
use super::{Connection, DBError, Result};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -9,27 +10,27 @@ use crate::{
|
||||||
hash::{hash, verify_password},
|
hash::{hash, verify_password},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum SignUpResult {
|
pub enum SignUpResult {
|
||||||
UserAlreadyExists,
|
UserAlreadyExists,
|
||||||
UserCreatedWaitingForValidation(String), // Validation token.
|
UserCreatedWaitingForValidation(String), // Validation token.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum UpdateUserResult {
|
pub enum UpdateUserResult {
|
||||||
EmailAlreadyTaken,
|
EmailAlreadyTaken,
|
||||||
UserUpdatedWaitingForRevalidation(String), // Validation token.
|
UserUpdatedWaitingForRevalidation(String), // Validation token.
|
||||||
Ok,
|
Ok,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum ValidationResult {
|
pub enum ValidationResult {
|
||||||
UnknownUser,
|
UnknownUser,
|
||||||
ValidationExpired,
|
ValidationExpired,
|
||||||
Ok(String, i64), // Returns token and user id.
|
Ok(String, i64), // Returns token and user id.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum SignInResult {
|
pub enum SignInResult {
|
||||||
UserNotFound,
|
UserNotFound,
|
||||||
WrongPassword,
|
WrongPassword,
|
||||||
|
|
@ -37,20 +38,20 @@ pub enum SignInResult {
|
||||||
Ok(String, i64), // Returns token and user id.
|
Ok(String, i64), // Returns token and user id.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum AuthenticationResult {
|
pub enum AuthenticationResult {
|
||||||
NotValidToken,
|
NotValidToken,
|
||||||
Ok(i64), // Returns user id.
|
Ok(i64), // Returns user id.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum GetTokenResetPasswordResult {
|
pub enum GetTokenResetPasswordResult {
|
||||||
PasswordAlreadyReset,
|
PasswordAlreadyReset,
|
||||||
EmailUnknown,
|
EmailUnknown,
|
||||||
Ok(String),
|
Ok(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
pub enum ResetPasswordResult {
|
pub enum ResetPasswordResult {
|
||||||
ResetTokenExpired,
|
ResetTokenExpired,
|
||||||
Ok,
|
Ok,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ pub async fn send_email(
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let email = Message::builder()
|
let email = Message::builder()
|
||||||
.message_id(None)
|
.message_id(None)
|
||||||
.from("recipes@recipes.gburri.org".parse()?)
|
.from(consts::EMAIL_ADDRESS.parse()?)
|
||||||
.to(email.parse()?)
|
.to(email.parse()?)
|
||||||
.subject(title)
|
.subject(title)
|
||||||
.body(message.to_string())?;
|
.body(message.to_string())?;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ const TRACING_DISPLAY_THREAD: bool = false;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Log {
|
pub struct Log {
|
||||||
guard: Arc<WorkerGuard>,
|
_guard: Arc<WorkerGuard>,
|
||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ impl Log {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
Log {
|
Log {
|
||||||
guard: Arc::new(guard),
|
_guard: Arc::new(guard),
|
||||||
directory: directory.as_ref().to_path_buf(),
|
directory: directory.as_ref().to_path_buf(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use axum_extra::extract::{
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use lettre::Address;
|
use lettre::Address;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use strum_macros::Display;
|
||||||
use tracing::{Level, event};
|
use tracing::{Level, event};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -23,6 +24,8 @@ use crate::{
|
||||||
translation::Sentence, utils,
|
translation::Sentence, utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const VALIDATION_TOKEN_KEY: &str = "validation_token";
|
||||||
|
|
||||||
/// SIGN UP ///
|
/// SIGN UP ///
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
|
|
@ -62,6 +65,7 @@ pub struct SignUpFormData {
|
||||||
password_2: String,
|
password_2: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Display)]
|
||||||
enum SignUpError {
|
enum SignUpError {
|
||||||
InvalidEmail,
|
InvalidEmail,
|
||||||
PasswordsNotEqual,
|
PasswordsNotEqual,
|
||||||
|
|
@ -84,6 +88,13 @@ pub async fn sign_up_post(
|
||||||
form_data: &SignUpFormData,
|
form_data: &SignUpFormData,
|
||||||
context: Context,
|
context: Context,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
|
event!(
|
||||||
|
Level::WARN,
|
||||||
|
"[Sign up] Unable to sign up with email {}: {}",
|
||||||
|
form_data.email,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
let invalid_password_mess = &context.tr.tp(
|
let invalid_password_mess = &context.tr.tp(
|
||||||
Sentence::InvalidPassword,
|
Sentence::InvalidPassword,
|
||||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||||
|
|
@ -160,8 +171,8 @@ pub async fn sign_up_post(
|
||||||
&context.tr.tp(
|
&context.tr.tp(
|
||||||
Sentence::SignUpFollowEmailLink,
|
Sentence::SignUpFollowEmailLink,
|
||||||
&[Box::new(format!(
|
&[Box::new(format!(
|
||||||
"{}/validation?validation_token={}",
|
"{}/validation?{}={}",
|
||||||
url, token
|
url, VALIDATION_TOKEN_KEY, token
|
||||||
))],
|
))],
|
||||||
),
|
),
|
||||||
&config.smtp_relay_address,
|
&config.smtp_relay_address,
|
||||||
|
|
@ -179,16 +190,10 @@ pub async fn sign_up_post(
|
||||||
.render()?,
|
.render()?,
|
||||||
)
|
)
|
||||||
.into_response()),
|
.into_response()),
|
||||||
Err(_) => {
|
Err(_) => error_response(SignUpError::UnableSendEmail, &form_data, context),
|
||||||
// error!("Email validation error: {}", error); // TODO: log
|
|
||||||
error_response(SignUpError::UnableSendEmail, &form_data, context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => error_response(SignUpError::DatabaseError, &form_data, context),
|
||||||
// error!("Signup database error: {}", error); // TODO: log
|
|
||||||
error_response(SignUpError::DatabaseError, &form_data, context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +206,12 @@ pub async fn sign_up_validation(
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
) -> Result<(CookieJar, impl IntoResponse)> {
|
) -> Result<(CookieJar, impl IntoResponse)> {
|
||||||
let mut jar = CookieJar::from_headers(&headers);
|
let mut jar = CookieJar::from_headers(&headers);
|
||||||
if context.user.is_some() {
|
if let Some(ref user) = context.user {
|
||||||
|
event!(
|
||||||
|
Level::WARN,
|
||||||
|
"[Sign up] Unable to validate: user already logged. Email: {}",
|
||||||
|
user.email
|
||||||
|
);
|
||||||
return Ok((
|
return Ok((
|
||||||
jar,
|
jar,
|
||||||
Html(
|
Html(
|
||||||
|
|
@ -215,7 +225,7 @@ pub async fn sign_up_validation(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(&headers, addr);
|
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(&headers, addr);
|
||||||
match query.get("validation_token") {
|
match query.get(VALIDATION_TOKEN_KEY) {
|
||||||
// 'validation_token' exists only when a user tries to validate a new account.
|
// 'validation_token' exists only when a user tries to validate a new account.
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
match connection
|
match connection
|
||||||
|
|
@ -244,41 +254,61 @@ pub async fn sign_up_validation(
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
db::user::ValidationResult::ValidationExpired => Ok((
|
db::user::ValidationResult::ValidationExpired => {
|
||||||
jar,
|
event!(
|
||||||
Html(
|
Level::WARN,
|
||||||
MessageTemplate::new_with_user(
|
"[Sign up] Unable to validate: validation expired. Token: {}",
|
||||||
context.tr.t(Sentence::SignUpValidationExpired),
|
token
|
||||||
context.tr,
|
);
|
||||||
context.user,
|
Ok((
|
||||||
)
|
jar,
|
||||||
.render()?,
|
Html(
|
||||||
),
|
MessageTemplate::new_with_user(
|
||||||
)),
|
context.tr.t(Sentence::SignUpValidationExpired),
|
||||||
db::user::ValidationResult::UnknownUser => Ok((
|
context.tr,
|
||||||
jar,
|
context.user,
|
||||||
Html(
|
)
|
||||||
MessageTemplate::new_with_user(
|
.render()?,
|
||||||
context.tr.t(Sentence::SignUpValidationErrorTryAgain),
|
),
|
||||||
context.tr,
|
))
|
||||||
context.user,
|
}
|
||||||
)
|
db::user::ValidationResult::UnknownUser => {
|
||||||
.render()?,
|
event!(
|
||||||
),
|
Level::WARN,
|
||||||
)),
|
"[Sign up] Unable to validate: unknown user. Token: {}",
|
||||||
|
token
|
||||||
|
);
|
||||||
|
Ok((
|
||||||
|
jar,
|
||||||
|
Html(
|
||||||
|
MessageTemplate::new_with_user(
|
||||||
|
context.tr.t(Sentence::SignUpValidationErrorTryAgain),
|
||||||
|
context.tr,
|
||||||
|
context.user,
|
||||||
|
)
|
||||||
|
.render()?,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Ok((
|
None => {
|
||||||
jar,
|
event!(
|
||||||
Html(
|
Level::WARN,
|
||||||
MessageTemplate::new_with_user(
|
"[Sign up] Unable to validate: no token provided"
|
||||||
context.tr.t(Sentence::ValidationError),
|
);
|
||||||
context.tr,
|
Ok((
|
||||||
context.user,
|
jar,
|
||||||
)
|
Html(
|
||||||
.render()?,
|
MessageTemplate::new_with_user(
|
||||||
),
|
context.tr.t(Sentence::ValidationError),
|
||||||
)),
|
context.tr,
|
||||||
|
context.user,
|
||||||
|
)
|
||||||
|
.render()?,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,30 +352,46 @@ pub async fn sign_in_post(
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
db::user::SignInResult::AccountNotValidated => Ok((
|
error @ db::user::SignInResult::AccountNotValidated => {
|
||||||
jar,
|
event!(
|
||||||
Html(
|
Level::WARN,
|
||||||
SignInFormTemplate {
|
"[Sign in] Account not validated, email: {}: {}",
|
||||||
email: &form_data.email,
|
form_data.email,
|
||||||
message: context.tr.t(Sentence::AccountMustBeValidatedFirst),
|
error
|
||||||
context,
|
);
|
||||||
}
|
Ok((
|
||||||
.render()?,
|
jar,
|
||||||
)
|
Html(
|
||||||
.into_response(),
|
SignInFormTemplate {
|
||||||
)),
|
email: &form_data.email,
|
||||||
db::user::SignInResult::UserNotFound | db::user::SignInResult::WrongPassword => Ok((
|
message: context.tr.t(Sentence::AccountMustBeValidatedFirst),
|
||||||
jar,
|
context,
|
||||||
Html(
|
}
|
||||||
SignInFormTemplate {
|
.render()?,
|
||||||
email: &form_data.email,
|
)
|
||||||
message: context.tr.t(Sentence::WrongEmailOrPassword),
|
.into_response(),
|
||||||
context,
|
))
|
||||||
}
|
}
|
||||||
.render()?,
|
error @ (db::user::SignInResult::UserNotFound | db::user::SignInResult::WrongPassword) => {
|
||||||
)
|
event!(
|
||||||
.into_response(),
|
Level::WARN,
|
||||||
)),
|
"[Sign in] Email: {}: {}",
|
||||||
|
form_data.email,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
Ok((
|
||||||
|
jar,
|
||||||
|
Html(
|
||||||
|
SignInFormTemplate {
|
||||||
|
email: &form_data.email,
|
||||||
|
message: context.tr.t(Sentence::WrongEmailOrPassword),
|
||||||
|
context,
|
||||||
|
}
|
||||||
|
.render()?,
|
||||||
|
)
|
||||||
|
.into_response(),
|
||||||
|
))
|
||||||
|
}
|
||||||
db::user::SignInResult::Ok(token, _user_id) => {
|
db::user::SignInResult::Ok(token, _user_id) => {
|
||||||
let cookie = Cookie::build((consts::COOKIE_AUTH_TOKEN_NAME, token))
|
let cookie = Cookie::build((consts::COOKIE_AUTH_TOKEN_NAME, token))
|
||||||
.same_site(cookie::SameSite::Strict);
|
.same_site(cookie::SameSite::Strict);
|
||||||
|
|
@ -586,6 +632,7 @@ pub struct ResetPasswordForm {
|
||||||
reset_token: String,
|
reset_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Display)]
|
||||||
enum ResetPasswordError {
|
enum ResetPasswordError {
|
||||||
PasswordsNotEqual,
|
PasswordsNotEqual,
|
||||||
InvalidPassword,
|
InvalidPassword,
|
||||||
|
|
@ -604,6 +651,16 @@ pub async fn reset_password_post(
|
||||||
form_data: &ResetPasswordForm,
|
form_data: &ResetPasswordForm,
|
||||||
context: Context,
|
context: Context,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
|
event!(
|
||||||
|
Level::WARN,
|
||||||
|
"[Reset password] Email: {}: {}",
|
||||||
|
if let Some(ref user) = context.user {
|
||||||
|
&user.email
|
||||||
|
} else {
|
||||||
|
"<Unknown user>"
|
||||||
|
},
|
||||||
|
error
|
||||||
|
);
|
||||||
let reset_password_mess = &context.tr.tp(
|
let reset_password_mess = &context.tr.tp(
|
||||||
Sentence::InvalidPassword,
|
Sentence::InvalidPassword,
|
||||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||||
|
|
@ -700,6 +757,7 @@ pub struct EditUserForm {
|
||||||
password_2: String,
|
password_2: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Display)]
|
||||||
enum ProfileUpdateError {
|
enum ProfileUpdateError {
|
||||||
InvalidEmail,
|
InvalidEmail,
|
||||||
EmailAlreadyTaken,
|
EmailAlreadyTaken,
|
||||||
|
|
@ -709,7 +767,6 @@ enum ProfileUpdateError {
|
||||||
UnableSendEmail,
|
UnableSendEmail,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: A lot of code are similar to 'sign_up_post', maybe find a way to factorize some.
|
|
||||||
#[debug_handler(state = AppState)]
|
#[debug_handler(state = AppState)]
|
||||||
pub async fn edit_user_post(
|
pub async fn edit_user_post(
|
||||||
Host(host): Host,
|
Host(host): Host,
|
||||||
|
|
@ -718,17 +775,22 @@ pub async fn edit_user_post(
|
||||||
Extension(context): Extension<Context>,
|
Extension(context): Extension<Context>,
|
||||||
Form(form_data): Form<EditUserForm>,
|
Form(form_data): Form<EditUserForm>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
event!(
|
|
||||||
Level::DEBUG,
|
|
||||||
"First day of the week: {:?}",
|
|
||||||
form_data.first_day_of_the_week
|
|
||||||
);
|
|
||||||
if let Some(ref user) = context.user {
|
if let Some(ref user) = context.user {
|
||||||
fn error_response(
|
fn error_response(
|
||||||
error: ProfileUpdateError,
|
error: ProfileUpdateError,
|
||||||
form_data: &EditUserForm,
|
form_data: &EditUserForm,
|
||||||
context: Context,
|
context: Context,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
|
event!(
|
||||||
|
Level::WARN,
|
||||||
|
"[Edit user] Email: {}: {}",
|
||||||
|
if let Some(ref user) = context.user {
|
||||||
|
&user.email
|
||||||
|
} else {
|
||||||
|
"<Unknown user>"
|
||||||
|
},
|
||||||
|
error
|
||||||
|
);
|
||||||
let invalid_password_mess = &context.tr.tp(
|
let invalid_password_mess = &context.tr.tp(
|
||||||
Sentence::InvalidPassword,
|
Sentence::InvalidPassword,
|
||||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||||
|
|
@ -810,8 +872,8 @@ pub async fn edit_user_post(
|
||||||
&context.tr.tp(
|
&context.tr.tp(
|
||||||
Sentence::ProfileFollowEmailLink,
|
Sentence::ProfileFollowEmailLink,
|
||||||
&[Box::new(format!(
|
&[Box::new(format!(
|
||||||
"{}/revalidation?validation_token={}",
|
"{}/revalidation?{}={}",
|
||||||
url, token
|
url, VALIDATION_TOKEN_KEY, token
|
||||||
))],
|
))],
|
||||||
),
|
),
|
||||||
&config.smtp_relay_address,
|
&config.smtp_relay_address,
|
||||||
|
|
@ -888,7 +950,7 @@ pub async fn email_revalidation(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(&headers, addr);
|
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(&headers, addr);
|
||||||
match query.get("validation_token") {
|
match query.get(VALIDATION_TOKEN_KEY) {
|
||||||
// 'validation_token' exists only when a user must validate a new email.
|
// 'validation_token' exists only when a user must validate a new email.
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
match connection
|
match connection
|
||||||
|
|
@ -917,28 +979,44 @@ pub async fn email_revalidation(
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
db::user::ValidationResult::ValidationExpired => Ok((
|
error @ db::user::ValidationResult::ValidationExpired => {
|
||||||
jar,
|
event!(
|
||||||
Html(
|
Level::WARN,
|
||||||
MessageTemplate::new_with_user(
|
"[Email revalidation] Token: {}: {}",
|
||||||
context.tr.t(Sentence::ValidationExpired),
|
token,
|
||||||
context.tr,
|
error
|
||||||
context.user,
|
);
|
||||||
)
|
Ok((
|
||||||
.render()?,
|
jar,
|
||||||
),
|
Html(
|
||||||
)),
|
MessageTemplate::new_with_user(
|
||||||
db::user::ValidationResult::UnknownUser => Ok((
|
context.tr.t(Sentence::ValidationExpired),
|
||||||
jar,
|
context.tr,
|
||||||
Html(
|
context.user,
|
||||||
MessageTemplate::new_with_user(
|
)
|
||||||
context.tr.t(Sentence::ValidationErrorTryToSignUpAgain),
|
.render()?,
|
||||||
context.tr,
|
),
|
||||||
context.user,
|
))
|
||||||
)
|
}
|
||||||
.render()?,
|
error @ db::user::ValidationResult::UnknownUser => {
|
||||||
),
|
event!(
|
||||||
)),
|
Level::WARN,
|
||||||
|
"[Email revalidation] Email: {}: {}",
|
||||||
|
token,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
Ok((
|
||||||
|
jar,
|
||||||
|
Html(
|
||||||
|
MessageTemplate::new_with_user(
|
||||||
|
context.tr.t(Sentence::ValidationErrorTryToSignUpAgain),
|
||||||
|
context.tr,
|
||||||
|
context.user,
|
||||||
|
)
|
||||||
|
.render()?,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Ok((
|
None => Ok((
|
||||||
|
|
|
||||||
|
|
@ -51,14 +51,14 @@ pub fn main() -> Result<(), JsValue> {
|
||||||
.unwrap_or(chrono::Weekday::Mon);
|
.unwrap_or(chrono::Weekday::Mon);
|
||||||
|
|
||||||
match path[..] {
|
match path[..] {
|
||||||
["recipe", "edit", id] => {
|
["recipe", "edit", id] => match id.parse::<i64>() {
|
||||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
Ok(id) => pages::recipe_edit::setup_page(id),
|
||||||
pages::recipe_edit::setup_page(id)
|
Err(error) => log!(format!("Error parsing recipe id: {}", error)),
|
||||||
}
|
},
|
||||||
["recipe", "view", id] => {
|
["recipe", "view", id] => match id.parse::<i64>() {
|
||||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
Ok(id) => pages::recipe_view::setup_page(id, is_user_logged, first_day_of_the_week),
|
||||||
pages::recipe_view::setup_page(id, is_user_logged, first_day_of_the_week)
|
Err(error) => log!(format!("Error parsing recipe id: {}", error)),
|
||||||
}
|
},
|
||||||
["dev_panel"] => pages::dev_panel::setup_page(),
|
["dev_panel"] => pages::dev_panel::setup_page(),
|
||||||
// Home.
|
// Home.
|
||||||
[""] => pages::home::setup_page(is_user_logged, first_day_of_the_week),
|
[""] => pages::home::setup_page(is_user_logged, first_day_of_the_week),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue