mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 09:07:09 +08:00
feat(user): implement invitations api (#5769)
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
use common_enums::PermissionGroup;
|
||||
use common_utils::pii;
|
||||
use masking::Secret;
|
||||
|
||||
pub mod role;
|
||||
|
||||
@ -138,3 +139,11 @@ pub struct ListUsersInEntityResponse {
|
||||
pub email: pii::Email,
|
||||
pub roles: Vec<role::MinimalRoleInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct ListInvitationForUserResponse {
|
||||
pub entity_id: String,
|
||||
pub entity_type: common_enums::EntityType,
|
||||
pub entity_name: Option<Secret<String>>,
|
||||
pub role_id: String,
|
||||
}
|
||||
|
||||
@ -8,7 +8,11 @@ use error_stack::{report, ResultExt};
|
||||
use router_env::logger;
|
||||
|
||||
use crate::{
|
||||
enums::UserRoleVersion, errors, query::generics, schema::user_roles::dsl, user_role::*,
|
||||
enums::{UserRoleVersion, UserStatus},
|
||||
errors,
|
||||
query::generics,
|
||||
schema::user_roles::dsl,
|
||||
user_role::*,
|
||||
PgPooledConn, StorageResult,
|
||||
};
|
||||
|
||||
@ -201,6 +205,7 @@ impl UserRole {
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn generic_user_roles_list_for_user(
|
||||
conn: &PgPooledConn,
|
||||
user_id: String,
|
||||
@ -208,7 +213,9 @@ impl UserRole {
|
||||
merchant_id: Option<id_type::MerchantId>,
|
||||
profile_id: Option<id_type::ProfileId>,
|
||||
entity_id: Option<String>,
|
||||
status: Option<UserStatus>,
|
||||
version: Option<UserRoleVersion>,
|
||||
limit: Option<u32>,
|
||||
) -> StorageResult<Vec<Self>> {
|
||||
let mut query = <Self as HasTable>::table()
|
||||
.filter(dsl::user_id.eq(user_id))
|
||||
@ -234,6 +241,14 @@ impl UserRole {
|
||||
query = query.filter(dsl::version.eq(version));
|
||||
}
|
||||
|
||||
if let Some(status) = status {
|
||||
query = query.filter(dsl::status.eq(status));
|
||||
}
|
||||
|
||||
if let Some(limit) = limit {
|
||||
query = query.limit(limit.into());
|
||||
}
|
||||
|
||||
router_env::logger::debug!(query = %debug_query::<Pg,_>(&query).to_string());
|
||||
|
||||
match generics::db_metrics::track_database_call::<Self, _, _>(
|
||||
|
||||
@ -26,7 +26,7 @@ pub struct UserRole {
|
||||
pub version: enums::UserRoleVersion,
|
||||
}
|
||||
|
||||
fn get_entity_id_and_type(user_role: &UserRole) -> (Option<String>, Option<EntityType>) {
|
||||
pub fn get_entity_id_and_type(user_role: &UserRole) -> (Option<String>, Option<EntityType>) {
|
||||
match (user_role.version, user_role.role_id.as_str()) {
|
||||
(enums::UserRoleVersion::V1, consts::ROLE_ID_ORGANIZATION_ADMIN) => (
|
||||
user_role
|
||||
|
||||
@ -33,7 +33,10 @@ use crate::services::email::types as email_types;
|
||||
use crate::{
|
||||
consts,
|
||||
core::encryption::send_request_to_key_service_for_user,
|
||||
db::domain::user_authentication_method::DEFAULT_USER_AUTH_METHOD,
|
||||
db::{
|
||||
domain::user_authentication_method::DEFAULT_USER_AUTH_METHOD,
|
||||
user_role::ListUserRolesByUserIdPayload,
|
||||
},
|
||||
routes::{app::ReqState, SessionState},
|
||||
services::{authentication as auth, authorization::roles, openidconnect, ApplicationResponse},
|
||||
types::{domain, transformers::ForeignInto},
|
||||
@ -2282,22 +2285,20 @@ pub async fn list_orgs_for_user(
|
||||
) -> UserResponse<Vec<user_api::ListOrgsForUserResponse>> {
|
||||
let orgs = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(
|
||||
user_from_token.user_id.as_str(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload {
|
||||
user_id: user_from_token.user_id.as_str(),
|
||||
org_id: None,
|
||||
merchant_id: None,
|
||||
profile_id: None,
|
||||
entity_id: None,
|
||||
version: None,
|
||||
status: Some(UserStatus::Active),
|
||||
limit: None,
|
||||
})
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into_iter()
|
||||
.filter_map(|user_role| {
|
||||
(user_role.status == UserStatus::Active)
|
||||
.then_some(user_role.org_id)
|
||||
.flatten()
|
||||
})
|
||||
.filter_map(|user_role| user_role.org_id)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let resp = futures::future::try_join_all(
|
||||
@ -2311,7 +2312,11 @@ pub async fn list_orgs_for_user(
|
||||
org_id: org.get_organization_id(),
|
||||
org_name: org.get_organization_name(),
|
||||
})
|
||||
.collect();
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if resp.is_empty() {
|
||||
Err(UserErrors::InternalServerError).attach_printable("No orgs found for a user")?;
|
||||
}
|
||||
|
||||
Ok(ApplicationResponse::Json(resp))
|
||||
}
|
||||
@ -2344,26 +2349,24 @@ pub async fn list_merchants_for_user_in_org(
|
||||
merchant_id: merchant_account.get_id().to_owned(),
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
let merchant_ids = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(
|
||||
user_from_token.user_id.as_str(),
|
||||
Some(&user_from_token.org_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload {
|
||||
user_id: user_from_token.user_id.as_str(),
|
||||
org_id: Some(&user_from_token.org_id),
|
||||
merchant_id: None,
|
||||
profile_id: None,
|
||||
entity_id: None,
|
||||
version: None,
|
||||
status: Some(UserStatus::Active),
|
||||
limit: None,
|
||||
})
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into_iter()
|
||||
.filter_map(|user_role| {
|
||||
(user_role.status == UserStatus::Active)
|
||||
.then_some(user_role.merchant_id)
|
||||
.flatten()
|
||||
})
|
||||
.filter_map(|user_role| user_role.merchant_id)
|
||||
.collect::<HashSet<_>>()
|
||||
.into_iter()
|
||||
.collect();
|
||||
@ -2379,9 +2382,13 @@ pub async fn list_merchants_for_user_in_org(
|
||||
merchant_id: merchant_account.get_id().to_owned(),
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
if merchant_accounts.is_empty() {
|
||||
Err(UserErrors::InternalServerError).attach_printable("No merchant found for a user")?;
|
||||
}
|
||||
|
||||
Ok(ApplicationResponse::Json(merchant_accounts))
|
||||
}
|
||||
|
||||
@ -2427,26 +2434,24 @@ pub async fn list_profiles_for_user_in_org_and_merchant_account(
|
||||
profile_name: profile.profile_name,
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
let profile_ids = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(
|
||||
user_from_token.user_id.as_str(),
|
||||
Some(&user_from_token.org_id),
|
||||
Some(&user_from_token.merchant_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload {
|
||||
user_id: user_from_token.user_id.as_str(),
|
||||
org_id: Some(&user_from_token.org_id),
|
||||
merchant_id: Some(&user_from_token.merchant_id),
|
||||
profile_id: None,
|
||||
entity_id: None,
|
||||
version: None,
|
||||
status: Some(UserStatus::Active),
|
||||
limit: None,
|
||||
})
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into_iter()
|
||||
.filter_map(|user_role| {
|
||||
(user_role.status == UserStatus::Active)
|
||||
.then_some(user_role.profile_id)
|
||||
.flatten()
|
||||
})
|
||||
.filter_map(|user_role| user_role.profile_id)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
futures::future::try_join_all(profile_ids.iter().map(|profile_id| {
|
||||
@ -2465,9 +2470,13 @@ pub async fn list_profiles_for_user_in_org_and_merchant_account(
|
||||
profile_name: profile.profile_name,
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
if profiles.is_empty() {
|
||||
Err(UserErrors::InternalServerError).attach_printable("No profile found for a user")?;
|
||||
}
|
||||
|
||||
Ok(ApplicationResponse::Json(profiles))
|
||||
}
|
||||
|
||||
@ -2503,23 +2512,23 @@ pub async fn switch_org_for_user(
|
||||
|
||||
let user_role = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(
|
||||
&user_from_token.user_id,
|
||||
Some(&request.org_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload {
|
||||
user_id: &user_from_token.user_id,
|
||||
org_id: Some(&request.org_id),
|
||||
merchant_id: None,
|
||||
profile_id: None,
|
||||
entity_id: None,
|
||||
version: None,
|
||||
status: Some(UserStatus::Active),
|
||||
limit: Some(1),
|
||||
})
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list user roles by user_id and org_id")?
|
||||
.into_iter()
|
||||
.find(|role| role.status == UserStatus::Active)
|
||||
.pop()
|
||||
.ok_or(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No user role found for the requested org_id".to_string(),
|
||||
))?
|
||||
.to_owned();
|
||||
))?;
|
||||
|
||||
let merchant_id = utils::user_role::get_single_merchant_id(&state, &user_role).await?;
|
||||
|
||||
@ -2547,7 +2556,7 @@ pub async fn switch_org_for_user(
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles by merchant_id")?
|
||||
.first()
|
||||
.pop()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the merchant_id")?
|
||||
.get_id()
|
||||
@ -2635,7 +2644,7 @@ pub async fn switch_merchant_for_user_in_org(
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles by merchant_id")?
|
||||
.first()
|
||||
.pop()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the given merchant_id")?
|
||||
.get_id()
|
||||
@ -2688,12 +2697,11 @@ pub async fn switch_merchant_for_user_in_org(
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles by merchant_id")?
|
||||
.first()
|
||||
.pop()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the merchant_id")?
|
||||
.get_id()
|
||||
.to_owned();
|
||||
|
||||
(
|
||||
user_from_token.org_id.clone(),
|
||||
merchant_id,
|
||||
@ -2705,25 +2713,25 @@ pub async fn switch_merchant_for_user_in_org(
|
||||
EntityType::Merchant | EntityType::Profile => {
|
||||
let user_role = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(
|
||||
&user_from_token.user_id,
|
||||
Some(&user_from_token.org_id),
|
||||
Some(&request.merchant_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload {
|
||||
user_id: &user_from_token.user_id,
|
||||
org_id: Some(&user_from_token.org_id),
|
||||
merchant_id: Some(&request.merchant_id),
|
||||
profile_id: None,
|
||||
entity_id: None,
|
||||
version: None,
|
||||
status: Some(UserStatus::Active),
|
||||
limit: Some(1),
|
||||
})
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable(
|
||||
"Failed to list user roles for the given user_id, org_id and merchant_id",
|
||||
)?
|
||||
.into_iter()
|
||||
.find(|role| role.status == UserStatus::Active)
|
||||
.pop()
|
||||
.ok_or(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No user role associated with the requested merchant_id".to_string(),
|
||||
))?
|
||||
.to_owned();
|
||||
))?;
|
||||
|
||||
let profile_id = if let Some(profile_id) = &user_role.profile_id {
|
||||
profile_id.clone()
|
||||
@ -2749,7 +2757,7 @@ pub async fn switch_merchant_for_user_in_org(
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles for the given merchant_id")?
|
||||
.first()
|
||||
.pop()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the given merchant_id")?
|
||||
.get_id()
|
||||
@ -2846,23 +2854,24 @@ pub async fn switch_profile_for_user_in_org_and_merchant(
|
||||
EntityType::Profile => {
|
||||
let user_role = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(
|
||||
&user_from_token.user_id,
|
||||
Some(&user_from_token.org_id),
|
||||
Some(&user_from_token.merchant_id),
|
||||
Some(&request.profile_id),
|
||||
None,
|
||||
None,
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload{
|
||||
user_id:&user_from_token.user_id,
|
||||
org_id: Some(&user_from_token.org_id),
|
||||
merchant_id: Some(&user_from_token.merchant_id),
|
||||
profile_id:Some(&request.profile_id),
|
||||
entity_id: None,
|
||||
version:None,
|
||||
status: Some(UserStatus::Active),
|
||||
limit: Some(1)
|
||||
}
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list user roles for the given user_id, org_id, merchant_id and profile_id")?
|
||||
.into_iter()
|
||||
.find(|role| role.status == UserStatus::Active)
|
||||
.pop()
|
||||
.ok_or(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No user role associated with the profile".to_string(),
|
||||
))?
|
||||
.to_owned();
|
||||
))?;
|
||||
|
||||
(request.profile_id, user_role.role_id)
|
||||
}
|
||||
|
||||
@ -3,14 +3,14 @@ use std::collections::{HashMap, HashSet};
|
||||
use api_models::{user as user_api, user_role as user_role_api};
|
||||
use diesel_models::{
|
||||
enums::{UserRoleVersion, UserStatus},
|
||||
user_role::UserRoleUpdate,
|
||||
user_role::{get_entity_id_and_type, UserRoleUpdate},
|
||||
};
|
||||
use error_stack::{report, ResultExt};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{
|
||||
core::errors::{StorageErrorExt, UserErrors, UserResponse},
|
||||
db::user_role::ListUserRolesByOrgIdPayload,
|
||||
db::user_role::{ListUserRolesByOrgIdPayload, ListUserRolesByUserIdPayload},
|
||||
routes::{app::ReqState, SessionState},
|
||||
services::{
|
||||
authentication as auth,
|
||||
@ -687,3 +687,41 @@ pub async fn list_users_in_lineage(
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn list_invitations_for_user(
|
||||
state: SessionState,
|
||||
user_from_token: auth::UserIdFromAuth,
|
||||
) -> UserResponse<Vec<user_role_api::ListInvitationForUserResponse>> {
|
||||
let invitations = state
|
||||
.store
|
||||
.list_user_roles_by_user_id(ListUserRolesByUserIdPayload {
|
||||
user_id: &user_from_token.user_id,
|
||||
org_id: None,
|
||||
merchant_id: None,
|
||||
profile_id: None,
|
||||
entity_id: None,
|
||||
version: None,
|
||||
status: Some(UserStatus::InvitationSent),
|
||||
limit: None,
|
||||
})
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list user roles by user id and invitation sent")?
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>()
|
||||
.into_iter()
|
||||
.filter_map(|user_role| {
|
||||
let (entity_id, entity_type) = get_entity_id_and_type(&user_role);
|
||||
entity_id.zip(entity_type).map(|(entity_id, entity_type)| {
|
||||
user_role_api::ListInvitationForUserResponse {
|
||||
entity_id,
|
||||
entity_type,
|
||||
entity_name: None,
|
||||
role_id: user_role.role_id,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(ApplicationResponse::Json(invitations))
|
||||
}
|
||||
|
||||
@ -35,7 +35,10 @@ use super::{
|
||||
user::{sample_data::BatchSampleDataInterface, UserInterface},
|
||||
user_authentication_method::UserAuthenticationMethodInterface,
|
||||
user_key_store::UserKeyStoreInterface,
|
||||
user_role::{InsertUserRolePayload, ListUserRolesByOrgIdPayload, UserRoleInterface},
|
||||
user_role::{
|
||||
InsertUserRolePayload, ListUserRolesByOrgIdPayload, ListUserRolesByUserIdPayload,
|
||||
UserRoleInterface,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "payouts")]
|
||||
use crate::services::kafka::payout::KafkaPayout;
|
||||
@ -2872,25 +2875,11 @@ impl UserRoleInterface for KafkaStore {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_user_roles_by_user_id(
|
||||
async fn list_user_roles_by_user_id<'a>(
|
||||
&self,
|
||||
user_id: &str,
|
||||
org_id: Option<&id_type::OrganizationId>,
|
||||
merchant_id: Option<&id_type::MerchantId>,
|
||||
profile_id: Option<&id_type::ProfileId>,
|
||||
entity_id: Option<&String>,
|
||||
version: Option<enums::UserRoleVersion>,
|
||||
payload: ListUserRolesByUserIdPayload<'a>,
|
||||
) -> CustomResult<Vec<storage::UserRole>, errors::StorageError> {
|
||||
self.diesel_store
|
||||
.list_user_roles_by_user_id(
|
||||
user_id,
|
||||
org_id,
|
||||
merchant_id,
|
||||
profile_id,
|
||||
entity_id,
|
||||
version,
|
||||
)
|
||||
.await
|
||||
self.diesel_store.list_user_roles_by_user_id(payload).await
|
||||
}
|
||||
|
||||
async fn list_user_roles_by_org_id<'a>(
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use common_utils::id_type;
|
||||
use diesel_models::{enums, user_role as storage};
|
||||
use diesel_models::{
|
||||
enums::{self, UserStatus},
|
||||
user_role as storage,
|
||||
};
|
||||
use error_stack::{report, ResultExt};
|
||||
use router_env::{instrument, tracing};
|
||||
|
||||
@ -33,6 +36,17 @@ pub struct ListUserRolesByOrgIdPayload<'a> {
|
||||
pub version: Option<enums::UserRoleVersion>,
|
||||
}
|
||||
|
||||
pub struct ListUserRolesByUserIdPayload<'a> {
|
||||
pub user_id: &'a str,
|
||||
pub org_id: Option<&'a id_type::OrganizationId>,
|
||||
pub merchant_id: Option<&'a id_type::MerchantId>,
|
||||
pub profile_id: Option<&'a id_type::ProfileId>,
|
||||
pub entity_id: Option<&'a String>,
|
||||
pub version: Option<enums::UserRoleVersion>,
|
||||
pub status: Option<UserStatus>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait UserRoleInterface {
|
||||
async fn insert_user_role(
|
||||
@ -93,14 +107,9 @@ pub trait UserRoleInterface {
|
||||
version: enums::UserRoleVersion,
|
||||
) -> CustomResult<storage::UserRole, errors::StorageError>;
|
||||
|
||||
async fn list_user_roles_by_user_id(
|
||||
async fn list_user_roles_by_user_id<'a>(
|
||||
&self,
|
||||
user_id: &str,
|
||||
org_id: Option<&id_type::OrganizationId>,
|
||||
merchant_id: Option<&id_type::MerchantId>,
|
||||
profile_id: Option<&id_type::ProfileId>,
|
||||
entity_id: Option<&String>,
|
||||
version: Option<enums::UserRoleVersion>,
|
||||
payload: ListUserRolesByUserIdPayload<'a>,
|
||||
) -> CustomResult<Vec<storage::UserRole>, errors::StorageError>;
|
||||
|
||||
async fn list_user_roles_by_org_id<'a>(
|
||||
@ -244,24 +253,21 @@ impl UserRoleInterface for Store {
|
||||
.map_err(|error| report!(errors::StorageError::from(error)))
|
||||
}
|
||||
|
||||
async fn list_user_roles_by_user_id(
|
||||
async fn list_user_roles_by_user_id<'a>(
|
||||
&self,
|
||||
user_id: &str,
|
||||
org_id: Option<&id_type::OrganizationId>,
|
||||
merchant_id: Option<&id_type::MerchantId>,
|
||||
profile_id: Option<&id_type::ProfileId>,
|
||||
entity_id: Option<&String>,
|
||||
version: Option<enums::UserRoleVersion>,
|
||||
payload: ListUserRolesByUserIdPayload<'a>,
|
||||
) -> CustomResult<Vec<storage::UserRole>, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
storage::UserRole::generic_user_roles_list_for_user(
|
||||
&conn,
|
||||
user_id.to_owned(),
|
||||
org_id.cloned(),
|
||||
merchant_id.cloned(),
|
||||
profile_id.cloned(),
|
||||
entity_id.cloned(),
|
||||
version,
|
||||
payload.user_id.to_owned(),
|
||||
payload.org_id.cloned(),
|
||||
payload.merchant_id.cloned(),
|
||||
payload.profile_id.cloned(),
|
||||
payload.entity_id.cloned(),
|
||||
payload.status,
|
||||
payload.version,
|
||||
payload.limit,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| report!(errors::StorageError::from(error)))
|
||||
@ -552,50 +558,52 @@ impl UserRoleInterface for MockDb {
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_user_roles_by_user_id(
|
||||
async fn list_user_roles_by_user_id<'a>(
|
||||
&self,
|
||||
user_id: &str,
|
||||
org_id: Option<&id_type::OrganizationId>,
|
||||
merchant_id: Option<&id_type::MerchantId>,
|
||||
profile_id: Option<&id_type::ProfileId>,
|
||||
entity_id: Option<&String>,
|
||||
version: Option<enums::UserRoleVersion>,
|
||||
payload: ListUserRolesByUserIdPayload<'a>,
|
||||
) -> CustomResult<Vec<storage::UserRole>, errors::StorageError> {
|
||||
let user_roles = self.user_roles.lock().await;
|
||||
|
||||
let filtered_roles: Vec<_> = user_roles
|
||||
let mut filtered_roles: Vec<_> = user_roles
|
||||
.iter()
|
||||
.filter_map(|role| {
|
||||
let mut filter_condition = role.user_id == user_id;
|
||||
let mut filter_condition = role.user_id == payload.user_id;
|
||||
|
||||
role.org_id
|
||||
.as_ref()
|
||||
.zip(org_id)
|
||||
.zip(payload.org_id)
|
||||
.inspect(|(role_org_id, org_id)| {
|
||||
filter_condition = filter_condition && role_org_id == org_id
|
||||
});
|
||||
role.merchant_id.as_ref().zip(merchant_id).inspect(
|
||||
role.merchant_id.as_ref().zip(payload.merchant_id).inspect(
|
||||
|(role_merchant_id, merchant_id)| {
|
||||
filter_condition = filter_condition && role_merchant_id == merchant_id
|
||||
},
|
||||
);
|
||||
role.profile_id.as_ref().zip(profile_id).inspect(
|
||||
role.profile_id.as_ref().zip(payload.profile_id).inspect(
|
||||
|(role_profile_id, profile_id)| {
|
||||
filter_condition = filter_condition && role_profile_id == profile_id
|
||||
},
|
||||
);
|
||||
role.entity_id
|
||||
.as_ref()
|
||||
.zip(entity_id)
|
||||
.inspect(|(role_entity_id, entity_id)| {
|
||||
role.entity_id.as_ref().zip(payload.entity_id).inspect(
|
||||
|(role_entity_id, entity_id)| {
|
||||
filter_condition = filter_condition && role_entity_id == entity_id
|
||||
});
|
||||
version.inspect(|ver| filter_condition = filter_condition && ver == &role.version);
|
||||
},
|
||||
);
|
||||
payload
|
||||
.version
|
||||
.inspect(|ver| filter_condition = filter_condition && ver == &role.version);
|
||||
payload.status.inspect(|status| {
|
||||
filter_condition = filter_condition && status == &role.status
|
||||
});
|
||||
|
||||
filter_condition.then(|| role.to_owned())
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Some(Ok(limit)) = payload.limit.map(|val| val.try_into()) {
|
||||
filtered_roles = filtered_roles.into_iter().take(limit).collect();
|
||||
}
|
||||
Ok(filtered_roles)
|
||||
}
|
||||
|
||||
|
||||
@ -1725,6 +1725,9 @@ impl User {
|
||||
.service(
|
||||
web::resource("/profile")
|
||||
.route(web::get().to(list_profiles_for_user_in_org_and_merchant)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/invitation").route(web::get().to(list_invitations_for_user)),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@ -250,6 +250,7 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::ListOrgForUser
|
||||
| Flow::ListMerchantsForUserInOrg
|
||||
| Flow::ListProfileForUserInOrgAndMerchant
|
||||
| Flow::ListInvitationsForUser
|
||||
| Flow::AuthSelect => Self::User,
|
||||
|
||||
Flow::ListRoles
|
||||
|
||||
@ -310,3 +310,23 @@ pub async fn list_updatable_roles_at_entity_level(
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_invitations_for_user(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::ListInvitationsForUser;
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state.clone(),
|
||||
&req,
|
||||
(),
|
||||
|state, user_id_from_token, _, _| {
|
||||
user_role_core::list_invitations_for_user(state, user_id_from_token)
|
||||
},
|
||||
&auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::AcceptInvite),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
@ -474,6 +474,8 @@ pub enum Flow {
|
||||
ListProfileForUserInOrgAndMerchant,
|
||||
/// List Users in Org
|
||||
ListUsersInLineage,
|
||||
/// List invitations for user
|
||||
ListInvitationsForUser,
|
||||
/// List initial webhook delivery attempts
|
||||
WebhookEventInitialDeliveryAttemptList,
|
||||
/// List delivery attempts for a webhook event
|
||||
|
||||
Reference in New Issue
Block a user