Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -129,34 +129,51 @@ export function usePermissions(): UsePermissionsReturn {
// Add the requested permission
newPermissions.push(permission);

// If enabling create, update, or delete, automatically enable read permission
// Handle dependencies from PERMISSION_REGISTRY
const resourceConfig = PERMISSION_REGISTRY[resource as keyof typeof PERMISSION_REGISTRY];
if (resourceConfig && resourceConfig[action as CrudAction]) {
const permissionDetails = resourceConfig[action as CrudAction];
if (permissionDetails?.dependsOn) {
permissionDetails.dependsOn.forEach((dependency) => {
if (!newPermissions.includes(dependency)) {
newPermissions.push(dependency);
}
});
}
}

// If enabling create, update, or delete, automatically enable read permission (backward compatibility)
if (action === CrudAction.Create || action === CrudAction.Update || action === CrudAction.Delete) {
const readPermission = `${resource}.${CrudAction.Read}`;
if (!newPermissions.includes(readPermission)) {
newPermissions.push(readPermission);
}
}
} else {
// When disabling a permission, check if we need to disable related permissions
// When disabling a permission, first remove the permission itself
newPermissions = newPermissions.filter((p) => p !== permission);

// Then check if we need to disable related permissions
if (action === CrudAction.Read) {
// If disabling read, also disable create, update, and delete since they depend on read
const dependentActions = [CrudAction.Create, CrudAction.Update, CrudAction.Delete];
dependentActions.forEach((dependentAction) => {
const dependentPermission = `${resource}.${dependentAction}`;
newPermissions = newPermissions.filter((p) => p !== dependentPermission);
});
} else if (
action === CrudAction.Create ||
action === CrudAction.Update ||
action === CrudAction.Delete
) {
// If disabling create, update, or delete, just remove that specific permission
// Read permission remains enabled
newPermissions = newPermissions.filter((p) => p !== permission);
} else {
// For other actions (custom actions), just remove the specific permission
newPermissions = newPermissions.filter((p) => p !== permission);
}

// Also remove any permissions that depend on this one
Object.entries(PERMISSION_REGISTRY).forEach(([res, config]) => {
Object.entries(config).forEach(([act, details]) => {
if (act.startsWith("_")) return; // Skip internal keys
const permissionDetails = details as any;
if (permissionDetails?.dependsOn?.includes(permission)) {
const dependentPermission = `${res}.${act}`;
newPermissions = newPermissions.filter((p) => p !== dependentPermission);
}
});
});
}

// Only add *.* back if all permissions are now selected
Expand Down
32 changes: 32 additions & 0 deletions packages/features/pbac/domain/types/permission-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface PermissionDetails {
i18nKey: string;
descriptionI18nKey: string;
scope?: Scope[]; // Optional for backward compatibility
dependsOn?: PermissionString[]; // Dependencies that must be enabled when this permission is enabled
}

