feat(rbac): role-based access control module (#14310)
This commit is contained in:
1 parent
d6d7d14a6a
commit
1bfde8dc57
74 files changed
+4186
-3
No files matched your search
@@ -0,0 +1,285 @@
|
|||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import {
|
||||||
|
adminHeaders,
|
||||||
|
createAdminUser,
|
||||||
|
} from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(60000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
testSuite: ({ dbConnection, api, getContainer }) => {
|
||||||
|
let container
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
container = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("RBAC Policies - Admin API", () => {
|
||||||
|
describe("POST /admin/rbac/policies", () => {
|
||||||
|
it("should create a policy", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Products",
|
||||||
|
description: "Permission to read products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.policy).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Products",
|
||||||
|
description: "Permission to read products",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a policy with metadata", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "write:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Orders",
|
||||||
|
metadata: { category: "order_management" },
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.policy).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "write",
|
||||||
|
metadata: { category: "order_management" },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /admin/rbac/policies", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "write:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "read:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Orders",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should list all policies", async () => {
|
||||||
|
const response = await api.get("/admin/rbac/policies", adminHeaders)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.count).toEqual(3)
|
||||||
|
expect(response.data.policies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "write",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "read",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should filter policies by resource", async () => {
|
||||||
|
const response = await api.get(
|
||||||
|
"/admin/rbac/policies?resource=product",
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.count).toEqual(2)
|
||||||
|
expect(response.data.policies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:products",
|
||||||
|
resource: "product",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should filter policies by operation", async () => {
|
||||||
|
const response = await api.get(
|
||||||
|
"/admin/rbac/policies?operation=read",
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.count).toEqual(2)
|
||||||
|
expect(response.data.policies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:products",
|
||||||
|
operation: "read",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:orders",
|
||||||
|
operation: "read",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /admin/rbac/policies/:id", () => {
|
||||||
|
it("should retrieve a policy by id", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "delete:users",
|
||||||
|
resource: "user",
|
||||||
|
operation: "delete",
|
||||||
|
name: "Delete Users",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const policyId = createResponse.data.policy.id
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
`/admin/rbac/policies/${policyId}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.policy).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: policyId,
|
||||||
|
key: "delete:users",
|
||||||
|
resource: "user",
|
||||||
|
operation: "delete",
|
||||||
|
name: "Delete Users",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/rbac/policies/:id", () => {
|
||||||
|
it("should update a policy", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "admin:system",
|
||||||
|
resource: "system",
|
||||||
|
operation: "admin",
|
||||||
|
name: "System Admin",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const policyId = createResponse.data.policy.id
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/rbac/policies/${policyId}`,
|
||||||
|
{
|
||||||
|
name: "System Administrator",
|
||||||
|
description: "Full system access",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.policy).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: policyId,
|
||||||
|
key: "admin:system",
|
||||||
|
name: "System Administrator",
|
||||||
|
description: "Full system access",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("DELETE /admin/rbac/policies/:id", () => {
|
||||||
|
it("should delete a policy", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "test:delete",
|
||||||
|
resource: "test",
|
||||||
|
operation: "delete",
|
||||||
|
name: "Test Delete",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const policyId = createResponse.data.policy.id
|
||||||
|
|
||||||
|
const deleteResponse = await api.delete(
|
||||||
|
`/admin/rbac/policies/${policyId}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(deleteResponse.status).toEqual(200)
|
||||||
|
expect(deleteResponse.data).toEqual({
|
||||||
|
id: policyId,
|
||||||
|
object: "rbac_policy",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const listResponse = await api.get(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
listResponse.data.policies.find((p) => p.id === policyId)
|
||||||
|
).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import {
|
||||||
|
adminHeaders,
|
||||||
|
createAdminUser,
|
||||||
|
} from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(60000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
testSuite: ({ dbConnection, api, getContainer }) => {
|
||||||
|
let container
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
container = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("RBAC Roles - Admin API", () => {
|
||||||
|
describe("POST /admin/rbac/roles", () => {
|
||||||
|
it("should create a role", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Viewer",
|
||||||
|
description: "Can view resources",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.role).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
name: "Viewer",
|
||||||
|
description: "Can view resources",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a role with metadata", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Editor",
|
||||||
|
description: "Can edit resources",
|
||||||
|
metadata: { department: "sales" },
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.role).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "Editor",
|
||||||
|
metadata: { department: "sales" },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /admin/rbac/roles", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Viewer",
|
||||||
|
description: "Can view resources",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Editor",
|
||||||
|
description: "Can edit resources",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Admin",
|
||||||
|
description: "Full access",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should list all roles", async () => {
|
||||||
|
const response = await api.get("/admin/rbac/roles", adminHeaders)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.count).toEqual(3)
|
||||||
|
expect(response.data.roles).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "Viewer",
|
||||||
|
description: "Can view resources",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "Editor",
|
||||||
|
description: "Can edit resources",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "Admin",
|
||||||
|
description: "Full access",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should filter roles by name", async () => {
|
||||||
|
const response = await api.get(
|
||||||
|
"/admin/rbac/roles?name=Viewer",
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.count).toEqual(1)
|
||||||
|
expect(response.data.roles[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "Viewer",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /admin/rbac/roles/:id", () => {
|
||||||
|
it("should retrieve a role by id", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Manager",
|
||||||
|
description: "Can manage resources",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const roleId = createResponse.data.role.id
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
`/admin/rbac/roles/${roleId}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.role).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: roleId,
|
||||||
|
name: "Manager",
|
||||||
|
description: "Can manage resources",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/rbac/roles/:id", () => {
|
||||||
|
it("should update a role", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Support",
|
||||||
|
description: "Support team",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const roleId = createResponse.data.role.id
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/rbac/roles/${roleId}`,
|
||||||
|
{
|
||||||
|
name: "Customer Support",
|
||||||
|
description: "Customer support team with limited access",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.role).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: roleId,
|
||||||
|
name: "Customer Support",
|
||||||
|
description: "Customer support team with limited access",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("DELETE /admin/rbac/roles/:id", () => {
|
||||||
|
it("should delete a role", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Temporary",
|
||||||
|
description: "Temporary role",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const roleId = createResponse.data.role.id
|
||||||
|
|
||||||
|
const deleteResponse = await api.delete(
|
||||||
|
`/admin/rbac/roles/${roleId}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(deleteResponse.status).toEqual(200)
|
||||||
|
expect(deleteResponse.data).toEqual({
|
||||||
|
id: roleId,
|
||||||
|
object: "rbac_role",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const listResponse = await api.get("/admin/rbac/roles", adminHeaders)
|
||||||
|
expect(
|
||||||
|
listResponse.data.roles.find((r) => r.id === roleId)
|
||||||
|
).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Role Policies", () => {
|
||||||
|
let policies
|
||||||
|
let viewerRole
|
||||||
|
let editorRole
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const policy1 = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const policy2 = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "write:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const policy3 = await api.post(
|
||||||
|
"/admin/rbac/policies",
|
||||||
|
{
|
||||||
|
key: "delete:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "delete",
|
||||||
|
name: "Delete Products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
policies = [
|
||||||
|
policy1.data.policy,
|
||||||
|
policy2.data.policy,
|
||||||
|
policy3.data.policy,
|
||||||
|
]
|
||||||
|
|
||||||
|
const viewer = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Product Viewer",
|
||||||
|
description: "Can view products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
viewerRole = viewer.data.role
|
||||||
|
|
||||||
|
const editor = await api.post(
|
||||||
|
"/admin/rbac/roles",
|
||||||
|
{
|
||||||
|
name: "Product Editor",
|
||||||
|
description: "Can edit products",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
editorRole = editor.data.role
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create role-policy associations", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
"/admin/rbac/role-policies",
|
||||||
|
{
|
||||||
|
role_id: viewerRole.id,
|
||||||
|
scope_id: policies[0].id,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.role_policy).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
role_id: viewerRole.id,
|
||||||
|
scope_id: policies[0].id,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should list role-policies for a specific role", async () => {
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/role-policies",
|
||||||
|
{
|
||||||
|
role_id: viewerRole.id,
|
||||||
|
scope_id: policies[0].id,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
"/admin/rbac/role-policies",
|
||||||
|
{
|
||||||
|
role_id: viewerRole.id,
|
||||||
|
scope_id: policies[1].id,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
`/admin/rbac/role-policies?role_id=${viewerRole.id}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.count).toEqual(2)
|
||||||
|
expect(response.data.role_policies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
role_id: viewerRole.id,
|
||||||
|
scope_id: policies[0].id,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
role_id: viewerRole.id,
|
||||||
|
scope_id: policies[1].id,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should delete a role-policy association", async () => {
|
||||||
|
const createResponse = await api.post(
|
||||||
|
"/admin/rbac/role-policies",
|
||||||
|
{
|
||||||
|
role_id: editorRole.id,
|
||||||
|
scope_id: policies[2].id,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
const rolePolicyId = createResponse.data.role_policy.id
|
||||||
|
|
||||||
|
const deleteResponse = await api.delete(
|
||||||
|
`/admin/rbac/role-policies/${rolePolicyId}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(deleteResponse.status).toEqual(200)
|
||||||
|
expect(deleteResponse.data).toEqual({
|
||||||
|
id: rolePolicyId,
|
||||||
|
object: "rbac_role_policy",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const listResponse = await api.get(
|
||||||
|
`/admin/rbac/role-policies?role_id=${editorRole.id}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
listResponse.data.role_policies.find((rp) => rp.id === rolePolicyId)
|
||||||
|
).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -66,6 +66,9 @@ const modules = {
|
|||||||
resolve: "@medusajs/index",
|
resolve: "@medusajs/index",
|
||||||
disable: process.env.ENABLE_INDEX_MODULE !== "true",
|
disable: process.env.ENABLE_INDEX_MODULE !== "true",
|
||||||
},
|
},
|
||||||
|
[Modules.RBAC]: {
|
||||||
|
resolve: "@medusajs/rbac",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.MEDUSA_FF_TRANSLATION === "true") {
|
if (process.env.MEDUSA_FF_TRANSLATION === "true") {
|
||||||
|
|||||||
@@ -0,0 +1,516 @@
|
|||||||
|
import {
|
||||||
|
createRbacPoliciesWorkflow,
|
||||||
|
createRbacRolesWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import { IRbacModuleService, MedusaContainer } from "@medusajs/types"
|
||||||
|
import { Modules } from "@medusajs/utils"
|
||||||
|
|
||||||
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: {},
|
||||||
|
testSuite: ({ getContainer }) => {
|
||||||
|
describe("Workflows: RBAC", () => {
|
||||||
|
let appContainer: MedusaContainer
|
||||||
|
let rbacService: IRbacModuleService
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
appContainer = getContainer()
|
||||||
|
rbacService = appContainer.resolve(Modules.RBAC)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Role Inheritance and Policy Management", () => {
|
||||||
|
it("should create roles with inheritance and policies, then list all inherited policies", async () => {
|
||||||
|
// Step 1: Create base policies
|
||||||
|
const policiesWorkflow = createRbacPoliciesWorkflow(appContainer)
|
||||||
|
const { result: createdPolicies } = await policiesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
policies: [
|
||||||
|
{
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Products",
|
||||||
|
description: "Permission to read products",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "write:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Products",
|
||||||
|
description: "Permission to write products",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "read:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Orders",
|
||||||
|
description: "Permission to read orders",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "write:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Orders",
|
||||||
|
description: "Permission to write orders",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "delete:users",
|
||||||
|
resource: "user",
|
||||||
|
operation: "delete",
|
||||||
|
name: "Delete Users",
|
||||||
|
description: "Permission to delete users",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(createdPolicies).toHaveLength(5)
|
||||||
|
|
||||||
|
// Step 2: Create base roles with their policies
|
||||||
|
const rolesWorkflow = createRbacRolesWorkflow(appContainer)
|
||||||
|
|
||||||
|
// Create "Viewer" role with read permissions
|
||||||
|
const { result: viewerRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Viewer",
|
||||||
|
description: "Can view products and orders",
|
||||||
|
policy_ids: [
|
||||||
|
createdPolicies[0].id, // read:products
|
||||||
|
createdPolicies[2].id, // read:orders
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(viewerRoles).toHaveLength(1)
|
||||||
|
const viewerRole = viewerRoles[0]
|
||||||
|
|
||||||
|
// Create "Editor" role with write permissions
|
||||||
|
const { result: editorRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Editor",
|
||||||
|
description: "Can write products and orders",
|
||||||
|
policy_ids: [
|
||||||
|
createdPolicies[1].id, // write:products
|
||||||
|
createdPolicies[3].id, // write:orders
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(editorRoles).toHaveLength(1)
|
||||||
|
const editorRole = editorRoles[0]
|
||||||
|
|
||||||
|
// Step 3: Create "Admin" role that inherits from both Viewer and Editor, plus additional permissions
|
||||||
|
const { result: adminRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Admin",
|
||||||
|
description:
|
||||||
|
"Inherits from Viewer and Editor, plus can delete users",
|
||||||
|
inherited_role_ids: [viewerRole.id, editorRole.id],
|
||||||
|
policy_ids: [
|
||||||
|
createdPolicies[4].id, // delete:users
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(adminRoles).toHaveLength(1)
|
||||||
|
const adminRole = adminRoles[0]
|
||||||
|
|
||||||
|
// Step 4: Verify role inheritance was created
|
||||||
|
const inheritances = await rbacService.listRbacRoleInheritances({
|
||||||
|
role_id: adminRole.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(inheritances).toHaveLength(2)
|
||||||
|
expect(inheritances).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
role_id: adminRole.id,
|
||||||
|
inherited_role_id: viewerRole.id,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
role_id: adminRole.id,
|
||||||
|
inherited_role_id: editorRole.id,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
// Step 5: Verify direct policies for Admin role
|
||||||
|
const adminDirectPolicies = await rbacService.listRbacRolePolicies({
|
||||||
|
role_id: adminRole.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(adminDirectPolicies).toHaveLength(1)
|
||||||
|
expect(adminDirectPolicies[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
role_id: adminRole.id,
|
||||||
|
scope_id: createdPolicies[4].id, // delete:users
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Step 6: List ALL policies for Admin role (including inherited)
|
||||||
|
const allAdminPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
adminRole.id
|
||||||
|
)
|
||||||
|
|
||||||
|
// Admin should have:
|
||||||
|
// - read:products (from Viewer)
|
||||||
|
// - read:orders (from Viewer)
|
||||||
|
// - write:products (from Editor)
|
||||||
|
// - write:orders (from Editor)
|
||||||
|
// - delete:users (direct)
|
||||||
|
expect(allAdminPolicies).toHaveLength(5)
|
||||||
|
|
||||||
|
const policyKeys = allAdminPolicies.map((p) => p.key).sort()
|
||||||
|
expect(policyKeys).toEqual([
|
||||||
|
"delete:users",
|
||||||
|
"read:orders",
|
||||||
|
"read:products",
|
||||||
|
"write:orders",
|
||||||
|
"write:products",
|
||||||
|
])
|
||||||
|
|
||||||
|
// Verify each policy has correct details
|
||||||
|
expect(allAdminPolicies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "read",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:products",
|
||||||
|
resource: "product",
|
||||||
|
operation: "write",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "read",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:orders",
|
||||||
|
resource: "order",
|
||||||
|
operation: "write",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "delete:users",
|
||||||
|
resource: "user",
|
||||||
|
operation: "delete",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
// Step 7: Verify Viewer role only has its direct policies
|
||||||
|
const viewerPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
viewerRole.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(viewerPolicies).toHaveLength(2)
|
||||||
|
expect(viewerPolicies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:products",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "read:orders",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
// Step 8: Verify Editor role only has its direct policies
|
||||||
|
const editorPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
editorRole.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(editorPolicies).toHaveLength(2)
|
||||||
|
expect(editorPolicies).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:products",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: "write:orders",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle multi-level role inheritance", async () => {
|
||||||
|
// Create policies
|
||||||
|
const policiesWorkflow = createRbacPoliciesWorkflow(appContainer)
|
||||||
|
const { result: policies } = await policiesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
policies: [
|
||||||
|
{
|
||||||
|
key: "read:catalog",
|
||||||
|
resource: "catalog",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Catalog",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "write:catalog",
|
||||||
|
resource: "catalog",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Catalog",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "admin:system",
|
||||||
|
resource: "system",
|
||||||
|
operation: "admin",
|
||||||
|
name: "System Admin",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create role hierarchy: Basic -> Manager -> SuperAdmin
|
||||||
|
const rolesWorkflow = createRbacRolesWorkflow(appContainer)
|
||||||
|
|
||||||
|
// Level 1: Basic role
|
||||||
|
const { result: basicRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Basic User",
|
||||||
|
description: "Basic read access",
|
||||||
|
policy_ids: [policies[0].id], // read:catalog
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const basicRole = basicRoles[0]
|
||||||
|
|
||||||
|
// Level 2: Manager inherits from Basic
|
||||||
|
const { result: managerRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Manager",
|
||||||
|
description: "Manager with write access",
|
||||||
|
inherited_role_ids: [basicRole.id],
|
||||||
|
policy_ids: [policies[1].id], // write:catalog
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const managerRole = managerRoles[0]
|
||||||
|
|
||||||
|
// Level 3: SuperAdmin inherits from Manager
|
||||||
|
const { result: superAdminRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "SuperAdmin",
|
||||||
|
description: "Super admin with all access",
|
||||||
|
inherited_role_ids: [managerRole.id],
|
||||||
|
policy_ids: [policies[2].id], // admin:system
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const superAdminRole = superAdminRoles[0]
|
||||||
|
|
||||||
|
// Verify SuperAdmin has all policies through inheritance chain
|
||||||
|
const superAdminPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
superAdminRole.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(superAdminPolicies).toHaveLength(3)
|
||||||
|
expect(superAdminPolicies.map((p) => p.key).sort()).toEqual([
|
||||||
|
"admin:system",
|
||||||
|
"read:catalog",
|
||||||
|
"write:catalog",
|
||||||
|
])
|
||||||
|
|
||||||
|
// Verify Manager has policies from Basic + its own
|
||||||
|
const managerPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
managerRole.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(managerPolicies).toHaveLength(2)
|
||||||
|
expect(managerPolicies.map((p) => p.key).sort()).toEqual([
|
||||||
|
"read:catalog",
|
||||||
|
"write:catalog",
|
||||||
|
])
|
||||||
|
|
||||||
|
// Verify Basic only has its own policy
|
||||||
|
const basicPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
basicRole.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(basicPolicies).toHaveLength(1)
|
||||||
|
expect(basicPolicies[0].key).toBe("read:catalog")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should propagate policy deletion from inherited role", async () => {
|
||||||
|
// Create policies
|
||||||
|
const policiesWorkflow = createRbacPoliciesWorkflow(appContainer)
|
||||||
|
const { result: policies } = await policiesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
policies: [
|
||||||
|
{
|
||||||
|
key: "read:inventory",
|
||||||
|
resource: "inventory",
|
||||||
|
operation: "read",
|
||||||
|
name: "Read Inventory",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "write:inventory",
|
||||||
|
resource: "inventory",
|
||||||
|
operation: "write",
|
||||||
|
name: "Write Inventory",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "admin:inventory",
|
||||||
|
resource: "inventory",
|
||||||
|
operation: "admin",
|
||||||
|
name: "Admin Inventory",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create role hierarchy: Basic -> Manager -> SuperAdmin
|
||||||
|
const rolesWorkflow = createRbacRolesWorkflow(appContainer)
|
||||||
|
|
||||||
|
// Level 1: Basic role with read permission
|
||||||
|
const { result: basicRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Basic Inventory User",
|
||||||
|
description: "Basic inventory read access",
|
||||||
|
policy_ids: [policies[0].id], // read:inventory
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const basicRole = basicRoles[0]
|
||||||
|
|
||||||
|
// Level 2: Manager inherits from Basic + write permission
|
||||||
|
const { result: managerRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Inventory Manager",
|
||||||
|
description: "Manager with write access",
|
||||||
|
inherited_role_ids: [basicRole.id],
|
||||||
|
policy_ids: [policies[1].id], // write:inventory
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const managerRole = managerRoles[0]
|
||||||
|
|
||||||
|
// Level 3: SuperAdmin inherits from Manager + admin permission
|
||||||
|
const { result: superAdminRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Inventory SuperAdmin",
|
||||||
|
description: "Super admin with all access",
|
||||||
|
inherited_role_ids: [managerRole.id],
|
||||||
|
policy_ids: [policies[2].id], // admin:inventory
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const superAdminRole = superAdminRoles[0]
|
||||||
|
|
||||||
|
// Verify initial state: SuperAdmin has all 3 policies
|
||||||
|
let superAdminPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
superAdminRole.id
|
||||||
|
)
|
||||||
|
expect(superAdminPolicies).toHaveLength(3)
|
||||||
|
expect(superAdminPolicies.map((p) => p.key).sort()).toEqual([
|
||||||
|
"admin:inventory",
|
||||||
|
"read:inventory",
|
||||||
|
"write:inventory",
|
||||||
|
])
|
||||||
|
|
||||||
|
// Verify Manager has 2 policies (Basic's + its own)
|
||||||
|
let managerPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
managerRole.id
|
||||||
|
)
|
||||||
|
expect(managerPolicies).toHaveLength(2)
|
||||||
|
expect(managerPolicies.map((p) => p.key).sort()).toEqual([
|
||||||
|
"read:inventory",
|
||||||
|
"write:inventory",
|
||||||
|
])
|
||||||
|
|
||||||
|
// Delete the read:inventory policy from Basic role
|
||||||
|
const basicRolePolicies = await rbacService.listRbacRolePolicies({
|
||||||
|
role_id: basicRole.id,
|
||||||
|
})
|
||||||
|
const readPolicyAssociation = basicRolePolicies.find(
|
||||||
|
(rp) => rp.scope_id === policies[0].id
|
||||||
|
)
|
||||||
|
await rbacService.deleteRbacRolePolicies([readPolicyAssociation!.id])
|
||||||
|
|
||||||
|
// Verify Basic role no longer has the read policy
|
||||||
|
const basicPoliciesAfterDelete =
|
||||||
|
await rbacService.listPoliciesForRole(basicRole.id)
|
||||||
|
expect(basicPoliciesAfterDelete).toHaveLength(0)
|
||||||
|
|
||||||
|
// Verify Manager role no longer inherits the read policy
|
||||||
|
managerPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
managerRole.id
|
||||||
|
)
|
||||||
|
expect(managerPolicies).toHaveLength(1)
|
||||||
|
expect(managerPolicies[0].key).toBe("write:inventory")
|
||||||
|
|
||||||
|
// Verify SuperAdmin role also lost the read policy through inheritance chain
|
||||||
|
superAdminPolicies = await rbacService.listPoliciesForRole(
|
||||||
|
superAdminRole.id
|
||||||
|
)
|
||||||
|
expect(superAdminPolicies).toHaveLength(2)
|
||||||
|
expect(superAdminPolicies.map((p) => p.key).sort()).toEqual([
|
||||||
|
"admin:inventory",
|
||||||
|
"write:inventory",
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle role with no inherited roles or policies", async () => {
|
||||||
|
const rolesWorkflow = createRbacRolesWorkflow(appContainer)
|
||||||
|
|
||||||
|
const { result: emptyRoles } = await rolesWorkflow.run({
|
||||||
|
input: {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: "Empty Role",
|
||||||
|
description: "Role with no permissions",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emptyRole = emptyRoles[0]
|
||||||
|
|
||||||
|
// Verify no policies
|
||||||
|
const policies = await rbacService.listPoliciesForRole(emptyRole.id)
|
||||||
|
expect(policies).toHaveLength(0)
|
||||||
|
|
||||||
|
// Verify no inheritance
|
||||||
|
const inheritances = await rbacService.listRbacRoleInheritances({
|
||||||
|
role_id: emptyRole.id,
|
||||||
|
})
|
||||||
|
expect(inheritances).toHaveLength(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -189,5 +189,9 @@ module.exports = defineConfig({
|
|||||||
key: "brand",
|
key: "brand",
|
||||||
resolve: "src/modules/brand",
|
resolve: "src/modules/brand",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: Modules.RBAC,
|
||||||
|
resolve: "@medusajs/rbac",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -21,6 +21,7 @@ export * from "./pricing"
|
|||||||
export * from "./product"
|
export * from "./product"
|
||||||
export * from "./product-category"
|
export * from "./product-category"
|
||||||
export * from "./promotion"
|
export * from "./promotion"
|
||||||
|
export * from "./rbac"
|
||||||
export * from "./region"
|
export * from "./region"
|
||||||
export * from "./reservation"
|
export * from "./reservation"
|
||||||
export * from "./return-reason"
|
export * from "./return-reason"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./steps"
|
||||||
|
export * from "./workflows"
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacPoliciesStepInput = {
|
||||||
|
policies: CreateRbacPolicyDTO[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacPoliciesStepId = "create-rbac-policies"
|
||||||
|
|
||||||
|
export const createRbacPoliciesStep = createStep(
|
||||||
|
createRbacPoliciesStepId,
|
||||||
|
async (data: CreateRbacPoliciesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const created = await service.createRbacPolicies(data.policies)
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
created,
|
||||||
|
(created ?? []).map((p) => p.id)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (createdIds: string[] | undefined, { container }) => {
|
||||||
|
if (!createdIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
await service.deleteRbacPolicies(createdIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type CreateRbacRoleInheritanceDTO = {
|
||||||
|
role_id: string
|
||||||
|
inherited_role_id: string
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacRoleInheritancesStepInput = {
|
||||||
|
role_inheritances: CreateRbacRoleInheritanceDTO[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacRoleInheritancesStepId = "create-rbac-role-inheritances"
|
||||||
|
|
||||||
|
export const createRbacRoleInheritancesStep = createStep(
|
||||||
|
createRbacRoleInheritancesStepId,
|
||||||
|
async (data: CreateRbacRoleInheritancesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
if (!data.role_inheritances || data.role_inheritances.length === 0) {
|
||||||
|
return new StepResponse([], [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const created = await service.createRbacRoleInheritances(
|
||||||
|
data.role_inheritances
|
||||||
|
)
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
created,
|
||||||
|
(created ?? []).map((ri) => ri.id)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (createdIds: string[] | undefined, { container }) => {
|
||||||
|
if (!createdIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
await service.deleteRbacRoleInheritances(createdIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacRolePoliciesStepInput = {
|
||||||
|
role_policies: CreateRbacRolePolicyDTO[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacRolePoliciesStepId = "create-rbac-role-policies"
|
||||||
|
|
||||||
|
export const createRbacRolePoliciesStep = createStep(
|
||||||
|
createRbacRolePoliciesStepId,
|
||||||
|
async (data: CreateRbacRolePoliciesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const created = await service.createRbacRolePolicies(data.role_policies)
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
created,
|
||||||
|
(created ?? []).map((rp) => rp.id)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (createdIds: string[] | undefined, { container }) => {
|
||||||
|
if (!createdIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
await service.deleteRbacRolePolicies(createdIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type CreateRbacRoleDTO = {
|
||||||
|
name: string
|
||||||
|
description?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacRolesStepInput = {
|
||||||
|
roles: CreateRbacRoleDTO[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacRolesStepId = "create-rbac-roles"
|
||||||
|
|
||||||
|
export const createRbacRolesStep = createStep(
|
||||||
|
createRbacRolesStepId,
|
||||||
|
async (data: CreateRbacRolesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const created = await service.createRbacRoles(data.roles)
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
created,
|
||||||
|
(created ?? []).map((r) => r.id)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (createdIds: string[] | undefined, { container }) => {
|
||||||
|
if (!createdIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
await service.deleteRbacRoles(createdIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type DeleteRbacPoliciesStepInput = string[]
|
||||||
|
|
||||||
|
export const deleteRbacPoliciesStepId = "delete-rbac-policies"
|
||||||
|
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
async () => {}
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type DeleteRbacRolePoliciesStepInput = string[]
|
||||||
|
|
||||||
|
export const deleteRbacRolePoliciesStepId = "delete-rbac-role-policies"
|
||||||
|
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
async () => {}
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type DeleteRbacRolesStepInput = string[]
|
||||||
|
|
||||||
|
export const deleteRbacRolesStepId = "delete-rbac-roles"
|
||||||
|
|
||||||
|
export const deleteRbacRolesStep = createStep(
|
||||||
|
{ name: deleteRbacRolesStepId, noCompensation: true },
|
||||||
|
async (ids: DeleteRbacRolesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
await service.deleteRbacRoles(ids)
|
||||||
|
return new StepResponse(void 0)
|
||||||
|
},
|
||||||
|
async () => {}
|
||||||
|
)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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-policies"
|
||||||
|
export * from "./delete-rbac-role-policies"
|
||||||
|
export * from "./update-rbac-role-policies"
|
||||||
|
|
||||||
|
export * from "./create-rbac-role-inheritances"
|
||||||
|
export * from "./set-role-inheritance"
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { Modules } from "@medusajs/framework/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type SetRoleInheritanceStepInput = Array<{
|
||||||
|
role_id: string
|
||||||
|
inherited_role_ids: string[]
|
||||||
|
}>
|
||||||
|
|
||||||
|
export const setRoleInheritanceStepId = "set-role-inheritance"
|
||||||
|
|
||||||
|
export const setRoleInheritanceStep = createStep(
|
||||||
|
setRoleInheritanceStepId,
|
||||||
|
async (data: SetRoleInheritanceStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const allCompensationData: Array<{
|
||||||
|
role_id: string
|
||||||
|
previousInheritedRoleIds: string[]
|
||||||
|
}> = []
|
||||||
|
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return new StepResponse(
|
||||||
|
{ created: [], removedCount: 0 },
|
||||||
|
allCompensationData
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const allToRemoveIds: string[] = []
|
||||||
|
const allToCreate: Array<{
|
||||||
|
role_id: string
|
||||||
|
inherited_role_id: string
|
||||||
|
}> = []
|
||||||
|
|
||||||
|
for (const roleData of data) {
|
||||||
|
const existingInheritance = await service.listRbacRoleInheritances({
|
||||||
|
role_id: roleData.role_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingInheritedRoleIds = existingInheritance.map(
|
||||||
|
(ri) => ri.inherited_role_id
|
||||||
|
)
|
||||||
|
|
||||||
|
allCompensationData.push({
|
||||||
|
role_id: roleData.role_id,
|
||||||
|
previousInheritedRoleIds: existingInheritedRoleIds,
|
||||||
|
})
|
||||||
|
|
||||||
|
const toAdd = roleData.inherited_role_ids.filter(
|
||||||
|
(id) => !existingInheritedRoleIds.includes(id)
|
||||||
|
)
|
||||||
|
const toRemove = existingInheritedRoleIds.filter(
|
||||||
|
(id) => !roleData.inherited_role_ids.includes(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (toRemove.length > 0) {
|
||||||
|
const toRemoveRecords = existingInheritance.filter((ri) =>
|
||||||
|
toRemove.includes(ri.inherited_role_id)
|
||||||
|
)
|
||||||
|
allToRemoveIds.push(...toRemoveRecords.map((ri) => ri.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toAdd.length > 0) {
|
||||||
|
allToCreate.push(
|
||||||
|
...toAdd.map((inherited_role_id) => ({
|
||||||
|
role_id: roleData.role_id,
|
||||||
|
inherited_role_id,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allToRemoveIds.length > 0) {
|
||||||
|
await service.deleteRbacRoleInheritances(allToRemoveIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
let created: any[] = []
|
||||||
|
if (allToCreate.length > 0) {
|
||||||
|
created = await service.createRbacRoleInheritances(allToCreate)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
{ created, removedCount: allToRemoveIds.length },
|
||||||
|
allCompensationData
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (
|
||||||
|
compensationData:
|
||||||
|
| Array<{ role_id: string; previousInheritedRoleIds: string[] }>
|
||||||
|
| undefined,
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
if (!compensationData || compensationData.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
for (const roleCompensation of compensationData) {
|
||||||
|
const currentInheritance = await service.listRbacRoleInheritances({
|
||||||
|
role_id: roleCompensation.role_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (currentInheritance.length > 0) {
|
||||||
|
await service.deleteRbacRoleInheritances(
|
||||||
|
currentInheritance.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,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
getSelectsAndRelationsFromObjectArray,
|
||||||
|
Modules,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService, UpdateRbacPolicyDTO } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type UpdateRbacPoliciesStepInput = {
|
||||||
|
selector: Record<string, any>
|
||||||
|
update: Omit<UpdateRbacPolicyDTO, "id">
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateRbacPoliciesStepId = "update-rbac-policies"
|
||||||
|
|
||||||
|
export const updateRbacPoliciesStep = createStep(
|
||||||
|
updateRbacPoliciesStepId,
|
||||||
|
async (data: UpdateRbacPoliciesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||||
|
data.update,
|
||||||
|
])
|
||||||
|
|
||||||
|
const prevData = await service.listRbacPolicies(data.selector, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const updates = (prevData ?? []).map((p) => ({
|
||||||
|
id: p.id,
|
||||||
|
...data.update,
|
||||||
|
})) as UpdateRbacPolicyDTO[]
|
||||||
|
|
||||||
|
const updated = await service.updateRbacPolicies(updates)
|
||||||
|
|
||||||
|
return new StepResponse(updated, {
|
||||||
|
prevData,
|
||||||
|
updateKeys: Object.keys(data.update ?? {}),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async (
|
||||||
|
compensationData: { prevData: any[]; updateKeys: string[] } | undefined,
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
if (!compensationData?.prevData?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const updates = compensationData.prevData.map((p) => {
|
||||||
|
const payload: Record<string, any> = { id: p.id }
|
||||||
|
for (const key of compensationData.updateKeys) {
|
||||||
|
payload[key] = p[key]
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}) as UpdateRbacPolicyDTO[]
|
||||||
|
|
||||||
|
await service.updateRbacPolicies(updates)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
getSelectsAndRelationsFromObjectArray,
|
||||||
|
Modules,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService, UpdateRbacRolePolicyDTO } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type UpdateRbacRolePoliciesStepInput = {
|
||||||
|
selector: Record<string, any>
|
||||||
|
update: Omit<UpdateRbacRolePolicyDTO, "id">
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateRbacRolePoliciesStepId = "update-rbac-role-policies"
|
||||||
|
|
||||||
|
export const updateRbacRolePoliciesStep = createStep(
|
||||||
|
updateRbacRolePoliciesStepId,
|
||||||
|
async (data: UpdateRbacRolePoliciesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||||
|
data.update,
|
||||||
|
])
|
||||||
|
|
||||||
|
const prevData = await service.listRbacRolePolicies(data.selector, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const updates = (prevData ?? []).map((rp) => ({
|
||||||
|
id: rp.id,
|
||||||
|
...data.update,
|
||||||
|
})) as UpdateRbacRolePolicyDTO[]
|
||||||
|
|
||||||
|
const updated = await service.updateRbacRolePolicies(updates)
|
||||||
|
|
||||||
|
return new StepResponse(updated, {
|
||||||
|
prevData,
|
||||||
|
updateKeys: Object.keys(data.update ?? {}),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async (
|
||||||
|
compensationData: { prevData: any[]; updateKeys: string[] } | undefined,
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
if (!compensationData?.prevData?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const updates = compensationData.prevData.map((rp) => {
|
||||||
|
const payload: Record<string, any> = { id: rp.id }
|
||||||
|
for (const key of compensationData.updateKeys) {
|
||||||
|
payload[key] = rp[key]
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}) as UpdateRbacRolePolicyDTO[]
|
||||||
|
|
||||||
|
await service.updateRbacRolePolicies(updates)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
getSelectsAndRelationsFromObjectArray,
|
||||||
|
Modules,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { IRbacModuleService, UpdateRbacRoleDTO } from "@medusajs/types"
|
||||||
|
|
||||||
|
export type UpdateRbacRolesStepInput = {
|
||||||
|
selector: Record<string, any>
|
||||||
|
update: Omit<UpdateRbacRoleDTO, "id">
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateRbacRolesStepId = "update-rbac-roles"
|
||||||
|
|
||||||
|
export const updateRbacRolesStep = createStep(
|
||||||
|
updateRbacRolesStepId,
|
||||||
|
async (data: UpdateRbacRolesStepInput, { container }) => {
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||||
|
data.update,
|
||||||
|
])
|
||||||
|
|
||||||
|
const prevData = await service.listRbacRoles(data.selector, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const updates = (prevData ?? []).map((r) => ({
|
||||||
|
id: r.id,
|
||||||
|
...data.update,
|
||||||
|
})) as UpdateRbacRoleDTO[]
|
||||||
|
|
||||||
|
const updated = await service.updateRbacRoles(updates)
|
||||||
|
|
||||||
|
return new StepResponse(updated, {
|
||||||
|
prevData,
|
||||||
|
updateKeys: Object.keys(data.update ?? {}),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async (
|
||||||
|
compensationData: { prevData: any[]; updateKeys: string[] } | undefined,
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
if (!compensationData?.prevData?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IRbacModuleService>(Modules.RBAC)
|
||||||
|
|
||||||
|
const updates = compensationData.prevData.map((r) => {
|
||||||
|
const payload: Record<string, any> = { id: r.id }
|
||||||
|
for (const key of compensationData.updateKeys) {
|
||||||
|
payload[key] = r[key]
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}) as UpdateRbacRoleDTO[]
|
||||||
|
|
||||||
|
await service.updateRbacRoles(updates)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { createRbacPoliciesStep } from "../steps"
|
||||||
|
|
||||||
|
export type CreateRbacPoliciesWorkflowInput = {
|
||||||
|
policies: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacPoliciesWorkflowId = "create-rbac-policies"
|
||||||
|
|
||||||
|
export const createRbacPoliciesWorkflow = createWorkflow(
|
||||||
|
createRbacPoliciesWorkflowId,
|
||||||
|
(input: WorkflowData<CreateRbacPoliciesWorkflowInput>) => {
|
||||||
|
return new WorkflowResponse(createRbacPoliciesStep(input))
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { createRbacRolePoliciesStep } from "../steps"
|
||||||
|
|
||||||
|
export type CreateRbacRolePoliciesWorkflowInput = {
|
||||||
|
role_policies: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacRolePoliciesWorkflowId = "create-rbac-role-policies"
|
||||||
|
|
||||||
|
export const createRbacRolePoliciesWorkflow = createWorkflow(
|
||||||
|
createRbacRolePoliciesWorkflowId,
|
||||||
|
(input: WorkflowData<CreateRbacRolePoliciesWorkflowInput>) => {
|
||||||
|
return new WorkflowResponse(createRbacRolePoliciesStep(input))
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import {
|
||||||
|
createRbacRoleInheritancesStep,
|
||||||
|
createRbacRolePoliciesStep,
|
||||||
|
createRbacRolesStep,
|
||||||
|
} from "../steps"
|
||||||
|
|
||||||
|
export type CreateRbacRolesWorkflowInput = {
|
||||||
|
roles: {
|
||||||
|
name: string
|
||||||
|
description?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
inherited_role_ids?: string[]
|
||||||
|
policy_ids?: string[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRbacRolesWorkflowId = "create-rbac-roles"
|
||||||
|
|
||||||
|
export const createRbacRolesWorkflow = createWorkflow(
|
||||||
|
createRbacRolesWorkflowId,
|
||||||
|
(input: WorkflowData<CreateRbacRolesWorkflowInput>) => {
|
||||||
|
const roleData = transform({ input }, ({ input }) => ({
|
||||||
|
roles: input.roles.map((r) => ({
|
||||||
|
name: r.name,
|
||||||
|
description: r.description,
|
||||||
|
metadata: r.metadata,
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const createdRoles = createRbacRolesStep(roleData)
|
||||||
|
|
||||||
|
const inheritanceData = transform(
|
||||||
|
{ input, createdRoles },
|
||||||
|
({ input, createdRoles }) => {
|
||||||
|
const inheritances: any[] = []
|
||||||
|
|
||||||
|
createdRoles.forEach((role, index) => {
|
||||||
|
const inheritedRoleIds = input.roles[index].inherited_role_ids || []
|
||||||
|
inheritedRoleIds.forEach((inheritedRoleId) => {
|
||||||
|
inheritances.push({
|
||||||
|
role_id: role.id,
|
||||||
|
inherited_role_id: inheritedRoleId,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return { role_inheritances: inheritances }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const policiesData = transform(
|
||||||
|
{ input, createdRoles },
|
||||||
|
({ input, createdRoles }) => {
|
||||||
|
const allPolicies: any[] = []
|
||||||
|
createdRoles.forEach((role, index) => {
|
||||||
|
const policyIds = input.roles[index].policy_ids || []
|
||||||
|
policyIds.forEach((policy_id) => {
|
||||||
|
allPolicies.push({
|
||||||
|
role_id: role.id,
|
||||||
|
scope_id: policy_id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return { role_policies: allPolicies }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
createRbacRoleInheritancesStep(inheritanceData)
|
||||||
|
|
||||||
|
createRbacRolePoliciesStep(policiesData)
|
||||||
|
|
||||||
|
return new WorkflowResponse(createdRoles)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { deleteRbacPoliciesStep } from "../steps"
|
||||||
|
|
||||||
|
export type DeleteRbacPoliciesWorkflowInput = {
|
||||||
|
ids: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deleteRbacPoliciesWorkflowId = "delete-rbac-policies"
|
||||||
|
|
||||||
|
export const deleteRbacPoliciesWorkflow = createWorkflow(
|
||||||
|
deleteRbacPoliciesWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<DeleteRbacPoliciesWorkflowInput>
|
||||||
|
): WorkflowData<void> => {
|
||||||
|
deleteRbacPoliciesStep(input.ids)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { deleteRbacRolePoliciesStep } from "../steps"
|
||||||
|
|
||||||
|
export type DeleteRbacRolePoliciesWorkflowInput = {
|
||||||
|
ids: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deleteRbacRolePoliciesWorkflowId = "delete-rbac-role-policies"
|
||||||
|
|
||||||
|
export const deleteRbacRolePoliciesWorkflow = createWorkflow(
|
||||||
|
deleteRbacRolePoliciesWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<DeleteRbacRolePoliciesWorkflowInput>
|
||||||
|
): WorkflowData<void> => {
|
||||||
|
deleteRbacRolePoliciesStep(input.ids)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { deleteRbacRolesStep } from "../steps"
|
||||||
|
|
||||||
|
export type DeleteRbacRolesWorkflowInput = {
|
||||||
|
ids: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deleteRbacRolesWorkflowId = "delete-rbac-roles"
|
||||||
|
|
||||||
|
export const deleteRbacRolesWorkflow = createWorkflow(
|
||||||
|
deleteRbacRolesWorkflowId,
|
||||||
|
(input: WorkflowData<DeleteRbacRolesWorkflowInput>): WorkflowData<void> => {
|
||||||
|
deleteRbacRolesStep(input.ids)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +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-policies"
|
||||||
|
export * from "./delete-rbac-role-policies"
|
||||||
|
export * from "./update-rbac-role-policies"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { UpdateRbacPolicyDTO } from "@medusajs/types"
|
||||||
|
import { updateRbacPoliciesStep } from "../steps/update-rbac-policies"
|
||||||
|
|
||||||
|
export type UpdateRbacPoliciesWorkflowInput = {
|
||||||
|
selector: Record<string, any>
|
||||||
|
update: Omit<UpdateRbacPolicyDTO, "id">
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateRbacPoliciesWorkflowId = "update-rbac-policies"
|
||||||
|
|
||||||
|
export const updateRbacPoliciesWorkflow = createWorkflow(
|
||||||
|
updateRbacPoliciesWorkflowId,
|
||||||
|
(input: WorkflowData<UpdateRbacPoliciesWorkflowInput>) => {
|
||||||
|
return new WorkflowResponse(updateRbacPoliciesStep(input))
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { UpdateRbacRolePolicyDTO } from "@medusajs/types"
|
||||||
|
import { updateRbacRolePoliciesStep } from "../steps/update-rbac-role-policies"
|
||||||
|
|
||||||
|
export type UpdateRbacRolePoliciesWorkflowInput = {
|
||||||
|
selector: Record<string, any>
|
||||||
|
update: Omit<UpdateRbacRolePolicyDTO, "id">
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateRbacRolePoliciesWorkflowId = "update-rbac-role-policies"
|
||||||
|
|
||||||
|
export const updateRbacRolePoliciesWorkflow = createWorkflow(
|
||||||
|
updateRbacRolePoliciesWorkflowId,
|
||||||
|
(input: WorkflowData<UpdateRbacRolePoliciesWorkflowInput>) => {
|
||||||
|
return new WorkflowResponse(updateRbacRolePoliciesStep(input))
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { isDefined } from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { UpdateRbacRoleDTO } from "@medusajs/types"
|
||||||
|
import { createRbacRolePoliciesStep, setRoleInheritanceStep } from "../steps"
|
||||||
|
import { updateRbacRolesStep } from "../steps/update-rbac-roles"
|
||||||
|
|
||||||
|
export type UpdateRbacRolesWorkflowInput = {
|
||||||
|
selector: Record<string, any>
|
||||||
|
update: Omit<UpdateRbacRoleDTO, "id"> & {
|
||||||
|
inherited_role_ids?: string[]
|
||||||
|
policy_ids?: string[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateRbacRolesWorkflowId = "update-rbac-roles"
|
||||||
|
|
||||||
|
export const updateRbacRolesWorkflow = createWorkflow(
|
||||||
|
updateRbacRolesWorkflowId,
|
||||||
|
(input: WorkflowData<UpdateRbacRolesWorkflowInput>) => {
|
||||||
|
const roleUpdateData = transform({ input }, ({ input }) => ({
|
||||||
|
selector: input.selector,
|
||||||
|
update: {
|
||||||
|
name: input.update.name,
|
||||||
|
description: input.update.description,
|
||||||
|
metadata: input.update.metadata,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const updatedRoles = updateRbacRolesStep(roleUpdateData)
|
||||||
|
|
||||||
|
const inheritanceUpdateData = transform(
|
||||||
|
{ input, updatedRoles },
|
||||||
|
({ input, updatedRoles }) => {
|
||||||
|
if (!isDefined(input.update.inherited_role_ids)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedRoles.map((role) => ({
|
||||||
|
role_id: role.id,
|
||||||
|
inherited_role_ids: input.update.inherited_role_ids || [],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
setRoleInheritanceStep(inheritanceUpdateData)
|
||||||
|
|
||||||
|
const policiesUpdateData = transform(
|
||||||
|
{ input, updatedRoles },
|
||||||
|
({ input, updatedRoles }) => {
|
||||||
|
if (!isDefined(input.update.policy_ids)) {
|
||||||
|
return { role_policies: [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
const allPolicies: any[] = []
|
||||||
|
updatedRoles.forEach((role) => {
|
||||||
|
const policyIds = input.update.policy_ids || []
|
||||||
|
policyIds.forEach((policy_id) => {
|
||||||
|
allPolicies.push({
|
||||||
|
role_id: role.id,
|
||||||
|
scope_id: policy_id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return { role_policies: allPolicies }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
createRbacRolePoliciesStep(policiesUpdateData)
|
||||||
|
|
||||||
|
return new WorkflowResponse(updatedRoles)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
IPricingModuleService,
|
IPricingModuleService,
|
||||||
IProductModuleService,
|
IProductModuleService,
|
||||||
IPromotionModuleService,
|
IPromotionModuleService,
|
||||||
|
IRbacModuleService,
|
||||||
IRegionModuleService,
|
IRegionModuleService,
|
||||||
ISalesChannelModuleService,
|
ISalesChannelModuleService,
|
||||||
ISettingsModuleService,
|
ISettingsModuleService,
|
||||||
@@ -82,6 +83,7 @@ declare module "@medusajs/types" {
|
|||||||
[Modules.CACHING]: ICachingModuleService
|
[Modules.CACHING]: ICachingModuleService
|
||||||
[Modules.INDEX]: IIndexService
|
[Modules.INDEX]: IIndexService
|
||||||
[Modules.TRANSLATION]: ITranslationModuleService
|
[Modules.TRANSLATION]: ITranslationModuleService
|
||||||
|
[Modules.RBAC]: IRbacModuleService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export * from "./pricing"
|
|||||||
export * from "./product"
|
export * from "./product"
|
||||||
export * from "./product-category"
|
export * from "./product-category"
|
||||||
export * from "./promotion"
|
export * from "./promotion"
|
||||||
|
export * from "./rbac"
|
||||||
export * from "./region"
|
export * from "./region"
|
||||||
export * from "./sales-channel"
|
export * from "./sales-channel"
|
||||||
export * from "./search"
|
export * from "./search"
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
export type RbacRoleDTO = {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FilterableRbacRoleProps = {
|
||||||
|
id?: string | string[]
|
||||||
|
name?: string
|
||||||
|
q?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RbacPolicyDTO = {
|
||||||
|
id: string
|
||||||
|
key: string
|
||||||
|
resource: string
|
||||||
|
operation: string
|
||||||
|
name?: string | null
|
||||||
|
description?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FilterableRbacPolicyProps = {
|
||||||
|
id?: string | string[]
|
||||||
|
key?: string
|
||||||
|
resource?: string
|
||||||
|
operation?: string
|
||||||
|
q?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RbacRolePolicyDTO = {
|
||||||
|
id: string
|
||||||
|
role_id: string
|
||||||
|
scope_id: string
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FilterableRbacRolePolicyProps = {
|
||||||
|
id?: string | string[]
|
||||||
|
role_id?: string | string[]
|
||||||
|
scope_id?: string | string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RbacRoleInheritanceDTO = {
|
||||||
|
id: string
|
||||||
|
role_id: string
|
||||||
|
inherited_role_id: string
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FilterableRbacRoleInheritanceProps = {
|
||||||
|
id?: string | string[]
|
||||||
|
role_id?: string | string[]
|
||||||
|
inherited_role_id?: string | string[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./common"
|
||||||
|
export * from "./mutations"
|
||||||
|
export * from "./service"
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
export type CreateRbacRoleDTO = {
|
||||||
|
name: string
|
||||||
|
description?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateRbacRoleDTO = Partial<CreateRbacRoleDTO> & {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacPolicyDTO = {
|
||||||
|
key: string
|
||||||
|
resource: string
|
||||||
|
operation: string
|
||||||
|
name?: string | null
|
||||||
|
description?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateRbacPolicyDTO = Partial<CreateRbacPolicyDTO> & {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacRolePolicyDTO = {
|
||||||
|
role_id: string
|
||||||
|
scope_id: string
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateRbacRolePolicyDTO = Partial<CreateRbacRolePolicyDTO> & {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateRbacRoleInheritanceDTO = {
|
||||||
|
role_id: string
|
||||||
|
inherited_role_id: string
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateRbacRoleInheritanceDTO =
|
||||||
|
Partial<CreateRbacRoleInheritanceDTO> & {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
import { FindConfig } from "../common"
|
||||||
|
import { IModuleService } from "../modules-sdk"
|
||||||
|
import { Context } from "../shared-context"
|
||||||
|
import {
|
||||||
|
FilterableRbacPolicyProps,
|
||||||
|
FilterableRbacRoleInheritanceProps,
|
||||||
|
FilterableRbacRolePolicyProps,
|
||||||
|
FilterableRbacRoleProps,
|
||||||
|
RbacPolicyDTO,
|
||||||
|
RbacRoleDTO,
|
||||||
|
RbacRoleInheritanceDTO,
|
||||||
|
RbacRolePolicyDTO,
|
||||||
|
} from "./common"
|
||||||
|
import {
|
||||||
|
CreateRbacPolicyDTO,
|
||||||
|
CreateRbacRoleDTO,
|
||||||
|
CreateRbacRoleInheritanceDTO,
|
||||||
|
CreateRbacRolePolicyDTO,
|
||||||
|
UpdateRbacPolicyDTO,
|
||||||
|
UpdateRbacRoleDTO,
|
||||||
|
UpdateRbacRoleInheritanceDTO,
|
||||||
|
UpdateRbacRolePolicyDTO,
|
||||||
|
} from "./mutations"
|
||||||
|
|
||||||
|
export interface IRbacModuleService extends IModuleService {
|
||||||
|
createRbacRoles(
|
||||||
|
data: CreateRbacRoleDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleDTO>
|
||||||
|
createRbacRoles(
|
||||||
|
data: CreateRbacRoleDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleDTO[]>
|
||||||
|
|
||||||
|
updateRbacRoles(
|
||||||
|
data: UpdateRbacRoleDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleDTO>
|
||||||
|
updateRbacRoles(
|
||||||
|
data: UpdateRbacRoleDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleDTO[]>
|
||||||
|
|
||||||
|
deleteRbacRoles(
|
||||||
|
ids: string | string[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<void>
|
||||||
|
|
||||||
|
retrieveRbacRole(
|
||||||
|
id: string,
|
||||||
|
config?: FindConfig<RbacRoleDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleDTO>
|
||||||
|
|
||||||
|
listRbacRoles(
|
||||||
|
filters?: FilterableRbacRoleProps,
|
||||||
|
config?: FindConfig<RbacRoleDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleDTO[]>
|
||||||
|
|
||||||
|
listAndCountRbacRoles(
|
||||||
|
filters?: FilterableRbacRoleProps,
|
||||||
|
config?: FindConfig<RbacRoleDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<[RbacRoleDTO[], number]>
|
||||||
|
|
||||||
|
createRbacPolicies(
|
||||||
|
data: CreateRbacPolicyDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO>
|
||||||
|
createRbacPolicies(
|
||||||
|
data: CreateRbacPolicyDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO[]>
|
||||||
|
|
||||||
|
updateRbacPolicies(
|
||||||
|
data: UpdateRbacPolicyDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO>
|
||||||
|
updateRbacPolicies(
|
||||||
|
data: UpdateRbacPolicyDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO[]>
|
||||||
|
|
||||||
|
deleteRbacPolicies(
|
||||||
|
ids: string | string[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<void>
|
||||||
|
|
||||||
|
retrieveRbacPolicy(
|
||||||
|
id: string,
|
||||||
|
config?: FindConfig<RbacPolicyDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO>
|
||||||
|
|
||||||
|
listRbacPolicies(
|
||||||
|
filters?: FilterableRbacPolicyProps,
|
||||||
|
config?: FindConfig<RbacPolicyDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO[]>
|
||||||
|
|
||||||
|
listAndCountRbacPolicies(
|
||||||
|
filters?: FilterableRbacPolicyProps,
|
||||||
|
config?: FindConfig<RbacPolicyDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<[RbacPolicyDTO[], number]>
|
||||||
|
|
||||||
|
createRbacRolePolicies(
|
||||||
|
data: CreateRbacRolePolicyDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRolePolicyDTO>
|
||||||
|
createRbacRolePolicies(
|
||||||
|
data: CreateRbacRolePolicyDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRolePolicyDTO[]>
|
||||||
|
|
||||||
|
updateRbacRolePolicies(
|
||||||
|
data: UpdateRbacRolePolicyDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRolePolicyDTO>
|
||||||
|
updateRbacRolePolicies(
|
||||||
|
data: UpdateRbacRolePolicyDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRolePolicyDTO[]>
|
||||||
|
|
||||||
|
deleteRbacRolePolicies(
|
||||||
|
ids: string | string[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<void>
|
||||||
|
|
||||||
|
retrieveRbacRolePolicy(
|
||||||
|
id: string,
|
||||||
|
config?: FindConfig<RbacRolePolicyDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRolePolicyDTO>
|
||||||
|
|
||||||
|
listRbacRolePolicies(
|
||||||
|
filters?: FilterableRbacRolePolicyProps,
|
||||||
|
config?: FindConfig<RbacRolePolicyDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRolePolicyDTO[]>
|
||||||
|
|
||||||
|
listAndCountRbacRolePolicies(
|
||||||
|
filters?: FilterableRbacRolePolicyProps,
|
||||||
|
config?: FindConfig<RbacRolePolicyDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<[RbacRolePolicyDTO[], number]>
|
||||||
|
|
||||||
|
createRbacRoleInheritances(
|
||||||
|
data: CreateRbacRoleInheritanceDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleInheritanceDTO>
|
||||||
|
createRbacRoleInheritances(
|
||||||
|
data: CreateRbacRoleInheritanceDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleInheritanceDTO[]>
|
||||||
|
|
||||||
|
updateRbacRoleInheritances(
|
||||||
|
data: UpdateRbacRoleInheritanceDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleInheritanceDTO>
|
||||||
|
updateRbacRoleInheritances(
|
||||||
|
data: UpdateRbacRoleInheritanceDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleInheritanceDTO[]>
|
||||||
|
|
||||||
|
deleteRbacRoleInheritances(
|
||||||
|
ids: string | string[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<void>
|
||||||
|
|
||||||
|
retrieveRbacRoleInheritance(
|
||||||
|
id: string,
|
||||||
|
config?: FindConfig<RbacRoleInheritanceDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleInheritanceDTO>
|
||||||
|
|
||||||
|
listRbacRoleInheritances(
|
||||||
|
filters?: FilterableRbacRoleInheritanceProps,
|
||||||
|
config?: FindConfig<RbacRoleInheritanceDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacRoleInheritanceDTO[]>
|
||||||
|
|
||||||
|
listAndCountRbacRoleInheritances(
|
||||||
|
filters?: FilterableRbacRoleInheritanceProps,
|
||||||
|
config?: FindConfig<RbacRoleInheritanceDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<[RbacRoleInheritanceDTO[], number]>
|
||||||
|
|
||||||
|
listPoliciesForRole(
|
||||||
|
roleId: string,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<RbacPolicyDTO[]>
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ export const Modules = {
|
|||||||
SETTINGS: "settings",
|
SETTINGS: "settings",
|
||||||
CACHING: "caching",
|
CACHING: "caching",
|
||||||
TRANSLATION: "translation",
|
TRANSLATION: "translation",
|
||||||
|
RBAC: "rbac",
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const MODULE_PACKAGE_NAMES = {
|
export const MODULE_PACKAGE_NAMES = {
|
||||||
@@ -62,6 +63,7 @@ export const MODULE_PACKAGE_NAMES = {
|
|||||||
[Modules.SETTINGS]: "@medusajs/medusa/settings",
|
[Modules.SETTINGS]: "@medusajs/medusa/settings",
|
||||||
[Modules.CACHING]: "@medusajs/caching",
|
[Modules.CACHING]: "@medusajs/caching",
|
||||||
[Modules.TRANSLATION]: "@medusajs/translation",
|
[Modules.TRANSLATION]: "@medusajs/translation",
|
||||||
|
[Modules.RBAC]: "@medusajs/medusa/rbac",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const REVERSED_MODULE_PACKAGE_NAMES = Object.entries(
|
export const REVERSED_MODULE_PACKAGE_NAMES = Object.entries(
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { join } from "path"
|
|
||||||
import { Modules } from "./definition"
|
|
||||||
import type { LoadedModule } from "@medusajs/types"
|
import type { LoadedModule } from "@medusajs/types"
|
||||||
|
import { join } from "path"
|
||||||
import { FileSystem } from "../common/file-system"
|
import { FileSystem } from "../common/file-system"
|
||||||
import { toUnixSlash } from "../common/to-unix-slash"
|
|
||||||
import { toCamelCase } from "../common/to-camel-case"
|
import { toCamelCase } from "../common/to-camel-case"
|
||||||
|
import { toUnixSlash } from "../common/to-unix-slash"
|
||||||
import { upperCaseFirst } from "../common/upper-case-first"
|
import { upperCaseFirst } from "../common/upper-case-first"
|
||||||
|
import { Modules } from "./definition"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For known services that has interfaces, we will set the container
|
* For known services that has interfaces, we will set the container
|
||||||
@@ -37,6 +37,10 @@ const SERVICES_INTERFACES = {
|
|||||||
[Modules.FILE]: "IFileModuleService",
|
[Modules.FILE]: "IFileModuleService",
|
||||||
[Modules.NOTIFICATION]: "INotificationModuleService",
|
[Modules.NOTIFICATION]: "INotificationModuleService",
|
||||||
[Modules.LOCKING]: "ILockingModule",
|
[Modules.LOCKING]: "ILockingModule",
|
||||||
|
[Modules.SETTINGS]: "ISettingsModuleService",
|
||||||
|
[Modules.CACHING]: "ICachingModuleService",
|
||||||
|
[Modules.TRANSLATION]: "ITranslationModuleService",
|
||||||
|
[Modules.RBAC]: "IRbacModuleService",
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { MiddlewareRoute } from "@medusajs/framework/http"
|
||||||
|
|
||||||
|
import { adminRbacPolicyRoutesMiddlewares } from "./policies/middlewares"
|
||||||
|
import { adminRbacRolePolicyRoutesMiddlewares } from "./role-policies/middlewares"
|
||||||
|
import { adminRbacRoleRoutesMiddlewares } from "./roles/middlewares"
|
||||||
|
|
||||||
|
export const adminRbacRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
...adminRbacRoleRoutesMiddlewares,
|
||||||
|
...adminRbacPolicyRoutesMiddlewares,
|
||||||
|
...adminRbacRolePolicyRoutesMiddlewares,
|
||||||
|
]
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import {
|
||||||
|
deleteRbacPoliciesWorkflow,
|
||||||
|
updateRbacPoliciesWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
MedusaError,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
import { AdminUpdateRbacPolicyType } from "../validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: policies } = await query.graph({
|
||||||
|
entity: "rbac_policy",
|
||||||
|
filters: { id: req.params.id },
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const policy = policies[0]
|
||||||
|
|
||||||
|
if (!policy) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Policy with id: ${req.params.id} not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ policy })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminUpdateRbacPolicyType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: existing } = await query.graph({
|
||||||
|
entity: "rbac_policy",
|
||||||
|
filters: { id: req.params.id },
|
||||||
|
fields: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingPolicy = existing[0]
|
||||||
|
if (!existingPolicy) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Policy with id "${req.params.id}" not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result } = await updateRbacPoliciesWorkflow(req.scope).run({
|
||||||
|
input: {
|
||||||
|
selector: { id: req.params.id },
|
||||||
|
update: req.validatedBody,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data: policies } = await query.graph({
|
||||||
|
entity: "rbac_policy",
|
||||||
|
filters: { id: result[0].id },
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const policy = policies[0]
|
||||||
|
|
||||||
|
res.status(200).json({ policy })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
|
||||||
|
await deleteRbacPoliciesWorkflow(req.scope).run({
|
||||||
|
input: { ids: [id] },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
id,
|
||||||
|
object: "rbac_policy",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
|
||||||
|
import {
|
||||||
|
validateAndTransformBody,
|
||||||
|
validateAndTransformQuery,
|
||||||
|
} from "@medusajs/framework"
|
||||||
|
import { MiddlewareRoute } from "@medusajs/framework/http"
|
||||||
|
|
||||||
|
import {
|
||||||
|
AdminCreateRbacPolicy,
|
||||||
|
AdminGetRbacPoliciesParams,
|
||||||
|
AdminGetRbacPolicyParams,
|
||||||
|
AdminUpdateRbacPolicy,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const adminRbacPolicyRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/rbac/policies",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacPoliciesParams,
|
||||||
|
QueryConfig.listTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/rbac/policies/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacPolicyParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/rbac/policies",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCreateRbacPolicy),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacPolicyParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/rbac/policies/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminUpdateRbacPolicy),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacPolicyParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["DELETE"],
|
||||||
|
matcher: "/admin/rbac/policies/:id",
|
||||||
|
middlewares: [],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export const defaultAdminRbacPolicyFields = [
|
||||||
|
"id",
|
||||||
|
"key",
|
||||||
|
"resource",
|
||||||
|
"operation",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveTransformQueryConfig = {
|
||||||
|
defaults: defaultAdminRbacPolicyFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
|
defaultLimit: 20,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { createRbacPoliciesWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
|
||||||
|
import { AdminCreateRbacPolicyType } from "./validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data: policies, metadata } = await query.graph({
|
||||||
|
entity: "rbac_policy",
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
filters: req.filterableFields,
|
||||||
|
pagination: req.queryConfig.pagination,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
policies,
|
||||||
|
count: metadata?.count ?? 0,
|
||||||
|
offset: metadata?.skip ?? 0,
|
||||||
|
limit: metadata?.take ?? 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminCreateRbacPolicyType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const input = [req.validatedBody]
|
||||||
|
|
||||||
|
const { result } = await createRbacPoliciesWorkflow(req.scope).run({
|
||||||
|
input: { policies: input },
|
||||||
|
})
|
||||||
|
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: policies } = await query.graph({
|
||||||
|
entity: "rbac_policy",
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
filters: { id: result[0].id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const policy = policies[0]
|
||||||
|
|
||||||
|
res.status(200).json({ policy })
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { applyAndAndOrOperators } from "../../../utils/common-validators"
|
||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../../utils/validators"
|
||||||
|
|
||||||
|
export type AdminGetRbacPolicyParamsType = z.infer<
|
||||||
|
typeof AdminGetRbacPolicyParams
|
||||||
|
>
|
||||||
|
export const AdminGetRbacPolicyParams = createSelectParams()
|
||||||
|
|
||||||
|
export const AdminGetRbacPoliciesParamsFields = z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
key: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
resource: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
operation: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AdminGetRbacPoliciesParamsType = z.infer<
|
||||||
|
typeof AdminGetRbacPoliciesParams
|
||||||
|
>
|
||||||
|
export const AdminGetRbacPoliciesParams = createFindParams({
|
||||||
|
limit: 50,
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
.merge(AdminGetRbacPoliciesParamsFields)
|
||||||
|
.merge(applyAndAndOrOperators(AdminGetRbacPoliciesParamsFields))
|
||||||
|
|
||||||
|
export type AdminCreateRbacPolicyType = z.infer<typeof AdminCreateRbacPolicy>
|
||||||
|
export const AdminCreateRbacPolicy = z
|
||||||
|
.object({
|
||||||
|
key: z.string(),
|
||||||
|
resource: z.string(),
|
||||||
|
operation: z.string(),
|
||||||
|
name: z.string().nullish(),
|
||||||
|
description: z.string().nullish(),
|
||||||
|
metadata: z.record(z.unknown()).nullish(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
|
|
||||||
|
export type AdminUpdateRbacPolicyType = z.infer<typeof AdminUpdateRbacPolicy>
|
||||||
|
export const AdminUpdateRbacPolicy = z
|
||||||
|
.object({
|
||||||
|
key: z.string().optional(),
|
||||||
|
resource: z.string().optional(),
|
||||||
|
operation: z.string().optional(),
|
||||||
|
name: z.string().nullish(),
|
||||||
|
description: z.string().nullish(),
|
||||||
|
metadata: z.record(z.unknown()).nullish(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import {
|
||||||
|
deleteRbacRolePoliciesWorkflow,
|
||||||
|
updateRbacRolePoliciesWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
MedusaError,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
import { AdminUpdateRbacRolePolicyType } from "../validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: rolePolicies } = await query.graph({
|
||||||
|
entity: "rbac_role_policy",
|
||||||
|
filters: { id: req.params.id },
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const role_policy = rolePolicies[0]
|
||||||
|
|
||||||
|
if (!role_policy) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Role policy with id: ${req.params.id} not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ role_policy })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminUpdateRbacRolePolicyType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: existing } = await query.graph({
|
||||||
|
entity: "rbac_role_policy",
|
||||||
|
filters: { id: req.params.id },
|
||||||
|
fields: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingRolePolicy = existing[0]
|
||||||
|
if (!existingRolePolicy) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Role policy with id "${req.params.id}" not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result } = await updateRbacRolePoliciesWorkflow(req.scope).run({
|
||||||
|
input: {
|
||||||
|
selector: { id: req.params.id },
|
||||||
|
update: req.validatedBody,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data: rolePolicies } = await query.graph({
|
||||||
|
entity: "rbac_role_policy",
|
||||||
|
filters: { id: result[0].id },
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const role_policy = rolePolicies[0]
|
||||||
|
|
||||||
|
res.status(200).json({ role_policy })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
|
||||||
|
await deleteRbacRolePoliciesWorkflow(req.scope).run({
|
||||||
|
input: { ids: [id] },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
id,
|
||||||
|
object: "rbac_role_policy",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
|
||||||
|
import {
|
||||||
|
validateAndTransformBody,
|
||||||
|
validateAndTransformQuery,
|
||||||
|
} from "@medusajs/framework"
|
||||||
|
import { MiddlewareRoute } from "@medusajs/framework/http"
|
||||||
|
|
||||||
|
import {
|
||||||
|
AdminCreateRbacRolePolicy,
|
||||||
|
AdminGetRbacRolePoliciesParams,
|
||||||
|
AdminGetRbacRolePolicyParams,
|
||||||
|
AdminUpdateRbacRolePolicy,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const adminRbacRolePolicyRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/rbac/role-policies",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRolePoliciesParams,
|
||||||
|
QueryConfig.listTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/rbac/role-policies/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRolePolicyParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/rbac/role-policies",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCreateRbacRolePolicy),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRolePolicyParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/rbac/role-policies/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminUpdateRbacRolePolicy),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRolePolicyParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["DELETE"],
|
||||||
|
matcher: "/admin/rbac/role-policies/:id",
|
||||||
|
middlewares: [],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export const defaultAdminRbacRolePolicyFields = [
|
||||||
|
"id",
|
||||||
|
"role_id",
|
||||||
|
"scope_id",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveTransformQueryConfig = {
|
||||||
|
defaults: defaultAdminRbacRolePolicyFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
|
defaultLimit: 20,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { createRbacRolePoliciesWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
|
||||||
|
import { AdminCreateRbacRolePolicyType } from "./validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data: role_policies, metadata } = await query.graph({
|
||||||
|
entity: "rbac_role_policy",
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
filters: req.filterableFields,
|
||||||
|
pagination: req.queryConfig.pagination,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
role_policies,
|
||||||
|
count: metadata?.count ?? 0,
|
||||||
|
offset: metadata?.skip ?? 0,
|
||||||
|
limit: metadata?.take ?? 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminCreateRbacRolePolicyType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const input = [req.validatedBody]
|
||||||
|
|
||||||
|
const { result } = await createRbacRolePoliciesWorkflow(req.scope).run({
|
||||||
|
input: { role_policies: input },
|
||||||
|
})
|
||||||
|
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: rolePolicies } = await query.graph({
|
||||||
|
entity: "rbac_role_policy",
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
filters: { id: result[0].id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const role_policy = rolePolicies[0]
|
||||||
|
|
||||||
|
res.status(200).json({ role_policy })
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { applyAndAndOrOperators } from "../../../utils/common-validators"
|
||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../../utils/validators"
|
||||||
|
|
||||||
|
export type AdminGetRbacRolePolicyParamsType = z.infer<
|
||||||
|
typeof AdminGetRbacRolePolicyParams
|
||||||
|
>
|
||||||
|
export const AdminGetRbacRolePolicyParams = createSelectParams()
|
||||||
|
|
||||||
|
export const AdminGetRbacRolePoliciesParamsFields = z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
role_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
scope_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AdminGetRbacRolePoliciesParamsType = z.infer<
|
||||||
|
typeof AdminGetRbacRolePoliciesParams
|
||||||
|
>
|
||||||
|
export const AdminGetRbacRolePoliciesParams = createFindParams({
|
||||||
|
limit: 50,
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
.merge(AdminGetRbacRolePoliciesParamsFields)
|
||||||
|
.merge(applyAndAndOrOperators(AdminGetRbacRolePoliciesParamsFields))
|
||||||
|
|
||||||
|
export type AdminCreateRbacRolePolicyType = z.infer<
|
||||||
|
typeof AdminCreateRbacRolePolicy
|
||||||
|
>
|
||||||
|
export const AdminCreateRbacRolePolicy = z
|
||||||
|
.object({
|
||||||
|
role_id: z.string(),
|
||||||
|
scope_id: z.string(),
|
||||||
|
metadata: z.record(z.unknown()).nullish(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
|
|
||||||
|
export type AdminUpdateRbacRolePolicyType = z.infer<
|
||||||
|
typeof AdminUpdateRbacRolePolicy
|
||||||
|
>
|
||||||
|
export const AdminUpdateRbacRolePolicy = z
|
||||||
|
.object({
|
||||||
|
metadata: z.record(z.unknown()).nullish(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import {
|
||||||
|
deleteRbacRolesWorkflow,
|
||||||
|
updateRbacRolesWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
MedusaError,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
import { AdminUpdateRbacRoleType } from "../validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: roles } = await query.graph({
|
||||||
|
entity: "rbac_role",
|
||||||
|
filters: { id: req.params.id },
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const role = roles[0]
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Role with id: ${req.params.id} not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ role })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminUpdateRbacRoleType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: existing } = await query.graph({
|
||||||
|
entity: "rbac_role",
|
||||||
|
filters: { id: req.params.id },
|
||||||
|
fields: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingRole = existing[0]
|
||||||
|
if (!existingRole) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Role with id "${req.params.id}" not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result } = await updateRbacRolesWorkflow(req.scope).run({
|
||||||
|
input: {
|
||||||
|
selector: { id: req.params.id },
|
||||||
|
update: req.validatedBody,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data: roles } = await query.graph({
|
||||||
|
entity: "rbac_role",
|
||||||
|
filters: { id: result[0].id },
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const role = roles[0]
|
||||||
|
|
||||||
|
res.status(200).json({ role })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
|
||||||
|
await deleteRbacRolesWorkflow(req.scope).run({
|
||||||
|
input: { ids: [id] },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
id,
|
||||||
|
object: "rbac_role",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export {}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
|
||||||
|
import {
|
||||||
|
validateAndTransformBody,
|
||||||
|
validateAndTransformQuery,
|
||||||
|
} from "@medusajs/framework"
|
||||||
|
import { MiddlewareRoute } from "@medusajs/framework/http"
|
||||||
|
|
||||||
|
import {
|
||||||
|
AdminCreateRbacRole,
|
||||||
|
AdminGetRbacRoleParams,
|
||||||
|
AdminGetRbacRolesParams,
|
||||||
|
AdminUpdateRbacRole,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const adminRbacRoleRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/rbac/roles",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRolesParams,
|
||||||
|
QueryConfig.listTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/rbac/roles/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRoleParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/rbac/roles",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCreateRbacRole),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRoleParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/rbac/roles/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminUpdateRbacRole),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetRbacRoleParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["DELETE"],
|
||||||
|
matcher: "/admin/rbac/roles/:id",
|
||||||
|
middlewares: [],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export const defaultAdminRbacRoleFields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"parent_id",
|
||||||
|
"description",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveTransformQueryConfig = {
|
||||||
|
defaults: defaultAdminRbacRoleFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
|
defaultLimit: 20,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { createRbacRolesWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
|
||||||
|
import { AdminCreateRbacRoleType } from "./validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data: roles, metadata } = await query.graph({
|
||||||
|
entity: "rbac_role",
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
filters: req.filterableFields,
|
||||||
|
pagination: req.queryConfig.pagination,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
roles,
|
||||||
|
count: metadata?.count ?? 0,
|
||||||
|
offset: metadata?.skip ?? 0,
|
||||||
|
limit: metadata?.take ?? 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminCreateRbacRoleType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const input = [req.validatedBody]
|
||||||
|
|
||||||
|
const { result } = await createRbacRolesWorkflow(req.scope).run({
|
||||||
|
input: { roles: input },
|
||||||
|
})
|
||||||
|
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
const { data: roles } = await query.graph({
|
||||||
|
entity: "rbac_role",
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
filters: { id: result[0].id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const role = roles[0]
|
||||||
|
|
||||||
|
res.status(200).json({ role })
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { applyAndAndOrOperators } from "../../../utils/common-validators"
|
||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../../utils/validators"
|
||||||
|
|
||||||
|
export type AdminGetRbacRoleParamsType = z.infer<typeof AdminGetRbacRoleParams>
|
||||||
|
export const AdminGetRbacRoleParams = createSelectParams()
|
||||||
|
|
||||||
|
export const AdminGetRbacRolesParamsFields = z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
parent_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AdminGetRbacRolesParamsType = z.infer<
|
||||||
|
typeof AdminGetRbacRolesParams
|
||||||
|
>
|
||||||
|
export const AdminGetRbacRolesParams = createFindParams({
|
||||||
|
limit: 50,
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
.merge(AdminGetRbacRolesParamsFields)
|
||||||
|
.merge(applyAndAndOrOperators(AdminGetRbacRolesParamsFields))
|
||||||
|
|
||||||
|
export type AdminCreateRbacRoleType = z.infer<typeof AdminCreateRbacRole>
|
||||||
|
export const AdminCreateRbacRole = z
|
||||||
|
.object({
|
||||||
|
name: z.string(),
|
||||||
|
parent_id: z.string().nullish(),
|
||||||
|
description: z.string().nullish(),
|
||||||
|
metadata: z.record(z.unknown()).nullish(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
|
|
||||||
|
export type AdminUpdateRbacRoleType = z.infer<typeof AdminUpdateRbacRole>
|
||||||
|
export const AdminUpdateRbacRole = z
|
||||||
|
.object({
|
||||||
|
name: z.string().optional(),
|
||||||
|
parent_id: z.string().nullish(),
|
||||||
|
description: z.string().nullish(),
|
||||||
|
metadata: z.record(z.unknown()).nullish(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
@@ -27,6 +27,7 @@ import { adminProductTypeRoutesMiddlewares } from "./admin/product-types/middlew
|
|||||||
import { adminProductVariantRoutesMiddlewares } from "./admin/product-variants/middlewares"
|
import { adminProductVariantRoutesMiddlewares } from "./admin/product-variants/middlewares"
|
||||||
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
|
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
|
||||||
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
||||||
|
import { adminRbacRoutesMiddlewares } from "./admin/rbac/middlewares"
|
||||||
import { adminRefundReasonsRoutesMiddlewares } from "./admin/refund-reasons/middlewares"
|
import { adminRefundReasonsRoutesMiddlewares } from "./admin/refund-reasons/middlewares"
|
||||||
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
||||||
import { adminReservationRoutesMiddlewares } from "./admin/reservations/middlewares"
|
import { adminReservationRoutesMiddlewares } from "./admin/reservations/middlewares"
|
||||||
@@ -92,6 +93,7 @@ export default defineMiddlewares([
|
|||||||
...adminReturnRoutesMiddlewares,
|
...adminReturnRoutesMiddlewares,
|
||||||
...storeRegionRoutesMiddlewares,
|
...storeRegionRoutesMiddlewares,
|
||||||
...adminRegionRoutesMiddlewares,
|
...adminRegionRoutesMiddlewares,
|
||||||
|
...adminRbacRoutesMiddlewares,
|
||||||
...adminReturnRoutesMiddlewares,
|
...adminReturnRoutesMiddlewares,
|
||||||
...adminUserRoutesMiddlewares,
|
...adminUserRoutesMiddlewares,
|
||||||
...adminInviteRoutesMiddlewares,
|
...adminInviteRoutesMiddlewares,
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/dist
|
||||||
|
node_modules
|
||||||
|
.DS_store
|
||||||
|
.env*
|
||||||
|
.env
|
||||||
|
*.sql
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const defineJestConfig = require("../../../define_jest_config")
|
||||||
|
module.exports = defineJestConfig({
|
||||||
|
moduleNameMapper: {
|
||||||
|
"^@models": "<rootDir>/src/models",
|
||||||
|
"^@services": "<rootDir>/src/services",
|
||||||
|
"^@repositories": "<rootDir>/src/repositories",
|
||||||
|
"^@types": "<rootDir>/src/types",
|
||||||
|
"^@utils": "<rootDir>/src/utils",
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineMikroOrmCliConfig } from "@medusajs/framework/utils"
|
||||||
|
import * as entities from "./src/models"
|
||||||
|
|
||||||
|
export default defineMikroOrmCliConfig("rbac", {
|
||||||
|
entities: Object.values(entities),
|
||||||
|
})
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "@medusajs/rbac",
|
||||||
|
"version": "2.12.4",
|
||||||
|
"description": "Medusa RBAC module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"!dist/**/__tests__",
|
||||||
|
"!dist/**/__mocks__",
|
||||||
|
"!dist/**/__fixtures__"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/medusajs/medusa",
|
||||||
|
"directory": "packages/modules/rbac"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"author": "Medusa",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"watch": "yarn run -T tsc --build --watch",
|
||||||
|
"watch:test": "yarn run -T tsc --build tsconfig.spec.json --watch",
|
||||||
|
"resolve:aliases": "yarn run -T tsc --showConfig -p tsconfig.json > tsconfig.resolved.json && yarn run -T tsc-alias -p tsconfig.resolved.json && yarn run -T rimraf tsconfig.resolved.json",
|
||||||
|
"build": "yarn run -T rimraf dist && yarn run -T tsc --build && npm run resolve:aliases",
|
||||||
|
"test": "../../../node_modules/.bin/jest --passWithNoTests --bail --forceExit --testPathPattern=src",
|
||||||
|
"test:integration": "../../../node_modules/.bin/jest --passWithNoTests --forceExit --testPathPattern=\"integration-tests/__tests__/.*\\.ts\"",
|
||||||
|
"migration:initial": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts MIKRO_ORM_ALLOW_GLOBAL_CLI=true medusa-mikro-orm migration:create --initial",
|
||||||
|
"migration:create": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts MIKRO_ORM_ALLOW_GLOBAL_CLI=true medusa-mikro-orm migration:create",
|
||||||
|
"migration:up": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts MIKRO_ORM_ALLOW_GLOBAL_CLI=true medusa-mikro-orm migration:up",
|
||||||
|
"orm:cache:clear": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts MIKRO_ORM_ALLOW_GLOBAL_CLI=true medusa-mikro-orm cache:clear"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@medusajs/framework": "2.12.4",
|
||||||
|
"@medusajs/test-utils": "2.12.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@medusajs/framework": "2.12.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { Module } from "@medusajs/framework/utils"
|
||||||
|
import { RbacModuleService } from "@services"
|
||||||
|
|
||||||
|
export default Module("rbac", {
|
||||||
|
service: RbacModuleService,
|
||||||
|
})
|
||||||
@@ -0,0 +1,568 @@
|
|||||||
|
{
|
||||||
|
"namespaces": [
|
||||||
|
"public"
|
||||||
|
],
|
||||||
|
"name": "public",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"name": "resource",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"operation": {
|
||||||
|
"name": "operation",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "rbac_policy",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_policy_deleted_at",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_policy_deleted_at\" ON \"rbac_policy\" (\"deleted_at\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_policy_key_unique",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_rbac_policy_key_unique\" ON \"rbac_policy\" (\"key\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_policy_resource",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_policy_resource\" ON \"rbac_policy\" (\"resource\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_policy_operation",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_policy_operation\" ON \"rbac_policy\" (\"operation\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "rbac_policy_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {},
|
||||||
|
"nativeEnums": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "rbac_role",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_deleted_at",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_deleted_at\" ON \"rbac_role\" (\"deleted_at\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_name_unique",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_rbac_role_name_unique\" ON \"rbac_role\" (\"name\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "rbac_role_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {},
|
||||||
|
"nativeEnums": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"role_id": {
|
||||||
|
"name": "role_id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"inherited_role_id": {
|
||||||
|
"name": "inherited_role_id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "rbac_role_inheritance",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_inheritance_role_id",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_inheritance_role_id\" ON \"rbac_role_inheritance\" (\"role_id\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_inheritance_inherited_role_id",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_inheritance_inherited_role_id\" ON \"rbac_role_inheritance\" (\"inherited_role_id\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_inheritance_deleted_at",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_inheritance_deleted_at\" ON \"rbac_role_inheritance\" (\"deleted_at\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_inheritance_role_id_inherited_role_id_unique",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_rbac_role_inheritance_role_id_inherited_role_id_unique\" ON \"rbac_role_inheritance\" (\"role_id\", \"inherited_role_id\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "rbac_role_inheritance_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {
|
||||||
|
"rbac_role_inheritance_role_id_foreign": {
|
||||||
|
"constraintName": "rbac_role_inheritance_role_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"role_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.rbac_role_inheritance",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.rbac_role",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
},
|
||||||
|
"rbac_role_inheritance_inherited_role_id_foreign": {
|
||||||
|
"constraintName": "rbac_role_inheritance_inherited_role_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"inherited_role_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.rbac_role_inheritance",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.rbac_role",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nativeEnums": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"role_id": {
|
||||||
|
"name": "role_id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"scope_id": {
|
||||||
|
"name": "scope_id",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "rbac_role_policy",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_policy_role_id",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_policy_role_id\" ON \"rbac_role_policy\" (\"role_id\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_policy_scope_id",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_policy_scope_id\" ON \"rbac_role_policy\" (\"scope_id\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_policy_deleted_at",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_rbac_role_policy_deleted_at\" ON \"rbac_role_policy\" (\"deleted_at\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "IDX_rbac_role_policy_role_id_scope_id_unique",
|
||||||
|
"columnNames": [],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false,
|
||||||
|
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_rbac_role_policy_role_id_scope_id_unique\" ON \"rbac_role_policy\" (\"role_id\", \"scope_id\") WHERE deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "rbac_role_policy_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {
|
||||||
|
"rbac_role_policy_role_id_foreign": {
|
||||||
|
"constraintName": "rbac_role_policy_role_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"role_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.rbac_role_policy",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.rbac_role",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
},
|
||||||
|
"rbac_role_policy_scope_id_foreign": {
|
||||||
|
"constraintName": "rbac_role_policy_scope_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"scope_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.rbac_role_policy",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.rbac_policy",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nativeEnums": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nativeEnums": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { Migration } from '@mikro-orm/migrations';
|
||||||
|
|
||||||
|
export class Migration20251215113723 extends Migration {
|
||||||
|
|
||||||
|
override async up(): Promise<void> {
|
||||||
|
this.addSql(`alter table if exists "rbac_role_policy" drop constraint if exists "rbac_role_policy_role_id_scope_id_unique";`);
|
||||||
|
this.addSql(`alter table if exists "rbac_role_inheritance" drop constraint if exists "rbac_role_inheritance_role_id_inherited_role_id_unique";`);
|
||||||
|
this.addSql(`alter table if exists "rbac_role" drop constraint if exists "rbac_role_name_unique";`);
|
||||||
|
this.addSql(`alter table if exists "rbac_policy" drop constraint if exists "rbac_policy_key_unique";`);
|
||||||
|
this.addSql(`create table if not exists "rbac_policy" ("id" text not null, "key" text not null, "resource" text not null, "operation" text not null, "name" text null, "description" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "rbac_policy_pkey" primary key ("id"));`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_policy_deleted_at" ON "rbac_policy" ("deleted_at") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_rbac_policy_key_unique" ON "rbac_policy" ("key") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_policy_resource" ON "rbac_policy" ("resource") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_policy_operation" ON "rbac_policy" ("operation") WHERE deleted_at IS NULL;`);
|
||||||
|
|
||||||
|
this.addSql(`create table if not exists "rbac_role" ("id" text not null, "name" text not null, "description" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "rbac_role_pkey" primary key ("id"));`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_deleted_at" ON "rbac_role" ("deleted_at") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_rbac_role_name_unique" ON "rbac_role" ("name") WHERE deleted_at IS NULL;`);
|
||||||
|
|
||||||
|
this.addSql(`create table if not exists "rbac_role_inheritance" ("id" text not null, "role_id" text not null, "inherited_role_id" text not null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "rbac_role_inheritance_pkey" primary key ("id"));`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_inheritance_role_id" ON "rbac_role_inheritance" ("role_id") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_inheritance_inherited_role_id" ON "rbac_role_inheritance" ("inherited_role_id") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_inheritance_deleted_at" ON "rbac_role_inheritance" ("deleted_at") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_rbac_role_inheritance_role_id_inherited_role_id_unique" ON "rbac_role_inheritance" ("role_id", "inherited_role_id") WHERE deleted_at IS NULL;`);
|
||||||
|
|
||||||
|
this.addSql(`create table if not exists "rbac_role_policy" ("id" text not null, "role_id" text not null, "scope_id" text not null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "rbac_role_policy_pkey" primary key ("id"));`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_policy_role_id" ON "rbac_role_policy" ("role_id") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_policy_scope_id" ON "rbac_role_policy" ("scope_id") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_rbac_role_policy_deleted_at" ON "rbac_role_policy" ("deleted_at") WHERE deleted_at IS NULL;`);
|
||||||
|
this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_rbac_role_policy_role_id_scope_id_unique" ON "rbac_role_policy" ("role_id", "scope_id") WHERE deleted_at IS NULL;`);
|
||||||
|
|
||||||
|
this.addSql(`alter table if exists "rbac_role_inheritance" add constraint "rbac_role_inheritance_role_id_foreign" foreign key ("role_id") references "rbac_role" ("id") on update cascade;`);
|
||||||
|
this.addSql(`alter table if exists "rbac_role_inheritance" add constraint "rbac_role_inheritance_inherited_role_id_foreign" foreign key ("inherited_role_id") references "rbac_role" ("id") on update cascade;`);
|
||||||
|
|
||||||
|
this.addSql(`alter table if exists "rbac_role_policy" add constraint "rbac_role_policy_role_id_foreign" foreign key ("role_id") references "rbac_role" ("id") on update cascade;`);
|
||||||
|
this.addSql(`alter table if exists "rbac_role_policy" add constraint "rbac_role_policy_scope_id_foreign" foreign key ("scope_id") references "rbac_policy" ("id") on update cascade;`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export { default as RbacPolicy } from "./rbac-policy"
|
||||||
|
export { default as RbacRole } from "./rbac-role"
|
||||||
|
export { default as RbacRoleInheritance } from "./rbac-role-inheritance"
|
||||||
|
export { default as RbacRolePolicy } from "./rbac-role-policy"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { model } from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
const RbacPolicy = model
|
||||||
|
.define("rbac_policy", {
|
||||||
|
id: model.id({ prefix: "rpol" }).primaryKey(),
|
||||||
|
key: model.text().searchable(),
|
||||||
|
resource: model.text().searchable(),
|
||||||
|
operation: model.text().searchable(),
|
||||||
|
name: model.text().searchable().nullable(),
|
||||||
|
description: model.text().nullable(),
|
||||||
|
metadata: model.json().nullable(),
|
||||||
|
})
|
||||||
|
.indexes([
|
||||||
|
{
|
||||||
|
on: ["key"],
|
||||||
|
unique: true,
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
on: ["resource"],
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
on: ["operation"],
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export default RbacPolicy
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { model } from "@medusajs/framework/utils"
|
||||||
|
import RbacRole from "./rbac-role"
|
||||||
|
|
||||||
|
const RbacRoleInheritance = model
|
||||||
|
.define("rbac_role_inheritance", {
|
||||||
|
id: model.id({ prefix: "rlin" }).primaryKey(),
|
||||||
|
role: model.belongsTo(() => RbacRole, { mappedBy: "inherited_roles" }),
|
||||||
|
inherited_role: model.belongsTo(() => RbacRole, {
|
||||||
|
mappedBy: "inheritedBy",
|
||||||
|
}),
|
||||||
|
metadata: model.json().nullable(),
|
||||||
|
})
|
||||||
|
.indexes([
|
||||||
|
{
|
||||||
|
on: ["role_id"],
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
on: ["inherited_role_id"],
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
on: ["role_id", "inherited_role_id"],
|
||||||
|
unique: true,
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export default RbacRoleInheritance
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { model } from "@medusajs/framework/utils"
|
||||||
|
import RbacPolicy from "./rbac-policy"
|
||||||
|
import RbacRole from "./rbac-role"
|
||||||
|
|
||||||
|
const RbacRolePolicy = model
|
||||||
|
.define("rbac_role_policy", {
|
||||||
|
id: model.id({ prefix: "rlpl" }).primaryKey(),
|
||||||
|
role: model.belongsTo(() => RbacRole),
|
||||||
|
scope: model.belongsTo(() => RbacPolicy),
|
||||||
|
metadata: model.json().nullable(),
|
||||||
|
})
|
||||||
|
.indexes([
|
||||||
|
{
|
||||||
|
on: ["role_id"],
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
on: ["scope_id"],
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
on: ["role_id", "scope_id"],
|
||||||
|
unique: true,
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export default RbacRolePolicy
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { model } from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
const RbacRole = model
|
||||||
|
.define("rbac_role", {
|
||||||
|
id: model.id({ prefix: "role" }).primaryKey(),
|
||||||
|
name: model.text().searchable(),
|
||||||
|
description: model.text().nullable(),
|
||||||
|
metadata: model.json().nullable(),
|
||||||
|
})
|
||||||
|
.indexes([
|
||||||
|
{
|
||||||
|
on: ["name"],
|
||||||
|
unique: true,
|
||||||
|
where: "deleted_at IS NULL",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export default RbacRole
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./rbac"
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { SqlEntityManager } from "@medusajs/framework/mikro-orm/postgresql"
|
||||||
|
import { Context } from "@medusajs/framework/types"
|
||||||
|
import { MikroOrmBase } from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
export class RbacRepository extends MikroOrmBase {
|
||||||
|
constructor() {
|
||||||
|
// @ts-ignore
|
||||||
|
// eslint-disable-next-line prefer-rest-params
|
||||||
|
super(...arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
async listPoliciesForRole(
|
||||||
|
roleId: string,
|
||||||
|
sharedContext: Context = {}
|
||||||
|
): Promise<any[]> {
|
||||||
|
const policiesByRole = await this.listPoliciesForRoles(
|
||||||
|
[roleId],
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
return policiesByRole.get(roleId) || []
|
||||||
|
}
|
||||||
|
|
||||||
|
async listPoliciesForRoles(
|
||||||
|
roleIds: string[],
|
||||||
|
sharedContext: Context = {}
|
||||||
|
): Promise<Map<string, any[]>> {
|
||||||
|
const manager = this.getActiveManager<SqlEntityManager>(sharedContext)
|
||||||
|
const knex = manager.getKnex()
|
||||||
|
|
||||||
|
if (!roleIds?.length) {
|
||||||
|
return new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
const placeholders = roleIds.map(() => "?").join(",")
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
WITH RECURSIVE role_hierarchy AS (
|
||||||
|
SELECT id, name, id as original_role_id
|
||||||
|
FROM rbac_role
|
||||||
|
WHERE id IN (${placeholders}) AND deleted_at IS NULL
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT r.id, r.name, rh.original_role_id
|
||||||
|
FROM rbac_role r
|
||||||
|
INNER JOIN rbac_role_inheritance ri ON ri.inherited_role_id = r.id
|
||||||
|
INNER JOIN role_hierarchy rh ON rh.id = ri.role_id
|
||||||
|
WHERE r.deleted_at IS NULL AND ri.deleted_at IS NULL
|
||||||
|
)
|
||||||
|
SELECT DISTINCT
|
||||||
|
rh.original_role_id,
|
||||||
|
p.id,
|
||||||
|
p.key,
|
||||||
|
p.resource,
|
||||||
|
p.operation,
|
||||||
|
p.name,
|
||||||
|
p.description,
|
||||||
|
p.metadata,
|
||||||
|
p.created_at,
|
||||||
|
p.updated_at,
|
||||||
|
CASE WHEN rp.role_id = rh.original_role_id THEN NULL ELSE rp.role_id END as inherited_from_role_id
|
||||||
|
FROM rbac_policy p
|
||||||
|
INNER JOIN rbac_role_policy rp ON rp.scope_id = p.id
|
||||||
|
INNER JOIN role_hierarchy rh ON rh.id = rp.role_id
|
||||||
|
WHERE p.deleted_at IS NULL AND rp.deleted_at IS NULL
|
||||||
|
ORDER BY rh.original_role_id, p.resource, p.operation, p.key
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await knex.raw(query, roleIds)
|
||||||
|
const rows = result.rows || []
|
||||||
|
|
||||||
|
// Group policies by role_id
|
||||||
|
const policiesByRole = new Map<string, any[]>()
|
||||||
|
|
||||||
|
for (const row of rows) {
|
||||||
|
const roleId = row.original_role_id
|
||||||
|
delete row.original_role_id
|
||||||
|
|
||||||
|
if (!policiesByRole.has(roleId)) {
|
||||||
|
policiesByRole.set(roleId, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
policiesByRole.get(roleId)!.push(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return policiesByRole
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as RbacModuleService } from "./rbac-module-service"
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import { Context, FindConfig } from "@medusajs/framework/types"
|
||||||
|
import {
|
||||||
|
InjectManager,
|
||||||
|
MedusaContext,
|
||||||
|
MedusaService,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
RbacPolicy,
|
||||||
|
RbacRole,
|
||||||
|
RbacRoleInheritance,
|
||||||
|
RbacRolePolicy,
|
||||||
|
} from "@models"
|
||||||
|
import { RbacRepository } from "../repositories"
|
||||||
|
|
||||||
|
type InjectedDependencies = {
|
||||||
|
rbacRepository: RbacRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class RbacModuleService extends MedusaService<{
|
||||||
|
RbacRole: { dto: any }
|
||||||
|
RbacPolicy: { dto: any }
|
||||||
|
RbacRoleInheritance: { dto: any }
|
||||||
|
RbacRolePolicy: { dto: any }
|
||||||
|
}>({
|
||||||
|
RbacRole,
|
||||||
|
RbacPolicy,
|
||||||
|
RbacRoleInheritance,
|
||||||
|
RbacRolePolicy,
|
||||||
|
}) {
|
||||||
|
protected readonly rbacRepository_: RbacRepository
|
||||||
|
|
||||||
|
constructor({ rbacRepository }: InjectedDependencies) {
|
||||||
|
// @ts-ignore
|
||||||
|
super(...arguments)
|
||||||
|
this.rbacRepository_ = rbacRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
async listPoliciesForRole(
|
||||||
|
roleId: string,
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<any[]> {
|
||||||
|
return await this.rbacRepository_.listPoliciesForRole(roleId, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
// @ts-expect-error
|
||||||
|
async listRbacRoles(
|
||||||
|
filters: any = {},
|
||||||
|
config: FindConfig<any> = {},
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<any[]> {
|
||||||
|
const roles = await super.listRbacRoles(filters, config, sharedContext)
|
||||||
|
|
||||||
|
const shouldIncludePolicies =
|
||||||
|
config.relations?.includes("policies") ||
|
||||||
|
config.select?.includes("policies")
|
||||||
|
|
||||||
|
if (shouldIncludePolicies && roles.length > 0) {
|
||||||
|
const roleIds = roles.map((role) => role.id)
|
||||||
|
const policiesByRole = await this.rbacRepository_.listPoliciesForRoles(
|
||||||
|
roleIds,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const role of roles) {
|
||||||
|
role.policies = policiesByRole.get(role.id) || []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
// @ts-expect-error
|
||||||
|
async listAndCountRbacRoles(
|
||||||
|
filters: any = {},
|
||||||
|
config: FindConfig<any> = {},
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<[any[], number]> {
|
||||||
|
const [roles, count] = await super.listAndCountRbacRoles(
|
||||||
|
filters,
|
||||||
|
config,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
const shouldIncludePolicies =
|
||||||
|
config.relations?.includes("policies") ||
|
||||||
|
config.select?.includes("policies")
|
||||||
|
|
||||||
|
if (shouldIncludePolicies && roles.length > 0) {
|
||||||
|
const roleIds = roles.map((role) => role.id)
|
||||||
|
const policiesByRole = await this.rbacRepository_.listPoliciesForRoles(
|
||||||
|
roleIds,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const role of roles) {
|
||||||
|
role.policies = policiesByRole.get(role.id) || []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [roles, count]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export type RbacModuleOptions = Record<string, unknown>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../../_tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@models": ["./src/models"],
|
||||||
|
"@services": ["./src/services"],
|
||||||
|
"@repositories": ["./src/repositories"],
|
||||||
|
"@types": ["./src/types"],
|
||||||
|
"@utils": ["./src/utils"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4013,6 +4013,17 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@medusajs/rbac@workspace:packages/modules/rbac":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@medusajs/rbac@workspace:packages/modules/rbac"
|
||||||
|
dependencies:
|
||||||
|
"@medusajs/framework": 2.12.4
|
||||||
|
"@medusajs/test-utils": 2.12.4
|
||||||
|
peerDependencies:
|
||||||
|
"@medusajs/framework": 2.12.4
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@medusajs/region@2.12.4, @medusajs/region@workspace:^, @medusajs/region@workspace:packages/modules/region":
|
"@medusajs/region@2.12.4, @medusajs/region@workspace:^, @medusajs/region@workspace:packages/modules/region":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@medusajs/region@workspace:packages/modules/region"
|
resolution: "@medusajs/region@workspace:packages/modules/region"
|
||||||
|
|||||||
Reference in new issue
Block a user