Check user is validated before creating a new recipe
This commit is contained in:
parent
104ae6b38e
commit
c8e0aa918c
5 changed files with 62 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2460,6 +2460,7 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"common",
|
"common",
|
||||||
"comrak",
|
"comrak",
|
||||||
|
"cookie",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lettre",
|
"lettre",
|
||||||
"rand 0.9.1",
|
"rand 0.9.1",
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ lettre = { version = "0.11", default-features = false, features = [
|
||||||
|
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
|
|
||||||
|
# Integration tests dependencies.
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
axum-test = "17"
|
axum-test = "17"
|
||||||
|
cookie = "0.18"
|
||||||
scraper = "0.23"
|
scraper = "0.23"
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ pub enum DBError {
|
||||||
)]
|
)]
|
||||||
UnsupportedVersion(u32),
|
UnsupportedVersion(u32),
|
||||||
|
|
||||||
|
#[error("User not validated")]
|
||||||
|
UserNotValidated,
|
||||||
|
|
||||||
#[error("Unknown error: {0}")]
|
#[error("Unknown error: {0}")]
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,21 @@ FROM [Recipe] WHERE [id] = $1
|
||||||
pub async fn create_recipe(&self, user_id: i64) -> Result<i64> {
|
pub async fn create_recipe(&self, user_id: i64) -> Result<i64> {
|
||||||
let mut tx = self.tx().await?;
|
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.
|
// Search for an existing empty recipe and return its id instead of creating a new one.
|
||||||
match sqlx::query_scalar::<_, i64>(
|
match sqlx::query_scalar::<_, i64>(
|
||||||
r#"
|
r#"
|
||||||
|
|
@ -944,6 +959,19 @@ mod tests {
|
||||||
Ok(())
|
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]
|
#[tokio::test]
|
||||||
async fn setters() -> Result<()> {
|
async fn setters() -> Result<()> {
|
||||||
let connection = Connection::new_in_memory().await?;
|
let connection = Connection::new_in_memory().await?;
|
||||||
|
|
@ -977,6 +1005,28 @@ mod tests {
|
||||||
Ok(())
|
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> {
|
async fn create_a_user(connection: &Connection) -> Result<i64> {
|
||||||
let user_id = 1;
|
let user_id = 1;
|
||||||
connection.execute_sql(
|
connection.execute_sql(
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ pub enum UpdateUserResult {
|
||||||
pub enum ValidationResult {
|
pub enum ValidationResult {
|
||||||
UnknownUser,
|
UnknownUser,
|
||||||
ValidationExpired,
|
ValidationExpired,
|
||||||
Ok(String, i64), // Returns token and user id.
|
/// Returns token and user id.
|
||||||
|
Ok(String, i64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
|
|
@ -35,13 +36,15 @@ pub enum SignInResult {
|
||||||
UserNotFound,
|
UserNotFound,
|
||||||
WrongPassword,
|
WrongPassword,
|
||||||
AccountNotValidated,
|
AccountNotValidated,
|
||||||
Ok(String, i64), // Returns token and user id.
|
/// Returns token and user id.
|
||||||
|
Ok(String, i64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
pub enum AuthenticationResult {
|
pub enum AuthenticationResult {
|
||||||
NotValidToken,
|
NotValidToken,
|
||||||
Ok(i64), // Returns user id.
|
/// Returns user id.
|
||||||
|
Ok(i64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue