Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(users): custom role at profile read #6875

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9c04ad6
chore: rename find_role_by_role_id_in_org_scopr
Riddhiagrawal001 Nov 28, 2024
35b89e8
refactor(users): refactor find_by_role_id_in_merchant_scope query for…
Riddhiagrawal001 Nov 29, 2024
5cb5954
fix: changes for list roles and list roles at entity-level
Riddhiagrawal001 Nov 29, 2024
16f6f59
Merge branch 'main' into change-roles-query
Riddhiagrawal001 Nov 29, 2024
d18866e
Merge branch 'main' into change-roles-query
Riddhiagrawal001 Nov 29, 2024
1137886
fix: changes for backfilling user-roles
Riddhiagrawal001 Dec 2, 2024
6606067
Merge branch 'change-roles-query' of https://github.com/juspay/hypers…
Riddhiagrawal001 Dec 2, 2024
aeec4bf
Merge branch 'main' into change-roles-query
Riddhiagrawal001 Dec 2, 2024
1cd045f
fix: addressed comments
Riddhiagrawal001 Dec 3, 2024
af27d60
Merge branch 'change-roles-query' of https://github.com/juspay/hypers…
Riddhiagrawal001 Dec 3, 2024
2b24810
refactor: code refactoring
Riddhiagrawal001 Dec 3, 2024
989b423
Merge branch 'main' into change-roles-query
Riddhiagrawal001 Dec 3, 2024
5a96d2e
merge branch:synced with main
Riddhiagrawal001 Dec 5, 2024
8e38e66
Merge branch 'change-roles-query' of https://github.com/juspay/hypers…
Riddhiagrawal001 Dec 5, 2024
f70f3cf
fix: addressed comments
Riddhiagrawal001 Dec 5, 2024
b3de586
Merge branch 'main' into change-roles-query
Riddhiagrawal001 Dec 5, 2024
55b3ecf
Merge branch 'change-roles-query' into custom-role-at-profile-read
Riddhiagrawal001 Dec 5, 2024
bc4a038
Merge branch 'main' into change-roles-query
Riddhiagrawal001 Dec 6, 2024
f307fee
Merge branch 'main' of https://github.com/juspay/hyperswitch into cha…
Riddhiagrawal001 Dec 8, 2024
26ff9ac
Merge branch 'change-roles-query' of https://github.com/juspay/hypers…
Riddhiagrawal001 Dec 8, 2024
5a428b4
Merge branch 'change-roles-query' into custom-role-at-profile-read
Riddhiagrawal001 Dec 10, 2024
abeac9c
changes-for-profile-read
Riddhiagrawal001 Dec 11, 2024
22ee8f0
Merge branch 'main' of https://github.com/juspay/hyperswitch into cus…
Riddhiagrawal001 Dec 11, 2024
335b359
refactor: removed unused code
Riddhiagrawal001 Dec 18, 2024
26eaa33
chore: run formatter
hyperswitch-bot[bot] Dec 18, 2024
cfbeeaf
fix: added indexes
Riddhiagrawal001 Dec 18, 2024
40cf084
Merge branch 'custom-role-at-profile-read' of https://github.com/jusp…
Riddhiagrawal001 Dec 18, 2024
04703e3
fix: variable name changes
Riddhiagrawal001 Dec 18, 2024
6a35c22
fix: query changes
Riddhiagrawal001 Dec 23, 2024
f8f5936
refactor: addressed comments
Riddhiagrawal001 Dec 23, 2024
0f7acd6
fix: addressed comments
Riddhiagrawal001 Dec 23, 2024
142ff92
refactor: refactor code
Riddhiagrawal001 Dec 23, 2024
10c5809
Merge branch 'main' of https://github.com/juspay/hyperswitch into cus…
Riddhiagrawal001 Dec 23, 2024
b1be688
chore: run formatter
hyperswitch-bot[bot] Dec 23, 2024
7fd671b
refactor: spell correction
Riddhiagrawal001 Dec 23, 2024
81336c1
Merge branch 'custom-role-at-profile-read' of https://github.com/jusp…
Riddhiagrawal001 Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/api_models/src/user_role/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct CreateRoleRequest {
pub role_name: String,
pub groups: Vec<PermissionGroup>,
pub role_scope: RoleScope,
pub entity_type: Option<EntityType>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
Expand All @@ -21,6 +22,7 @@ pub struct RoleInfoWithGroupsResponse {
pub groups: Vec<PermissionGroup>,
pub role_name: String,
pub role_scope: RoleScope,
pub entity_type: EntityType,
}

#[derive(Debug, serde::Serialize)]
Expand Down
14 changes: 13 additions & 1 deletion crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2799,8 +2799,19 @@ pub enum TransactionType {
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RoleScope {
Merchant,
Organization,
Merchant,
Profile,
}

impl From<RoleScope> for EntityType {
fn from(role_scope: RoleScope) -> Self {
match role_scope {
RoleScope::Organization => Self::Organization,
RoleScope::Merchant => Self::Merchant,
RoleScope::Profile => Self::Profile,
}
}
}

/// Indicates the transaction status
Expand Down Expand Up @@ -3255,6 +3266,7 @@ pub enum ApiVersion {
serde::Serialize,
strum::Display,
strum::EnumString,
strum::EnumIter,
ToSchema,
Hash,
)]
Expand Down
128 changes: 85 additions & 43 deletions crates/diesel_models/src/query/role.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use async_bb8_diesel::AsyncRunQueryDsl;
use common_enums::EntityType;
use common_utils::id_type;
use diesel::{
associations::HasTable, debug_query, pg::Pg, result::Error as DieselError,
BoolExpressionMethods, ExpressionMethods, QueryDsl,
};
use error_stack::{report, ResultExt};
use strum::IntoEnumIterator;

use crate::{
enums::RoleScope, errors, query::generics, role::*, schema::roles::dsl, PgPooledConn,
Expand All @@ -18,28 +20,23 @@ impl RoleNew {
}

impl Role {
pub async fn find_by_role_id(conn: &PgPooledConn, role_id: &str) -> StorageResult<Self> {
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
conn,
dsl::role_id.eq(role_id.to_owned()),
)
.await
fn get_entity_list(
current_entity: EntityType,
is_lineage_data_required: bool,
) -> Vec<EntityType> {
is_lineage_data_required
.then(|| {
EntityType::iter()
.filter(|variant| *variant <= current_entity)
.collect()
})
.unwrap_or_else(|| vec![current_entity])
}

// TODO: Remove once find_by_role_id_in_lineage is stable
pub async fn find_by_role_id_in_merchant_scope(
conn: &PgPooledConn,
role_id: &str,
merchant_id: &id_type::MerchantId,
org_id: &id_type::OrganizationId,
) -> StorageResult<Self> {
pub async fn find_by_role_id(conn: &PgPooledConn, role_id: &str) -> StorageResult<Self> {
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
conn,
dsl::role_id.eq(role_id.to_owned()).and(
dsl::merchant_id.eq(merchant_id.to_owned()).or(dsl::org_id
.eq(org_id.to_owned())
.and(dsl::scope.eq(RoleScope::Organization))),
),
dsl::role_id.eq(role_id.to_owned()),
)
.await
}
Expand All @@ -49,16 +46,22 @@ impl Role {
role_id: &str,
merchant_id: &id_type::MerchantId,
org_id: &id_type::OrganizationId,
profile_id: &id_type::ProfileId,
) -> StorageResult<Self> {
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
conn,
dsl::role_id
.eq(role_id.to_owned())
.and(dsl::org_id.eq(org_id.to_owned()))
.and(
dsl::scope.eq(RoleScope::Organization).or(dsl::merchant_id
.eq(merchant_id.to_owned())
.and(dsl::scope.eq(RoleScope::Merchant))),
dsl::scope
.eq(RoleScope::Organization)
.or(dsl::merchant_id
.eq(merchant_id.to_owned())
.and(dsl::scope.eq(RoleScope::Merchant)))
.or(dsl::profile_id
.eq(profile_id.to_owned())
.and(dsl::scope.eq(RoleScope::Profile))),
),
)
.await
Expand Down Expand Up @@ -104,32 +107,12 @@ impl Role {
.await
}

pub async fn list_roles(
conn: &PgPooledConn,
merchant_id: &id_type::MerchantId,
org_id: &id_type::OrganizationId,
) -> StorageResult<Vec<Self>> {
let predicate = dsl::org_id.eq(org_id.to_owned()).and(
dsl::scope.eq(RoleScope::Organization).or(dsl::merchant_id
.eq(merchant_id.to_owned())
.and(dsl::scope.eq(RoleScope::Merchant))),
);

generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
conn,
predicate,
None,
None,
Some(dsl::last_modified_at.asc()),
)
.await
}

//TODO: Remove once generic_list_roles_by_entity_type is stable
pub async fn generic_roles_list_for_org(
conn: &PgPooledConn,
org_id: id_type::OrganizationId,
merchant_id: Option<id_type::MerchantId>,
entity_type: Option<common_enums::EntityType>,
entity_type: Option<EntityType>,
limit: Option<u32>,
) -> StorageResult<Vec<Self>> {
let mut query = <Self as HasTable>::table()
Expand Down Expand Up @@ -170,4 +153,63 @@ impl Role {
},
}
}

pub async fn generic_list_roles_by_entity_type(
conn: &PgPooledConn,
payload: ListRolesByEntityPayload,
is_lineage_data_required: bool,
) -> StorageResult<Vec<Self>> {
let mut query = <Self as HasTable>::table().into_boxed();

match payload {
ListRolesByEntityPayload::Organization(org_id) => {
let entity_in_vec =
Self::get_entity_list(EntityType::Organization, is_lineage_data_required);
query = query
.filter(dsl::org_id.eq(org_id))
.filter(dsl::entity_type.eq_any(entity_in_vec))
}

ListRolesByEntityPayload::Merchant(org_id, merchant_id) => {
let entity_in_vec =
Self::get_entity_list(EntityType::Merchant, is_lineage_data_required);
query = query
.filter(dsl::org_id.eq(org_id))
.filter(
dsl::scope
.eq(RoleScope::Organization)
.or(dsl::merchant_id.eq(merchant_id)),
)
.filter(dsl::entity_type.eq_any(entity_in_vec))
}

ListRolesByEntityPayload::Profile(org_id, merchant_id, profile_id) => {
let entity_in_vec =
Self::get_entity_list(EntityType::Profile, is_lineage_data_required);
query = query
.filter(dsl::org_id.eq(org_id))
.filter(
dsl::scope
.eq(RoleScope::Organization)
.or(dsl::scope
.eq(RoleScope::Merchant)
.and(dsl::merchant_id.eq(merchant_id.clone())))
.or(dsl::profile_id.eq(profile_id)),
)
.filter(dsl::entity_type.eq_any(entity_in_vec))
}
};

router_env::logger::debug!(query = %debug_query::<Pg,_>(&query).to_string());

match generics::db_metrics::track_database_call::<Self, _, _>(
query.get_results_async(conn),
generics::db_metrics::DatabaseOperation::Filter,
)
.await
{
Ok(value) => Ok(value),
Err(err) => Err(report!(err)).change_context(errors::DatabaseError::Others),
}
}
}
37 changes: 37 additions & 0 deletions crates/diesel_models/src/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct Role {
pub last_modified_at: PrimitiveDateTime,
pub last_modified_by: String,
pub entity_type: enums::EntityType,
pub profile_id: Option<id_type::ProfileId>,
}

#[derive(router_derive::Setter, Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
Expand All @@ -36,6 +37,7 @@ pub struct RoleNew {
pub last_modified_at: PrimitiveDateTime,
pub last_modified_by: String,
pub entity_type: enums::EntityType,
pub profile_id: Option<id_type::ProfileId>,
}

#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
Expand Down Expand Up @@ -73,3 +75,38 @@ impl From<RoleUpdate> for RoleUpdateInternal {
}
}
}

#[derive(Clone, Debug)]
pub enum ListRolesByEntityPayload {
Profile(
id_type::OrganizationId,
id_type::MerchantId,
id_type::ProfileId,
),
Merchant(id_type::OrganizationId, id_type::MerchantId),
Organization(id_type::OrganizationId),
}

impl ListRolesByEntityPayload {
pub fn get_organization_id(&self) -> Option<id_type::OrganizationId> {
match self {
Self::Organization(org_id)
| Self::Merchant(org_id, _)
| Self::Profile(org_id, _, _) => Some(org_id.to_owned()),
}
}
pub fn get_merchant_id(&self) -> Option<id_type::MerchantId> {
match self {
Self::Organization(_) => None,
Self::Merchant(_, merchant_id) | Self::Profile(_, merchant_id, _) => {
Some(merchant_id.to_owned())
}
}
}
pub fn get_profile_id(&self) -> Option<id_type::ProfileId> {
match self {
Self::Organization(_) | Self::Merchant(_, _) => None,
Self::Profile(_, _, profile_id) => Some(profile_id.to_owned()),
}
}
}
2 changes: 2 additions & 0 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,8 @@ diesel::table! {
last_modified_by -> Varchar,
#[max_length = 64]
entity_type -> Varchar,
#[max_length = 64]
profile_id -> Nullable<Varchar>,
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/diesel_models/src/schema_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,8 @@ diesel::table! {
last_modified_by -> Varchar,
#[max_length = 64]
entity_type -> Varchar,
#[max_length = 64]
profile_id -> Nullable<Varchar>,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/router/src/core/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ async fn handle_invitation(
&request.role_id,
&user_from_token.merchant_id,
&user_from_token.org_id,
&user_from_token.profile_id,
)
.await
.to_not_found_response(UserErrors::InvalidRoleId)?;
Expand Down
3 changes: 3 additions & 0 deletions crates/router/src/core/user_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ pub async fn update_user_role(
&req.role_id,
&user_from_token.merchant_id,
&user_from_token.org_id,
&user_from_token.profile_id,
)
.await
.to_not_found_response(UserErrors::InvalidRoleId)?;
Expand Down Expand Up @@ -527,6 +528,7 @@ pub async fn delete_user_role(
&role_to_be_deleted.role_id,
&user_from_token.merchant_id,
&user_from_token.org_id,
&user_from_token.profile_id,
)
.await
.change_context(UserErrors::InternalServerError)?;
Expand Down Expand Up @@ -597,6 +599,7 @@ pub async fn delete_user_role(
&role_to_be_deleted.role_id,
&user_from_token.merchant_id,
&user_from_token.org_id,
&user_from_token.profile_id,
)
.await
.change_context(UserErrors::InternalServerError)?;
Expand Down
Loading
Loading