roles-privileges-payload-plugin 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/collections/roles.d.ts +32 -0
- package/dist/collections/roles.js +122 -0
- package/dist/collections/roles.js.map +1 -0
- package/dist/components/PrivilegesSelect.d.ts +19 -0
- package/dist/components/PrivilegesSelect.js +471 -0
- package/dist/components/PrivilegesSelect.js.map +1 -0
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.js +3 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/exports/types.d.ts +3 -0
- package/dist/exports/types.js +5 -0
- package/dist/exports/types.js.map +1 -0
- package/dist/exports/utilities.d.ts +6 -0
- package/dist/exports/utilities.js +14 -0
- package/dist/exports/utilities.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +179 -0
- package/dist/index.js.map +1 -0
- package/dist/roles-privileges-payload-plugin-1.1.1.tgz +0 -0
- package/dist/translations/index.d.ts +7 -0
- package/dist/translations/index.js +50 -0
- package/dist/translations/index.js.map +1 -0
- package/dist/translations/languages/en.d.ts +2 -0
- package/dist/translations/languages/en.js +76 -0
- package/dist/translations/languages/en.js.map +1 -0
- package/dist/translations/languages/fr.d.ts +2 -0
- package/dist/translations/languages/fr.js +76 -0
- package/dist/translations/languages/fr.js.map +1 -0
- package/dist/translations/types.d.ts +67 -0
- package/dist/translations/types.js +3 -0
- package/dist/translations/types.js.map +1 -0
- package/dist/utils/createCustomPrivilege.d.ts +89 -0
- package/dist/utils/createCustomPrivilege.js +77 -0
- package/dist/utils/createCustomPrivilege.js.map +1 -0
- package/dist/utils/generateGlobalPrivileges.d.ts +48 -0
- package/dist/utils/generateGlobalPrivileges.js +133 -0
- package/dist/utils/generateGlobalPrivileges.js.map +1 -0
- package/dist/utils/generatePrivileges.d.ts +51 -0
- package/dist/utils/generatePrivileges.js +162 -0
- package/dist/utils/generatePrivileges.js.map +1 -0
- package/dist/utils/privilegesAccess.d.ts +71 -0
- package/dist/utils/privilegesAccess.js +144 -0
- package/dist/utils/privilegesAccess.js.map +1 -0
- package/dist/utils/seedSuperAdminRole.d.ts +6 -0
- package/dist/utils/seedSuperAdminRole.js +60 -0
- package/dist/utils/seedSuperAdminRole.js.map +1 -0
- package/package.json +12 -1
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Roles & Privileges Payload Plugin
|
|
2
2
|
|
|
3
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
4
|
+
[](https://www.npmjs.com/package/roles-privileges-payload-plugin)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
3
7
|
A powerful Payload CMS plugin that automatically generates role-based access control (RBAC) with granular CRUD privileges for all your collections.
|
|
4
8
|
|
|
5
9
|
## Features
|
|
@@ -632,4 +636,4 @@ describe('Plugin tests', () => {
|
|
|
632
636
|
expect(...)
|
|
633
637
|
})
|
|
634
638
|
})
|
|
635
|
-
```
|
|
639
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CollectionBeforeChangeHook, CollectionBeforeDeleteHook, CollectionConfig } from 'payload';
|
|
2
|
+
import type { GlobalPrivilege } from '../utils/generateGlobalPrivileges.js';
|
|
3
|
+
import type { Privilege } from '../utils/generatePrivileges.js';
|
|
4
|
+
export type CollectionData = {
|
|
5
|
+
collectionSlug: string;
|
|
6
|
+
collectionLabel: {
|
|
7
|
+
en: string;
|
|
8
|
+
fr: string;
|
|
9
|
+
};
|
|
10
|
+
privileges: Record<string, Privilege>;
|
|
11
|
+
};
|
|
12
|
+
export type GlobalData = {
|
|
13
|
+
globalSlug: string;
|
|
14
|
+
globalLabel: {
|
|
15
|
+
en: string;
|
|
16
|
+
fr: string;
|
|
17
|
+
};
|
|
18
|
+
privileges: Record<string, GlobalPrivilege>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Hook to ensure the Super Admin role cannot be deleted
|
|
22
|
+
*/
|
|
23
|
+
export declare const ensureSuperAdminDontGetDeleted: CollectionBeforeDeleteHook;
|
|
24
|
+
/**
|
|
25
|
+
* Hook to ensure the Super Admin role slug cannot be changed
|
|
26
|
+
*/
|
|
27
|
+
export declare const ensureSuperAdminDontGetUpdated: CollectionBeforeChangeHook;
|
|
28
|
+
/**
|
|
29
|
+
* Roles collection configuration
|
|
30
|
+
* This collection manages user roles and their associated privileges
|
|
31
|
+
*/
|
|
32
|
+
export declare const createRolesCollection: (collections?: CollectionData[], globals?: GlobalData[]) => CollectionConfig;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { hasPrivilege } from '../utils/privilegesAccess.js';
|
|
3
|
+
/**
|
|
4
|
+
* Hook to ensure the Super Admin role cannot be deleted
|
|
5
|
+
*/ export const ensureSuperAdminDontGetDeleted = async ({ req, id })=>{
|
|
6
|
+
const role = await req.payload.findByID({
|
|
7
|
+
collection: 'roles',
|
|
8
|
+
id
|
|
9
|
+
});
|
|
10
|
+
if (role && role.slug === 'super-admin') {
|
|
11
|
+
throw new APIError(req.t('plugin-roles-privileges:error-cannot-delete-super-admin'), 400);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Hook to ensure the Super Admin role slug cannot be changed
|
|
16
|
+
*/ export const ensureSuperAdminDontGetUpdated = async ({ data, originalDoc, req })=>{
|
|
17
|
+
if (originalDoc && originalDoc.slug === 'super-admin') {
|
|
18
|
+
if (data.slug && data.slug !== 'super-admin') {
|
|
19
|
+
throw new APIError(req.t('plugin-roles-privileges:error-cannot-modify-super-admin-slug'), 400);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Roles collection configuration
|
|
26
|
+
* This collection manages user roles and their associated privileges
|
|
27
|
+
*/ export const createRolesCollection = (collections, globals)=>{
|
|
28
|
+
return {
|
|
29
|
+
slug: 'roles',
|
|
30
|
+
labels: {
|
|
31
|
+
singular: ({ t })=>t('plugin-roles-privileges:roles-collection-label-singular'),
|
|
32
|
+
plural: ({ t })=>t('plugin-roles-privileges:roles-collection-label-plural')
|
|
33
|
+
},
|
|
34
|
+
access: {
|
|
35
|
+
// Allow authenticated users to read roles (needed for user role resolution)
|
|
36
|
+
read: ()=>true,
|
|
37
|
+
// Require specific privileges for other operations
|
|
38
|
+
create: hasPrivilege('roles-create'),
|
|
39
|
+
update: hasPrivilege('roles-update'),
|
|
40
|
+
delete: hasPrivilege('roles-delete')
|
|
41
|
+
},
|
|
42
|
+
admin: {
|
|
43
|
+
useAsTitle: 'title',
|
|
44
|
+
defaultColumns: [
|
|
45
|
+
'title',
|
|
46
|
+
'slug'
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
fields: [
|
|
50
|
+
{
|
|
51
|
+
name: 'title',
|
|
52
|
+
type: 'text',
|
|
53
|
+
required: true,
|
|
54
|
+
label: ({ t })=>t('plugin-roles-privileges:roles-field-title-label')
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'slug',
|
|
58
|
+
type: 'text',
|
|
59
|
+
required: true,
|
|
60
|
+
unique: true,
|
|
61
|
+
label: ({ t })=>t('plugin-roles-privileges:roles-field-slug-label'),
|
|
62
|
+
admin: {
|
|
63
|
+
description: ({ t })=>t('plugin-roles-privileges:roles-field-slug-description')
|
|
64
|
+
},
|
|
65
|
+
hooks: {
|
|
66
|
+
beforeValidate: [
|
|
67
|
+
({ value })=>{
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'privileges',
|
|
78
|
+
type: 'array',
|
|
79
|
+
label: ({ t })=>t('plugin-roles-privileges:roles-field-privileges-label'),
|
|
80
|
+
admin: {
|
|
81
|
+
description: ({ t })=>t('plugin-roles-privileges:roles-field-privileges-description'),
|
|
82
|
+
components: {
|
|
83
|
+
Field: {
|
|
84
|
+
path: 'roles-privileges-payload-plugin/client#PrivilegesSelect',
|
|
85
|
+
clientProps: {
|
|
86
|
+
collections: collections || [],
|
|
87
|
+
globals: globals || []
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
minRows: 1,
|
|
93
|
+
fields: [
|
|
94
|
+
{
|
|
95
|
+
name: 'privilege',
|
|
96
|
+
type: 'text',
|
|
97
|
+
required: true,
|
|
98
|
+
label: ({ t })=>t('plugin-roles-privileges:roles-field-privileges-label')
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'description',
|
|
104
|
+
type: 'textarea',
|
|
105
|
+
label: ({ t })=>t('plugin-roles-privileges:roles-field-description-label'),
|
|
106
|
+
admin: {
|
|
107
|
+
description: ({ t })=>t('plugin-roles-privileges:roles-field-description-description')
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
hooks: {
|
|
112
|
+
beforeChange: [
|
|
113
|
+
ensureSuperAdminDontGetUpdated
|
|
114
|
+
],
|
|
115
|
+
beforeDelete: [
|
|
116
|
+
ensureSuperAdminDontGetDeleted
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=roles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/collections/roles.ts"],"sourcesContent":["import type {\n CollectionBeforeChangeHook,\n CollectionBeforeDeleteHook,\n CollectionConfig,\n} from 'payload'\nimport { APIError } from 'payload'\nimport type { GlobalPrivilege } from '../utils/generateGlobalPrivileges.js'\nimport type { Privilege } from '../utils/generatePrivileges.js'\nimport { hasPrivilege } from '../utils/privilegesAccess.js'\n\nexport type CollectionData = {\n collectionSlug: string\n collectionLabel: { en: string; fr: string }\n privileges: Record<string, Privilege>\n}\n\nexport type GlobalData = {\n globalSlug: string\n globalLabel: { en: string; fr: string }\n privileges: Record<string, GlobalPrivilege>\n}\n\n/**\n * Hook to ensure the Super Admin role cannot be deleted\n */\nexport const ensureSuperAdminDontGetDeleted: CollectionBeforeDeleteHook = async ({ req, id }) => {\n const role = await req.payload.findByID({\n collection: 'roles',\n id,\n })\n\n if (role && role.slug === 'super-admin') {\n throw new APIError(\n (req.t as (key: string) => string)('plugin-roles-privileges:error-cannot-delete-super-admin'),\n 400,\n )\n }\n}\n\n/**\n * Hook to ensure the Super Admin role slug cannot be changed\n */\nexport const ensureSuperAdminDontGetUpdated: CollectionBeforeChangeHook = async ({\n data,\n originalDoc,\n req,\n}) => {\n if (originalDoc && originalDoc.slug === 'super-admin') {\n if (data.slug && data.slug !== 'super-admin') {\n throw new APIError(\n (req.t as (key: string) => string)(\n 'plugin-roles-privileges:error-cannot-modify-super-admin-slug',\n ),\n 400,\n )\n }\n }\n return data\n}\n\n/**\n * Roles collection configuration\n * This collection manages user roles and their associated privileges\n */\nexport const createRolesCollection = (\n collections?: CollectionData[],\n globals?: GlobalData[],\n): CollectionConfig => {\n return {\n slug: 'roles',\n labels: {\n singular: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-collection-label-singular'),\n plural: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-collection-label-plural'),\n },\n access: {\n // Allow authenticated users to read roles (needed for user role resolution)\n read: () => true,\n // Require specific privileges for other operations\n create: hasPrivilege('roles-create'),\n update: hasPrivilege('roles-update'),\n delete: hasPrivilege('roles-delete'),\n },\n admin: {\n useAsTitle: 'title',\n defaultColumns: ['title', 'slug'],\n },\n fields: [\n {\n name: 'title',\n type: 'text',\n required: true,\n label: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-field-title-label'),\n },\n {\n name: 'slug',\n type: 'text',\n required: true,\n unique: true,\n label: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-field-slug-label'),\n admin: {\n description: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-field-slug-description'),\n },\n hooks: {\n beforeValidate: [\n ({ value }) => {\n if (typeof value === 'string') {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '')\n }\n return value\n },\n ],\n },\n },\n {\n name: 'privileges',\n type: 'array',\n label: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-field-privileges-label'),\n admin: {\n description: ({ t }) =>\n (t as (key: string) => string)(\n 'plugin-roles-privileges:roles-field-privileges-description',\n ),\n components: {\n Field: {\n path: 'roles-privileges-payload-plugin/client#PrivilegesSelect',\n clientProps: {\n collections: collections || [],\n globals: globals || [],\n },\n },\n },\n },\n minRows: 1,\n fields: [\n {\n name: 'privilege',\n type: 'text',\n required: true,\n label: ({ t }) =>\n (t as (key: string) => string)(\n 'plugin-roles-privileges:roles-field-privileges-label',\n ),\n },\n ],\n },\n {\n name: 'description',\n type: 'textarea',\n label: ({ t }) =>\n (t as (key: string) => string)('plugin-roles-privileges:roles-field-description-label'),\n admin: {\n description: ({ t }) =>\n (t as (key: string) => string)(\n 'plugin-roles-privileges:roles-field-description-description',\n ),\n },\n },\n ],\n hooks: {\n beforeChange: [ensureSuperAdminDontGetUpdated],\n beforeDelete: [ensureSuperAdminDontGetDeleted],\n },\n }\n}\n"],"names":["APIError","hasPrivilege","ensureSuperAdminDontGetDeleted","req","id","role","payload","findByID","collection","slug","t","ensureSuperAdminDontGetUpdated","data","originalDoc","createRolesCollection","collections","globals","labels","singular","plural","access","read","create","update","delete","admin","useAsTitle","defaultColumns","fields","name","type","required","label","unique","description","hooks","beforeValidate","value","toLowerCase","replace","components","Field","path","clientProps","minRows","beforeChange","beforeDelete"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { GlobalPrivilege } from '../utils/generateGlobalPrivileges.js';
|
|
2
|
+
import type { Privilege } from '../utils/generatePrivileges.js';
|
|
3
|
+
type CollectionPrivileges = {
|
|
4
|
+
collectionSlug: string;
|
|
5
|
+
collectionLabel: Record<string, string>;
|
|
6
|
+
privileges: Record<string, Privilege>;
|
|
7
|
+
};
|
|
8
|
+
type GlobalPrivileges = {
|
|
9
|
+
globalSlug: string;
|
|
10
|
+
globalLabel: Record<string, string>;
|
|
11
|
+
privileges: Record<string, GlobalPrivilege>;
|
|
12
|
+
};
|
|
13
|
+
declare const _default_1: import("react").NamedExoticComponent<{
|
|
14
|
+
readonly validate?: import("payload").ArrayFieldValidation;
|
|
15
|
+
} & import("payload").FieldPaths & {
|
|
16
|
+
readonly field: Omit<import("payload").ArrayFieldClient, "type"> & Partial<Pick<import("payload").ArrayFieldClient, "type">>;
|
|
17
|
+
} & Omit<import("payload").ClientComponentProps, "customComponents" | "field">>;
|
|
18
|
+
export default _default_1;
|
|
19
|
+
export type { CollectionPrivileges, GlobalPrivileges };
|