diff --git a/crates/diesel_models/src/role.rs b/crates/diesel_models/src/role.rs index ba63dd61a0..67fb04099c 100644 --- a/crates/diesel_models/src/role.rs +++ b/crates/diesel_models/src/role.rs @@ -9,7 +9,7 @@ use crate::{enums, schema::roles}; pub struct Role { pub role_name: String, pub role_id: String, - pub merchant_id: id_type::MerchantId, + pub merchant_id: Option, pub org_id: id_type::OrganizationId, #[diesel(deserialize_as = super::DieselArray)] pub groups: Vec, @@ -28,7 +28,7 @@ pub struct Role { pub struct RoleNew { pub role_name: String, pub role_id: String, - pub merchant_id: id_type::MerchantId, + pub merchant_id: Option, pub org_id: id_type::OrganizationId, #[diesel(deserialize_as = super::DieselArray)] pub groups: Vec, diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 374b341a47..c25acc386f 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -1361,7 +1361,7 @@ diesel::table! { #[max_length = 64] role_id -> Varchar, #[max_length = 64] - merchant_id -> Varchar, + merchant_id -> Nullable, #[max_length = 64] org_id -> Varchar, groups -> Array>, diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 0e7f63dbfc..8f857a4db2 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -1291,7 +1291,7 @@ diesel::table! { #[max_length = 64] role_id -> Varchar, #[max_length = 64] - merchant_id -> Varchar, + merchant_id -> Nullable, #[max_length = 64] org_id -> Varchar, groups -> Array>, diff --git a/crates/router/src/core/user_role/role.rs b/crates/router/src/core/user_role/role.rs index 34f0e8187c..9bb8be9cc6 100644 --- a/crates/router/src/core/user_role/role.rs +++ b/crates/router/src/core/user_role/role.rs @@ -78,13 +78,6 @@ pub async fn create_role( return Err(report!(UserErrors::InvalidRoleOperation)) .attach_printable("User trying to create org level custom role"); } - - // TODO: Remove in PR custom-role-write-pr - if matches!(role_entity_type, EntityType::Profile) { - return Err(report!(UserErrors::InvalidRoleOperation)) - .attach_printable("User trying to create profile level custom role"); - } - let requestor_entity_from_role_scope = EntityType::from(req.role_scope); if requestor_entity_from_role_scope < role_entity_type { @@ -120,13 +113,15 @@ pub async fn create_role( .await?; let (org_id, merchant_id, profile_id) = match role_entity_type { - EntityType::Organization | EntityType::Tenant => { - (user_from_token.org_id, user_from_token.merchant_id, None) - } - EntityType::Merchant => (user_from_token.org_id, user_from_token.merchant_id, None), + EntityType::Organization | EntityType::Tenant => (user_from_token.org_id, None, None), + EntityType::Merchant => ( + user_from_token.org_id, + Some(user_from_token.merchant_id), + None, + ), EntityType::Profile => ( user_from_token.org_id, - user_from_token.merchant_id, + Some(user_from_token.merchant_id), Some(user_from_token.profile_id), ), }; diff --git a/crates/router/src/db/role.rs b/crates/router/src/db/role.rs index 532a59f514..ecb962d8d2 100644 --- a/crates/router/src/db/role.rs +++ b/crates/router/src/db/role.rs @@ -265,7 +265,13 @@ impl RoleInterface for MockDb { && (role.tenant_id == *tenant_id) && role.org_id == *org_id && ((role.scope == RoleScope::Organization) - || (role.merchant_id == *merchant_id && role.scope == RoleScope::Merchant) + || (role + .merchant_id + .as_ref() + .is_some_and(|merchant_id_from_role| { + merchant_id_from_role == merchant_id + && role.scope == RoleScope::Merchant + })) || (role .profile_id .as_ref() @@ -369,10 +375,10 @@ impl RoleInterface for MockDb { let roles_list: Vec<_> = roles .iter() .filter(|role| { - let matches_merchant = match merchant_id { - Some(merchant_id) => role.merchant_id == *merchant_id, - None => true, - }; + let matches_merchant = merchant_id + .zip(role.merchant_id.as_ref()) + .map(|(merchant_id, role_merchant_id)| merchant_id == role_merchant_id) + .unwrap_or(true); matches_merchant && role.org_id == *org_id @@ -420,17 +426,26 @@ impl RoleInterface for MockDb { vec![EntityType::Merchant] }; + let matches_merchant = role + .merchant_id + .as_ref() + .is_some_and(|merchant_id_from_role| merchant_id_from_role == merchant_id); + role.tenant_id == tenant_id && role.org_id == org_id - && (role.scope == RoleScope::Organization - || role.merchant_id == *merchant_id) + && (role.scope == RoleScope::Organization || matches_merchant) && entity_in_vec.contains(&role.entity_type) } storage::ListRolesByEntityPayload::Profile(merchant_id, profile_id) => { let entity_in_vec = [EntityType::Profile]; let matches_merchant = - role.merchant_id == *merchant_id && role.scope == RoleScope::Merchant; + role.merchant_id + .as_ref() + .is_some_and(|merchant_id_from_role| { + merchant_id_from_role == merchant_id + && role.scope == RoleScope::Merchant + }); let matches_profile = role.profile_id diff --git a/migrations/2025-02-06-122415_udpate-roles/down.sql b/migrations/2025-02-06-122415_udpate-roles/down.sql new file mode 100644 index 0000000000..be66247abf --- /dev/null +++ b/migrations/2025-02-06-122415_udpate-roles/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE roles ALTER COLUMN merchant_id SET NOT NULL; \ No newline at end of file diff --git a/migrations/2025-02-06-122415_udpate-roles/up.sql b/migrations/2025-02-06-122415_udpate-roles/up.sql new file mode 100644 index 0000000000..490f5bcb92 --- /dev/null +++ b/migrations/2025-02-06-122415_udpate-roles/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE roles ALTER COLUMN merchant_id DROP NOT NULL; \ No newline at end of file