diff --git a/crates/api_models/src/user/dashboard_metadata.rs b/crates/api_models/src/user/dashboard_metadata.rs index 11588bbfbaf..66831c7aeb8 100644 --- a/crates/api_models/src/user/dashboard_metadata.rs +++ b/crates/api_models/src/user/dashboard_metadata.rs @@ -24,6 +24,8 @@ pub enum SetMetaDataRequest { ConfigureWoocom, SetupWoocomWebhook, IsMultipleConfiguration, + #[serde(skip)] + IsChangePasswordRequired, } #[derive(Debug, serde::Deserialize, serde::Serialize)] @@ -110,6 +112,7 @@ pub enum GetMetaDataRequest { ConfigureWoocom, SetupWoocomWebhook, IsMultipleConfiguration, + IsChangePasswordRequired, } #[derive(Debug, serde::Deserialize, serde::Serialize)] @@ -146,4 +149,5 @@ pub enum GetMetaDataResponse { ConfigureWoocom(bool), SetupWoocomWebhook(bool), IsMultipleConfiguration(bool), + IsChangePasswordRequired(bool), } diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index babffdbc4a8..93a98dc824b 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -511,4 +511,5 @@ pub enum DashboardMetadata { ConfigureWoocom, SetupWoocomWebhook, IsMultipleConfiguration, + IsChangePasswordRequired, } diff --git a/crates/diesel_models/src/query/dashboard_metadata.rs b/crates/diesel_models/src/query/dashboard_metadata.rs index b1cb034eb1f..d91a4078128 100644 --- a/crates/diesel_models/src/query/dashboard_metadata.rs +++ b/crates/diesel_models/src/query/dashboard_metadata.rs @@ -105,7 +105,7 @@ impl DashboardMetadata { .await } - pub async fn delete_user_scoped_dashboard_metadata_by_merchant_id( + pub async fn delete_all_user_scoped_dashboard_metadata_by_merchant_id( conn: &PgPooledConn, user_id: String, merchant_id: String, @@ -118,4 +118,20 @@ impl DashboardMetadata { ) .await } + + pub async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + conn: &PgPooledConn, + user_id: String, + merchant_id: String, + data_key: enums::DashboardMetadata, + ) -> StorageResult { + generics::generic_delete_one_with_result::<::Table, _, _>( + conn, + dsl::user_id + .eq(user_id) + .and(dsl::merchant_id.eq(merchant_id)) + .and(dsl::data_key.eq(data_key)), + ) + .await + } } diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 41a407bd670..58d702cbac1 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -8,8 +8,9 @@ use error_stack::ResultExt; use masking::ExposeInterface; #[cfg(feature = "email")] use router_env::env; -#[cfg(feature = "email")] use router_env::logger; +#[cfg(not(feature = "email"))] +use user_api::dashboard_metadata::SetMetaDataRequest; use super::errors::{UserErrors, UserResponse, UserResult}; #[cfg(feature = "email")] @@ -308,6 +309,20 @@ pub async fn change_password( .await .change_context(UserErrors::InternalServerError)?; + #[cfg(not(feature = "email"))] + { + state + .store + .delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + &user_from_token.user_id, + &user_from_token.merchant_id, + diesel_models::enums::DashboardMetadata::IsChangePasswordRequired, + ) + .await + .map_err(|e| logger::error!("Error while deleting dashboard metadata {}", e)) + .ok(); + } + Ok(ApplicationResponse::StatusOk) } @@ -475,8 +490,8 @@ pub async fn invite_user( .insert_user_role(UserRoleNew { user_id: new_user.get_user_id().to_owned(), merchant_id: user_from_token.merchant_id.clone(), - role_id: request.role_id, - org_id: user_from_token.org_id, + role_id: request.role_id.clone(), + org_id: user_from_token.org_id.clone(), status: invitation_status, created_by: user_from_token.user_id.clone(), last_modified_by: user_from_token.user_id, @@ -515,6 +530,20 @@ pub async fn invite_user( #[cfg(not(feature = "email"))] { is_email_sent = false; + let invited_user_token = auth::UserFromToken { + user_id: new_user.get_user_id(), + merchant_id: user_from_token.merchant_id, + org_id: user_from_token.org_id, + role_id: request.role_id, + }; + + let set_metadata_request = SetMetaDataRequest::IsChangePasswordRequired; + dashboard_metadata::set_metadata( + state.clone(), + invited_user_token, + set_metadata_request, + ) + .await?; } Ok(ApplicationResponse::Json(user_api::InviteUserResponse { @@ -692,6 +721,17 @@ async fn handle_new_user_invitation( #[cfg(not(feature = "email"))] { is_email_sent = false; + + let invited_user_token = auth::UserFromToken { + user_id: new_user.get_user_id(), + merchant_id: user_from_token.merchant_id.clone(), + org_id: user_from_token.org_id.clone(), + role_id: request.role_id.clone(), + }; + + let set_metadata_request = SetMetaDataRequest::IsChangePasswordRequired; + dashboard_metadata::set_metadata(state.clone(), invited_user_token, set_metadata_request) + .await?; } Ok(InviteMultipleUserResponse { diff --git a/crates/router/src/core/user/dashboard_metadata.rs b/crates/router/src/core/user/dashboard_metadata.rs index 24ff292870e..82f95564768 100644 --- a/crates/router/src/core/user/dashboard_metadata.rs +++ b/crates/router/src/core/user/dashboard_metadata.rs @@ -105,6 +105,9 @@ fn parse_set_request(data_enum: api::SetMetaDataRequest) -> UserResult { Ok(types::MetaData::IsMultipleConfiguration(true)) } + api::SetMetaDataRequest::IsChangePasswordRequired => { + Ok(types::MetaData::IsChangePasswordRequired(true)) + } } } @@ -131,6 +134,7 @@ fn parse_get_request(data_enum: api::GetMetaDataRequest) -> DBEnum { api::GetMetaDataRequest::ConfigureWoocom => DBEnum::ConfigureWoocom, api::GetMetaDataRequest::SetupWoocomWebhook => DBEnum::SetupWoocomWebhook, api::GetMetaDataRequest::IsMultipleConfiguration => DBEnum::IsMultipleConfiguration, + api::GetMetaDataRequest::IsChangePasswordRequired => DBEnum::IsChangePasswordRequired, } } @@ -207,6 +211,9 @@ fn into_response( DBEnum::IsMultipleConfiguration => Ok(api::GetMetaDataResponse::IsMultipleConfiguration( data.is_some(), )), + DBEnum::IsChangePasswordRequired => Ok(api::GetMetaDataResponse::IsChangePasswordRequired( + data.is_some(), + )), } } @@ -520,6 +527,17 @@ async fn insert_metadata( ) .await } + types::MetaData::IsChangePasswordRequired(data) => { + utils::insert_user_scoped_metadata_to_db( + state, + user.user_id, + user.merchant_id, + user.org_id, + metadata_key, + data, + ) + .await + } } } diff --git a/crates/router/src/db/dashboard_metadata.rs b/crates/router/src/db/dashboard_metadata.rs index 8e2ac0b6ad3..49dd43313c4 100644 --- a/crates/router/src/db/dashboard_metadata.rs +++ b/crates/router/src/db/dashboard_metadata.rs @@ -14,6 +14,7 @@ pub trait DashboardMetadataInterface { &self, metadata: storage::DashboardMetadataNew, ) -> CustomResult; + async fn update_metadata( &self, user_id: Option, @@ -30,6 +31,7 @@ pub trait DashboardMetadataInterface { org_id: &str, data_keys: Vec, ) -> CustomResult, errors::StorageError>; + async fn find_merchant_scoped_dashboard_metadata( &self, merchant_id: &str, @@ -37,11 +39,18 @@ pub trait DashboardMetadataInterface { data_keys: Vec, ) -> CustomResult, errors::StorageError>; - async fn delete_user_scoped_dashboard_metadata_by_merchant_id( + async fn delete_all_user_scoped_dashboard_metadata_by_merchant_id( &self, user_id: &str, merchant_id: &str, ) -> CustomResult; + + async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + &self, + user_id: &str, + merchant_id: &str, + data_key: enums::DashboardMetadata, + ) -> CustomResult; } #[async_trait::async_trait] @@ -117,16 +126,34 @@ impl DashboardMetadataInterface for Store { .map_err(Into::into) .into_report() } - async fn delete_user_scoped_dashboard_metadata_by_merchant_id( + async fn delete_all_user_scoped_dashboard_metadata_by_merchant_id( &self, user_id: &str, merchant_id: &str, ) -> CustomResult { let conn = connection::pg_connection_write(self).await?; - storage::DashboardMetadata::delete_user_scoped_dashboard_metadata_by_merchant_id( + storage::DashboardMetadata::delete_all_user_scoped_dashboard_metadata_by_merchant_id( + &conn, + user_id.to_owned(), + merchant_id.to_owned(), + ) + .await + .map_err(Into::into) + .into_report() + } + + async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + &self, + user_id: &str, + merchant_id: &str, + data_key: enums::DashboardMetadata, + ) -> CustomResult { + let conn = connection::pg_connection_write(self).await?; + storage::DashboardMetadata::delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( &conn, user_id.to_owned(), merchant_id.to_owned(), + data_key, ) .await .map_err(Into::into) @@ -267,7 +294,7 @@ impl DashboardMetadataInterface for MockDb { } Ok(query_result) } - async fn delete_user_scoped_dashboard_metadata_by_merchant_id( + async fn delete_all_user_scoped_dashboard_metadata_by_merchant_id( &self, user_id: &str, merchant_id: &str, @@ -294,4 +321,31 @@ impl DashboardMetadataInterface for MockDb { Ok(true) } + + async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + &self, + user_id: &str, + merchant_id: &str, + data_key: enums::DashboardMetadata, + ) -> CustomResult { + let mut dashboard_metadata = self.dashboard_metadata.lock().await; + + let index_to_remove = dashboard_metadata + .iter() + .position(|metadata_inner| { + metadata_inner + .user_id + .as_deref() + .map_or(false, |user_id_inner| user_id_inner == user_id) + && metadata_inner.merchant_id == merchant_id + && metadata_inner.data_key == data_key + }) + .ok_or(errors::StorageError::ValueNotFound( + "No data found".to_string(), + ))?; + + let deleted_value = dashboard_metadata.swap_remove(index_to_remove); + + Ok(deleted_value) + } } diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 0a9030bae29..029b1a57764 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1964,6 +1964,7 @@ impl UserRoleInterface for KafkaStore { .update_user_role_by_user_id_merchant_id(user_id, merchant_id, update) .await } + async fn delete_user_role_by_user_id_merchant_id( &self, user_id: &str, @@ -2021,6 +2022,7 @@ impl DashboardMetadataInterface for KafkaStore { .find_user_scoped_dashboard_metadata(user_id, merchant_id, org_id, data_keys) .await } + async fn find_merchant_scoped_dashboard_metadata( &self, merchant_id: &str, @@ -2032,13 +2034,28 @@ impl DashboardMetadataInterface for KafkaStore { .await } - async fn delete_user_scoped_dashboard_metadata_by_merchant_id( + async fn delete_all_user_scoped_dashboard_metadata_by_merchant_id( &self, user_id: &str, merchant_id: &str, ) -> CustomResult { self.diesel_store - .delete_user_scoped_dashboard_metadata_by_merchant_id(user_id, merchant_id) + .delete_all_user_scoped_dashboard_metadata_by_merchant_id(user_id, merchant_id) + .await + } + + async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + &self, + user_id: &str, + merchant_id: &str, + data_key: enums::DashboardMetadata, + ) -> CustomResult { + self.diesel_store + .delete_user_scoped_dashboard_metadata_by_merchant_id_data_key( + user_id, + merchant_id, + data_key, + ) .await } } diff --git a/crates/router/src/types/domain/user/dashboard_metadata.rs b/crates/router/src/types/domain/user/dashboard_metadata.rs index 5e4017a3cb1..9c00809238e 100644 --- a/crates/router/src/types/domain/user/dashboard_metadata.rs +++ b/crates/router/src/types/domain/user/dashboard_metadata.rs @@ -25,6 +25,7 @@ pub enum MetaData { ConfigureWoocom(bool), SetupWoocomWebhook(bool), IsMultipleConfiguration(bool), + IsChangePasswordRequired(bool), } impl From<&MetaData> for DBEnum { @@ -51,6 +52,7 @@ impl From<&MetaData> for DBEnum { MetaData::ConfigureWoocom(_) => Self::ConfigureWoocom, MetaData::SetupWoocomWebhook(_) => Self::SetupWoocomWebhook, MetaData::IsMultipleConfiguration(_) => Self::IsMultipleConfiguration, + MetaData::IsChangePasswordRequired(_) => Self::IsChangePasswordRequired, } } } diff --git a/crates/router/src/utils/user/dashboard_metadata.rs b/crates/router/src/utils/user/dashboard_metadata.rs index bcf270010ea..ac3d918a34f 100644 --- a/crates/router/src/utils/user/dashboard_metadata.rs +++ b/crates/router/src/utils/user/dashboard_metadata.rs @@ -219,7 +219,9 @@ pub fn separate_metadata_type_based_on_scope( | DBEnum::ConfigureWoocom | DBEnum::SetupWoocomWebhook | DBEnum::IsMultipleConfiguration => merchant_scoped.push(key), - DBEnum::Feedback | DBEnum::ProdIntent => user_scoped.push(key), + DBEnum::Feedback | DBEnum::ProdIntent | DBEnum::IsChangePasswordRequired => { + user_scoped.push(key) + } } } (merchant_scoped, user_scoped)