feat: sqlx postgres adapter for oauth domain

This commit is contained in:
Aravinth Manivannan 2024-05-04 22:41:47 +05:30
parent c718ae6f4d
commit 9b328a0935
Signed by: realaravinth
GPG key ID: F8F50389936984FF
8 changed files with 285 additions and 0 deletions

View file

@ -0,0 +1,34 @@
use std::sync::Arc;
use sqlx::PgPool;
use url::Url;
use crate::db::migrate::RunMigrations;
use crate::forge::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
pub mod postgres;
#[derive(Clone)]
pub struct DBAdapter {
pub save_oauth_state_adapter: Arc<dyn SaveOAuthState>,
pg_adapter: postgres::DBOutPostgresAdapter,
}
impl DBAdapter {
pub async fn init(database_url: &str) -> Self {
let pool = PgPool::connect(database_url).await.unwrap();
Self::new(pool)
}
fn new(pool: PgPool) -> Self {
let pg_adapter = postgres::DBOutPostgresAdapter::new(pool);
Self {
save_oauth_state_adapter: Arc::new(pg_adapter.clone()),
pg_adapter,
}
}
pub fn migratable(&self) -> Arc<dyn RunMigrations> {
self.pg_adapter.migratable()
}
}

View file

@ -0,0 +1,28 @@
use derive_more::Display;
use serde::{Deserialize, Serialize};
use sqlx::Error as SqlxError;
use crate::forge::auth::application::port::out::db::errors::OutDBPortError;
impl From<SqlxError> for OutDBPortError {
fn from(value: SqlxError) -> Self {
unimplemented!()
}
}
//impl From<ProcessAuthorizationServiceError> for OutDBPostgresError {
// fn from(v: ProcessAuthorizationServiceError) -> Self {
// match v {
// ProcessAuthorizationServiceError::InteralError => Self::InternalServerError,
// ProcessAuthorizationServiceError::BadRequest => Self::BadRequest,
// }
// }
//}
//
//impl From<RequestAuthorizationServiceError> for OutDBPostgresError {
// fn from(v: RequestAuthorizationServiceError) -> Self {
// match v {
// RequestAuthorizationServiceError::InteralError => Self::InternalServerError,
// }
// }
//}

View file

@ -0,0 +1,24 @@
//use crate::forge::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
use std::sync::Arc;
use sqlx::postgres::PgPool;
use crate::db::{migrate::RunMigrations, sqlx_postgres::Postgres};
mod errors;
mod save_oauth_state;
#[derive(Clone)]
pub struct DBOutPostgresAdapter {
pool: PgPool,
}
impl DBOutPostgresAdapter {
pub fn new(pool: PgPool) -> Self {
Self { pool }
}
pub fn migratable(&self) -> Arc<dyn RunMigrations> {
Arc::new(Postgres::new(self.pool.clone()))
}
}

View file

@ -0,0 +1,52 @@
use url::Url;
use super::DBOutPostgresAdapter;
use crate::forge::auth::application::port::out::db::{
errors::OutDBPortResult, save_oauth_state::SaveOAuthState,
};
#[async_trait::async_trait]
impl SaveOAuthState for DBOutPostgresAdapter {
async fn save_oauth_state(
&self,
state: &str,
oauth_provider: &str,
redirect_uri: &Url,
) -> OutDBPortResult<()> {
sqlx::query!(
"INSERT INTO oauth_state (state, oauth_provider, redirect_uri) VALUES ($1, $2, $3)",
state,
oauth_provider,
redirect_uri.as_str()
)
.execute(&self.pool)
.await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[actix_rt::test]
async fn test_postgres_save_oauth_state() {
let state = "statetestpostgres";
let oauth_provider = "oauthprovitestpostgres";
let redirect_uri = Url::parse("https://oauthprovitestpostgres").unwrap();
let settings = crate::settings::tests::get_settings().await;
let db = super::DBOutPostgresAdapter::new(
sqlx::postgres::PgPool::connect(&settings.database.url)
.await
.unwrap(),
);
db.save_oauth_state(state, oauth_provider, &redirect_uri)
.await
.unwrap();
settings.drop_db().await;
}
}

View file

@ -0,0 +1,24 @@
use url::Url;
use super::Forgejo;
use crate::forge::auth::application::port::out::forge::{
errors::OutForgePortResult, get_redirect_uri::GetRedirectUri,
};
impl GetRedirectUri for Forgejo {
fn get_redirect_uri(
&self,
state: &str,
process_authorization_response_uri: &Url,
) -> OutForgePortResult<Url> {
let mut u = self.url().to_owned();
u.set_path("/login/oauth/authorize");
u.set_query(Some(&format!(
"client_id={}&redirect_uri={}&response_type=code&state={state}",
self.client_id(),
process_authorization_response_uri.as_str()
)));
Ok(u)
}
}

View file

@ -0,0 +1,32 @@
use url::Url;
mod get_redirect_uri;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Forgejo {
url: Url,
client_id: String,
client_secret: String,
}
impl Forgejo {
pub fn new(url: Url, client_id: String, client_secret: String) -> Self {
Self {
url,
client_id,
client_secret,
}
}
pub fn url(&self) -> &Url {
&self.url
}
pub fn client_id(&self) -> &str {
&self.client_id
}
pub fn client_secret(&self) -> &str {
&self.client_secret
}
}

View file

@ -0,0 +1,89 @@
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use derive_more::Display;
use serde::{Deserialize, Serialize};
use crate::forge::auth::application::port::out::forge::get_redirect_uri::GetRedirectUri;
use self::forgejo::Forgejo;
pub mod forgejo;
#[derive(Clone)]
pub struct ForgeAdapter {
pub get_redirect_uri_adapter: Arc<dyn GetRedirectUri>,
}
#[derive(Clone, Default)]
pub struct ForgeRepository {
forges: HashMap<SupportedForges, ForgeAdapter>,
}
impl ForgeRepository {
fn add_forge(&mut self, name: SupportedForges, forge_factory: ForgeAdapter) {
self.forges.insert(name, forge_factory);
}
pub fn get_supported_forge_str(&self) -> Vec<String> {
self.forges
.clone()
.into_keys()
.map(|v| v.to_string())
.collect()
}
pub fn get_supported_forges(&self) -> Vec<SupportedForges> {
self.forges.clone().into_keys().collect()
}
pub fn get_forge(&self, name: &SupportedForges) -> Option<&ForgeAdapter> {
self.forges.get(name)
}
pub fn new(forgejo: Forgejo) -> Self {
let forgejo_adapter = ForgeAdapter {
get_redirect_uri_adapter: Arc::new(forgejo),
};
let mut s = Self::default();
s.add_forge(SupportedForges::Forgejo, forgejo_adapter);
s
}
}
#[derive(Debug, Display, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "lowercase")]
pub enum SupportedForges {
#[display(fmt = "forgejo")]
Forgejo,
}
impl FromStr for SupportedForges {
type Err = SupportedForgesError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim() {
"forgejo" => Ok(SupportedForges::Forgejo),
_ => Err(SupportedForgesError::UnsupportedForge),
}
}
}
#[derive(Debug, Display, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum SupportedForgesError {
UnsupportedForge,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_supported_forges() {
assert_eq!(SupportedForges::Forgejo.to_string(), "forgejo");
assert_eq!(
SupportedForges::from_str("forgejo").unwrap(),
SupportedForges::Forgejo
);
}
}

View file

@ -0,0 +1,2 @@
pub mod db;
pub mod forge;