mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(themes): Setup themes table (#6533)
This commit is contained in:
@ -3,6 +3,8 @@ pub mod keymanager;
|
|||||||
|
|
||||||
/// Enum for Authentication Level
|
/// Enum for Authentication Level
|
||||||
pub mod authentication;
|
pub mod authentication;
|
||||||
|
/// Enum for Theme Lineage
|
||||||
|
pub mod theme;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
|||||||
39
crates/common_utils/src/types/theme.rs
Normal file
39
crates/common_utils/src/types/theme.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use crate::id_type;
|
||||||
|
|
||||||
|
/// Enum for having all the required lineage for every level.
|
||||||
|
/// Currently being used for theme related APIs and queries.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ThemeLineage {
|
||||||
|
/// Tenant lineage variant
|
||||||
|
Tenant {
|
||||||
|
/// tenant_id: String
|
||||||
|
tenant_id: String,
|
||||||
|
},
|
||||||
|
/// Org lineage variant
|
||||||
|
Organization {
|
||||||
|
/// tenant_id: String
|
||||||
|
tenant_id: String,
|
||||||
|
/// org_id: OrganizationId
|
||||||
|
org_id: id_type::OrganizationId,
|
||||||
|
},
|
||||||
|
/// Merchant lineage variant
|
||||||
|
Merchant {
|
||||||
|
/// tenant_id: String
|
||||||
|
tenant_id: String,
|
||||||
|
/// org_id: OrganizationId
|
||||||
|
org_id: id_type::OrganizationId,
|
||||||
|
/// merchant_id: MerchantId
|
||||||
|
merchant_id: id_type::MerchantId,
|
||||||
|
},
|
||||||
|
/// Profile lineage variant
|
||||||
|
Profile {
|
||||||
|
/// tenant_id: String
|
||||||
|
tenant_id: String,
|
||||||
|
/// org_id: OrganizationId
|
||||||
|
org_id: id_type::OrganizationId,
|
||||||
|
/// merchant_id: MerchantId
|
||||||
|
merchant_id: id_type::MerchantId,
|
||||||
|
/// profile_id: ProfileId
|
||||||
|
profile_id: id_type::ProfileId,
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
use common_utils::pii;
|
use common_utils::pii;
|
||||||
use diesel::{associations::HasTable, ExpressionMethods};
|
use diesel::{associations::HasTable, ExpressionMethods};
|
||||||
|
|
||||||
pub mod sample_data;
|
pub mod sample_data;
|
||||||
|
pub mod theme;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
query::generics, schema::users::dsl as users_dsl, user::*, PgPooledConn, StorageResult,
|
query::generics, schema::users::dsl as users_dsl, user::*, PgPooledConn, StorageResult,
|
||||||
|
|||||||
95
crates/diesel_models/src/query/user/theme.rs
Normal file
95
crates/diesel_models/src/query/user/theme.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
use common_utils::types::theme::ThemeLineage;
|
||||||
|
use diesel::{
|
||||||
|
associations::HasTable,
|
||||||
|
pg::Pg,
|
||||||
|
sql_types::{Bool, Nullable},
|
||||||
|
BoolExpressionMethods, ExpressionMethods, NullableExpressionMethods,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
query::generics,
|
||||||
|
schema::themes::dsl,
|
||||||
|
user::theme::{Theme, ThemeNew},
|
||||||
|
PgPooledConn, StorageResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl ThemeNew {
|
||||||
|
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Theme> {
|
||||||
|
generics::generic_insert(conn, self).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Theme {
|
||||||
|
fn lineage_filter(
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> Box<
|
||||||
|
dyn diesel::BoxableExpression<<Self as HasTable>::Table, Pg, SqlType = Nullable<Bool>>
|
||||||
|
+ 'static,
|
||||||
|
> {
|
||||||
|
match lineage {
|
||||||
|
ThemeLineage::Tenant { tenant_id } => Box::new(
|
||||||
|
dsl::tenant_id
|
||||||
|
.eq(tenant_id)
|
||||||
|
.and(dsl::org_id.is_null())
|
||||||
|
.and(dsl::merchant_id.is_null())
|
||||||
|
.and(dsl::profile_id.is_null())
|
||||||
|
.nullable(),
|
||||||
|
),
|
||||||
|
ThemeLineage::Organization { tenant_id, org_id } => Box::new(
|
||||||
|
dsl::tenant_id
|
||||||
|
.eq(tenant_id)
|
||||||
|
.and(dsl::org_id.eq(org_id))
|
||||||
|
.and(dsl::merchant_id.is_null())
|
||||||
|
.and(dsl::profile_id.is_null()),
|
||||||
|
),
|
||||||
|
ThemeLineage::Merchant {
|
||||||
|
tenant_id,
|
||||||
|
org_id,
|
||||||
|
merchant_id,
|
||||||
|
} => Box::new(
|
||||||
|
dsl::tenant_id
|
||||||
|
.eq(tenant_id)
|
||||||
|
.and(dsl::org_id.eq(org_id))
|
||||||
|
.and(dsl::merchant_id.eq(merchant_id))
|
||||||
|
.and(dsl::profile_id.is_null()),
|
||||||
|
),
|
||||||
|
ThemeLineage::Profile {
|
||||||
|
tenant_id,
|
||||||
|
org_id,
|
||||||
|
merchant_id,
|
||||||
|
profile_id,
|
||||||
|
} => Box::new(
|
||||||
|
dsl::tenant_id
|
||||||
|
.eq(tenant_id)
|
||||||
|
.and(dsl::org_id.eq(org_id))
|
||||||
|
.and(dsl::merchant_id.eq(merchant_id))
|
||||||
|
.and(dsl::profile_id.eq(profile_id)),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_by_lineage(
|
||||||
|
conn: &PgPooledConn,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> StorageResult<Self> {
|
||||||
|
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
||||||
|
conn,
|
||||||
|
Self::lineage_filter(lineage),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_by_theme_id_and_lineage(
|
||||||
|
conn: &PgPooledConn,
|
||||||
|
theme_id: String,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> StorageResult<Self> {
|
||||||
|
generics::generic_delete_one_with_result::<<Self as HasTable>::Table, _, _>(
|
||||||
|
conn,
|
||||||
|
dsl::theme_id
|
||||||
|
.eq(theme_id)
|
||||||
|
.and(Self::lineage_filter(lineage)),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1262,6 +1262,26 @@ diesel::table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
use crate::enums::diesel_exports::*;
|
||||||
|
|
||||||
|
themes (theme_id) {
|
||||||
|
#[max_length = 64]
|
||||||
|
theme_id -> Varchar,
|
||||||
|
#[max_length = 64]
|
||||||
|
tenant_id -> Varchar,
|
||||||
|
#[max_length = 64]
|
||||||
|
org_id -> Nullable<Varchar>,
|
||||||
|
#[max_length = 64]
|
||||||
|
merchant_id -> Nullable<Varchar>,
|
||||||
|
#[max_length = 64]
|
||||||
|
profile_id -> Nullable<Varchar>,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
last_modified_at -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use crate::enums::diesel_exports::*;
|
use crate::enums::diesel_exports::*;
|
||||||
@ -1408,6 +1428,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||||||
reverse_lookup,
|
reverse_lookup,
|
||||||
roles,
|
roles,
|
||||||
routing_algorithm,
|
routing_algorithm,
|
||||||
|
themes,
|
||||||
unified_translations,
|
unified_translations,
|
||||||
user_authentication_methods,
|
user_authentication_methods,
|
||||||
user_key_store,
|
user_key_store,
|
||||||
|
|||||||
@ -1208,6 +1208,26 @@ diesel::table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
use crate::enums::diesel_exports::*;
|
||||||
|
|
||||||
|
themes (theme_id) {
|
||||||
|
#[max_length = 64]
|
||||||
|
theme_id -> Varchar,
|
||||||
|
#[max_length = 64]
|
||||||
|
tenant_id -> Varchar,
|
||||||
|
#[max_length = 64]
|
||||||
|
org_id -> Nullable<Varchar>,
|
||||||
|
#[max_length = 64]
|
||||||
|
merchant_id -> Nullable<Varchar>,
|
||||||
|
#[max_length = 64]
|
||||||
|
profile_id -> Nullable<Varchar>,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
last_modified_at -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use crate::enums::diesel_exports::*;
|
use crate::enums::diesel_exports::*;
|
||||||
@ -1355,6 +1375,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||||||
reverse_lookup,
|
reverse_lookup,
|
||||||
roles,
|
roles,
|
||||||
routing_algorithm,
|
routing_algorithm,
|
||||||
|
themes,
|
||||||
unified_translations,
|
unified_translations,
|
||||||
user_authentication_methods,
|
user_authentication_methods,
|
||||||
user_key_store,
|
user_key_store,
|
||||||
|
|||||||
@ -6,8 +6,9 @@ use time::PrimitiveDateTime;
|
|||||||
use crate::{diesel_impl::OptionalDieselArray, enums::TotpStatus, schema::users};
|
use crate::{diesel_impl::OptionalDieselArray, enums::TotpStatus, schema::users};
|
||||||
|
|
||||||
pub mod dashboard_metadata;
|
pub mod dashboard_metadata;
|
||||||
|
|
||||||
pub mod sample_data;
|
pub mod sample_data;
|
||||||
|
pub mod theme;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
|
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
|
||||||
#[diesel(table_name = users, primary_key(user_id), check_for_backend(diesel::pg::Pg))]
|
#[diesel(table_name = users, primary_key(user_id), check_for_backend(diesel::pg::Pg))]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
|
|||||||
29
crates/diesel_models/src/user/theme.rs
Normal file
29
crates/diesel_models/src/user/theme.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use common_utils::id_type;
|
||||||
|
use diesel::{Identifiable, Insertable, Queryable, Selectable};
|
||||||
|
use time::PrimitiveDateTime;
|
||||||
|
|
||||||
|
use crate::schema::themes;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
|
||||||
|
#[diesel(table_name = themes, primary_key(theme_id), check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct Theme {
|
||||||
|
pub theme_id: String,
|
||||||
|
pub tenant_id: String,
|
||||||
|
pub org_id: Option<id_type::OrganizationId>,
|
||||||
|
pub merchant_id: Option<id_type::MerchantId>,
|
||||||
|
pub profile_id: Option<id_type::ProfileId>,
|
||||||
|
pub created_at: PrimitiveDateTime,
|
||||||
|
pub last_modified_at: PrimitiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
|
||||||
|
#[diesel(table_name = themes)]
|
||||||
|
pub struct ThemeNew {
|
||||||
|
pub theme_id: String,
|
||||||
|
pub tenant_id: String,
|
||||||
|
pub org_id: Option<id_type::OrganizationId>,
|
||||||
|
pub merchant_id: Option<id_type::MerchantId>,
|
||||||
|
pub profile_id: Option<id_type::ProfileId>,
|
||||||
|
pub created_at: PrimitiveDateTime,
|
||||||
|
pub last_modified_at: PrimitiveDateTime,
|
||||||
|
}
|
||||||
@ -145,6 +145,7 @@ pub trait GlobalStorageInterface:
|
|||||||
+ user::UserInterface
|
+ user::UserInterface
|
||||||
+ user_role::UserRoleInterface
|
+ user_role::UserRoleInterface
|
||||||
+ user_key_store::UserKeyStoreInterface
|
+ user_key_store::UserKeyStoreInterface
|
||||||
|
+ user::theme::ThemeInterface
|
||||||
+ 'static
|
+ 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use common_enums::enums::MerchantStorageScheme;
|
use common_enums::enums::MerchantStorageScheme;
|
||||||
use common_utils::{errors::CustomResult, id_type, pii, types::keymanager::KeyManagerState};
|
use common_utils::{
|
||||||
|
errors::CustomResult,
|
||||||
|
id_type, pii,
|
||||||
|
types::{keymanager::KeyManagerState, theme::ThemeLineage},
|
||||||
|
};
|
||||||
use diesel_models::{
|
use diesel_models::{
|
||||||
enums,
|
enums,
|
||||||
enums::ProcessTrackerStatus,
|
enums::ProcessTrackerStatus,
|
||||||
@ -34,7 +38,7 @@ use time::PrimitiveDateTime;
|
|||||||
use super::{
|
use super::{
|
||||||
dashboard_metadata::DashboardMetadataInterface,
|
dashboard_metadata::DashboardMetadataInterface,
|
||||||
role::RoleInterface,
|
role::RoleInterface,
|
||||||
user::{sample_data::BatchSampleDataInterface, UserInterface},
|
user::{sample_data::BatchSampleDataInterface, theme::ThemeInterface, UserInterface},
|
||||||
user_authentication_method::UserAuthenticationMethodInterface,
|
user_authentication_method::UserAuthenticationMethodInterface,
|
||||||
user_key_store::UserKeyStoreInterface,
|
user_key_store::UserKeyStoreInterface,
|
||||||
user_role::{ListUserRolesByOrgIdPayload, ListUserRolesByUserIdPayload, UserRoleInterface},
|
user_role::{ListUserRolesByOrgIdPayload, ListUserRolesByUserIdPayload, UserRoleInterface},
|
||||||
@ -3683,3 +3687,30 @@ impl UserAuthenticationMethodInterface for KafkaStore {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ThemeInterface for KafkaStore {
|
||||||
|
async fn insert_theme(
|
||||||
|
&self,
|
||||||
|
theme: storage::theme::ThemeNew,
|
||||||
|
) -> CustomResult<storage::theme::Theme, errors::StorageError> {
|
||||||
|
self.diesel_store.insert_theme(theme).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_theme_by_lineage(
|
||||||
|
&self,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::theme::Theme, errors::StorageError> {
|
||||||
|
self.diesel_store.find_theme_by_lineage(lineage).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_theme_by_lineage_and_theme_id(
|
||||||
|
&self,
|
||||||
|
theme_id: String,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::theme::Theme, errors::StorageError> {
|
||||||
|
self.diesel_store
|
||||||
|
.delete_theme_by_lineage_and_theme_id(theme_id, lineage)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use crate::{
|
|||||||
services::Store,
|
services::Store,
|
||||||
};
|
};
|
||||||
pub mod sample_data;
|
pub mod sample_data;
|
||||||
|
pub mod theme;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait UserInterface {
|
pub trait UserInterface {
|
||||||
|
|||||||
203
crates/router/src/db/user/theme.rs
Normal file
203
crates/router/src/db/user/theme.rs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
use common_utils::types::theme::ThemeLineage;
|
||||||
|
use diesel_models::user::theme as storage;
|
||||||
|
use error_stack::report;
|
||||||
|
|
||||||
|
use super::MockDb;
|
||||||
|
use crate::{
|
||||||
|
connection,
|
||||||
|
core::errors::{self, CustomResult},
|
||||||
|
services::Store,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait ThemeInterface {
|
||||||
|
async fn insert_theme(
|
||||||
|
&self,
|
||||||
|
theme: storage::ThemeNew,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError>;
|
||||||
|
|
||||||
|
async fn find_theme_by_lineage(
|
||||||
|
&self,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError>;
|
||||||
|
|
||||||
|
async fn delete_theme_by_lineage_and_theme_id(
|
||||||
|
&self,
|
||||||
|
theme_id: String,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ThemeInterface for Store {
|
||||||
|
async fn insert_theme(
|
||||||
|
&self,
|
||||||
|
theme: storage::ThemeNew,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError> {
|
||||||
|
let conn = connection::pg_connection_write(self).await?;
|
||||||
|
theme
|
||||||
|
.insert(&conn)
|
||||||
|
.await
|
||||||
|
.map_err(|error| report!(errors::StorageError::from(error)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_theme_by_lineage(
|
||||||
|
&self,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError> {
|
||||||
|
let conn = connection::pg_connection_read(self).await?;
|
||||||
|
storage::Theme::find_by_lineage(&conn, lineage)
|
||||||
|
.await
|
||||||
|
.map_err(|error| report!(errors::StorageError::from(error)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_theme_by_lineage_and_theme_id(
|
||||||
|
&self,
|
||||||
|
theme_id: String,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError> {
|
||||||
|
let conn = connection::pg_connection_write(self).await?;
|
||||||
|
storage::Theme::delete_by_theme_id_and_lineage(&conn, theme_id, lineage)
|
||||||
|
.await
|
||||||
|
.map_err(|error| report!(errors::StorageError::from(error)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_theme_with_lineage(theme: &storage::Theme, lineage: &ThemeLineage) -> bool {
|
||||||
|
match lineage {
|
||||||
|
ThemeLineage::Tenant { tenant_id } => {
|
||||||
|
&theme.tenant_id == tenant_id
|
||||||
|
&& theme.org_id.is_none()
|
||||||
|
&& theme.merchant_id.is_none()
|
||||||
|
&& theme.profile_id.is_none()
|
||||||
|
}
|
||||||
|
ThemeLineage::Organization { tenant_id, org_id } => {
|
||||||
|
&theme.tenant_id == tenant_id
|
||||||
|
&& theme
|
||||||
|
.org_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|org_id_inner| org_id_inner == org_id)
|
||||||
|
&& theme.merchant_id.is_none()
|
||||||
|
&& theme.profile_id.is_none()
|
||||||
|
}
|
||||||
|
ThemeLineage::Merchant {
|
||||||
|
tenant_id,
|
||||||
|
org_id,
|
||||||
|
merchant_id,
|
||||||
|
} => {
|
||||||
|
&theme.tenant_id == tenant_id
|
||||||
|
&& theme
|
||||||
|
.org_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|org_id_inner| org_id_inner == org_id)
|
||||||
|
&& theme
|
||||||
|
.merchant_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|merchant_id_inner| merchant_id_inner == merchant_id)
|
||||||
|
&& theme.profile_id.is_none()
|
||||||
|
}
|
||||||
|
ThemeLineage::Profile {
|
||||||
|
tenant_id,
|
||||||
|
org_id,
|
||||||
|
merchant_id,
|
||||||
|
profile_id,
|
||||||
|
} => {
|
||||||
|
&theme.tenant_id == tenant_id
|
||||||
|
&& theme
|
||||||
|
.org_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|org_id_inner| org_id_inner == org_id)
|
||||||
|
&& theme
|
||||||
|
.merchant_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|merchant_id_inner| merchant_id_inner == merchant_id)
|
||||||
|
&& theme
|
||||||
|
.profile_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|profile_id_inner| profile_id_inner == profile_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ThemeInterface for MockDb {
|
||||||
|
async fn insert_theme(
|
||||||
|
&self,
|
||||||
|
new_theme: storage::ThemeNew,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError> {
|
||||||
|
let mut themes = self.themes.lock().await;
|
||||||
|
for theme in themes.iter() {
|
||||||
|
if new_theme.theme_id == theme.theme_id {
|
||||||
|
return Err(errors::StorageError::DuplicateValue {
|
||||||
|
entity: "theme_id",
|
||||||
|
key: None,
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_theme.tenant_id == theme.tenant_id
|
||||||
|
&& new_theme.org_id == theme.org_id
|
||||||
|
&& new_theme.merchant_id == theme.merchant_id
|
||||||
|
&& new_theme.profile_id == theme.profile_id
|
||||||
|
{
|
||||||
|
return Err(errors::StorageError::DuplicateValue {
|
||||||
|
entity: "lineage",
|
||||||
|
key: None,
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let theme = storage::Theme {
|
||||||
|
theme_id: new_theme.theme_id,
|
||||||
|
tenant_id: new_theme.tenant_id,
|
||||||
|
org_id: new_theme.org_id,
|
||||||
|
merchant_id: new_theme.merchant_id,
|
||||||
|
profile_id: new_theme.profile_id,
|
||||||
|
created_at: new_theme.created_at,
|
||||||
|
last_modified_at: new_theme.last_modified_at,
|
||||||
|
};
|
||||||
|
themes.push(theme.clone());
|
||||||
|
|
||||||
|
Ok(theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_theme_by_lineage(
|
||||||
|
&self,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError> {
|
||||||
|
let themes = self.themes.lock().await;
|
||||||
|
themes
|
||||||
|
.iter()
|
||||||
|
.find(|theme| check_theme_with_lineage(theme, &lineage))
|
||||||
|
.cloned()
|
||||||
|
.ok_or(
|
||||||
|
errors::StorageError::ValueNotFound(format!(
|
||||||
|
"Theme with lineage {:?} not found",
|
||||||
|
lineage
|
||||||
|
))
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_theme_by_lineage_and_theme_id(
|
||||||
|
&self,
|
||||||
|
theme_id: String,
|
||||||
|
lineage: ThemeLineage,
|
||||||
|
) -> CustomResult<storage::Theme, errors::StorageError> {
|
||||||
|
let mut themes = self.themes.lock().await;
|
||||||
|
let index = themes
|
||||||
|
.iter()
|
||||||
|
.position(|theme| {
|
||||||
|
theme.theme_id == theme_id && check_theme_with_lineage(theme, &lineage)
|
||||||
|
})
|
||||||
|
.ok_or(errors::StorageError::ValueNotFound(format!(
|
||||||
|
"Theme with id {} and lineage {:?} not found",
|
||||||
|
theme_id, lineage
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
let theme = themes.remove(index);
|
||||||
|
|
||||||
|
Ok(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -60,6 +60,7 @@ pub struct MockDb {
|
|||||||
pub user_key_store: Arc<Mutex<Vec<store::user_key_store::UserKeyStore>>>,
|
pub user_key_store: Arc<Mutex<Vec<store::user_key_store::UserKeyStore>>>,
|
||||||
pub user_authentication_methods:
|
pub user_authentication_methods:
|
||||||
Arc<Mutex<Vec<store::user_authentication_method::UserAuthenticationMethod>>>,
|
Arc<Mutex<Vec<store::user_authentication_method::UserAuthenticationMethod>>>,
|
||||||
|
pub themes: Arc<Mutex<Vec<store::user::theme::Theme>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockDb {
|
impl MockDb {
|
||||||
@ -105,6 +106,7 @@ impl MockDb {
|
|||||||
roles: Default::default(),
|
roles: Default::default(),
|
||||||
user_key_store: Default::default(),
|
user_key_store: Default::default(),
|
||||||
user_authentication_methods: Default::default(),
|
user_authentication_methods: Default::default(),
|
||||||
|
themes: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
migrations/2024-11-06-121933_setup-themes-table/down.sql
Normal file
3
migrations/2024-11-06-121933_setup-themes-table/down.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- This file should undo anything in `up.sql`
|
||||||
|
DROP INDEX IF EXISTS themes_index;
|
||||||
|
DROP TABLE IF EXISTS themes;
|
||||||
17
migrations/2024-11-06-121933_setup-themes-table/up.sql
Normal file
17
migrations/2024-11-06-121933_setup-themes-table/up.sql
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
-- Your SQL goes here
|
||||||
|
CREATE TABLE IF NOT EXISTS themes (
|
||||||
|
theme_id VARCHAR(64) PRIMARY KEY,
|
||||||
|
tenant_id VARCHAR(64) NOT NULL,
|
||||||
|
org_id VARCHAR(64),
|
||||||
|
merchant_id VARCHAR(64),
|
||||||
|
profile_id VARCHAR(64),
|
||||||
|
created_at TIMESTAMP NOT NULL,
|
||||||
|
last_modified_at TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS themes_index ON themes (
|
||||||
|
tenant_id,
|
||||||
|
COALESCE(org_id, '0'),
|
||||||
|
COALESCE(merchant_id, '0'),
|
||||||
|
COALESCE(profile_id, '0')
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user