feat: db port and (pg) adapter to check if verification secret exists

This commit is contained in:
Aravinth Manivannan 2024-05-18 18:28:34 +05:30
parent fbb5435d3c
commit 36f85e2e18
Signed by: realaravinth
GPG key ID: F8F50389936984FF
9 changed files with 177 additions and 7 deletions

View file

@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (\n SELECT 1\n FROM verification_otp\n WHERE\n username = $1\n AND\n purpose = $2\n AND\n secret = $3\n );",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "3edf94a78114819085b573ff51702faee1c444c24bbf6d33ec1b4b245dd9f675"
}

View file

@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM\n verification_otp\n WHERE\n username = $1\n AND\n purpose = $2\n AND\n secret = $3;",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "c54d1b89ee39ceb11326e82962eef3d8f588f6252ba4bbac99fb73cdbbcd2204"
}

View file

@ -15,7 +15,7 @@ impl CreateVerificationSecretOutDBPort for DBOutPostgresAdapter {
VALUES ($1, $2, $3, $4);", VALUES ($1, $2, $3, $4);",
&msg.secret, &msg.secret,
OffsetDateTime::now_utc(), OffsetDateTime::now_utc(),
&msg.purpose, REGISTRATION_SECRET_PURPOSE,
&msg.username, &msg.username,
) )
.execute(&self.pool) .execute(&self.pool)
@ -39,7 +39,6 @@ mod tests {
let msg = CreateSecretMsgBuilder::default() let msg = CreateSecretMsgBuilder::default()
.secret("secret".into()) .secret("secret".into())
.purpose("purpose".into())
.username("username".into()) .username("username".into())
.build() .build()
.unwrap(); .unwrap();

View file

@ -10,9 +10,11 @@ use sqlx::postgres::PgPool;
use crate::db::{migrate::RunMigrations, sqlx_postgres::Postgres}; use crate::db::{migrate::RunMigrations, sqlx_postgres::Postgres};
pub mod create_verification_secret; pub mod create_verification_secret;
pub mod delete_verification_secret;
pub mod email_exists; pub mod email_exists;
mod errors; mod errors;
pub mod username_exists; pub mod username_exists;
pub mod verification_secret_exists;
#[derive(Clone)] #[derive(Clone)]
pub struct DBOutPostgresAdapter { pub struct DBOutPostgresAdapter {

View file

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use super::DBOutPostgresAdapter;
use crate::identity::application::port::output::db::{errors::*, verification_secret_exists::*};
#[async_trait::async_trait]
impl VerificationSecretExistsOutDBPort for DBOutPostgresAdapter {
async fn verification_secret_exists(
&self,
msg: &VerifySecretExistsMsg,
) -> OutDBPortResult<bool> {
let res = sqlx::query!(
"SELECT EXISTS (
SELECT 1
FROM verification_otp
WHERE
username = $1
AND
purpose = $2
AND
secret = $3
);",
msg.username,
REGISTRATION_SECRET_PURPOSE,
msg.secret,
)
.fetch_one(&self.pool)
.await?;
if let Some(x) = res.exists {
Ok(x)
} else {
Ok(false)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::identity::application::port::output::db::create_verification_secret::*;
#[actix_rt::test]
async fn test_postgres_verification_secret_exists() {
let username = "batman";
let secret = "bsdasdf";
let settings = crate::settings::tests::get_settings().await;
let db = super::DBOutPostgresAdapter::new(
sqlx::postgres::PgPool::connect(&settings.database.url)
.await
.unwrap(),
);
let msg = VerifySecretExistsMsgBuilder::default()
.username(username.into())
.secret(secret.into())
.build()
.unwrap();
// state doesn't exist
assert!(!db.verification_secret_exists(&msg).await.unwrap());
let create_msg = CreateSecretMsgBuilder::default()
.secret(secret.into())
.username(username.into())
.build()
.unwrap();
db.create_verification_secret(create_msg).await.unwrap();
// state exists
assert!(db.verification_secret_exists(&msg).await.unwrap());
settings.drop_db().await;
}
}

View file

@ -15,9 +15,9 @@ pub use tests::*;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Builder)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Builder)]
pub struct CreateSecretMsg { pub struct CreateSecretMsg {
pub secret: String, pub secret: String,
pub purpose: String,
pub username: String, pub username: String,
} }
pub const REGISTRATION_SECRET_PURPOSE: &str = "account_validation";
#[automock] #[automock]
#[async_trait::async_trait] #[async_trait::async_trait]

View file

@ -3,8 +3,8 @@
// SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-License-Identifier: AGPL-3.0-or-later
pub mod create_verification_secret; pub mod create_verification_secret;
pub mod delete_verification_secret;
pub mod email_exists; pub mod email_exists;
pub mod errors; pub mod errors;
pub mod username_exists; pub mod username_exists;
//pub mod get_verification_secret; pub mod verification_secret_exists;
//pub mod delete_verification_secret;

View file

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_builder::Builder;
use mockall::predicate::*;
use mockall::*;
use serde::{Deserialize, Serialize};
pub use super::create_verification_secret::REGISTRATION_SECRET_PURPOSE;
use super::errors::*;
#[cfg(test)]
#[allow(unused_imports)]
pub use tests::*;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Builder)]
pub struct VerifySecretExistsMsg {
pub secret: String,
pub username: String,
}
#[automock]
#[async_trait::async_trait]
pub trait VerificationSecretExistsOutDBPort: Send + Sync {
async fn verification_secret_exists(
&self,
msg: &VerifySecretExistsMsg,
) -> OutDBPortResult<bool>;
}
pub type VerificationSecretExistsOutDBPortObj =
std::sync::Arc<dyn VerificationSecretExistsOutDBPort>;
#[cfg(test)]
pub mod tests {
use super::*;
use std::sync::Arc;
pub fn mock_verification_secret_exists_db_port(
times: Option<usize>,
returning: bool,
) -> VerificationSecretExistsOutDBPortObj {
let mut m = MockVerificationSecretExistsOutDBPort::new();
if let Some(times) = times {
m.expect_verification_secret_exists()
.times(times)
.returning(move |_| Ok(returning));
} else {
m.expect_verification_secret_exists()
.returning(move |_| Ok(returning));
}
Arc::new(m)
}
}

View file

@ -13,7 +13,6 @@ use crate::identity::application::port::output::{
use crate::utils::random_string::*; use crate::utils::random_string::*;
pub const SECRET_LEN: usize = 20; pub const SECRET_LEN: usize = 20;
pub const REGISTRATION_SECRET_PURPOSE: &str = "account_validation";
#[derive(Builder)] #[derive(Builder)]
pub struct RegisterUserService { pub struct RegisterUserService {
@ -54,7 +53,6 @@ impl RegisterUserUseCase for RegisterUserService {
.create_verification_secret( .create_verification_secret(
CreateSecretMsgBuilder::default() CreateSecretMsgBuilder::default()
.secret(secret.clone()) .secret(secret.clone())
.purpose(REGISTRATION_SECRET_PURPOSE.into())
.username(cmd.username().into()) .username(cmd.username().into())
.build() .build()
.unwrap(), .unwrap(),