export type ResourceConfig = {
Expand Down Expand Up @@ -122,6 +123,7 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "role",
i18nKey: "pbac_action_create",
descriptionI18nKey: "pbac_desc_create_roles",
dependsOn: ["role.read"],
},
[CrudAction.Read]: {
description: "View roles",
Expand All @@ -134,12 +136,14 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "role",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_roles",
dependsOn: ["role.read"],
},
[CrudAction.Delete]: {
description: "Delete roles",
category: "role",
i18nKey: "pbac_action_delete",
descriptionI18nKey: "pbac_desc_delete_roles",
dependsOn: ["role.read"],
},
},
[Resource.EventType]: {
Expand All @@ -151,6 +155,7 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "event",
i18nKey: "pbac_action_create",
descriptionI18nKey: "pbac_desc_create_event_types",
dependsOn: ["eventType.read"],
},
[CrudAction.Read]: {
description: "View event types",
Expand All @@ -163,12 +168,14 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "event",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_event_types",
dependsOn: ["eventType.read"],
},
[CrudAction.Delete]: {
description: "Delete event types",
category: "event",
i18nKey: "pbac_action_delete",
descriptionI18nKey: "pbac_desc_delete_event_types",
dependsOn: ["eventType.read"],
},
},
[Resource.Team]: {
Expand All @@ -181,6 +188,7 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
i18nKey: "pbac_action_create",
descriptionI18nKey: "pbac_desc_create_teams",
scope: [Scope.Organization],
dependsOn: ["team.read"],
},
[CrudAction.Read]: {
description: "View team details",
Expand All @@ -193,30 +201,35 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "team",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_team_settings",
dependsOn: ["team.read"],
},
[CrudAction.Delete]: {
description: "Delete team",
category: "team",
i18nKey: "pbac_action_delete",
descriptionI18nKey: "pbac_desc_delete_team",
dependsOn: ["team.read"],
},
[CustomAction.Invite]: {
description: "Invite team members",
category: "team",
i18nKey: "pbac_action_invite",
descriptionI18nKey: "pbac_desc_invite_team_members",
dependsOn: ["team.read"],
},
[CustomAction.Remove]: {
description: "Remove team members",
category: "team",
i18nKey: "pbac_action_remove",
descriptionI18nKey: "pbac_desc_remove_team_members",
dependsOn: ["team.read"],
},
[CustomAction.ChangeMemberRole]: {
description: "Change role of team members",
category: "team",
i18nKey: "pbac_action_change_member_role",
descriptionI18nKey: "pbac_desc_change_team_member_role",
dependsOn: ["team.read"],
},
},
[Resource.Organization]: {
Expand All @@ -243,41 +256,47 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
i18nKey: "pbac_action_list_members",
descriptionI18nKey: "pbac_desc_list_organization_members",
scope: [Scope.Organization],
dependsOn: ["organization.read"],
},
[CustomAction.Invite]: {
description: "Invite organization members",
category: "org",
i18nKey: "pbac_action_invite",
descriptionI18nKey: "pbac_desc_invite_organization_members",
scope: [Scope.Organization],
dependsOn: ["organization.listMembers"],
},
[CustomAction.Remove]: {
description: "Remove organization members",
category: "org",
i18nKey: "pbac_action_remove",
descriptionI18nKey: "pbac_desc_remove_organization_members",
scope: [Scope.Organization],
dependsOn: ["organization.listMembers"],
},
[CustomAction.ManageBilling]: {
description: "Manage organization billing",
category: "org",
i18nKey: "pbac_action_manage_billing",
descriptionI18nKey: "pbac_desc_manage_organization_billing",
scope: [Scope.Organization],
dependsOn: ["organization.read"],
},
[CustomAction.ChangeMemberRole]: {
description: "Change role of team members",
category: "org",
i18nKey: "pbac_action_change_member_role",
descriptionI18nKey: "pbac_desc_change_organization_member_role",
scope: [Scope.Organization],
dependsOn: ["organization.listMembers", "role.read"],
},
[CrudAction.Update]: {
description: "Edit organization settings",
category: "org",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_edit_organization_settings",
scope: [Scope.Organization],
dependsOn: ["organization.read"],
},
},
[Resource.Booking]: {
Expand All @@ -296,25 +315,29 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
i18nKey: "pbac_action_read_team_bookings",
descriptionI18nKey: "pbac_desc_view_team_bookings",
scope: [Scope.Team],
dependsOn: ["booking.read"],
},
[CustomAction.ReadOrgBookings]: {
description: "View organization bookings",
category: "booking",
i18nKey: "pbac_action_read_org_bookings",
descriptionI18nKey: "pbac_desc_view_organization_bookings",
scope: [Scope.Organization],
dependsOn: ["booking.read"],
},
[CustomAction.ReadRecordings]: {
description: "View booking recordings",
category: "booking",
i18nKey: "pbac_action_read_recordings",
descriptionI18nKey: "pbac_desc_view_booking_recordings",
dependsOn: ["booking.read"],
},
[CrudAction.Update]: {
description: "Update bookings",
category: "booking",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_bookings",
dependsOn: ["booking.read"],
},
},
[Resource.Insights]: {
Expand All @@ -337,6 +360,7 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "workflow",
i18nKey: "pbac_action_create",
descriptionI18nKey: "pbac_desc_create_workflows",
dependsOn: ["workflow.read"],
},
[CrudAction.Read]: {
description: "View workflows",
Expand All @@ -349,12 +373,14 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "workflow",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_workflows",
dependsOn: ["workflow.read"],
},
[CrudAction.Delete]: {
description: "Delete workflows",
category: "workflow",
i18nKey: "pbac_action_delete",
descriptionI18nKey: "pbac_desc_delete_workflows",
dependsOn: ["workflow.read"],
},
},
[Resource.Attributes]: {
Expand All @@ -372,18 +398,21 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "attributes",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_organization_attributes",
dependsOn: ["organization.attributes.read"],
},
[CrudAction.Delete]: {
description: "Delete organization attributes",
category: "attributes",
i18nKey: "pbac_action_delete",
descriptionI18nKey: "pbac_desc_delete_organization_attributes",
dependsOn: ["organization.attributes.read"],
},
[CrudAction.Create]: {
description: "Create organization attributes",
category: "attributes",
i18nKey: "pbac_action_create",
descriptionI18nKey: "pbac_desc_create_organization_attributes",
dependsOn: ["organization.attributes.read"],
},
},
[Resource.RoutingForm]: {
Expand All @@ -395,6 +424,7 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "routing",
i18nKey: "pbac_action_create",
descriptionI18nKey: "pbac_desc_create_routing_forms",
dependsOn: ["routingForm.read"],
},
[CrudAction.Read]: {
description: "View routing forms",
Expand All @@ -407,12 +437,14 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
category: "routing",
i18nKey: "pbac_action_update",
descriptionI18nKey: "pbac_desc_update_routing_forms",
dependsOn: ["routingForm.read"],
},
[CrudAction.Delete]: {
description: "Delete routing forms",
category: "routing",
i18nKey: "pbac_action_delete",
descriptionI18nKey: "pbac_desc_delete_routing_forms",
dependsOn: ["routingForm.read"],
},
},
};
Loading