[Database] Add 'creation_datetime' to User + some little things
This commit is contained in:
parent
91ab379718
commit
7a09e2360e
14 changed files with 179 additions and 131 deletions
|
|
@ -1,18 +1,20 @@
|
||||||
INSERT INTO [User] ([id], [email], [name], [password], [validation_token_datetime], [validation_token])
|
INSERT INTO [User] ([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||||
VALUES (
|
VALUES (
|
||||||
1,
|
1,
|
||||||
'paul@atreides.com',
|
'paul@atreides.com',
|
||||||
'Paul',
|
'Paul',
|
||||||
|
'2025-01-07T10:41:05.697884837+00:00',
|
||||||
'$argon2id$v=19$m=4096,t=4,p=2$l1fAMRc0VfkNzqpEfFEReg$/gsUsY2aML8EbKjPeCxucenxkxhiFSXDmizWZPLvNuo',
|
'$argon2id$v=19$m=4096,t=4,p=2$l1fAMRc0VfkNzqpEfFEReg$/gsUsY2aML8EbKjPeCxucenxkxhiFSXDmizWZPLvNuo',
|
||||||
0,
|
0,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO [User] ([id], [email], [name], [password], [validation_token_datetime], [validation_token])
|
INSERT INTO [User] ([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||||
VALUES (
|
VALUES (
|
||||||
2,
|
2,
|
||||||
'alia@atreides.com',
|
'alia@atreides.com',
|
||||||
'Alia',
|
'Alia',
|
||||||
|
'2025-01-07T10:41:05.697884837+00:00',
|
||||||
'$argon2id$v=19$m=4096,t=3,p=1$1vtXcacYjUHZxMrN6b2Xng$wW8Z59MIoMcsIljnjHmxn3EBcc5ymEySZPUVXHlRxcY',
|
'$argon2id$v=19$m=4096,t=3,p=1$1vtXcacYjUHZxMrN6b2Xng$wW8Z59MIoMcsIljnjHmxn3EBcc5ymEySZPUVXHlRxcY',
|
||||||
0,
|
0,
|
||||||
NULL
|
NULL
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@ CREATE TABLE [Version] (
|
||||||
|
|
||||||
CREATE TABLE [User] (
|
CREATE TABLE [User] (
|
||||||
[id] INTEGER PRIMARY KEY,
|
[id] INTEGER PRIMARY KEY,
|
||||||
|
|
||||||
[email] TEXT NOT NULL,
|
[email] TEXT NOT NULL,
|
||||||
[name] TEXT NOT NULL DEFAULT '',
|
[name] TEXT NOT NULL DEFAULT '',
|
||||||
|
[creation_datetime] TEXT NOT NULL,
|
||||||
|
|
||||||
[default_servings] INTEGER DEFAULT 4,
|
[default_servings] INTEGER DEFAULT 4,
|
||||||
[lang] TEXT NOT NULL DEFAULT 'en',
|
[lang] TEXT NOT NULL DEFAULT 'en',
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -628,14 +628,15 @@ mod tests {
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO [User]
|
INSERT INTO [User]
|
||||||
([id], [email], [name], [password], [validation_token_datetime], [validation_token])
|
([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||||
VALUES
|
VALUES
|
||||||
($1, $2, $3, $4, $5, $6)
|
($1, $2, $3, $4, $5, $6, $7)
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.bind(user_id)
|
.bind(user_id)
|
||||||
.bind("paul@atreides.com")
|
.bind("paul@atreides.com")
|
||||||
.bind("paul")
|
.bind("paul")
|
||||||
|
.bind("")
|
||||||
.bind("$argon2id$v=19$m=4096,t=3,p=1$G4fjepS05MkRbTqEImUdYg$GGziE8uVQe1L1oFHk37lBno10g4VISnVqynSkLCH3Lc")
|
.bind("$argon2id$v=19$m=4096,t=3,p=1$G4fjepS05MkRbTqEImUdYg$GGziE8uVQe1L1oFHk37lBno10g4VISnVqynSkLCH3Lc")
|
||||||
.bind("2022-11-29 22:05:04.121407300+00:00")
|
.bind("2022-11-29 22:05:04.121407300+00:00")
|
||||||
.bind(None::<&str>) // 'null'.
|
.bind(None::<&str>) // 'null'.
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,12 @@ WHERE [id] = $1
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO [User]
|
INSERT INTO [User]
|
||||||
([email], [validation_token], [validation_token_datetime], [password])
|
([email], [creation_datetime], [validation_token], [validation_token_datetime], [password])
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(email)
|
.bind(email)
|
||||||
|
.bind(Utc::now())
|
||||||
.bind(&token)
|
.bind(&token)
|
||||||
.bind(datetime)
|
.bind(datetime)
|
||||||
.bind(hashed_password)
|
.bind(hashed_password)
|
||||||
|
|
@ -509,11 +510,12 @@ mod tests {
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
[User] ([id], [email], [name], [password], [validation_token_datetime], [validation_token])
|
[User] ([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||||
VALUES (
|
VALUES (
|
||||||
1,
|
1,
|
||||||
'paul@atreides.com',
|
'paul@atreides.com',
|
||||||
'paul',
|
'paul',
|
||||||
|
'',
|
||||||
'$argon2id$v=19$m=4096,t=3,p=1$1vtXcacYjUHZxMrN6b2Xng$wW8Z59MIoMcsIljnjHmxn3EBcc5ymEySZPUVXHlRxcY',
|
'$argon2id$v=19$m=4096,t=3,p=1$1vtXcacYjUHZxMrN6b2Xng$wW8Z59MIoMcsIljnjHmxn3EBcc5ymEySZPUVXHlRxcY',
|
||||||
0,
|
0,
|
||||||
NULL
|
NULL
|
||||||
|
|
@ -557,10 +559,11 @@ INSERT INTO
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO [User]
|
INSERT INTO [User]
|
||||||
([id], [email], [name], [password], [validation_token_datetime], [validation_token])
|
([id], [email], [creation_datetime], [name], [password], [validation_token_datetime], [validation_token])
|
||||||
VALUES (
|
VALUES (
|
||||||
1,
|
1,
|
||||||
'paul@atreides.com',
|
'paul@atreides.com',
|
||||||
|
'',
|
||||||
'paul',
|
'paul',
|
||||||
'$argon2id$v=19$m=4096,t=3,p=1$1vtXcacYjUHZxMrN6b2Xng$wW8Z59MIoMcsIljnjHmxn3EBcc5ymEySZPUVXHlRxcY',
|
'$argon2id$v=19$m=4096,t=3,p=1$1vtXcacYjUHZxMrN6b2Xng$wW8Z59MIoMcsIljnjHmxn3EBcc5ymEySZPUVXHlRxcY',
|
||||||
0,
|
0,
|
||||||
|
|
@ -896,17 +899,11 @@ VALUES (
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO [User]
|
INSERT INTO [User]
|
||||||
([id], [email], [name], [password], [validation_token_datetime], [validation_token])
|
([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||||
VALUES
|
VALUES
|
||||||
($1, $2, $3, $4, $5, $6)
|
(1, 'paul@atreides.com', 'paul', '', '$argon2id$v=19$m=4096,t=3,p=1$G4fjepS05MkRbTqEImUdYg$GGziE8uVQe1L1oFHk37lBno10g4VISnVqynSkLCH3Lc', '2022-11-29 22:05:04.121407300+00:00', NULL)
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.bind(1)
|
|
||||||
.bind("paul@atreides.com")
|
|
||||||
.bind("paul")
|
|
||||||
.bind("$argon2id$v=19$m=4096,t=3,p=1$G4fjepS05MkRbTqEImUdYg$GGziE8uVQe1L1oFHk37lBno10g4VISnVqynSkLCH3Lc")
|
|
||||||
.bind("2022-11-29 22:05:04.121407300+00:00")
|
|
||||||
.bind(None::<&str>) // 'null'.
|
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
let user = connection.load_user(1).await?.unwrap();
|
let user = connection.load_user(1).await?.unwrap();
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,16 @@ pub struct HomeTemplate {
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "message.html")]
|
#[template(path = "message.html")]
|
||||||
pub struct MessageTemplate {
|
pub struct MessageTemplate<'a> {
|
||||||
pub user: Option<model::User>,
|
pub user: Option<model::User>,
|
||||||
pub tr: Tr,
|
pub tr: Tr,
|
||||||
|
|
||||||
pub message: String,
|
pub message: &'a str,
|
||||||
pub as_code: bool, // Display the message in <pre> markup.
|
pub as_code: bool, // Display the message in <pre> markup.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageTemplate {
|
impl<'a> MessageTemplate<'a> {
|
||||||
pub fn new(message: String, tr: Tr) -> MessageTemplate {
|
pub fn new(message: &'a str, tr: Tr) -> MessageTemplate<'a> {
|
||||||
MessageTemplate {
|
MessageTemplate {
|
||||||
user: None,
|
user: None,
|
||||||
tr,
|
tr,
|
||||||
|
|
@ -46,7 +46,11 @@ impl MessageTemplate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_user(message: String, tr: Tr, user: Option<model::User>) -> MessageTemplate {
|
pub fn new_with_user(
|
||||||
|
message: &'a str,
|
||||||
|
tr: Tr,
|
||||||
|
user: Option<model::User>,
|
||||||
|
) -> MessageTemplate<'a> {
|
||||||
MessageTemplate {
|
MessageTemplate {
|
||||||
user,
|
user,
|
||||||
tr,
|
tr,
|
||||||
|
|
@ -58,59 +62,59 @@ impl MessageTemplate {
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "sign_up_form.html")]
|
#[template(path = "sign_up_form.html")]
|
||||||
pub struct SignUpFormTemplate {
|
pub struct SignUpFormTemplate<'a> {
|
||||||
pub user: Option<model::User>,
|
pub user: Option<model::User>,
|
||||||
pub tr: Tr,
|
pub tr: Tr,
|
||||||
|
|
||||||
pub email: String,
|
pub email: String,
|
||||||
pub message: String,
|
pub message: &'a str,
|
||||||
pub message_email: String,
|
pub message_email: &'a str,
|
||||||
pub message_password: String,
|
pub message_password: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "sign_in_form.html")]
|
#[template(path = "sign_in_form.html")]
|
||||||
pub struct SignInFormTemplate {
|
pub struct SignInFormTemplate<'a> {
|
||||||
pub user: Option<model::User>,
|
pub user: Option<model::User>,
|
||||||
pub tr: Tr,
|
pub tr: Tr,
|
||||||
|
|
||||||
pub email: String,
|
pub email: &'a str,
|
||||||
pub message: String,
|
pub message: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "ask_reset_password.html")]
|
#[template(path = "ask_reset_password.html")]
|
||||||
pub struct AskResetPasswordTemplate {
|
pub struct AskResetPasswordTemplate<'a> {
|
||||||
pub user: Option<model::User>,
|
pub user: Option<model::User>,
|
||||||
pub tr: Tr,
|
pub tr: Tr,
|
||||||
|
|
||||||
pub email: String,
|
pub email: &'a str,
|
||||||
pub message: String,
|
pub message: &'a str,
|
||||||
pub message_email: String,
|
pub message_email: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "reset_password.html")]
|
#[template(path = "reset_password.html")]
|
||||||
pub struct ResetPasswordTemplate {
|
pub struct ResetPasswordTemplate<'a> {
|
||||||
pub user: Option<model::User>,
|
pub user: Option<model::User>,
|
||||||
pub tr: Tr,
|
pub tr: Tr,
|
||||||
|
|
||||||
pub reset_token: String,
|
pub reset_token: &'a str,
|
||||||
pub message: String,
|
pub message: &'a str,
|
||||||
pub message_password: String,
|
pub message_password: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "profile.html")]
|
#[template(path = "profile.html")]
|
||||||
pub struct ProfileTemplate {
|
pub struct ProfileTemplate<'a> {
|
||||||
pub user: Option<model::User>,
|
pub user: Option<model::User>,
|
||||||
pub tr: Tr,
|
pub tr: Tr,
|
||||||
|
|
||||||
pub username: String,
|
pub username: &'a str,
|
||||||
pub email: String,
|
pub email: &'a str,
|
||||||
pub message: String,
|
pub message: &'a str,
|
||||||
pub message_email: String,
|
pub message_email: &'a str,
|
||||||
pub message_password: String,
|
pub message_password: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,11 @@ async fn translation(
|
||||||
.map(|l| l.split('-').next().unwrap_or_default())
|
.map(|l| l.split('-').next().unwrap_or_default())
|
||||||
.find_or_first(|l| available_codes.contains(l));
|
.find_or_first(|l| available_codes.contains(l));
|
||||||
|
|
||||||
accept_language.unwrap_or("en").to_string()
|
match accept_language {
|
||||||
|
Some(lang) if !lang.is_empty() => lang,
|
||||||
|
_ => translation::DEFAULT_LANGUAGE_CODE,
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ pub async fn ron_error_to_html(
|
||||||
};
|
};
|
||||||
return Ok(MessageTemplate {
|
return Ok(MessageTemplate {
|
||||||
user: None,
|
user: None,
|
||||||
message,
|
message: &message,
|
||||||
as_code: true,
|
as_code: true,
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +78,6 @@ pub async fn not_found(
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
(
|
(
|
||||||
StatusCode::NOT_FOUND,
|
StatusCode::NOT_FOUND,
|
||||||
MessageTemplate::new_with_user("404: Not found".to_string(), tr, user),
|
MessageTemplate::new_with_user("404: Not found", tr, user),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +79,7 @@ pub async fn view(
|
||||||
&& (user.is_none() || recipe.user_id != user.as_ref().unwrap().id)
|
&& (user.is_none() || recipe.user_id != user.as_ref().unwrap().id)
|
||||||
{
|
{
|
||||||
return Ok(MessageTemplate::new_with_user(
|
return Ok(MessageTemplate::new_with_user(
|
||||||
tr.tp(Sentence::RecipeNotAllowedToView, &[Box::new(recipe_id)]),
|
&tr.tp(Sentence::RecipeNotAllowedToView, &[Box::new(recipe_id)]),
|
||||||
tr,
|
tr,
|
||||||
user,
|
user,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,9 @@ pub async fn sign_up_get(
|
||||||
user,
|
user,
|
||||||
tr,
|
tr,
|
||||||
email: String::new(),
|
email: String::new(),
|
||||||
message: String::new(),
|
message: "",
|
||||||
message_email: String::new(),
|
message_email: "",
|
||||||
message_password: String::new(),
|
message_password: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,26 +71,27 @@ pub async fn sign_up_post(
|
||||||
user: Option<model::User>,
|
user: Option<model::User>,
|
||||||
tr: translation::Tr,
|
tr: translation::Tr,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
|
let invalid_password_mess = &tr.tp(
|
||||||
|
Sentence::InvalidPassword,
|
||||||
|
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||||
|
);
|
||||||
Ok(SignUpFormTemplate {
|
Ok(SignUpFormTemplate {
|
||||||
user,
|
user,
|
||||||
email: form_data.email.clone(),
|
email: form_data.email.clone(),
|
||||||
message_email: match error {
|
message_email: match error {
|
||||||
SignUpError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
SignUpError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
message_password: match error {
|
message_password: match error {
|
||||||
SignUpError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
SignUpError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
||||||
SignUpError::InvalidPassword => tr.tp(
|
SignUpError::InvalidPassword => invalid_password_mess,
|
||||||
Sentence::InvalidPassword,
|
_ => "",
|
||||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
|
||||||
),
|
|
||||||
_ => String::new(),
|
|
||||||
},
|
},
|
||||||
message: match error {
|
message: match error {
|
||||||
SignUpError::UserAlreadyExists => tr.t(Sentence::EmailAlreadyTaken),
|
SignUpError::UserAlreadyExists => tr.t(Sentence::EmailAlreadyTaken),
|
||||||
SignUpError::DatabaseError => "Database error".to_string(),
|
SignUpError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||||
SignUpError::UnableSendEmail => tr.t(Sentence::UnableToSendEmail),
|
SignUpError::UnableSendEmail => tr.t(Sentence::UnableToSendEmail),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -235,8 +236,8 @@ pub async fn sign_in_get(
|
||||||
Ok(SignInFormTemplate {
|
Ok(SignInFormTemplate {
|
||||||
user,
|
user,
|
||||||
tr,
|
tr,
|
||||||
email: String::new(),
|
email: "",
|
||||||
message: String::new(),
|
message: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +272,7 @@ pub async fn sign_in_post(
|
||||||
jar,
|
jar,
|
||||||
SignInFormTemplate {
|
SignInFormTemplate {
|
||||||
user,
|
user,
|
||||||
email: form_data.email,
|
email: &form_data.email,
|
||||||
message: tr.t(Sentence::AccountMustBeValidatedFirst),
|
message: tr.t(Sentence::AccountMustBeValidatedFirst),
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +282,7 @@ pub async fn sign_in_post(
|
||||||
jar,
|
jar,
|
||||||
SignInFormTemplate {
|
SignInFormTemplate {
|
||||||
user,
|
user,
|
||||||
email: form_data.email,
|
email: &form_data.email,
|
||||||
message: tr.t(Sentence::WrongEmailOrPassword),
|
message: tr.t(Sentence::WrongEmailOrPassword),
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -326,9 +327,9 @@ pub async fn ask_reset_password_get(
|
||||||
Ok(AskResetPasswordTemplate {
|
Ok(AskResetPasswordTemplate {
|
||||||
user,
|
user,
|
||||||
tr,
|
tr,
|
||||||
email: String::new(),
|
email: "",
|
||||||
message: String::new(),
|
message: "",
|
||||||
message_email: String::new(),
|
message_email: "",
|
||||||
}
|
}
|
||||||
.into_response())
|
.into_response())
|
||||||
}
|
}
|
||||||
|
|
@ -364,10 +365,10 @@ pub async fn ask_reset_password_post(
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
Ok(AskResetPasswordTemplate {
|
Ok(AskResetPasswordTemplate {
|
||||||
user,
|
user,
|
||||||
email: email.to_string(),
|
email,
|
||||||
message_email: match error {
|
message_email: match error {
|
||||||
AskResetPasswordError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
AskResetPasswordError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
message: match error {
|
message: match error {
|
||||||
AskResetPasswordError::EmailAlreadyReset => {
|
AskResetPasswordError::EmailAlreadyReset => {
|
||||||
|
|
@ -376,7 +377,7 @@ pub async fn ask_reset_password_post(
|
||||||
AskResetPasswordError::EmailUnknown => tr.t(Sentence::EmailUnknown),
|
AskResetPasswordError::EmailUnknown => tr.t(Sentence::EmailUnknown),
|
||||||
AskResetPasswordError::UnableSendEmail => tr.t(Sentence::UnableToSendResetEmail),
|
AskResetPasswordError::UnableSendEmail => tr.t(Sentence::UnableToSendResetEmail),
|
||||||
AskResetPasswordError::DatabaseError => tr.t(Sentence::DatabaseError),
|
AskResetPasswordError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -470,9 +471,9 @@ pub async fn reset_password_get(
|
||||||
Ok(ResetPasswordTemplate {
|
Ok(ResetPasswordTemplate {
|
||||||
user,
|
user,
|
||||||
tr,
|
tr,
|
||||||
reset_token: reset_token.to_string(),
|
reset_token,
|
||||||
message: String::new(),
|
message: "",
|
||||||
message_password: String::new(),
|
message_password: "",
|
||||||
}
|
}
|
||||||
.into_response())
|
.into_response())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -510,21 +511,22 @@ pub async fn reset_password_post(
|
||||||
user: Option<model::User>,
|
user: Option<model::User>,
|
||||||
tr: translation::Tr,
|
tr: translation::Tr,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
Ok(ResetPasswordTemplate {
|
let reset_password_mess = &tr.tp(
|
||||||
user,
|
|
||||||
reset_token: form_data.reset_token.clone(),
|
|
||||||
message_password: match error {
|
|
||||||
ResetPasswordError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
|
||||||
ResetPasswordError::InvalidPassword => tr.tp(
|
|
||||||
Sentence::InvalidPassword,
|
Sentence::InvalidPassword,
|
||||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||||
),
|
);
|
||||||
_ => String::new(),
|
Ok(ResetPasswordTemplate {
|
||||||
|
user,
|
||||||
|
reset_token: &form_data.reset_token,
|
||||||
|
message_password: match error {
|
||||||
|
ResetPasswordError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
||||||
|
ResetPasswordError::InvalidPassword => reset_password_mess,
|
||||||
|
_ => "",
|
||||||
},
|
},
|
||||||
message: match error {
|
message: match error {
|
||||||
ResetPasswordError::TokenExpired => tr.t(Sentence::AskResetTokenExpired),
|
ResetPasswordError::TokenExpired => tr.t(Sentence::AskResetTokenExpired),
|
||||||
ResetPasswordError::DatabaseError => tr.t(Sentence::DatabaseError),
|
ResetPasswordError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -571,12 +573,12 @@ pub async fn edit_user_get(
|
||||||
) -> Response {
|
) -> Response {
|
||||||
if let Some(user) = user {
|
if let Some(user) = user {
|
||||||
ProfileTemplate {
|
ProfileTemplate {
|
||||||
username: user.name.clone(),
|
username: &user.name,
|
||||||
email: user.email.clone(),
|
email: &user.email,
|
||||||
message: String::new(),
|
message: "",
|
||||||
message_email: String::new(),
|
message_email: "",
|
||||||
message_password: String::new(),
|
message_password: "",
|
||||||
user: Some(user),
|
user: Some(user.clone()),
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
.into_response()
|
.into_response()
|
||||||
|
|
@ -592,6 +594,7 @@ pub struct EditUserForm {
|
||||||
password_1: String,
|
password_1: String,
|
||||||
password_2: String,
|
password_2: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ProfileUpdateError {
|
enum ProfileUpdateError {
|
||||||
InvalidEmail,
|
InvalidEmail,
|
||||||
EmailAlreadyTaken,
|
EmailAlreadyTaken,
|
||||||
|
|
@ -618,27 +621,28 @@ pub async fn edit_user_post(
|
||||||
user: model::User,
|
user: model::User,
|
||||||
tr: translation::Tr,
|
tr: translation::Tr,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
|
let invalid_password_mess = &tr.tp(
|
||||||
|
Sentence::InvalidPassword,
|
||||||
|
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
||||||
|
);
|
||||||
Ok(ProfileTemplate {
|
Ok(ProfileTemplate {
|
||||||
user: Some(user),
|
user: Some(user),
|
||||||
username: form_data.name.clone(),
|
username: &form_data.name,
|
||||||
email: form_data.email.clone(),
|
email: &form_data.email,
|
||||||
message_email: match error {
|
message_email: match error {
|
||||||
ProfileUpdateError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
ProfileUpdateError::InvalidEmail => tr.t(Sentence::InvalidEmail),
|
||||||
ProfileUpdateError::EmailAlreadyTaken => tr.t(Sentence::EmailAlreadyTaken),
|
ProfileUpdateError::EmailAlreadyTaken => tr.t(Sentence::EmailAlreadyTaken),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
message_password: match error {
|
message_password: match error {
|
||||||
ProfileUpdateError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
ProfileUpdateError::PasswordsNotEqual => tr.t(Sentence::PasswordDontMatch),
|
||||||
ProfileUpdateError::InvalidPassword => tr.tp(
|
ProfileUpdateError::InvalidPassword => invalid_password_mess,
|
||||||
Sentence::InvalidPassword,
|
_ => "",
|
||||||
&[Box::new(common::consts::MIN_PASSWORD_SIZE)],
|
|
||||||
),
|
|
||||||
_ => String::new(),
|
|
||||||
},
|
},
|
||||||
message: match error {
|
message: match error {
|
||||||
ProfileUpdateError::DatabaseError => tr.t(Sentence::DatabaseError),
|
ProfileUpdateError::DatabaseError => tr.t(Sentence::DatabaseError),
|
||||||
ProfileUpdateError::UnableSendEmail => tr.t(Sentence::UnableToSendEmail),
|
ProfileUpdateError::UnableSendEmail => tr.t(Sentence::UnableToSendEmail),
|
||||||
_ => String::new(),
|
_ => "",
|
||||||
},
|
},
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
|
|
@ -666,7 +670,7 @@ pub async fn edit_user_post(
|
||||||
};
|
};
|
||||||
|
|
||||||
let email_trimmed = form_data.email.trim();
|
let email_trimmed = form_data.email.trim();
|
||||||
let message: String;
|
let message: &str;
|
||||||
|
|
||||||
match connection
|
match connection
|
||||||
.update_user(
|
.update_user(
|
||||||
|
|
@ -725,11 +729,11 @@ pub async fn edit_user_post(
|
||||||
|
|
||||||
Ok(ProfileTemplate {
|
Ok(ProfileTemplate {
|
||||||
user,
|
user,
|
||||||
username: form_data.name,
|
username: &form_data.name,
|
||||||
email: form_data.email,
|
email: &form_data.email,
|
||||||
message,
|
message,
|
||||||
message_email: String::new(),
|
message_email: "",
|
||||||
message_password: String::new(),
|
message_password: "",
|
||||||
tr,
|
tr,
|
||||||
}
|
}
|
||||||
.into_response())
|
.into_response())
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use strum::EnumCount;
|
||||||
use strum_macros::EnumCount;
|
use strum_macros::EnumCount;
|
||||||
use tracing::{event, Level};
|
use tracing::{event, Level};
|
||||||
|
|
||||||
use crate::consts;
|
use crate::{consts, utils};
|
||||||
|
|
||||||
#[derive(Debug, Clone, EnumCount, Deserialize)]
|
#[derive(Debug, Clone, EnumCount, Deserialize)]
|
||||||
pub enum Sentence {
|
pub enum Sentence {
|
||||||
|
|
@ -108,7 +108,8 @@ pub enum Sentence {
|
||||||
RecipeIngredientComment,
|
RecipeIngredientComment,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_LANGUAGE_CODE: &str = "en";
|
pub const DEFAULT_LANGUAGE_CODE: &str = "en";
|
||||||
|
pub const PLACEHOLDER_SUBSTITUTE: &str = "{}";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Tr {
|
pub struct Tr {
|
||||||
|
|
@ -122,38 +123,21 @@ impl Tr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn t(&self, sentence: Sentence) -> String {
|
pub fn t(&self, sentence: Sentence) -> &'static str {
|
||||||
//&'static str {
|
self.lang.get(sentence)
|
||||||
self.lang.get(sentence).to_string()
|
|
||||||
// match self.lang.translation.get(&sentence) {
|
|
||||||
// Some(str) => str.clone(),
|
|
||||||
// None => format!(
|
|
||||||
// "Translation missing, lang: {}/{}, element: {:?}",
|
|
||||||
// self.lang.name, self.lang.code, sentence
|
|
||||||
// ),
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tp(&self, sentence: Sentence, params: &[Box<dyn ToString + Send>]) -> String {
|
pub fn tp(&self, sentence: Sentence, params: &[Box<dyn ToString + Send>]) -> String {
|
||||||
// match self.lang.translation.get(&sentence) {
|
|
||||||
// Some(str) => {
|
|
||||||
// let mut result = str.clone();
|
|
||||||
// for p in params {
|
|
||||||
// result = result.replacen("{}", &p.to_string(), 1);
|
|
||||||
// }
|
|
||||||
// result
|
|
||||||
// }
|
|
||||||
// None => format!(
|
|
||||||
// "Translation missing, lang: {}/{}, element: {:?}",
|
|
||||||
// self.lang.name, self.lang.code, sentence
|
|
||||||
// ),
|
|
||||||
// }
|
|
||||||
let text = self.lang.get(sentence);
|
let text = self.lang.get(sentence);
|
||||||
let mut result = text.to_string();
|
let params_as_string: Vec<String> = params.iter().map(|p| p.to_string()).collect();
|
||||||
for p in params {
|
utils::substitute(
|
||||||
result = result.replacen("{}", &p.to_string(), 1);
|
text,
|
||||||
}
|
PLACEHOLDER_SUBSTITUTE,
|
||||||
result
|
¶ms_as_string
|
||||||
|
.iter()
|
||||||
|
.map(AsRef::as_ref)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_lang_code(&self) -> &str {
|
pub fn current_lang_code(&self) -> &str {
|
||||||
|
|
@ -191,7 +175,6 @@ struct Language {
|
||||||
|
|
||||||
impl Language {
|
impl Language {
|
||||||
pub fn from_stored_language(stored_language: StoredLanguage) -> Self {
|
pub fn from_stored_language(stored_language: StoredLanguage) -> Self {
|
||||||
println!("!!!!!!!!!!!! {:?}", &stored_language.code);
|
|
||||||
Self {
|
Self {
|
||||||
code: stored_language.code,
|
code: stored_language.code,
|
||||||
name: stored_language.name,
|
name: stored_language.name,
|
||||||
|
|
|
||||||
|
|
@ -39,3 +39,44 @@ pub fn get_url_from_host(host: &str) -> String {
|
||||||
host
|
host
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn substitute(str: &str, pattern: &str, replacements: &[&str]) -> String {
|
||||||
|
let mut result = String::with_capacity(
|
||||||
|
(str.len() + replacements.iter().map(|s| s.len()).sum::<usize>())
|
||||||
|
.saturating_sub(pattern.len() * replacements.len()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
for s in str.split(pattern) {
|
||||||
|
result.push_str(s);
|
||||||
|
if i < replacements.len() {
|
||||||
|
result.push_str(replacements[i]);
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 1 {
|
||||||
|
return str.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_substitute() {
|
||||||
|
assert_eq!(substitute("", "", &[]), "");
|
||||||
|
assert_eq!(substitute("", "", &[""]), "");
|
||||||
|
assert_eq!(substitute("", "{}", &["a"]), "");
|
||||||
|
assert_eq!(substitute("a", "{}", &["b"]), "a");
|
||||||
|
assert_eq!(substitute("a{}", "{}", &["b"]), "ab");
|
||||||
|
assert_eq!(substitute("{}c", "{}", &["b"]), "bc");
|
||||||
|
assert_eq!(substitute("a{}c", "{}", &["b"]), "abc");
|
||||||
|
assert_eq!(substitute("{}b{}", "{}", &["a", "c"]), "abc");
|
||||||
|
assert_eq!(substitute("{}{}{}", "{}", &["a", "bc", "def"]), "abcdef");
|
||||||
|
assert_eq!(substitute("{}{}{}", "{}", &["a"]), "a");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,14 @@ async fn reload_recipes_list(current_recipe_id: i64) {
|
||||||
pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
// Title.
|
// Title.
|
||||||
{
|
{
|
||||||
let title: HtmlInputElement = by_id("input-title");
|
let Some(title) = document().get_element_by_id("input-title") else {
|
||||||
|
return Err(JsValue::from_str("Unable to find 'input-title' element"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let title: HtmlInputElement = title.dyn_into().unwrap();
|
||||||
|
|
||||||
|
// Check if the recipe has been loaded.
|
||||||
|
|
||||||
let mut current_title = title.value();
|
let mut current_title = title.value();
|
||||||
EventListener::new(&title.clone(), "blur", move |_event| {
|
EventListener::new(&title.clone(), "blur", move |_event| {
|
||||||
if title.value() != current_title {
|
if title.value() != current_title {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ mod request;
|
||||||
mod toast;
|
mod toast;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use gloo::{events::EventListener, utils::window};
|
use gloo::{console::log, events::EventListener, utils::window};
|
||||||
use utils::by_id;
|
use utils::by_id;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
|
|
@ -22,7 +22,9 @@ pub fn main() -> Result<(), JsValue> {
|
||||||
|
|
||||||
if let ["recipe", "edit", id] = path[..] {
|
if let ["recipe", "edit", id] = path[..] {
|
||||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
||||||
handles::recipe_edit(id)?;
|
if let Err(error) = handles::recipe_edit(id) {
|
||||||
|
log!(error);
|
||||||
|
}
|
||||||
|
|
||||||
// Disable: user editing data are now submitted as classic form data.
|
// Disable: user editing data are now submitted as classic form data.
|
||||||
// ["user", "edit"] => {
|
// ["user", "edit"] => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue