Add first day of the week feature to user settings and calendar functionality
This commit is contained in:
parent
39f5b968b4
commit
fdbf2e4f27
15 changed files with 191 additions and 42 deletions
|
|
@ -77,7 +77,7 @@ FROM [UserLoginToken] WHERE [token] = $1
|
|||
|
||||
pub async fn load_user(&self, user_id: i64) -> Result<Option<model::User>> {
|
||||
sqlx::query_as(
|
||||
"SELECT [id], [email], [name], [default_servings], [lang], [is_admin] FROM [User] WHERE [id] = $1",
|
||||
"SELECT [id], [email], [name], [default_servings], [first_day_of_the_week], [lang], [is_admin] FROM [User] WHERE [id] = $1",
|
||||
)
|
||||
.bind(user_id)
|
||||
.fetch_optional(&self.pool)
|
||||
|
|
@ -93,16 +93,17 @@ FROM [UserLoginToken] WHERE [token] = $1
|
|||
new_email: Option<&str>,
|
||||
new_name: Option<&str>,
|
||||
new_default_servings: Option<u32>,
|
||||
new_first_day_of_the_week: Option<Weekday>,
|
||||
new_password: Option<&str>,
|
||||
) -> Result<UpdateUserResult> {
|
||||
let mut tx = self.tx().await?;
|
||||
let hashed_new_password = new_password.map(|p| hash(p).unwrap());
|
||||
|
||||
let (email, name, default_servings, hashed_password) = sqlx::query_as::<
|
||||
let (email, name, default_servings, first_day_of_the_week, hashed_password) = sqlx::query_as::<
|
||||
_,
|
||||
(String, String, u32, String),
|
||||
(String, String, u32, u8, String),
|
||||
>(
|
||||
"SELECT [email], [name], [default_servings], [password] FROM [User] WHERE [id] = $1",
|
||||
"SELECT [email], [name], [default_servings], [first_day_of_the_week], [password] FROM [User] WHERE [id] = $1",
|
||||
)
|
||||
.bind(user_id)
|
||||
.fetch_one(&mut *tx)
|
||||
|
|
@ -148,7 +149,7 @@ WHERE [id] = $1
|
|||
sqlx::query(
|
||||
r#"
|
||||
UPDATE [User]
|
||||
SET [email] = $2, [name] = $3, [default_servings] = $4, [password] = $5
|
||||
SET [email] = $2, [name] = $3, [default_servings] = $4, [first_day_of_the_week] = $5, [password] = $6
|
||||
WHERE [id] = $1
|
||||
"#,
|
||||
)
|
||||
|
|
@ -156,6 +157,7 @@ WHERE [id] = $1
|
|||
.bind(new_email.unwrap_or(&email))
|
||||
.bind(new_name.map(str::trim).unwrap_or(&name))
|
||||
.bind(new_default_servings.unwrap_or(default_servings))
|
||||
.bind(new_first_day_of_the_week.map(|d| d as u8).unwrap_or(first_day_of_the_week))
|
||||
.bind(hashed_new_password.unwrap_or(hashed_password))
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
|
@ -179,8 +181,13 @@ WHERE [id] = $1
|
|||
.map_err(DBError::from)
|
||||
}
|
||||
|
||||
pub async fn sign_up(&self, email: &str, password: &str) -> Result<SignUpResult> {
|
||||
self.sign_up_with_given_time(email, password, Utc::now())
|
||||
pub async fn sign_up(
|
||||
&self,
|
||||
email: &str,
|
||||
password: &str,
|
||||
first_day_of_the_week: Weekday,
|
||||
) -> Result<SignUpResult> {
|
||||
self.sign_up_with_given_time(email, password, first_day_of_the_week, Utc::now())
|
||||
.await
|
||||
}
|
||||
|
||||
|
|
@ -188,6 +195,7 @@ WHERE [id] = $1
|
|||
&self,
|
||||
email: &str,
|
||||
password: &str,
|
||||
first_day_of_the_week: Weekday,
|
||||
datetime: DateTime<Utc>,
|
||||
) -> Result<SignUpResult> {
|
||||
let mut tx = self.tx().await?;
|
||||
|
|
@ -229,11 +237,12 @@ WHERE [id] = $1
|
|||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO [User]
|
||||
([email], [creation_datetime], [validation_token], [validation_token_datetime], [password])
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
([email], [first_day_of_the_week], [creation_datetime], [validation_token], [validation_token_datetime], [password])
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
"#,
|
||||
)
|
||||
.bind(email)
|
||||
.bind(first_day_of_the_week as u8)
|
||||
.bind(Utc::now())
|
||||
.bind(&token)
|
||||
.bind(datetime)
|
||||
|
|
@ -525,7 +534,10 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn sign_up() -> Result<()> {
|
||||
let connection = Connection::new_in_memory().await?;
|
||||
match connection.sign_up("paul@atreides.com", "12345").await? {
|
||||
match connection
|
||||
.sign_up("paul@atreides.com", "12345", Weekday::Mon)
|
||||
.await?
|
||||
{
|
||||
SignUpResult::UserCreatedWaitingForValidation(_) => (), // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
}
|
||||
|
|
@ -550,7 +562,10 @@ INSERT INTO
|
|||
NULL
|
||||
);
|
||||
"#)).await?;
|
||||
match connection.sign_up("paul@atreides.com", "12345").await? {
|
||||
match connection
|
||||
.sign_up("paul@atreides.com", "12345", Weekday::Mon)
|
||||
.await?
|
||||
{
|
||||
SignUpResult::UserAlreadyExists => (), // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
}
|
||||
|
|
@ -564,7 +579,7 @@ INSERT INTO
|
|||
let email = "paul@atreides.com";
|
||||
let password = "12345";
|
||||
|
||||
match connection.sign_up(email, password).await? {
|
||||
match connection.sign_up(email, password, Weekday::Mon).await? {
|
||||
SignUpResult::UserCreatedWaitingForValidation(_) => (), // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
}
|
||||
|
|
@ -600,7 +615,10 @@ VALUES (
|
|||
)
|
||||
"#
|
||||
).bind(token)).await?;
|
||||
match connection.sign_up("paul@atreides.com", "12345").await? {
|
||||
match connection
|
||||
.sign_up("paul@atreides.com", "12345", Weekday::Mon)
|
||||
.await?
|
||||
{
|
||||
SignUpResult::UserCreatedWaitingForValidation(_) => (), // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
}
|
||||
|
|
@ -610,7 +628,10 @@ VALUES (
|
|||
#[tokio::test]
|
||||
async fn sign_up_then_send_validation_at_time() -> Result<()> {
|
||||
let connection = Connection::new_in_memory().await?;
|
||||
let validation_token = match connection.sign_up("paul@atreides.com", "12345").await? {
|
||||
let validation_token = match connection
|
||||
.sign_up("paul@atreides.com", "12345", Weekday::Mon)
|
||||
.await?
|
||||
{
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
};
|
||||
|
|
@ -633,7 +654,12 @@ VALUES (
|
|||
async fn sign_up_then_send_validation_too_late() -> Result<()> {
|
||||
let connection = Connection::new_in_memory().await?;
|
||||
let validation_token = match connection
|
||||
.sign_up_with_given_time("paul@atreides.com", "12345", Utc::now() - Duration::days(1))
|
||||
.sign_up_with_given_time(
|
||||
"paul@atreides.com",
|
||||
"12345",
|
||||
Weekday::Mon,
|
||||
Utc::now() - Duration::days(1),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
|
|
@ -657,7 +683,10 @@ VALUES (
|
|||
#[tokio::test]
|
||||
async fn sign_up_then_send_validation_with_bad_token() -> Result<()> {
|
||||
let connection = Connection::new_in_memory().await?;
|
||||
let _validation_token = match connection.sign_up("paul@atreides.com", "12345").await? {
|
||||
let _validation_token = match connection
|
||||
.sign_up("paul@atreides.com", "12345", Weekday::Mon)
|
||||
.await?
|
||||
{
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
};
|
||||
|
|
@ -685,7 +714,7 @@ VALUES (
|
|||
let password = "12345";
|
||||
|
||||
// Sign up.
|
||||
let validation_token = match connection.sign_up(email, password).await? {
|
||||
let validation_token = match connection.sign_up(email, password, Weekday::Mon).await? {
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
};
|
||||
|
|
@ -724,7 +753,7 @@ VALUES (
|
|||
let password = "12345";
|
||||
|
||||
// Sign up.
|
||||
let validation_token = match connection.sign_up(email, password).await? {
|
||||
let validation_token = match connection.sign_up(email, password, Weekday::Mon).await? {
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
};
|
||||
|
|
@ -778,7 +807,7 @@ VALUES (
|
|||
let password = "12345";
|
||||
|
||||
// Sign up.
|
||||
let validation_token = match connection.sign_up(email, password).await? {
|
||||
let validation_token = match connection.sign_up(email, password, Weekday::Mon).await? {
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
};
|
||||
|
|
@ -855,7 +884,7 @@ VALUES (
|
|||
let new_password = "54321";
|
||||
|
||||
// Sign up.
|
||||
let validation_token = match connection.sign_up(email, password).await? {
|
||||
let validation_token = match connection.sign_up(email, password, Weekday::Mon).await? {
|
||||
SignUpResult::UserCreatedWaitingForValidation(token) => token, // Nominal case.
|
||||
other => panic!("{:?}", other),
|
||||
};
|
||||
|
|
@ -946,6 +975,7 @@ VALUES
|
|||
Some("muaddib@fremen.com"),
|
||||
Some("muaddib"),
|
||||
None,
|
||||
None,
|
||||
Some("Chani"),
|
||||
)
|
||||
.await?
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ pub struct User {
|
|||
pub name: String,
|
||||
pub email: String,
|
||||
pub default_servings: u32,
|
||||
|
||||
#[sqlx(try_from = "u8")]
|
||||
pub first_day_of_the_week: Weekday,
|
||||
|
||||
pub lang: String,
|
||||
pub is_admin: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,16 @@ struct Context {
|
|||
dark_theme: bool,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn first_day_of_the_week(&self) -> Weekday {
|
||||
if let Some(user) = &self.user {
|
||||
user.first_day_of_the_week
|
||||
} else {
|
||||
self.tr.first_day_of_week()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should main returns 'Result'?
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,11 @@ pub async fn sign_up_post(
|
|||
}
|
||||
|
||||
match connection
|
||||
.sign_up(&form_data.email, &form_data.password_1)
|
||||
.sign_up(
|
||||
&form_data.email,
|
||||
&form_data.password_1,
|
||||
context.tr.first_day_of_week(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(db::user::SignUpResult::UserAlreadyExists) => {
|
||||
|
|
@ -691,6 +695,7 @@ pub struct EditUserForm {
|
|||
name: String,
|
||||
email: String,
|
||||
default_servings: u32,
|
||||
first_day_of_the_week: chrono::Weekday,
|
||||
password_1: String,
|
||||
password_2: String,
|
||||
}
|
||||
|
|
@ -713,6 +718,11 @@ pub async fn edit_user_post(
|
|||
Extension(context): Extension<Context>,
|
||||
Form(form_data): Form<EditUserForm>,
|
||||
) -> Result<Response> {
|
||||
event!(
|
||||
Level::DEBUG,
|
||||
"First day of the week: {:?}",
|
||||
form_data.first_day_of_the_week
|
||||
);
|
||||
if let Some(ref user) = context.user {
|
||||
fn error_response(
|
||||
error: ProfileUpdateError,
|
||||
|
|
@ -783,6 +793,7 @@ pub async fn edit_user_post(
|
|||
Some(email_trimmed),
|
||||
Some(&form_data.name),
|
||||
Some(form_data.default_servings),
|
||||
Some(form_data.first_day_of_the_week),
|
||||
new_password,
|
||||
)
|
||||
.await
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::{borrow::Borrow, fs::File, sync::LazyLock};
|
||||
|
||||
use chrono::Weekday;
|
||||
use common::utils;
|
||||
use ron::de::from_reader;
|
||||
use serde::Deserialize;
|
||||
|
|
@ -80,6 +81,7 @@ pub enum Sentence {
|
|||
ProfileTitle,
|
||||
ProfileEmail,
|
||||
ProfileDefaultServings,
|
||||
ProfileFirstDayOfWeek,
|
||||
ProfileNewPassword,
|
||||
ProfileFollowEmailTitle,
|
||||
ProfileFollowEmailLink,
|
||||
|
|
@ -126,6 +128,13 @@ pub enum Sentence {
|
|||
RecipeEstimatedTimeMinAbbreviation,
|
||||
|
||||
// Calendar.
|
||||
CalendarMonday,
|
||||
CalendarTuesday,
|
||||
CalendarWednesday,
|
||||
CalendarThursday,
|
||||
CalendarFriday,
|
||||
CalendarSaturday,
|
||||
CalendarSunday,
|
||||
CalendarMondayAbbreviation,
|
||||
CalendarTuesdayAbbreviation,
|
||||
CalendarWednesdayAbbreviation,
|
||||
|
|
@ -197,6 +206,13 @@ impl Tr {
|
|||
pub fn current_lang_and_territory_code(&self) -> String {
|
||||
format!("{}-{}", self.lang.code, self.lang.territory)
|
||||
}
|
||||
|
||||
pub fn first_day_of_week(&self) -> Weekday {
|
||||
match (self.lang.code.as_ref(), self.lang.territory.as_ref()) {
|
||||
("en", "US") => Weekday::Sun,
|
||||
_ => Weekday::Mon,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[macro_export]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue