diff --git a/crates/api_models/src/user/dashboard_metadata.rs b/crates/api_models/src/user/dashboard_metadata.rs index 11588bbfba..66831c7aeb 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 d65f6c5efa..7ca65ac4b7 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -498,4 +498,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 b1cb034eb1..d91a407812 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 7b37f529f8..002452a8a3 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::{StorageErrorExt, UserErrors, UserResponse, UserResult}; #[cfg(feature = "email")] @@ -310,6 +311,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) } @@ -483,8 +498,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, @@ -523,6 +538,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 { @@ -706,6 +735,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 24ff292870..82f9556476 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 8e2ac0b6ad..49dd43313c 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,13 +126,13 @@ 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(), @@ -132,6 +141,24 @@ impl DashboardMetadataInterface for Store { .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) + .into_report() + } } #[async_trait::async_trait] @@ -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 0a9030bae2..029b1a5776 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 5e4017a3cb..9c00809238 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 bcf270010e..ac3d918a34 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)