Check user is validated before creating a new recipe

This commit is contained in:
Greg Burri 2025-04-30 11:11:01 +02:00
parent 104ae6b38e
commit c8e0aa918c
5 changed files with 62 additions and 3 deletions

1
Cargo.lock generated
View file

@ -2460,6 +2460,7 @@ dependencies = [
"clap",
"common",
"comrak",
"cookie",
"itertools",
"lettre",
"rand 0.9.1",

View file

@ -50,6 +50,8 @@ lettre = { version = "0.11", default-features = false, features = [
thiserror = "2"
# Integration tests dependencies.
[dev-dependencies]
axum-test = "17"
cookie = "0.18"
scraper = "0.23"

View file

@ -33,6 +33,9 @@ pub enum DBError {
)]
UnsupportedVersion(u32),
#[error("User not validated")]
UserNotValidated,
#[error("Unknown error: {0}")]
Other(String),
}

View file

@ -281,6 +281,21 @@ FROM [Recipe] WHERE [id] = $1
pub async fn create_recipe(&self, user_id: i64) -> Result<i64> {
let mut tx = self.tx().await?;
// Check that the user is validated.
if !sqlx::query_scalar(
r#"
SELECT COUNT(*) = 1
FROM [User] WHERE
[User].[id] = $1 AND [User].[validation_token] IS NULL
"#,
)
.bind(user_id)
.fetch_one(&mut *tx)
.await?
{
return Err(DBError::UserNotValidated);
}
// Search for an existing empty recipe and return its id instead of creating a new one.
match sqlx::query_scalar::<_, i64>(
r#"
@ -944,6 +959,19 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn create_a_new_recipe_by_an_unvalidated_user() -> Result<()> {
let connection = Connection::new_in_memory().await?;
let user_id = create_an_unvalidated_user(&connection).await?;
match connection.create_recipe(user_id).await {
Err(DBError::UserNotValidated) => (), // Nominal case.
other => panic!("{:?}", other),
}
Ok(())
}
#[tokio::test]
async fn setters() -> Result<()> {
let connection = Connection::new_in_memory().await?;
@ -977,6 +1005,28 @@ mod tests {
Ok(())
}
async fn create_an_unvalidated_user(connection: &Connection) -> Result<i64> {
let user_id = 1;
connection.execute_sql(
sqlx::query(
r#"
INSERT INTO [User]
([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
VALUES
($1, $2, $3, $4, $5, $6, $7)
"#
)
.bind(user_id)
.bind("paul@atreides.com")
.bind("paul")
.bind("")
.bind("$argon2id$v=19$m=4096,t=3,p=1$G4fjepS05MkRbTqEImUdYg$GGziE8uVQe1L1oFHk37lBno10g4VISnVqynSkLCH3Lc")
.bind("2022-11-29 22:05:04.121407300+00:00")
.bind(Some("SOME_TOKEN")) // not 'null'.
).await?;
Ok(user_id)
}
async fn create_a_user(connection: &Connection) -> Result<i64> {
let user_id = 1;
connection.execute_sql(

View file

@ -27,7 +27,8 @@ pub enum UpdateUserResult {
pub enum ValidationResult {
UnknownUser,
ValidationExpired,
Ok(String, i64), // Returns token and user id.
/// Returns token and user id.
Ok(String, i64),
}
#[derive(Debug, Display)]
@ -35,13 +36,15 @@ pub enum SignInResult {
UserNotFound,
WrongPassword,
AccountNotValidated,
Ok(String, i64), // Returns token and user id.
/// Returns token and user id.
Ok(String, i64),
}
#[derive(Debug, Display)]
pub enum AuthenticationResult {
NotValidToken,
Ok(i64), // Returns user id.
/// Returns user id.
Ok(i64),
}
#[derive(Debug, Display)]