mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(user): add user_list and switch_list apis (#3033)
Co-authored-by: Mani Chandra Dulam <mani.dchandra@juspay.in>
This commit is contained in:
@ -7,7 +7,7 @@ use crate::user::{
|
||||
GetMetaDataRequest, GetMetaDataResponse, GetMultipleMetaDataPayload, SetMetaDataRequest,
|
||||
},
|
||||
ChangePasswordRequest, ConnectAccountRequest, ConnectAccountResponse,
|
||||
CreateInternalUserRequest, SwitchMerchantIdRequest, UserMerchantCreate,
|
||||
CreateInternalUserRequest, GetUsersResponse, SwitchMerchantIdRequest, UserMerchantCreate,
|
||||
};
|
||||
|
||||
impl ApiEventMetric for ConnectAccountResponse {
|
||||
@ -29,7 +29,8 @@ common_utils::impl_misc_api_event_type!(
|
||||
SetMetaDataRequest,
|
||||
SwitchMerchantIdRequest,
|
||||
CreateInternalUserRequest,
|
||||
UserMerchantCreate
|
||||
UserMerchantCreate,
|
||||
GetUsersResponse
|
||||
);
|
||||
|
||||
#[cfg(feature = "dummy_connector")]
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
use common_utils::pii;
|
||||
use masking::Secret;
|
||||
|
||||
use crate::user_role::UserStatus;
|
||||
pub mod dashboard_metadata;
|
||||
#[cfg(feature = "dummy_connector")]
|
||||
pub mod sample_data;
|
||||
@ -45,3 +47,18 @@ pub struct CreateInternalUserRequest {
|
||||
pub struct UserMerchantCreate {
|
||||
pub company_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct GetUsersResponse(pub Vec<UserDetails>);
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct UserDetails {
|
||||
pub user_id: String,
|
||||
pub email: pii::Email,
|
||||
pub name: Secret<String>,
|
||||
pub role_id: String,
|
||||
pub role_name: String,
|
||||
pub status: UserStatus,
|
||||
#[serde(with = "common_utils::custom_serde::iso8601")]
|
||||
pub last_modified_at: time::PrimitiveDateTime,
|
||||
}
|
||||
|
||||
@ -80,3 +80,9 @@ pub struct UpdateUserRoleRequest {
|
||||
pub user_id: String,
|
||||
pub role_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub enum UserStatus {
|
||||
Active,
|
||||
InvitationSent,
|
||||
}
|
||||
|
||||
@ -5,7 +5,10 @@ use crate::{
|
||||
enums,
|
||||
query::generics,
|
||||
schema::dashboard_metadata::dsl,
|
||||
user::dashboard_metadata::{DashboardMetadata, DashboardMetadataNew},
|
||||
user::dashboard_metadata::{
|
||||
DashboardMetadata, DashboardMetadataNew, DashboardMetadataUpdate,
|
||||
DashboardMetadataUpdateInternal,
|
||||
},
|
||||
PgPooledConn, StorageResult,
|
||||
};
|
||||
|
||||
@ -17,6 +20,31 @@ impl DashboardMetadataNew {
|
||||
}
|
||||
|
||||
impl DashboardMetadata {
|
||||
pub async fn update(
|
||||
conn: &PgPooledConn,
|
||||
user_id: Option<String>,
|
||||
merchant_id: String,
|
||||
org_id: String,
|
||||
data_key: enums::DashboardMetadata,
|
||||
dashboard_metadata_update: DashboardMetadataUpdate,
|
||||
) -> StorageResult<Self> {
|
||||
generics::generic_update_with_unique_predicate_get_result::<
|
||||
<Self as HasTable>::Table,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
>(
|
||||
conn,
|
||||
dsl::user_id
|
||||
.eq(user_id.to_owned())
|
||||
.and(dsl::merchant_id.eq(merchant_id.to_owned()))
|
||||
.and(dsl::org_id.eq(org_id.to_owned()))
|
||||
.and(dsl::data_key.eq(data_key.to_owned())),
|
||||
DashboardMetadataUpdateInternal::from(dashboard_metadata_update),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn find_user_scoped_dashboard_metadata(
|
||||
conn: &PgPooledConn,
|
||||
user_id: String,
|
||||
|
||||
@ -1,13 +1,24 @@
|
||||
use diesel::{associations::HasTable, ExpressionMethods};
|
||||
use error_stack::report;
|
||||
use router_env::tracing::{self, instrument};
|
||||
use async_bb8_diesel::AsyncRunQueryDsl;
|
||||
use diesel::{
|
||||
associations::HasTable, debug_query, result::Error as DieselError, ExpressionMethods,
|
||||
JoinOnDsl, QueryDsl,
|
||||
};
|
||||
use error_stack::{report, IntoReport};
|
||||
use router_env::{
|
||||
logger,
|
||||
tracing::{self, instrument},
|
||||
};
|
||||
pub mod sample_data;
|
||||
|
||||
use crate::{
|
||||
errors::{self},
|
||||
query::generics,
|
||||
schema::users::dsl,
|
||||
schema::{
|
||||
user_roles::{self, dsl as user_roles_dsl},
|
||||
users::dsl as users_dsl,
|
||||
},
|
||||
user::*,
|
||||
user_role::UserRole,
|
||||
PgPooledConn, StorageResult,
|
||||
};
|
||||
|
||||
@ -22,7 +33,7 @@ impl User {
|
||||
pub async fn find_by_user_email(conn: &PgPooledConn, user_email: &str) -> StorageResult<Self> {
|
||||
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
||||
conn,
|
||||
dsl::email.eq(user_email.to_owned()),
|
||||
users_dsl::email.eq(user_email.to_owned()),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -30,7 +41,7 @@ impl User {
|
||||
pub async fn find_by_user_id(conn: &PgPooledConn, user_id: &str) -> StorageResult<Self> {
|
||||
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
||||
conn,
|
||||
dsl::user_id.eq(user_id.to_owned()),
|
||||
users_dsl::user_id.eq(user_id.to_owned()),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -42,7 +53,7 @@ impl User {
|
||||
) -> StorageResult<Self> {
|
||||
generics::generic_update_with_results::<<Self as HasTable>::Table, _, _, _>(
|
||||
conn,
|
||||
dsl::user_id.eq(user_id.to_owned()),
|
||||
users_dsl::user_id.eq(user_id.to_owned()),
|
||||
UserUpdateInternal::from(user),
|
||||
)
|
||||
.await?
|
||||
@ -56,8 +67,28 @@ impl User {
|
||||
pub async fn delete_by_user_id(conn: &PgPooledConn, user_id: &str) -> StorageResult<bool> {
|
||||
generics::generic_delete::<<Self as HasTable>::Table, _>(
|
||||
conn,
|
||||
dsl::user_id.eq(user_id.to_owned()),
|
||||
users_dsl::user_id.eq(user_id.to_owned()),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn find_joined_users_and_roles_by_merchant_id(
|
||||
conn: &PgPooledConn,
|
||||
mid: &str,
|
||||
) -> StorageResult<Vec<(Self, UserRole)>> {
|
||||
let query = Self::table()
|
||||
.inner_join(user_roles::table.on(user_roles_dsl::user_id.eq(users_dsl::user_id)))
|
||||
.filter(user_roles_dsl::merchant_id.eq(mid.to_owned()));
|
||||
|
||||
logger::debug!(query = %debug_query::<diesel::pg::Pg,_>(&query).to_string());
|
||||
|
||||
query
|
||||
.get_results_async::<(Self, UserRole)>(conn)
|
||||
.await
|
||||
.into_report()
|
||||
.map_err(|err| match err.current_context() {
|
||||
DieselError::NotFound => err.change_context(errors::DatabaseError::NotFound),
|
||||
_ => err.change_context(errors::DatabaseError::Others),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,3 +33,40 @@ pub struct DashboardMetadataNew {
|
||||
pub last_modified_by: String,
|
||||
pub last_modified_at: PrimitiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
router_derive::Setter, Clone, Debug, Insertable, router_derive::DebugAsDisplay, AsChangeset,
|
||||
)]
|
||||
#[diesel(table_name = dashboard_metadata)]
|
||||
pub struct DashboardMetadataUpdateInternal {
|
||||
pub data_key: enums::DashboardMetadata,
|
||||
pub data_value: serde_json::Value,
|
||||
pub last_modified_by: String,
|
||||
pub last_modified_at: PrimitiveDateTime,
|
||||
}
|
||||
|
||||
pub enum DashboardMetadataUpdate {
|
||||
UpdateData {
|
||||
data_key: enums::DashboardMetadata,
|
||||
data_value: serde_json::Value,
|
||||
last_modified_by: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<DashboardMetadataUpdate> for DashboardMetadataUpdateInternal {
|
||||
fn from(metadata_update: DashboardMetadataUpdate) -> Self {
|
||||
let last_modified_at = common_utils::date_time::now();
|
||||
match metadata_update {
|
||||
DashboardMetadataUpdate::UpdateData {
|
||||
data_key,
|
||||
data_value,
|
||||
last_modified_by,
|
||||
} => Self {
|
||||
data_key,
|
||||
data_value,
|
||||
last_modified_by,
|
||||
last_modified_at,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,3 +324,29 @@ pub async fn create_merchant_account(
|
||||
|
||||
Ok(ApplicationResponse::StatusOk)
|
||||
}
|
||||
|
||||
pub async fn list_merchant_ids_for_user(
|
||||
state: AppState,
|
||||
user: auth::UserFromToken,
|
||||
) -> UserResponse<Vec<String>> {
|
||||
Ok(ApplicationResponse::Json(
|
||||
utils::user::get_merchant_ids_for_user(state, &user.user_id).await?,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_users_for_merchant_account(
|
||||
state: AppState,
|
||||
user_from_token: auth::UserFromToken,
|
||||
) -> UserResponse<user_api::GetUsersResponse> {
|
||||
let users = state
|
||||
.store
|
||||
.find_users_and_roles_by_merchant_id(user_from_token.merchant_id.as_str())
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("No users for given merchant id")?
|
||||
.into_iter()
|
||||
.filter_map(|(user, role)| domain::UserAndRoleJoined(user, role).try_into().ok())
|
||||
.collect();
|
||||
|
||||
Ok(ApplicationResponse::Json(user_api::GetUsersResponse(users)))
|
||||
}
|
||||
|
||||
@ -14,6 +14,14 @@ pub trait DashboardMetadataInterface {
|
||||
&self,
|
||||
metadata: storage::DashboardMetadataNew,
|
||||
) -> CustomResult<storage::DashboardMetadata, errors::StorageError>;
|
||||
async fn update_metadata(
|
||||
&self,
|
||||
user_id: Option<String>,
|
||||
merchant_id: String,
|
||||
org_id: String,
|
||||
data_key: enums::DashboardMetadata,
|
||||
dashboard_metadata_update: storage::DashboardMetadataUpdate,
|
||||
) -> CustomResult<storage::DashboardMetadata, errors::StorageError>;
|
||||
|
||||
async fn find_user_scoped_dashboard_metadata(
|
||||
&self,
|
||||
@ -44,6 +52,28 @@ impl DashboardMetadataInterface for Store {
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn update_metadata(
|
||||
&self,
|
||||
user_id: Option<String>,
|
||||
merchant_id: String,
|
||||
org_id: String,
|
||||
data_key: enums::DashboardMetadata,
|
||||
dashboard_metadata_update: storage::DashboardMetadataUpdate,
|
||||
) -> CustomResult<storage::DashboardMetadata, errors::StorageError> {
|
||||
let conn = connection::pg_connection_write(self).await?;
|
||||
storage::DashboardMetadata::update(
|
||||
&conn,
|
||||
user_id,
|
||||
merchant_id,
|
||||
org_id,
|
||||
data_key,
|
||||
dashboard_metadata_update,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn find_user_scoped_dashboard_metadata(
|
||||
&self,
|
||||
user_id: &str,
|
||||
@ -121,6 +151,41 @@ impl DashboardMetadataInterface for MockDb {
|
||||
Ok(metadata_new)
|
||||
}
|
||||
|
||||
async fn update_metadata(
|
||||
&self,
|
||||
user_id: Option<String>,
|
||||
merchant_id: String,
|
||||
org_id: String,
|
||||
data_key: enums::DashboardMetadata,
|
||||
dashboard_metadata_update: storage::DashboardMetadataUpdate,
|
||||
) -> CustomResult<storage::DashboardMetadata, errors::StorageError> {
|
||||
let mut dashboard_metadata = self.dashboard_metadata.lock().await;
|
||||
|
||||
let dashboard_metadata_to_update = dashboard_metadata
|
||||
.iter_mut()
|
||||
.find(|metadata| {
|
||||
metadata.user_id == user_id
|
||||
&& metadata.merchant_id == merchant_id
|
||||
&& metadata.org_id == org_id
|
||||
&& metadata.data_key == data_key
|
||||
})
|
||||
.ok_or(errors::StorageError::MockDbError)?;
|
||||
|
||||
match dashboard_metadata_update {
|
||||
storage::DashboardMetadataUpdate::UpdateData {
|
||||
data_key,
|
||||
data_value,
|
||||
last_modified_by,
|
||||
} => {
|
||||
dashboard_metadata_to_update.data_key = data_key;
|
||||
dashboard_metadata_to_update.data_value = data_value;
|
||||
dashboard_metadata_to_update.last_modified_by = last_modified_by;
|
||||
dashboard_metadata_to_update.last_modified_at = common_utils::date_time::now();
|
||||
}
|
||||
}
|
||||
Ok(dashboard_metadata_to_update.clone())
|
||||
}
|
||||
|
||||
async fn find_user_scoped_dashboard_metadata(
|
||||
&self,
|
||||
user_id: &str,
|
||||
|
||||
@ -1878,6 +1878,15 @@ impl UserInterface for KafkaStore {
|
||||
) -> CustomResult<bool, errors::StorageError> {
|
||||
self.diesel_store.delete_user_by_user_id(user_id).await
|
||||
}
|
||||
|
||||
async fn find_users_and_roles_by_merchant_id(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<Vec<(storage::User, user_storage::UserRole)>, errors::StorageError> {
|
||||
self.diesel_store
|
||||
.find_users_and_roles_by_merchant_id(merchant_id)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl RedisConnInterface for KafkaStore {
|
||||
@ -1930,6 +1939,25 @@ impl DashboardMetadataInterface for KafkaStore {
|
||||
self.diesel_store.insert_metadata(metadata).await
|
||||
}
|
||||
|
||||
async fn update_metadata(
|
||||
&self,
|
||||
user_id: Option<String>,
|
||||
merchant_id: String,
|
||||
org_id: String,
|
||||
data_key: enums::DashboardMetadata,
|
||||
dashboard_metadata_update: storage::DashboardMetadataUpdate,
|
||||
) -> CustomResult<storage::DashboardMetadata, errors::StorageError> {
|
||||
self.diesel_store
|
||||
.update_metadata(
|
||||
user_id,
|
||||
merchant_id,
|
||||
org_id,
|
||||
data_key,
|
||||
dashboard_metadata_update,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn find_user_scoped_dashboard_metadata(
|
||||
&self,
|
||||
user_id: &str,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use diesel_models::user as storage;
|
||||
use diesel_models::{user as storage, user_role::UserRole};
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use masking::Secret;
|
||||
|
||||
@ -37,6 +37,11 @@ pub trait UserInterface {
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> CustomResult<bool, errors::StorageError>;
|
||||
|
||||
async fn find_users_and_roles_by_merchant_id(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<Vec<(storage::User, UserRole)>, errors::StorageError>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@ -97,6 +102,17 @@ impl UserInterface for Store {
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn find_users_and_roles_by_merchant_id(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<Vec<(storage::User, UserRole)>, errors::StorageError> {
|
||||
let conn = connection::pg_connection_write(self).await?;
|
||||
storage::User::find_joined_users_and_roles_by_merchant_id(&conn, merchant_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@ -222,45 +238,11 @@ impl UserInterface for MockDb {
|
||||
users.remove(user_index);
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "kafka_events")]
|
||||
#[async_trait::async_trait]
|
||||
impl UserInterface for super::KafkaStore {
|
||||
async fn insert_user(
|
||||
&self,
|
||||
user_data: storage::UserNew,
|
||||
) -> CustomResult<storage::User, errors::StorageError> {
|
||||
self.diesel_store.insert_user(user_data).await
|
||||
}
|
||||
|
||||
async fn find_user_by_email(
|
||||
async fn find_users_and_roles_by_merchant_id(
|
||||
&self,
|
||||
user_email: &str,
|
||||
) -> CustomResult<storage::User, errors::StorageError> {
|
||||
self.diesel_store.find_user_by_email(user_email).await
|
||||
}
|
||||
|
||||
async fn find_user_by_id(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> CustomResult<storage::User, errors::StorageError> {
|
||||
self.diesel_store.find_user_by_id(user_id).await
|
||||
}
|
||||
|
||||
async fn update_user_by_user_id(
|
||||
&self,
|
||||
user_id: &str,
|
||||
user: storage::UserUpdate,
|
||||
) -> CustomResult<storage::User, errors::StorageError> {
|
||||
self.diesel_store
|
||||
.update_user_by_user_id(user_id, user)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn delete_user_by_user_id(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> CustomResult<bool, errors::StorageError> {
|
||||
self.diesel_store.delete_user_by_user_id(user_id).await
|
||||
_merchant_id: &str,
|
||||
) -> CustomResult<Vec<(storage::User, UserRole)>, errors::StorageError> {
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
}
|
||||
|
||||
@ -839,6 +839,8 @@ impl User {
|
||||
web::resource("/create_merchant")
|
||||
.route(web::post().to(user_merchant_account_create)),
|
||||
)
|
||||
.service(web::resource("/switch/list").route(web::get().to(list_merchant_ids_for_user)))
|
||||
.service(web::resource("/user/list").route(web::get().to(get_user_details)))
|
||||
// User Role APIs
|
||||
.service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
|
||||
.service(web::resource("/user/update_role").route(web::post().to(update_user_role)))
|
||||
|
||||
@ -157,7 +157,9 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::SwitchMerchant
|
||||
| Flow::UserMerchantAccountCreate
|
||||
| Flow::GenerateSampleData
|
||||
| Flow::DeleteSampleData => Self::User,
|
||||
| Flow::DeleteSampleData
|
||||
| Flow::UserMerchantAccountList
|
||||
| Flow::GetUserDetails => Self::User,
|
||||
|
||||
Flow::ListRoles | Flow::GetRole | Flow::UpdateUserRole | Flow::GetAuthorizationInfo => {
|
||||
Self::UserRole
|
||||
|
||||
@ -204,3 +204,34 @@ pub async fn delete_sample_data(
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_merchant_ids_for_user(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::UserMerchantAccountList;
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
(),
|
||||
|state, user, _| user_core::list_merchant_ids_for_user(state, user),
|
||||
&auth::DashboardNoPermissionAuth,
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_user_details(state: web::Data<AppState>, req: HttpRequest) -> HttpResponse {
|
||||
let flow = Flow::GetUserDetails;
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state.clone(),
|
||||
&req,
|
||||
(),
|
||||
|state, user, _| user_core::get_users_for_merchant_account(state, user),
|
||||
&auth::JWTAuth(Permission::UsersRead),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ use crate::{
|
||||
routes::AppState,
|
||||
services::{
|
||||
authentication::{AuthToken, UserFromToken},
|
||||
authorization::info,
|
||||
authorization::{info, predefined_permissions},
|
||||
},
|
||||
types::transformers::ForeignFrom,
|
||||
utils::user::password,
|
||||
@ -671,3 +671,30 @@ impl TryFrom<info::PermissionInfo> for user_role_api::PermissionInfo {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserAndRoleJoined(pub storage_user::User, pub UserRole);
|
||||
|
||||
impl TryFrom<UserAndRoleJoined> for user_api::UserDetails {
|
||||
type Error = ();
|
||||
fn try_from(user_and_role: UserAndRoleJoined) -> Result<Self, Self::Error> {
|
||||
let status = match user_and_role.1.status {
|
||||
UserStatus::Active => user_role_api::UserStatus::Active,
|
||||
UserStatus::InvitationSent => user_role_api::UserStatus::InvitationSent,
|
||||
};
|
||||
|
||||
let role_id = user_and_role.1.role_id;
|
||||
let role_name = predefined_permissions::get_role_name_from_id(role_id.as_str())
|
||||
.ok_or(())?
|
||||
.to_string();
|
||||
|
||||
Ok(Self {
|
||||
user_id: user_and_role.0.user_id,
|
||||
email: user_and_role.0.email,
|
||||
name: user_and_role.0.name,
|
||||
role_id,
|
||||
status,
|
||||
role_name,
|
||||
last_modified_at: user_and_role.1.last_modified_at,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use diesel_models::enums::UserStatus;
|
||||
use error_stack::ResultExt;
|
||||
|
||||
use crate::{
|
||||
@ -51,3 +52,19 @@ impl UserFromToken {
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_merchant_ids_for_user(state: AppState, user_id: &str) -> UserResult<Vec<String>> {
|
||||
Ok(state
|
||||
.store
|
||||
.list_user_roles_by_user_id(user_id)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into_iter()
|
||||
.filter_map(|ele| {
|
||||
if ele.status == UserStatus::Active {
|
||||
return Some(ele.merchant_id);
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
@ -283,6 +283,10 @@ pub enum Flow {
|
||||
GenerateSampleData,
|
||||
/// Delete Sample Data
|
||||
DeleteSampleData,
|
||||
/// List merchant accounts for user
|
||||
UserMerchantAccountList,
|
||||
/// Get users for merchant account
|
||||
GetUserDetails,
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user