chore(rbac): user link and utils (#14320)
This commit is contained in:
@@ -1,15 +1,6 @@
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
import { IRbacModuleService } from "@medusajs/types"
|
||||
|
||||
export type CreateRbacPolicyDTO = {
|
||||
key: string
|
||||
resource: string
|
||||
operation: string
|
||||
name?: string | null
|
||||
description?: string | null
|
||||
metadata?: Record<string, unknown> | null
|
||||
}
|
||||
import { CreateRbacPolicyDTO, IRbacModuleService } from "@medusajs/types"
|
||||
|
||||
export type CreateRbacPoliciesStepInput = {
|
||||
policies: CreateRbacPolicyDTO[]
|
||||
@@ -22,7 +13,14 @@ export const createRbacPoliciesStep = createStep(
|
||||
async (data: CreateRbacPoliciesStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
const created = await service.createRbacPolicies(data.policies)
|
||||
// Normalize resource and operation to lowercase
|
||||
const normalizedPolicies = data.policies.map((policy) => ({
|
||||
...policy,
|
||||
resource: policy.resource.toLowerCase(),
|
||||
operation: policy.operation.toLowerCase(),
|
||||
}))
|
||||
|
||||
const created = await service.createRbacPolicies(normalizedPolicies)
|
||||
|
||||
return new StepResponse(
|
||||
created,
|
||||
|
||||
+11
-13
@@ -2,30 +2,28 @@ import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
import { IRbacModuleService } from "@medusajs/types"
|
||||
|
||||
export type CreateRbacRoleInheritanceDTO = {
|
||||
export type CreateRbacRoleParentDTO = {
|
||||
role_id: string
|
||||
inherited_role_id: string
|
||||
parent_id: string
|
||||
metadata?: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
export type CreateRbacRoleInheritancesStepInput = {
|
||||
role_inheritances: CreateRbacRoleInheritanceDTO[]
|
||||
export type CreateRbacRoleParentsStepInput = {
|
||||
role_parents: CreateRbacRoleParentDTO[]
|
||||
}
|
||||
|
||||
export const createRbacRoleInheritancesStepId = "create-rbac-role-inheritances"
|
||||
export const createRbacRoleParentsStepId = "create-rbac-role-parents"
|
||||
|
||||
export const createRbacRoleInheritancesStep = createStep(
|
||||
createRbacRoleInheritancesStepId,
|
||||
async (data: CreateRbacRoleInheritancesStepInput, { container }) => {
|
||||
export const createRbacRoleParentsStep = createStep(
|
||||
createRbacRoleParentsStepId,
|
||||
async (data: CreateRbacRoleParentsStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
if (!data.role_inheritances || data.role_inheritances.length === 0) {
|
||||
if (!data.role_parents?.length) {
|
||||
return new StepResponse([], [])
|
||||
}
|
||||
|
||||
const created = await service.createRbacRoleInheritances(
|
||||
data.role_inheritances
|
||||
)
|
||||
const created = await service.createRbacRoleParents(data.role_parents)
|
||||
|
||||
return new StepResponse(
|
||||
created,
|
||||
@@ -38,6 +36,6 @@ export const createRbacRoleInheritancesStep = createStep(
|
||||
}
|
||||
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
await service.deleteRbacRoleInheritances(createdIds)
|
||||
await service.deleteRbacRoleParents(createdIds)
|
||||
}
|
||||
)
|
||||
@@ -1,15 +1,9 @@
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
import { IRbacModuleService } from "@medusajs/types"
|
||||
|
||||
export type CreateRbacRolePolicyDTO = {
|
||||
role_id: string
|
||||
scope_id: string
|
||||
metadata?: Record<string, unknown> | null
|
||||
}
|
||||
import { CreateRbacRolePolicyDTO, IRbacModuleService } from "@medusajs/types"
|
||||
|
||||
export type CreateRbacRolePoliciesStepInput = {
|
||||
role_policies: CreateRbacRolePolicyDTO[]
|
||||
policies: CreateRbacRolePolicyDTO[]
|
||||
}
|
||||
|
||||
export const createRbacRolePoliciesStepId = "create-rbac-role-policies"
|
||||
@@ -19,7 +13,11 @@ export const createRbacRolePoliciesStep = createStep(
|
||||
async (data: CreateRbacRolePoliciesStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
const created = await service.createRbacRolePolicies(data.role_policies)
|
||||
if (!data.policies?.length) {
|
||||
return new StepResponse([], [])
|
||||
}
|
||||
|
||||
const created = await service.createRbacRolePolicies(data.policies)
|
||||
|
||||
return new StepResponse(
|
||||
created,
|
||||
|
||||
@@ -19,6 +19,9 @@ export const createRbacRolesStep = createStep(
|
||||
async (data: CreateRbacRolesStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
if (!data.roles?.length) {
|
||||
return new StepResponse([], [])
|
||||
}
|
||||
const created = await service.createRbacRoles(data.roles)
|
||||
|
||||
return new StepResponse(
|
||||
|
||||
@@ -10,8 +10,23 @@ export const deleteRbacPoliciesStep = createStep(
|
||||
{ name: deleteRbacPoliciesStepId, noCompensation: true },
|
||||
async (ids: DeleteRbacPoliciesStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
await service.deleteRbacPolicies(ids)
|
||||
return new StepResponse(void 0)
|
||||
|
||||
if (!ids?.length) {
|
||||
return new StepResponse([] as any, [])
|
||||
}
|
||||
|
||||
const deleted = await service.deleteRbacPolicies(ids)
|
||||
|
||||
return new StepResponse(deleted, ids)
|
||||
},
|
||||
async () => {}
|
||||
async (deletedPoliciesIds, { container }) => {
|
||||
if (!deletedPoliciesIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
// Restore the soft-deleted roles during compensation
|
||||
await service.restoreRbacPolicies(deletedPoliciesIds)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -10,8 +10,21 @@ export const deleteRbacRolePoliciesStep = createStep(
|
||||
{ name: deleteRbacRolePoliciesStepId, noCompensation: true },
|
||||
async (ids: DeleteRbacRolePoliciesStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
await service.deleteRbacRolePolicies(ids)
|
||||
return new StepResponse(void 0)
|
||||
|
||||
if (!ids?.length) {
|
||||
return new StepResponse([] as any, [])
|
||||
}
|
||||
|
||||
const deleted = await service.deleteRbacRolePolicies(ids)
|
||||
|
||||
return new StepResponse(deleted, ids)
|
||||
},
|
||||
async () => {}
|
||||
async (deletedRolePolicyIds, { container }) => {
|
||||
if (!deletedRolePolicyIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
await service.restoreRbacRolePolicies(deletedRolePolicyIds)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -6,12 +6,33 @@ export type DeleteRbacRolesStepInput = string[]
|
||||
|
||||
export const deleteRbacRolesStepId = "delete-rbac-roles"
|
||||
|
||||
/**
|
||||
* This step deletes one or more RBAC roles.
|
||||
* @param ids - The IDs of the roles to delete
|
||||
* @param container - The workflow container
|
||||
* @returns A step response with the deleted role IDs
|
||||
*/
|
||||
export const deleteRbacRolesStep = createStep(
|
||||
{ name: deleteRbacRolesStepId, noCompensation: true },
|
||||
deleteRbacRolesStepId,
|
||||
async (ids: DeleteRbacRolesStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
await service.deleteRbacRoles(ids)
|
||||
return new StepResponse(void 0)
|
||||
|
||||
if (!ids?.length) {
|
||||
return new StepResponse([] as any, [])
|
||||
}
|
||||
|
||||
const deleted = await service.deleteRbacRoles(ids)
|
||||
|
||||
return new StepResponse(deleted, ids)
|
||||
},
|
||||
async () => {}
|
||||
async (deletedRoleIds, { container }) => {
|
||||
if (!deletedRoleIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
// Restore the soft-deleted roles during compensation
|
||||
await service.restoreRbacRoles(deletedRoleIds)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
export * from "./create-rbac-roles"
|
||||
export * from "./delete-rbac-roles"
|
||||
export * from "./update-rbac-roles"
|
||||
|
||||
export * from "./create-rbac-policies"
|
||||
export * from "./delete-rbac-policies"
|
||||
export * from "./update-rbac-policies"
|
||||
|
||||
export * from "./create-rbac-role-parents"
|
||||
export * from "./create-rbac-role-policies"
|
||||
export * from "./create-rbac-roles"
|
||||
export * from "./delete-rbac-policies"
|
||||
export * from "./delete-rbac-role-policies"
|
||||
export * from "./update-rbac-role-policies"
|
||||
|
||||
export * from "./create-rbac-role-inheritances"
|
||||
export * from "./set-role-inheritance"
|
||||
export * from "./delete-rbac-roles"
|
||||
export * from "./set-role-parent"
|
||||
export * from "./update-rbac-policies"
|
||||
export * from "./update-rbac-roles"
|
||||
export * from "./validate-user-permissions"
|
||||
|
||||
+29
-35
@@ -2,21 +2,21 @@ import { Modules } from "@medusajs/framework/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||
import { IRbacModuleService } from "@medusajs/types"
|
||||
|
||||
export type SetRoleInheritanceStepInput = Array<{
|
||||
export type SetRoleParentStepInput = Array<{
|
||||
role_id: string
|
||||
inherited_role_ids: string[]
|
||||
parent_ids: string[]
|
||||
}>
|
||||
|
||||
export const setRoleInheritanceStepId = "set-role-inheritance"
|
||||
export const setRoleParentStepId = "set-role-parent"
|
||||
|
||||
export const setRoleInheritanceStep = createStep(
|
||||
setRoleInheritanceStepId,
|
||||
async (data: SetRoleInheritanceStepInput, { container }) => {
|
||||
export const setRoleParentStep = createStep(
|
||||
setRoleParentStepId,
|
||||
async (data: SetRoleParentStepInput, { container }) => {
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
const allCompensationData: Array<{
|
||||
role_id: string
|
||||
previousInheritedRoleIds: string[]
|
||||
previous_inherited_role_ids: string[]
|
||||
}> = []
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
@@ -29,54 +29,52 @@ export const setRoleInheritanceStep = createStep(
|
||||
const allToRemoveIds: string[] = []
|
||||
const allToCreate: Array<{
|
||||
role_id: string
|
||||
inherited_role_id: string
|
||||
parent_id: string
|
||||
}> = []
|
||||
|
||||
for (const roleData of data) {
|
||||
const existingInheritance = await service.listRbacRoleInheritances({
|
||||
const existingParent = await service.listRbacRoleParents({
|
||||
role_id: roleData.role_id,
|
||||
})
|
||||
|
||||
const existingInheritedRoleIds = existingInheritance.map(
|
||||
(ri) => ri.inherited_role_id
|
||||
)
|
||||
const existingInheritedRoleIds = existingParent.map((ri) => ri.parent_id)
|
||||
|
||||
allCompensationData.push({
|
||||
role_id: roleData.role_id,
|
||||
previousInheritedRoleIds: existingInheritedRoleIds,
|
||||
previous_inherited_role_ids: existingInheritedRoleIds,
|
||||
})
|
||||
|
||||
const toAdd = roleData.inherited_role_ids.filter(
|
||||
const toAdd = roleData.parent_ids.filter(
|
||||
(id) => !existingInheritedRoleIds.includes(id)
|
||||
)
|
||||
const toRemove = existingInheritedRoleIds.filter(
|
||||
(id) => !roleData.inherited_role_ids.includes(id)
|
||||
(id) => !roleData.parent_ids.includes(id)
|
||||
)
|
||||
|
||||
if (toRemove.length > 0) {
|
||||
const toRemoveRecords = existingInheritance.filter((ri) =>
|
||||
toRemove.includes(ri.inherited_role_id)
|
||||
const toRemoveRecords = existingParent.filter((ri) =>
|
||||
toRemove.includes(ri.parent_id)
|
||||
)
|
||||
allToRemoveIds.push(...toRemoveRecords.map((ri) => ri.id))
|
||||
}
|
||||
|
||||
if (toAdd.length > 0) {
|
||||
allToCreate.push(
|
||||
...toAdd.map((inherited_role_id) => ({
|
||||
...toAdd.map((parent_id) => ({
|
||||
role_id: roleData.role_id,
|
||||
inherited_role_id,
|
||||
parent_id,
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (allToRemoveIds.length > 0) {
|
||||
await service.deleteRbacRoleInheritances(allToRemoveIds)
|
||||
await service.deleteRbacRoleParents(allToRemoveIds)
|
||||
}
|
||||
|
||||
let created: any[] = []
|
||||
if (allToCreate.length > 0) {
|
||||
created = await service.createRbacRoleInheritances(allToCreate)
|
||||
created = await service.createRbacRoleParents(allToCreate)
|
||||
}
|
||||
|
||||
return new StepResponse(
|
||||
@@ -86,7 +84,7 @@ export const setRoleInheritanceStep = createStep(
|
||||
},
|
||||
async (
|
||||
compensationData:
|
||||
| Array<{ role_id: string; previousInheritedRoleIds: string[] }>
|
||||
| Array<{ role_id: string; previous_inherited_role_ids: string[] }>
|
||||
| undefined,
|
||||
{ container }
|
||||
) => {
|
||||
@@ -97,24 +95,20 @@ export const setRoleInheritanceStep = createStep(
|
||||
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||
|
||||
for (const roleCompensation of compensationData) {
|
||||
const currentInheritance = await service.listRbacRoleInheritances({
|
||||
const currentParent = await service.listRbacRoleParents({
|
||||
role_id: roleCompensation.role_id,
|
||||
})
|
||||
|
||||
if (currentInheritance.length > 0) {
|
||||
await service.deleteRbacRoleInheritances(
|
||||
currentInheritance.map((ri) => ri.id)
|
||||
)
|
||||
if (currentParent.length > 0) {
|
||||
await service.deleteRbacRoleParents(currentParent.map((ri) => ri.id))
|
||||
}
|
||||
|
||||
if (roleCompensation.previousInheritedRoleIds.length > 0) {
|
||||
await service.createRbacRoleInheritances(
|
||||
roleCompensation.previousInheritedRoleIds.map(
|
||||
(inherited_role_id) => ({
|
||||
role_id: roleCompensation.role_id,
|
||||
inherited_role_id,
|
||||
})
|
||||
)
|
||||
if (roleCompensation.previous_inherited_role_ids.length > 0) {
|
||||
await service.createRbacRoleParents(
|
||||
roleCompensation.previous_inherited_role_ids.map((parent_id) => ({
|
||||
role_id: roleCompensation.role_id,
|
||||
parent_id,
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,18 @@ export const updateRbacPoliciesStep = createStep(
|
||||
relations,
|
||||
})
|
||||
|
||||
// Normalize resource and operation to lowercase if present
|
||||
const normalizedUpdate = { ...data.update }
|
||||
if (normalizedUpdate.resource) {
|
||||
normalizedUpdate.resource = normalizedUpdate.resource.toLowerCase()
|
||||
}
|
||||
if (normalizedUpdate.operation) {
|
||||
normalizedUpdate.operation = normalizedUpdate.operation.toLowerCase()
|
||||
}
|
||||
|
||||
const updates = (prevData ?? []).map((p) => ({
|
||||
id: p.id,
|
||||
...data.update,
|
||||
...normalizedUpdate,
|
||||
})) as UpdateRbacPolicyDTO[]
|
||||
|
||||
const updated = await service.updateRbacPolicies(updates)
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
toSnakeCase,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
export type ValidateUserPermissionsStepInput = {
|
||||
actor_id: string
|
||||
actor?: string
|
||||
policy_ids?: string[]
|
||||
actions?: {
|
||||
resource: string
|
||||
operation: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export const validateUserPermissionsStepId = "validate-user-permissions"
|
||||
|
||||
/**
|
||||
* Validates that a user has access to all the policies they are trying to assign.
|
||||
* A user can only create roles and add policies that they themselves have access to.
|
||||
*/
|
||||
export const validateUserPermissionsStep = createStep(
|
||||
validateUserPermissionsStepId,
|
||||
async (data: ValidateUserPermissionsStepInput, { container }) => {
|
||||
const { actor_id, actor, policy_ids, actions } = data
|
||||
|
||||
if (!policy_ids?.length && !actions?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const query = container.resolve(ContainerRegistrationKeys.QUERY)
|
||||
const { data: users } = await query.graph({
|
||||
entity: actor ?? "user",
|
||||
fields: ["rbac_roles.id", "rbac_roles.policies.*"],
|
||||
filters: { id: actor_id },
|
||||
})
|
||||
|
||||
if (!users?.[0]?.rbac_roles || users[0].rbac_roles.length === 0) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNAUTHORIZED,
|
||||
`User does not have any roles assigned and cannot create roles or assign policies`
|
||||
)
|
||||
}
|
||||
|
||||
const operationMap = new Map()
|
||||
users[0].rbac_roles.forEach((role) => {
|
||||
role.policies.forEach((policy) => {
|
||||
const op =
|
||||
policy.operation === "*" ? "*" : toSnakeCase(policy.operation)
|
||||
operationMap.set(`${policy.resource}:${op}`, policy.id)
|
||||
})
|
||||
})
|
||||
|
||||
const allUserPolicies = users[0].rbac_roles.flatMap(
|
||||
(role) => role.policies || []
|
||||
)
|
||||
const userPolicyIds = new Set(allUserPolicies.map((p) => p.id))
|
||||
|
||||
let unauthorizedPolicies: string[] = []
|
||||
|
||||
if (policy_ids?.length) {
|
||||
unauthorizedPolicies = policy_ids.filter(
|
||||
(policyId) => !userPolicyIds.has(policyId)
|
||||
)
|
||||
} else if (actions?.length) {
|
||||
unauthorizedPolicies = actions
|
||||
.filter((action) => {
|
||||
const op =
|
||||
action.operation === "*" ? "*" : toSnakeCase(action.operation)
|
||||
|
||||
return (
|
||||
!operationMap.has(`${action.resource}:${op}`) &&
|
||||
!operationMap.has(`${action.resource}:*`)
|
||||
)
|
||||
})
|
||||
.map((action) => `${action.resource}:${action.operation}`)
|
||||
}
|
||||
|
||||
if (unauthorizedPolicies.length) {
|
||||
const policyMap = new Map(
|
||||
allUserPolicies.map((p) => [p.id, p.name || p.key])
|
||||
)
|
||||
|
||||
const unauthorizedNames = unauthorizedPolicies
|
||||
.map((id) => policyMap.get(id) || id)
|
||||
.join(", ")
|
||||
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNAUTHORIZED,
|
||||
`User does not have access to the following policies and cannot assign them: ${unauthorizedNames}`
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -2,11 +2,19 @@ import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
transform,
|
||||
when,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { createRbacRolePoliciesStep } from "../steps"
|
||||
import { validateUserPermissionsStep } from "../steps/validate-user-permissions"
|
||||
|
||||
export type CreateRbacRolePoliciesWorkflowInput = {
|
||||
role_policies: any[]
|
||||
actor_id?: string
|
||||
actor?: string
|
||||
policies: {
|
||||
role_id: string
|
||||
policy_id: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export const createRbacRolePoliciesWorkflowId = "create-rbac-role-policies"
|
||||
@@ -14,6 +22,31 @@ export const createRbacRolePoliciesWorkflowId = "create-rbac-role-policies"
|
||||
export const createRbacRolePoliciesWorkflow = createWorkflow(
|
||||
createRbacRolePoliciesWorkflowId,
|
||||
(input: WorkflowData<CreateRbacRolePoliciesWorkflowInput>) => {
|
||||
return new WorkflowResponse(createRbacRolePoliciesStep(input))
|
||||
const validationData = transform({ input }, ({ input }) => {
|
||||
if (!input.actor_id) {
|
||||
return null
|
||||
}
|
||||
|
||||
const policyIds = new Set<string>()
|
||||
input.policies.forEach((rp) => policyIds.add(rp.policy_id))
|
||||
|
||||
return {
|
||||
actor_id: input.actor_id,
|
||||
actor: input.actor,
|
||||
policy_ids: Array.from(policyIds),
|
||||
}
|
||||
})
|
||||
|
||||
when({ validationData }, ({ validationData }) => {
|
||||
return !!validationData?.actor_id && !!validationData?.policy_ids?.length
|
||||
}).then(() => {
|
||||
validateUserPermissionsStep(validationData)
|
||||
})
|
||||
|
||||
const rolePolicies = createRbacRolePoliciesStep({
|
||||
policies: input.policies,
|
||||
})
|
||||
|
||||
return new WorkflowResponse(rolePolicies)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
transform,
|
||||
when,
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
createRbacRoleInheritancesStep,
|
||||
createRbacRoleParentsStep,
|
||||
createRbacRolePoliciesStep,
|
||||
createRbacRolesStep,
|
||||
} from "../steps"
|
||||
import { validateUserPermissionsStep } from "../steps/validate-user-permissions"
|
||||
|
||||
export type CreateRbacRolesWorkflowInput = {
|
||||
actor_id?: string
|
||||
actor?: string
|
||||
roles: {
|
||||
name: string
|
||||
description?: string | null
|
||||
metadata?: Record<string, unknown> | null
|
||||
inherited_role_ids?: string[]
|
||||
parent_ids?: string[]
|
||||
policy_ids?: string[]
|
||||
}[]
|
||||
}
|
||||
@@ -25,6 +29,24 @@ export const createRbacRolesWorkflowId = "create-rbac-roles"
|
||||
export const createRbacRolesWorkflow = createWorkflow(
|
||||
createRbacRolesWorkflowId,
|
||||
(input: WorkflowData<CreateRbacRolesWorkflowInput>) => {
|
||||
const validationData = transform({ input }, ({ input }) => {
|
||||
const allPolicyIds = new Set<string>()
|
||||
input.roles.forEach((role) => {
|
||||
role.policy_ids?.forEach((policyId) => allPolicyIds.add(policyId))
|
||||
})
|
||||
return {
|
||||
actor_id: input.actor_id!,
|
||||
actor: input.actor,
|
||||
policy_ids: Array.from(allPolicyIds),
|
||||
}
|
||||
})
|
||||
|
||||
when({ validationData }, ({ validationData }) => {
|
||||
return !!validationData?.actor_id && !!validationData?.policy_ids?.length
|
||||
}).then(() => {
|
||||
validateUserPermissionsStep(validationData)
|
||||
})
|
||||
|
||||
const roleData = transform({ input }, ({ input }) => ({
|
||||
roles: input.roles.map((r) => ({
|
||||
name: r.name,
|
||||
@@ -35,22 +57,22 @@ export const createRbacRolesWorkflow = createWorkflow(
|
||||
|
||||
const createdRoles = createRbacRolesStep(roleData)
|
||||
|
||||
const inheritanceData = transform(
|
||||
const parentData = transform(
|
||||
{ input, createdRoles },
|
||||
({ input, createdRoles }) => {
|
||||
const inheritances: any[] = []
|
||||
const parents: any[] = []
|
||||
|
||||
createdRoles.forEach((role, index) => {
|
||||
const inheritedRoleIds = input.roles[index].inherited_role_ids || []
|
||||
const inheritedRoleIds = input.roles[index].parent_ids || []
|
||||
inheritedRoleIds.forEach((inheritedRoleId) => {
|
||||
inheritances.push({
|
||||
parents.push({
|
||||
role_id: role.id,
|
||||
inherited_role_id: inheritedRoleId,
|
||||
parent_id: inheritedRoleId,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return { role_inheritances: inheritances }
|
||||
return { role_parents: parents }
|
||||
}
|
||||
)
|
||||
|
||||
@@ -63,15 +85,15 @@ export const createRbacRolesWorkflow = createWorkflow(
|
||||
policyIds.forEach((policy_id) => {
|
||||
allPolicies.push({
|
||||
role_id: role.id,
|
||||
scope_id: policy_id,
|
||||
policy_id: policy_id,
|
||||
})
|
||||
})
|
||||
})
|
||||
return { role_policies: allPolicies }
|
||||
return { policies: allPolicies }
|
||||
}
|
||||
)
|
||||
|
||||
createRbacRoleInheritancesStep(inheritanceData)
|
||||
createRbacRoleParentsStep(parentData)
|
||||
|
||||
createRbacRolePoliciesStep(policiesData)
|
||||
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { deleteRbacRolePoliciesStep } from "../steps"
|
||||
|
||||
export type DeleteRbacRolePoliciesWorkflowInput = {
|
||||
ids: string[]
|
||||
role_policy_ids: string[]
|
||||
}
|
||||
|
||||
export const deleteRbacRolePoliciesWorkflowId = "delete-rbac-role-policies"
|
||||
|
||||
export const deleteRbacRolePoliciesWorkflow = createWorkflow(
|
||||
deleteRbacRolePoliciesWorkflowId,
|
||||
(
|
||||
input: WorkflowData<DeleteRbacRolePoliciesWorkflowInput>
|
||||
): WorkflowData<void> => {
|
||||
deleteRbacRolePoliciesStep(input.ids)
|
||||
(input: WorkflowData<DeleteRbacRolePoliciesWorkflowInput>) => {
|
||||
const deletedRolePolicies = deleteRbacRolePoliciesStep(
|
||||
input.role_policy_ids
|
||||
)
|
||||
|
||||
return new WorkflowResponse(deletedRolePolicies)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -8,4 +8,3 @@ export * from "./update-rbac-policies"
|
||||
|
||||
export * from "./create-rbac-role-policies"
|
||||
export * from "./delete-rbac-role-policies"
|
||||
export * from "./update-rbac-role-policies"
|
||||
|
||||
@@ -4,15 +4,19 @@ import {
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
transform,
|
||||
when,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { UpdateRbacRoleDTO } from "@medusajs/types"
|
||||
import { createRbacRolePoliciesStep, setRoleInheritanceStep } from "../steps"
|
||||
import { createRbacRolePoliciesStep, setRoleParentStep } from "../steps"
|
||||
import { updateRbacRolesStep } from "../steps/update-rbac-roles"
|
||||
import { validateUserPermissionsStep } from "../steps/validate-user-permissions"
|
||||
|
||||
export type UpdateRbacRolesWorkflowInput = {
|
||||
actor_id?: string
|
||||
actor?: string
|
||||
selector: Record<string, any>
|
||||
update: Omit<UpdateRbacRoleDTO, "id"> & {
|
||||
inherited_role_ids?: string[]
|
||||
parent_ids?: string[]
|
||||
policy_ids?: string[]
|
||||
}
|
||||
}
|
||||
@@ -22,6 +26,21 @@ export const updateRbacRolesWorkflowId = "update-rbac-roles"
|
||||
export const updateRbacRolesWorkflow = createWorkflow(
|
||||
updateRbacRolesWorkflowId,
|
||||
(input: WorkflowData<UpdateRbacRolesWorkflowInput>) => {
|
||||
const validationData = transform({ input }, ({ input }) => {
|
||||
const policyIds = input.update.policy_ids || []
|
||||
return {
|
||||
actor_id: input.actor_id!,
|
||||
policy_ids: policyIds,
|
||||
actor: input.actor,
|
||||
}
|
||||
})
|
||||
|
||||
when({ validationData }, ({ validationData }) => {
|
||||
return !!validationData?.actor_id && !!validationData?.policy_ids?.length
|
||||
}).then(() => {
|
||||
validateUserPermissionsStep(validationData)
|
||||
})
|
||||
|
||||
const roleUpdateData = transform({ input }, ({ input }) => ({
|
||||
selector: input.selector,
|
||||
update: {
|
||||
@@ -33,40 +52,40 @@ export const updateRbacRolesWorkflow = createWorkflow(
|
||||
|
||||
const updatedRoles = updateRbacRolesStep(roleUpdateData)
|
||||
|
||||
const inheritanceUpdateData = transform(
|
||||
const parentUpdateData = transform(
|
||||
{ input, updatedRoles },
|
||||
({ input, updatedRoles }) => {
|
||||
if (!isDefined(input.update.inherited_role_ids)) {
|
||||
if (!isDefined(input.update.parent_ids)) {
|
||||
return []
|
||||
}
|
||||
|
||||
return updatedRoles.map((role) => ({
|
||||
role_id: role.id,
|
||||
inherited_role_ids: input.update.inherited_role_ids || [],
|
||||
parent_ids: input.update.parent_ids || [],
|
||||
}))
|
||||
}
|
||||
)
|
||||
|
||||
setRoleInheritanceStep(inheritanceUpdateData)
|
||||
setRoleParentStep(parentUpdateData)
|
||||
|
||||
const policiesUpdateData = transform(
|
||||
{ input, updatedRoles },
|
||||
({ input, updatedRoles }) => {
|
||||
if (!isDefined(input.update.policy_ids)) {
|
||||
return { role_policies: [] }
|
||||
return { policies: [] }
|
||||
}
|
||||
|
||||
const allPolicies: any[] = []
|
||||
updatedRoles.forEach((role) => {
|
||||
const policyIds = input.update.policy_ids || []
|
||||
policyIds.forEach((policy_id) => {
|
||||
policyIds.forEach((policyId) => {
|
||||
allPolicies.push({
|
||||
role_id: role.id,
|
||||
scope_id: policy_id,
|
||||
policy_id: policyId,
|
||||
})
|
||||
})
|
||||
})
|
||||
return { role_policies: allPolicies }
|
||||
return { policies: allPolicies }
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user