Skip to content

Commit

Permalink
feat(user): implement force password reset (#3572)
Browse files Browse the repository at this point in the history
  • Loading branch information
apoorvdixit88 authored Feb 9, 2024
1 parent bebaf41 commit cfa10aa
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 11 deletions.
4 changes: 4 additions & 0 deletions crates/api_models/src/user/dashboard_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub enum SetMetaDataRequest {
ConfigureWoocom,
SetupWoocomWebhook,
IsMultipleConfiguration,
#[serde(skip)]
IsChangePasswordRequired,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
Expand Down Expand Up @@ -110,6 +112,7 @@ pub enum GetMetaDataRequest {
ConfigureWoocom,
SetupWoocomWebhook,
IsMultipleConfiguration,
IsChangePasswordRequired,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
Expand Down Expand Up @@ -146,4 +149,5 @@ pub enum GetMetaDataResponse {
ConfigureWoocom(bool),
SetupWoocomWebhook(bool),
IsMultipleConfiguration(bool),
IsChangePasswordRequired(bool),
}
1 change: 1 addition & 0 deletions crates/diesel_models/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,4 +498,5 @@ pub enum DashboardMetadata {
ConfigureWoocom,
SetupWoocomWebhook,
IsMultipleConfiguration,
IsChangePasswordRequired,
}
18 changes: 17 additions & 1 deletion crates/diesel_models/src/query/dashboard_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<Self> {
generics::generic_delete_one_with_result::<<Self as HasTable>::Table, _, _>(
conn,
dsl::user_id
.eq(user_id)
.and(dsl::merchant_id.eq(merchant_id))
.and(dsl::data_key.eq(data_key)),
)
.await
}
}
46 changes: 43 additions & 3 deletions crates/router/src/core/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
18 changes: 18 additions & 0 deletions crates/router/src/core/user/dashboard_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ fn parse_set_request(data_enum: api::SetMetaDataRequest) -> UserResult<types::Me
api::SetMetaDataRequest::IsMultipleConfiguration => {
Ok(types::MetaData::IsMultipleConfiguration(true))
}
api::SetMetaDataRequest::IsChangePasswordRequired => {
Ok(types::MetaData::IsChangePasswordRequired(true))
}
}
}

Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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(),
)),
}
}

Expand Down Expand Up @@ -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
}
}
}

Expand Down
62 changes: 58 additions & 4 deletions crates/router/src/db/dashboard_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub trait DashboardMetadataInterface {
&self,
metadata: storage::DashboardMetadataNew,
) -> CustomResult<storage::DashboardMetadata, errors::StorageError>;

async fn update_metadata(
&self,
user_id: Option<String>,
Expand All @@ -30,18 +31,26 @@ pub trait DashboardMetadataInterface {
org_id: &str,
data_keys: Vec<enums::DashboardMetadata>,
) -> CustomResult<Vec<storage::DashboardMetadata>, errors::StorageError>;

async fn find_merchant_scoped_dashboard_metadata(
&self,
merchant_id: &str,
org_id: &str,
data_keys: Vec<enums::DashboardMetadata>,
) -> CustomResult<Vec<storage::DashboardMetadata>, 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<bool, errors::StorageError>;

async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key(
&self,
user_id: &str,
merchant_id: &str,
data_key: enums::DashboardMetadata,
) -> CustomResult<storage::DashboardMetadata, errors::StorageError>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -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<bool, errors::StorageError> {
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<storage::DashboardMetadata, errors::StorageError> {
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)
Expand Down Expand Up @@ -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,
Expand All @@ -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<storage::DashboardMetadata, errors::StorageError> {
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)
}
}
21 changes: 19 additions & 2 deletions crates/router/src/db/kafka_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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<bool, errors::StorageError> {
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<storage::DashboardMetadata, errors::StorageError> {
self.diesel_store
.delete_user_scoped_dashboard_metadata_by_merchant_id_data_key(
user_id,
merchant_id,
data_key,
)
.await
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/router/src/types/domain/user/dashboard_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub enum MetaData {
ConfigureWoocom(bool),
SetupWoocomWebhook(bool),
IsMultipleConfiguration(bool),
IsChangePasswordRequired(bool),
}

impl From<&MetaData> for DBEnum {
Expand All @@ -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,
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion crates/router/src/utils/user/dashboard_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit cfa10aa

Please sign in to comment.