Merge pull request #2422 from automatisch/aut-1515
feat(migrations): introduce manage permissions instead of create, update, delete, publish
This commit is contained in:
@@ -112,5 +112,6 @@
|
||||
"src/"
|
||||
],
|
||||
"ext": "js"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('PATCH /api/v1/admin/roles/:roleId', () => {
|
||||
|
||||
it('should return the updated role with sanitized permissions', async () => {
|
||||
const validPermission = {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
conditions: ['isCreator'],
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: role.id,
|
||||
});
|
||||
|
||||
@@ -15,14 +15,7 @@ describe('DELETE /api/v1/connections/:connectionId', () => {
|
||||
currentUserRole = await currentUser.$relatedQuery('role');
|
||||
|
||||
await createPermission({
|
||||
action: 'delete',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('POST /api/v1/connections/:connectionId/auth-url', () => {
|
||||
currentUser = await createUser();
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUser.roleId,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('POST /api/v1/connections/:connectionId/reset', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -68,7 +68,7 @@ describe('POST /api/v1/connections/:connectionId/reset', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -84,7 +84,7 @@ describe('POST /api/v1/connections/:connectionId/reset', () => {
|
||||
const notExistingConnectionUUID = Crypto.randomUUID();
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -98,7 +98,7 @@ describe('POST /api/v1/connections/:connectionId/reset', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -63,7 +63,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -88,7 +88,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -109,7 +109,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('PATCH /api/v1/connections/:connectionId', () => {
|
||||
const currentUserConnection = await createConnection(connectionData);
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -72,7 +72,7 @@ describe('PATCH /api/v1/connections/:connectionId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -88,7 +88,7 @@ describe('PATCH /api/v1/connections/:connectionId', () => {
|
||||
const notExistingConnectionUUID = Crypto.randomUUID();
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -102,7 +102,7 @@ describe('PATCH /api/v1/connections/:connectionId', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('POST /api/v1/connections/:connectionId/verify', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -54,7 +54,7 @@ describe('POST /api/v1/connections/:connectionId/verify', () => {
|
||||
const notExistingConnectionUUID = Crypto.randomUUID();
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -68,7 +68,7 @@ describe('POST /api/v1/connections/:connectionId/verify', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('POST /api/v1/flows', () => {
|
||||
|
||||
it('should create an empty flow when no templateId is provided', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -42,7 +42,7 @@ describe('POST /api/v1/flows', () => {
|
||||
|
||||
it('should create a flow from template when templateId is provided', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -36,7 +36,7 @@ describe('POST /api/v1/flows/:flowId/steps', () => {
|
||||
await createPermission({
|
||||
roleId: currentUser.roleId,
|
||||
subject: 'Flow',
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('POST /api/v1/flows/:flowId/steps', () => {
|
||||
await createPermission({
|
||||
roleId: currentUser.roleId,
|
||||
subject: 'Flow',
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
conditions: [],
|
||||
});
|
||||
|
||||
@@ -109,7 +109,7 @@ describe('POST /api/v1/flows/:flowId/steps', () => {
|
||||
await createPermission({
|
||||
roleId: currentUser.roleId,
|
||||
subject: 'Flow',
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
|
||||
@@ -133,7 +133,7 @@ describe('POST /api/v1/flows/:flowId/steps', () => {
|
||||
await createPermission({
|
||||
roleId: currentUser.roleId,
|
||||
subject: 'Flow',
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
|
||||
@@ -159,7 +159,7 @@ describe('POST /api/v1/flows/:flowId/steps', () => {
|
||||
await createPermission({
|
||||
roleId: currentUser.roleId,
|
||||
subject: 'Flow',
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('DELETE /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'delete',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -52,7 +52,7 @@ describe('DELETE /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'delete',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -73,7 +73,7 @@ describe('DELETE /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'delete',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -96,7 +96,7 @@ describe('DELETE /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'delete',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('POST /api/v1/flows/:flowId/duplicate', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -106,7 +106,7 @@ describe('POST /api/v1/flows/:flowId/duplicate', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -143,7 +143,7 @@ describe('POST /api/v1/flows/:flowId/duplicate', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -169,7 +169,7 @@ describe('POST /api/v1/flows/:flowId/duplicate', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -190,7 +190,7 @@ describe('POST /api/v1/flows/:flowId/duplicate', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('POST /api/v1/flows/:flowId/export', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -113,7 +113,7 @@ describe('POST /api/v1/flows/:flowId/export', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -141,7 +141,7 @@ describe('POST /api/v1/flows/:flowId/export', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -167,7 +167,7 @@ describe('POST /api/v1/flows/:flowId/export', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -188,7 +188,7 @@ describe('POST /api/v1/flows/:flowId/export', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('POST /api/v1/flows/import', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -124,7 +124,7 @@ describe('POST /api/v1/flows/import', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -206,7 +206,7 @@ describe('POST /api/v1/flows/import', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -279,7 +279,7 @@ describe('POST /api/v1/flows/import', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -330,7 +330,7 @@ describe('POST /api/v1/flows/import', () => {
|
||||
const currentUserFlow = await createFlow({ userId: currentUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -77,7 +77,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -96,7 +96,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
const anotherUserFolder = await createFolder({ userId: anotherUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -111,7 +111,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
|
||||
it('should return not found response for not existing flow UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -130,7 +130,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
const flow = await createFlow({ userId: currentUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -147,7 +147,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
|
||||
it('should return bad request response for invalid flow UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
@@ -160,7 +160,7 @@ describe('PATCH /api/v1/flows/:flowId/folder', () => {
|
||||
|
||||
it('should return bad request response for invalid folder UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('PATCH /api/v1/flows/:flowId/status', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'publish',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -114,7 +114,7 @@ describe('PATCH /api/v1/flows/:flowId/status', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'publish',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -152,7 +152,7 @@ describe('PATCH /api/v1/flows/:flowId/status', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'publish',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -178,7 +178,7 @@ describe('PATCH /api/v1/flows/:flowId/status', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'publish',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -199,7 +199,7 @@ describe('PATCH /api/v1/flows/:flowId/status', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'publish',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('PATCH /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -65,7 +65,7 @@ describe('PATCH /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -98,7 +98,7 @@ describe('PATCH /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -121,7 +121,7 @@ describe('PATCH /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -144,7 +144,7 @@ describe('PATCH /api/v1/flows/:flowId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('POST /api/v1/folders', () => {
|
||||
|
||||
it('should return created flow', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('DELETE /api/v1/folders/:folderId', () => {
|
||||
const currentUserFolder = await createFolder({ userId: currentUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
@@ -34,7 +34,7 @@ describe('DELETE /api/v1/folders/:folderId', () => {
|
||||
|
||||
it('should return not found response for not existing folder UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
@@ -49,7 +49,7 @@ describe('DELETE /api/v1/folders/:folderId', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('PATCH /api/v1/folders/:folderId', () => {
|
||||
const currentUserFolder = await createFolder({ userId: currentUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
@@ -47,7 +47,7 @@ describe('PATCH /api/v1/folders/:folderId', () => {
|
||||
|
||||
it('should return not found response for not existing folder UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
@@ -62,7 +62,7 @@ describe('PATCH /api/v1/folders/:folderId', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
@@ -77,7 +77,7 @@ describe('PATCH /api/v1/folders/:folderId', () => {
|
||||
const currentUserFolder = await createFolder({ userId: currentUser.id });
|
||||
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -102,7 +102,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -156,7 +156,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -177,7 +177,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
|
||||
it('should return not found response for not existing step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -200,7 +200,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
|
||||
it('should return not found response for existing step UUID without app key', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -223,7 +223,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -78,7 +78,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -102,7 +102,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
||||
|
||||
it('should return not found response for not existing step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -125,7 +125,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
||||
|
||||
it('should return not found response for existing step UUID without app key', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -149,7 +149,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('DELETE /api/v1/steps/:stepId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -76,7 +76,7 @@ describe('DELETE /api/v1/steps/:stepId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -90,7 +90,7 @@ describe('DELETE /api/v1/steps/:stepId', () => {
|
||||
|
||||
it('should return not found response for not existing step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -113,7 +113,7 @@ describe('DELETE /api/v1/steps/:stepId', () => {
|
||||
|
||||
it('should return bad request response for invalid step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -108,7 +108,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -129,7 +129,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
||||
|
||||
it('should return not found response for not existing step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -152,7 +152,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
||||
|
||||
it('should return bad request response for invalid UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
|
||||
@@ -69,7 +69,7 @@ describe('POST /api/v1/steps/:stepId/test', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
@@ -140,7 +140,7 @@ describe('POST /api/v1/steps/:stepId/test', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -165,7 +165,7 @@ describe('POST /api/v1/steps/:stepId/test', () => {
|
||||
|
||||
it('should return not found response for not existing step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -188,7 +188,7 @@ describe('POST /api/v1/steps/:stepId/test', () => {
|
||||
|
||||
it('should return bad request response for invalid step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('PATCH /api/v1/steps/:stepId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUser.roleId,
|
||||
conditions: ['isCreator'],
|
||||
@@ -96,7 +96,7 @@ describe('PATCH /api/v1/steps/:stepId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUser.roleId,
|
||||
conditions: [],
|
||||
@@ -145,7 +145,7 @@ describe('PATCH /api/v1/steps/:stepId', () => {
|
||||
});
|
||||
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUser.roleId,
|
||||
conditions: ['isCreator'],
|
||||
@@ -169,7 +169,7 @@ describe('PATCH /api/v1/steps/:stepId', () => {
|
||||
|
||||
it('should return not found response for not existing step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUser.roleId,
|
||||
conditions: [],
|
||||
@@ -192,7 +192,7 @@ describe('PATCH /api/v1/steps/:stepId', () => {
|
||||
|
||||
it('should return bad request response for invalid step UUID', async () => {
|
||||
await createPermission({
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUser.roleId,
|
||||
conditions: [],
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('GET /api/v1/templates', () => {
|
||||
|
||||
it('should return templates when templates are enabled and user has create flow permission', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
@@ -45,7 +45,7 @@ describe('GET /api/v1/templates', () => {
|
||||
|
||||
it('should return 403 when templates are disabled', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: [],
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
export async function up(knex) {
|
||||
const roles = await knex('roles').select('id', 'name');
|
||||
|
||||
// Define the required actions for each subject
|
||||
const subjectActionMap = {
|
||||
Connection: ['create', 'delete', 'update'],
|
||||
Flow: ['create', 'delete', 'publish', 'update'],
|
||||
User: ['create', 'delete', 'update'],
|
||||
Role: ['create', 'delete', 'update'],
|
||||
SamlAuthProvider: ['create', 'delete', 'update'],
|
||||
Config: ['update'],
|
||||
App: ['create', 'delete', 'update'],
|
||||
};
|
||||
|
||||
for (const role of roles) {
|
||||
for (const [subject, actions] of Object.entries(subjectActionMap)) {
|
||||
const rolePermissions = await knex('permissions')
|
||||
.where({ role_id: role.id, subject })
|
||||
.whereIn('action', actions)
|
||||
.select('id', 'action', 'conditions');
|
||||
|
||||
const actionCounts = rolePermissions.reduce((counts, perm) => {
|
||||
counts[perm.action] = (counts[perm.action] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
|
||||
let allActionsExist = true;
|
||||
for (const action of actions) {
|
||||
if (actionCounts[action] !== 1) {
|
||||
allActionsExist = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if any of the permissions has the 'isCreator' condition
|
||||
const hasIsCreatorCondition = rolePermissions.some(
|
||||
(perm) => perm.conditions && perm.conditions.includes('isCreator')
|
||||
);
|
||||
|
||||
// Delete the existing permissions for the required actions
|
||||
await knex('permissions')
|
||||
.where({ role_id: role.id, subject })
|
||||
.whereIn('action', actions)
|
||||
.del();
|
||||
|
||||
// If all required actions exist, insert a new permission with the 'manage' action
|
||||
if (allActionsExist) {
|
||||
await knex('permissions').insert({
|
||||
role_id: role.id,
|
||||
subject,
|
||||
action: 'manage',
|
||||
conditions: JSON.stringify(
|
||||
hasIsCreatorCondition ? ['isCreator'] : []
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
export async function down(knex) {
|
||||
const roles = await knex('roles').select('id', 'name');
|
||||
|
||||
// Define the required actions for each subject
|
||||
const subjectActionMap = {
|
||||
Connection: ['create', 'delete', 'update'],
|
||||
Flow: ['create', 'delete', 'publish', 'update'],
|
||||
User: ['create', 'delete', 'update'],
|
||||
Role: ['create', 'delete', 'update'],
|
||||
SamlAuthProvider: ['create', 'delete', 'update'],
|
||||
Config: ['update'],
|
||||
App: ['create', 'delete', 'update'],
|
||||
};
|
||||
|
||||
for (const role of roles) {
|
||||
for (const [subject, actions] of Object.entries(subjectActionMap)) {
|
||||
// Find the 'manage' permission for the subject
|
||||
const managePermission = await knex('permissions')
|
||||
.where({ role_id: role.id, subject, action: 'manage' })
|
||||
.first();
|
||||
|
||||
if (managePermission) {
|
||||
// Determine if the 'manage' permission has the 'isCreator' condition
|
||||
const hasIsCreatorCondition =
|
||||
managePermission.conditions.includes('isCreator');
|
||||
|
||||
// Delete the 'manage' permission
|
||||
await knex('permissions')
|
||||
.where({ role_id: role.id, subject, action: 'manage' })
|
||||
.del();
|
||||
|
||||
// Restore the original permissions for the subject
|
||||
const restoredPermissions = actions.map((action) => ({
|
||||
role_id: role.id,
|
||||
subject,
|
||||
action,
|
||||
conditions: JSON.stringify(
|
||||
hasIsCreatorCondition ? ['isCreator'] : []
|
||||
),
|
||||
}));
|
||||
|
||||
await knex('permissions').insert(restoredPermissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -22,19 +22,19 @@ const authorizationList = {
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/flows/': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'PATCH /api/v1/flows/:flowId': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'DELETE /api/v1/flows/:flowId': {
|
||||
action: 'delete',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'GET /api/v1/templates/': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'GET /api/v1/steps/:stepId/connection': {
|
||||
@@ -42,23 +42,23 @@ const authorizationList = {
|
||||
subject: 'Flow',
|
||||
},
|
||||
'PATCH /api/v1/steps/:stepId': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/steps/:stepId/test': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'GET /api/v1/steps/:stepId/previous-steps': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/steps/:stepId/dynamic-fields': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/steps/:stepId/dynamic-data': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'GET /api/v1/connections/:connectionId/flows': {
|
||||
@@ -66,11 +66,11 @@ const authorizationList = {
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/connections/:connectionId/test': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'POST /api/v1/connections/:connectionId/verify': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'GET /api/v1/apps/:appKey/flows': {
|
||||
@@ -94,59 +94,59 @@ const authorizationList = {
|
||||
subject: 'Execution',
|
||||
},
|
||||
'DELETE /api/v1/steps/:stepId': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'PATCH /api/v1/connections/:connectionId': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'DELETE /api/v1/connections/:connectionId': {
|
||||
action: 'delete',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'POST /api/v1/connections/:connectionId/reset': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'PATCH /api/v1/flows/:flowId/status': {
|
||||
action: 'publish',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/flows/:flowId/duplicate': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/flows/:flowId/export': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/flows/import': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/flows/:flowId/steps': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'POST /api/v1/apps/:appKey/connections': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'POST /api/v1/connections/:connectionId/auth-url': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'POST /api/v1/folders/': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'PATCH /api/v1/folders/:folderId': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'DELETE /api/v1/folders/:folderId': {
|
||||
action: 'create',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'GET /api/v1/folders/': {
|
||||
@@ -154,7 +154,7 @@ const authorizationList = {
|
||||
subject: 'Flow',
|
||||
},
|
||||
'PATCH /api/v1/flows/:flowId/folder': {
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
},
|
||||
'GET /api/v1/flows/:flowId/folder': {
|
||||
|
||||
@@ -17,56 +17,22 @@ const permissionCatalog = {
|
||||
conditions: [
|
||||
{
|
||||
key: 'isCreator',
|
||||
label: 'Is creator'
|
||||
}
|
||||
label: 'Is creator',
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
label: 'Create',
|
||||
key: 'create',
|
||||
subjects: [
|
||||
Connection.key,
|
||||
Flow.key,
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Read',
|
||||
key: 'read',
|
||||
subjects: [
|
||||
Connection.key,
|
||||
Execution.key,
|
||||
Flow.key,
|
||||
]
|
||||
subjects: [Connection.key, Execution.key, Flow.key],
|
||||
},
|
||||
{
|
||||
label: 'Update',
|
||||
key: 'update',
|
||||
subjects: [
|
||||
Connection.key,
|
||||
Flow.key,
|
||||
]
|
||||
label: 'Manage',
|
||||
key: 'manage',
|
||||
subjects: [Connection.key, Flow.key],
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete',
|
||||
subjects: [
|
||||
Connection.key,
|
||||
Flow.key,
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Publish',
|
||||
key: 'publish',
|
||||
subjects: [
|
||||
Flow.key,
|
||||
]
|
||||
}
|
||||
],
|
||||
subjects: [
|
||||
Connection,
|
||||
Flow,
|
||||
Execution
|
||||
]
|
||||
subjects: [Connection, Flow, Execution],
|
||||
};
|
||||
|
||||
export default permissionCatalog;
|
||||
|
||||
@@ -14,10 +14,10 @@ describe('Permission model', () => {
|
||||
it('filter should return only valid permissions based on permission catalog', () => {
|
||||
const permissions = [
|
||||
{ action: 'read', subject: 'Flow', conditions: ['isCreator'] },
|
||||
{ action: 'delete', subject: 'Connection', conditions: [] },
|
||||
{ action: 'publish', subject: 'Flow', conditions: ['isCreator'] },
|
||||
{ action: 'update', subject: 'Execution', conditions: [] }, // Invalid subject
|
||||
{ action: 'read', subject: 'Execution', conditions: ['invalid'] }, // Invalid condition
|
||||
{ action: 'manage', subject: 'Connection', conditions: [] },
|
||||
{ action: 'manage', subject: 'Flow', conditions: ['isCreator'] },
|
||||
{ action: 'manage', subject: 'Execution', conditions: [] }, // Invalid subject
|
||||
{ action: 'manage', subject: 'Execution', conditions: ['invalid'] }, // Invalid condition
|
||||
{ action: 'invalid', subject: 'Execution', conditions: [] }, // Invalid action
|
||||
];
|
||||
|
||||
@@ -25,15 +25,15 @@ describe('Permission model', () => {
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{ action: 'read', subject: 'Flow', conditions: ['isCreator'] },
|
||||
{ action: 'delete', subject: 'Connection', conditions: [] },
|
||||
{ action: 'publish', subject: 'Flow', conditions: ['isCreator'] },
|
||||
{ action: 'manage', subject: 'Connection', conditions: [] },
|
||||
{ action: 'manage', subject: 'Flow', conditions: ['isCreator'] },
|
||||
]);
|
||||
});
|
||||
|
||||
describe('findAction', () => {
|
||||
it('should return action from permission catalog', () => {
|
||||
const action = Permission.findAction('create');
|
||||
expect(action.key).toStrictEqual('create');
|
||||
const action = Permission.findAction('manage');
|
||||
expect(action.key).toStrictEqual('manage');
|
||||
});
|
||||
|
||||
it('should return undefined for invalid actions', () => {
|
||||
@@ -45,7 +45,7 @@ describe('Permission model', () => {
|
||||
describe('isSubjectValid', () => {
|
||||
it('should return true for valid subjects', () => {
|
||||
const validAction = permissionCatalog.actions.find(
|
||||
(action) => action.key === 'create'
|
||||
(action) => action.key === 'manage'
|
||||
);
|
||||
|
||||
const validSubject = Permission.isSubjectValid('Connection', validAction);
|
||||
@@ -54,7 +54,7 @@ describe('Permission model', () => {
|
||||
|
||||
it('should return false for invalid subjects', () => {
|
||||
const validAction = permissionCatalog.actions.find(
|
||||
(action) => action.key === 'create'
|
||||
(action) => action.key === 'manage'
|
||||
);
|
||||
|
||||
const invalidSubject = Permission.isSubjectValid(
|
||||
|
||||
@@ -166,7 +166,7 @@ describe('Role model', () => {
|
||||
description: 'Updated description',
|
||||
permissions: [
|
||||
{
|
||||
action: 'update',
|
||||
action: 'manage',
|
||||
subject: 'Flow',
|
||||
conditions: [],
|
||||
},
|
||||
|
||||
@@ -1,31 +1,16 @@
|
||||
const getPermissionsCatalogMock = async () => {
|
||||
const data = {
|
||||
actions: [
|
||||
{
|
||||
key: 'create',
|
||||
label: 'Create',
|
||||
subjects: ['Connection', 'Flow'],
|
||||
},
|
||||
{
|
||||
key: 'read',
|
||||
label: 'Read',
|
||||
subjects: ['Connection', 'Execution', 'Flow'],
|
||||
},
|
||||
{
|
||||
key: 'update',
|
||||
label: 'Update',
|
||||
key: 'manage',
|
||||
label: 'Manage',
|
||||
subjects: ['Connection', 'Flow'],
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: 'Delete',
|
||||
subjects: ['Connection', 'Flow'],
|
||||
},
|
||||
{
|
||||
key: 'publish',
|
||||
label: 'Publish',
|
||||
subjects: ['Flow'],
|
||||
},
|
||||
],
|
||||
conditions: [
|
||||
{
|
||||
|
||||
@@ -14,98 +14,22 @@ export class AdminCreateRolePage extends AuthenticatedPage {
|
||||
this.nameInput = page.getByTestId('name-input');
|
||||
this.descriptionInput = page.getByTestId('description-input');
|
||||
this.createButton = page.getByTestId('create-button');
|
||||
this.connectionRow = page.getByTestId('Connection-permission-row');
|
||||
this.executionRow = page.getByTestId('Execution-permission-row');
|
||||
this.flowRow = page.getByTestId('Flow-permission-row');
|
||||
this.pageTitle = page.getByTestId('create-role-title');
|
||||
this.permissionsCatalog = page.getByTestId('permissions-catalog');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {('Connection'|'Execution'|'Flow')} subject
|
||||
*/
|
||||
getRoleConditionsModal(subject) {
|
||||
return new RoleConditionsModal(this.page, subject);
|
||||
}
|
||||
|
||||
async getPermissionConfigs() {
|
||||
const subjects = ['Connection', 'Flow', 'Execution'];
|
||||
const permissionConfigs = [];
|
||||
for (let subject of subjects) {
|
||||
const row = this.getSubjectRow(subject);
|
||||
const actionInputs = await this.getRowInputs(row);
|
||||
Object.keys(actionInputs).forEach((action) => {
|
||||
permissionConfigs.push({
|
||||
action,
|
||||
locator: actionInputs[action],
|
||||
subject,
|
||||
row,
|
||||
});
|
||||
});
|
||||
}
|
||||
return permissionConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {(
|
||||
* 'Connection' | 'Flow' | 'Execution'
|
||||
* )} subject
|
||||
*/
|
||||
getSubjectRow(subject) {
|
||||
const k = `${subject.toLowerCase()}Row`;
|
||||
if (this[k]) {
|
||||
return this[k];
|
||||
} else {
|
||||
throw 'Unknown row';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('@playwright/test').Locator} row
|
||||
*/
|
||||
async getRowInputs(row) {
|
||||
const inputs = {
|
||||
// settingsButton: row.getByTestId('permission-settings-button')
|
||||
};
|
||||
for (let input of ['create', 'read', 'update', 'delete', 'publish']) {
|
||||
const testId = `${input}-checkbox`;
|
||||
if ((await row.getByTestId(testId).count()) > 0) {
|
||||
inputs[input] = row.getByTestId(testId).locator('input');
|
||||
}
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('@playwright/test').Locator} row
|
||||
*/
|
||||
async clickPermissionSettings(row) {
|
||||
await row.getByTestId('permission-settings-button').click();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} subject
|
||||
* @param {'create'|'read'|'update'|'delete'|'publish'} action
|
||||
* @param {boolean} val
|
||||
*/
|
||||
async updateAction(subject, action, val) {
|
||||
const row = await this.getSubjectRow(subject);
|
||||
const inputs = await this.getRowInputs(row);
|
||||
if (inputs[action]) {
|
||||
if (await inputs[action].isChecked()) {
|
||||
if (!val) {
|
||||
await inputs[action].click();
|
||||
}
|
||||
} else {
|
||||
if (val) {
|
||||
await inputs[action].click();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${subject} does not have action ${action}`);
|
||||
}
|
||||
this.connectionPermissionRow = page.getByTestId(
|
||||
'Connection-permission-row'
|
||||
);
|
||||
this.flowPermissionRow = page.getByTestId('Flow-permission-row');
|
||||
this.executionPermissionRow = page.getByTestId('Execution-permission-row');
|
||||
this.isCreatorReadCheckbox = page
|
||||
.getByTestId('isCreator-read-checkbox')
|
||||
.locator('input');
|
||||
this.readCheckbox = page.getByTestId('read-checkbox').locator('input');
|
||||
this.isCreatorManageCheckbox = page
|
||||
.getByTestId('isCreator-manage-checkbox')
|
||||
.locator('input');
|
||||
this.manageCheckbox = page.getByTestId('manage-checkbox').locator('input');
|
||||
}
|
||||
|
||||
async waitForPermissionsCatalogToVisible() {
|
||||
|
||||
@@ -1,69 +1,55 @@
|
||||
const { test, expect } = require('../../fixtures/index');
|
||||
|
||||
test(
|
||||
'Role permissions conform with role conditions ',
|
||||
async({ adminRolesPage, adminCreateRolePage }) => {
|
||||
await adminRolesPage.navigateTo();
|
||||
await adminRolesPage.createRoleButton.click();
|
||||
|
||||
/*
|
||||
example config: {
|
||||
action: 'read',
|
||||
subject: 'connection',
|
||||
row: page.getByTestId('connection-permission-row'),
|
||||
locator: row.getByTestId('read-checkbox')
|
||||
}
|
||||
*/
|
||||
const permissionConfigs =
|
||||
await adminCreateRolePage.getPermissionConfigs();
|
||||
test('Check Own permissions when All are checked', async ({
|
||||
adminRolesPage,
|
||||
adminCreateRolePage,
|
||||
}) => {
|
||||
await adminRolesPage.navigateTo();
|
||||
await adminRolesPage.createRoleButton.click();
|
||||
await adminCreateRolePage.waitForPermissionsCatalogToVisible();
|
||||
|
||||
await test.step(
|
||||
'Iterate over each permission config and make sure role conditions conform',
|
||||
async () => {
|
||||
for (let config of permissionConfigs) {
|
||||
await config.locator.click();
|
||||
await adminCreateRolePage.clickPermissionSettings(config.row);
|
||||
const modal = adminCreateRolePage.getRoleConditionsModal(
|
||||
config.subject
|
||||
);
|
||||
await expect(modal.modal).toBeVisible();
|
||||
const conditions = await modal.getAvailableConditions();
|
||||
for (let conditionAction of Object.keys(conditions)) {
|
||||
if (conditionAction === config.action) {
|
||||
await expect(conditions[conditionAction]).not.toBeDisabled();
|
||||
} else {
|
||||
await expect(conditions[conditionAction]).toBeDisabled();
|
||||
}
|
||||
}
|
||||
await modal.close();
|
||||
await config.locator.click();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
await adminCreateRolePage.connectionPermissionRow
|
||||
.locator(adminCreateRolePage.readCheckbox)
|
||||
.check();
|
||||
await expect(
|
||||
adminCreateRolePage.connectionPermissionRow.locator(
|
||||
adminCreateRolePage.isCreatorReadCheckbox
|
||||
)
|
||||
).toBeChecked();
|
||||
|
||||
test(
|
||||
'Default role permissions conforms with role conditions',
|
||||
async({ adminRolesPage, adminCreateRolePage }) => {
|
||||
await adminRolesPage.navigateTo();
|
||||
await adminRolesPage.createRoleButton.click();
|
||||
await adminCreateRolePage.flowPermissionRow
|
||||
.locator(adminCreateRolePage.readCheckbox)
|
||||
.check();
|
||||
await expect(
|
||||
adminCreateRolePage.flowPermissionRow.locator(
|
||||
adminCreateRolePage.isCreatorReadCheckbox
|
||||
)
|
||||
).toBeChecked();
|
||||
|
||||
const subjects = ['Connection', 'Execution', 'Flow'];
|
||||
for (let subject of subjects) {
|
||||
const row = adminCreateRolePage.getSubjectRow(subject);
|
||||
const modal = adminCreateRolePage.getRoleConditionsModal(subject);
|
||||
await adminCreateRolePage.clickPermissionSettings(row);
|
||||
await expect(modal.modal).toBeVisible();
|
||||
const availableConditions = await modal.getAvailableConditions();
|
||||
const conditions = ['create', 'read', 'update', 'delete', 'publish'];
|
||||
for (let condition of conditions) {
|
||||
if (availableConditions[condition]) {
|
||||
await expect(availableConditions[condition]).toBeDisabled();
|
||||
}
|
||||
}
|
||||
await modal.close();
|
||||
}
|
||||
await adminCreateRolePage.executionPermissionRow
|
||||
.locator(adminCreateRolePage.readCheckbox)
|
||||
.check();
|
||||
await expect(
|
||||
adminCreateRolePage.executionPermissionRow.locator(
|
||||
adminCreateRolePage.isCreatorReadCheckbox
|
||||
)
|
||||
).toBeChecked();
|
||||
|
||||
}
|
||||
);
|
||||
await adminCreateRolePage.connectionPermissionRow
|
||||
.locator(adminCreateRolePage.manageCheckbox)
|
||||
.check();
|
||||
await expect(
|
||||
adminCreateRolePage.connectionPermissionRow.locator(
|
||||
adminCreateRolePage.isCreatorManageCheckbox
|
||||
)
|
||||
).toBeChecked();
|
||||
|
||||
await adminCreateRolePage.flowPermissionRow
|
||||
.locator(adminCreateRolePage.manageCheckbox)
|
||||
.check();
|
||||
await expect(
|
||||
adminCreateRolePage.flowPermissionRow.locator(
|
||||
adminCreateRolePage.isCreatorManageCheckbox
|
||||
)
|
||||
).toBeChecked();
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ export default (
|
||||
<Route
|
||||
path={URLS.CREATE_USER}
|
||||
element={
|
||||
<Can I="create" a="User">
|
||||
<Can I="manage" a="User">
|
||||
<CreateUser />
|
||||
</Can>
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export default (
|
||||
<Route
|
||||
path={URLS.USER_PATTERN}
|
||||
element={
|
||||
<Can I="update" a="User">
|
||||
<Can I="manage" a="User">
|
||||
<EditUser />
|
||||
</Can>
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export default (
|
||||
<Route
|
||||
path={URLS.CREATE_ROLE}
|
||||
element={
|
||||
<Can I="create" a="Role">
|
||||
<Can I="manage" a="Role">
|
||||
<CreateRole />
|
||||
</Can>
|
||||
}
|
||||
@@ -67,7 +67,7 @@ export default (
|
||||
<Route
|
||||
path={URLS.ROLE_PATTERN}
|
||||
element={
|
||||
<Can I="update" a="Role">
|
||||
<Can I="manage" a="Role">
|
||||
<EditRole />
|
||||
</Can>
|
||||
}
|
||||
@@ -76,7 +76,7 @@ export default (
|
||||
<Route
|
||||
path={URLS.USER_INTERFACE}
|
||||
element={
|
||||
<Can I="update" a="Config">
|
||||
<Can I="manage" a="Config">
|
||||
<UserInterface />
|
||||
</Can>
|
||||
}
|
||||
@@ -86,8 +86,8 @@ export default (
|
||||
path={URLS.AUTHENTICATION}
|
||||
element={
|
||||
<Can I="read" a="SamlAuthProvider">
|
||||
<Can I="update" a="SamlAuthProvider">
|
||||
<Can I="create" a="SamlAuthProvider">
|
||||
<Can I="manage" a="SamlAuthProvider">
|
||||
<Can I="manage" a="SamlAuthProvider">
|
||||
<Authentication />
|
||||
</Can>
|
||||
</Can>
|
||||
@@ -98,7 +98,7 @@ export default (
|
||||
<Route
|
||||
path={URLS.ADMIN_APPS}
|
||||
element={
|
||||
<Can I="update" a="App">
|
||||
<Can I="manage" a="App">
|
||||
<AdminApplications />
|
||||
</Can>
|
||||
}
|
||||
@@ -107,7 +107,7 @@ export default (
|
||||
<Route
|
||||
path={`${URLS.ADMIN_APP_PATTERN}/*`}
|
||||
element={
|
||||
<Can I="update" a="App">
|
||||
<Can I="manage" a="App">
|
||||
<AdminApplication />
|
||||
</Can>
|
||||
}
|
||||
@@ -116,7 +116,7 @@ export default (
|
||||
<Route
|
||||
path={`${URLS.ADMIN_TEMPLATES}/*`}
|
||||
element={
|
||||
<Can I="update" a="Config">
|
||||
<Can I="manage" a="Config">
|
||||
<AdminTemplates />
|
||||
</Can>
|
||||
}
|
||||
@@ -125,7 +125,7 @@ export default (
|
||||
<Route
|
||||
path={`${URLS.ADMIN_CREATE_TEMPLATE_PATTERN}/*`}
|
||||
element={
|
||||
<Can I="update" a="Config">
|
||||
<Can I="manage" a="Config">
|
||||
<AdminCreateTemplate />
|
||||
</Can>
|
||||
}
|
||||
@@ -134,7 +134,7 @@ export default (
|
||||
<Route
|
||||
path={`${URLS.ADMIN_UPDATE_TEMPLATE_PATTERN}/*`}
|
||||
element={
|
||||
<Can I="update" a="Config">
|
||||
<Can I="manage" a="Config">
|
||||
<AdminUpdateTemplate />
|
||||
</Can>
|
||||
}
|
||||
|
||||
@@ -93,15 +93,15 @@ function SettingsLayout() {
|
||||
const closeDrawer = () => setDrawerOpen(false);
|
||||
|
||||
const drawerLinks = createDrawerLinks({
|
||||
canCreateFlows: currentUserAbility.can('create', 'Flow'),
|
||||
canCreateFlows: currentUserAbility.can('manage', 'Flow'),
|
||||
canReadUser: currentUserAbility.can('read', 'User'),
|
||||
canReadRole: currentUserAbility.can('read', 'Role'),
|
||||
canUpdateConfig: currentUserAbility.can('update', 'Config'),
|
||||
canManageSamlAuthProvider:
|
||||
currentUserAbility.can('read', 'SamlAuthProvider') &&
|
||||
currentUserAbility.can('update', 'SamlAuthProvider') &&
|
||||
currentUserAbility.can('create', 'SamlAuthProvider'),
|
||||
canUpdateApp: currentUserAbility.can('update', 'App'),
|
||||
canUpdateConfig: currentUserAbility.can('manage', 'Config'),
|
||||
canManageSamlAuthProvider: currentUserAbility.can(
|
||||
'manage',
|
||||
'SamlAuthProvider',
|
||||
),
|
||||
canUpdateApp: currentUserAbility.can('manage', 'App'),
|
||||
});
|
||||
|
||||
const drawerBottomLinks = [
|
||||
|
||||
@@ -41,7 +41,7 @@ function AdminTemplateContextMenu(props) {
|
||||
hideBackdrop={false}
|
||||
anchorEl={anchorEl}
|
||||
>
|
||||
<Can I="delete" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem disabled={!allowed} onClick={onTemplateDelete}>
|
||||
{formatMessage('adminTemplateContextMenu.delete')}
|
||||
|
||||
@@ -51,7 +51,7 @@ function ContextMenu(props) {
|
||||
)}
|
||||
</Can>
|
||||
|
||||
<Can I="update" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem
|
||||
onClick={createActionHandler({ type: 'test' })}
|
||||
@@ -62,7 +62,7 @@ function ContextMenu(props) {
|
||||
)}
|
||||
</Can>
|
||||
|
||||
<Can I="create" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem
|
||||
component={Link}
|
||||
@@ -79,7 +79,7 @@ function ContextMenu(props) {
|
||||
)}
|
||||
</Can>
|
||||
|
||||
<Can I="delete" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem
|
||||
onClick={createActionHandler({ type: 'delete' })}
|
||||
|
||||
@@ -20,7 +20,7 @@ function AppConnections(props) {
|
||||
|
||||
if (!hasConnections) {
|
||||
return (
|
||||
<Can I="create" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<NoResultFound
|
||||
text={formatMessage('app.noConnections')}
|
||||
|
||||
@@ -37,7 +37,7 @@ function AppFlows(props) {
|
||||
|
||||
if (!hasFlows) {
|
||||
return (
|
||||
<Can I="create" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<NoResultFound
|
||||
text={formatMessage('app.noFlows')}
|
||||
|
||||
@@ -53,7 +53,7 @@ function DeleteRoleButton(props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Can I="delete" a="Role" passThrough>
|
||||
<Can I="manage" a="Role" passThrough>
|
||||
{(allowed) => (
|
||||
<IconButton
|
||||
disabled={!allowed || disabled}
|
||||
|
||||
@@ -126,7 +126,7 @@ export default function EditorLayout() {
|
||||
)}
|
||||
</Can>
|
||||
|
||||
<Can I="publish" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<Button
|
||||
disabled={!allowed || !flow}
|
||||
|
||||
@@ -130,7 +130,7 @@ function ContextMenu(props) {
|
||||
)}
|
||||
</Can>
|
||||
|
||||
<Can I="create" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem disabled={!allowed} onClick={onFlowDuplicate}>
|
||||
{formatMessage('flow.duplicate')}
|
||||
@@ -139,7 +139,7 @@ function ContextMenu(props) {
|
||||
</Can>
|
||||
|
||||
{isCurrentUserAdmin && (
|
||||
<Can I="create" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem disabled={!allowed} onClick={onCreateTemplate}>
|
||||
{formatMessage('flow.createTemplateFromFlow')}
|
||||
@@ -148,7 +148,7 @@ function ContextMenu(props) {
|
||||
</Can>
|
||||
)}
|
||||
|
||||
<Can I="update" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem disabled={!allowed} onClick={onFlowFolderUpdate}>
|
||||
{formatMessage('flow.moveTo')}
|
||||
@@ -164,7 +164,7 @@ function ContextMenu(props) {
|
||||
)}
|
||||
</Can>
|
||||
|
||||
<Can I="delete" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<MenuItem disabled={!allowed} onClick={onFlowDelete}>
|
||||
{formatMessage('flow.delete')}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function FlowsButtons() {
|
||||
const theme = useTheme();
|
||||
const { data: config } = useAutomatischConfig();
|
||||
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const canCreateFlow = currentUserAbility.can('create', 'Flow');
|
||||
const canCreateFlow = currentUserAbility.can('manage', 'Flow');
|
||||
const enableTemplates = config?.data.enableTemplates === true;
|
||||
|
||||
const createFlowButtonData = {
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import PropTypes from 'prop-types';
|
||||
import ControlledCheckbox from 'components/ControlledCheckbox';
|
||||
|
||||
const ActionField = ({ action, subject, disabled, name, syncIsCreator }) => {
|
||||
const { formState, resetField } = useFormContext();
|
||||
|
||||
const actionDefaultValue =
|
||||
formState.defaultValues?.[name]?.[subject.key]?.[action.key].value;
|
||||
const conditionFieldName = `${name}.${subject.key}.${action.key}.conditions.isCreator`;
|
||||
const conditionFieldTouched =
|
||||
formState.touchedFields?.[name]?.[subject.key]?.[action.key]?.conditions
|
||||
?.isCreator === true;
|
||||
|
||||
const handleSyncIsCreator = (newValue) => {
|
||||
if (
|
||||
syncIsCreator &&
|
||||
actionDefaultValue === false &&
|
||||
!conditionFieldTouched
|
||||
) {
|
||||
resetField(conditionFieldName, { defaultValue: newValue });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ControlledCheckbox
|
||||
disabled={disabled}
|
||||
name={`${name}.${subject.key}.${action.key}.value`}
|
||||
dataTest={`${action.key.toLowerCase()}-checkbox`}
|
||||
onChange={(e, value) => {
|
||||
handleSyncIsCreator(value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
ActionField.propTypes = {
|
||||
action: PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
subjects: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
}),
|
||||
subject: PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
name: PropTypes.string.isRequired,
|
||||
syncIsCreator: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default ActionField;
|
||||
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import PropTypes from 'prop-types';
|
||||
import ControlledCheckbox from 'components/ControlledCheckbox';
|
||||
|
||||
const AllEntitiesPermissions = ({
|
||||
action,
|
||||
subject,
|
||||
disabled,
|
||||
name,
|
||||
syncIsCreator,
|
||||
}) => {
|
||||
const { getValues, formState, resetField } = useFormContext();
|
||||
|
||||
const fieldName = `${name}.${subject.key}.${action.key}.allEntities`;
|
||||
const defaultValue =
|
||||
formState.defaultValues?.[name]?.[subject.key]?.[action.key].allEntities;
|
||||
const ownEntitiesFieldName = `${name}.${subject.key}.${action.key}.ownEntities`;
|
||||
const ownEntitiesFieldTouched =
|
||||
formState.touchedFields?.[name]?.[subject.key]?.[action.key]
|
||||
?.ownEntities === true;
|
||||
|
||||
const currentValue = getValues(fieldName);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (currentValue === true) {
|
||||
resetField(ownEntitiesFieldName, { defaultValue: true });
|
||||
}
|
||||
}, [ownEntitiesFieldName, currentValue]);
|
||||
|
||||
const handleSyncIsCreator = (newValue) => {
|
||||
if (syncIsCreator && defaultValue === false && !ownEntitiesFieldTouched) {
|
||||
resetField(ownEntitiesFieldName, { defaultValue: newValue });
|
||||
}
|
||||
|
||||
if (newValue === true) {
|
||||
resetField(ownEntitiesFieldName, { defaultValue: true });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ControlledCheckbox
|
||||
disabled={disabled}
|
||||
name={fieldName}
|
||||
dataTest={`${action.key.toLowerCase()}-checkbox`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
AllEntitiesPermissions.propTypes = {
|
||||
action: PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
subjects: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
}),
|
||||
subject: PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
name: PropTypes.string.isRequired,
|
||||
syncIsCreator: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default AllEntitiesPermissions;
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import PropTypes from 'prop-types';
|
||||
import ControlledCheckbox from 'components/ControlledCheckbox';
|
||||
|
||||
const OwnEntitiesPermission = ({ action, subject, disabled, name }) => {
|
||||
const { getValues, resetField } = useFormContext();
|
||||
|
||||
const fieldName = `${name}.${subject.key}.${action.key}.ownEntities`;
|
||||
const allEntitiesFieldName = `${name}.${subject.key}.${action.key}.allEntities`;
|
||||
|
||||
const currentValue = getValues(fieldName);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (currentValue === false) {
|
||||
resetField(allEntitiesFieldName, { defaultValue: false });
|
||||
}
|
||||
}, [allEntitiesFieldName, currentValue]);
|
||||
|
||||
return (
|
||||
<ControlledCheckbox
|
||||
name={fieldName}
|
||||
disabled={disabled}
|
||||
dataTest={`isCreator-${action.key.toLowerCase()}-checkbox`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
OwnEntitiesPermission.propTypes = {
|
||||
action: PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
subjects: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
}),
|
||||
subject: PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
name: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default OwnEntitiesPermission;
|
||||
@@ -1,7 +1,5 @@
|
||||
import {
|
||||
IconButton,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
@@ -10,7 +8,6 @@ import {
|
||||
TableRow,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
|
||||
import ControlledCheckbox from 'components/ControlledCheckbox';
|
||||
|
||||
@@ -21,7 +18,7 @@ const PermissionCatalogFieldLoader = () => {
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell component="th" />
|
||||
{[...Array(5)].map((row, index) => (
|
||||
{[...Array(4)].map((row, index) => (
|
||||
<TableCell key={index} component="th">
|
||||
<Skeleton />
|
||||
</TableCell>
|
||||
@@ -30,27 +27,26 @@ const PermissionCatalogFieldLoader = () => {
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{[...Array(3)].map((row, index) => (
|
||||
<TableRow key={index} sx={{ '&:last-child td': { border: 0 } }}>
|
||||
{[...Array(3)].map((row, subjectIndex) => (
|
||||
<TableRow
|
||||
key={subjectIndex}
|
||||
sx={{ '&:last-child td': { border: 0 } }}
|
||||
>
|
||||
<TableCell scope="row">
|
||||
<Skeleton width={40} />
|
||||
</TableCell>
|
||||
|
||||
{[...Array(5)].map((action, index) => (
|
||||
<TableCell key={index} align="center">
|
||||
<Typography variant="subtitle2">
|
||||
<ControlledCheckbox name="value" disabled />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
<TableCell>
|
||||
<Stack direction="row" gap={1} justifyContent="right">
|
||||
<IconButton color="info" size="small" disabled>
|
||||
<SettingsIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
{[...Array(4)].map(
|
||||
(action, actionIndex) =>
|
||||
(subjectIndex !== 2 ||
|
||||
(actionIndex !== 3 && actionIndex !== 2)) && (
|
||||
<TableCell key={actionIndex} align="center">
|
||||
<Typography variant="subtitle2">
|
||||
<ControlledCheckbox name="value" disabled />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
),
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableBody from '@mui/material/TableBody';
|
||||
import TableCell from '@mui/material/TableCell';
|
||||
@@ -10,12 +6,14 @@ import TableContainer from '@mui/material/TableContainer';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
import usePermissionCatalog from 'hooks/usePermissionCatalog.ee';
|
||||
import PermissionSettings from './PermissionSettings.ee';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import AllEntitiesPermissions from './AllEntitiesPermissions';
|
||||
import ConditionField from './OwnEntitiesPermission';
|
||||
import PermissionCatalogFieldLoader from './PermissionCatalogFieldLoader';
|
||||
import ActionField from './ActionField';
|
||||
|
||||
const PermissionCatalogField = ({
|
||||
name = 'permissions',
|
||||
@@ -23,10 +21,10 @@ const PermissionCatalogField = ({
|
||||
syncIsCreator = false,
|
||||
loading = false,
|
||||
}) => {
|
||||
const formatMessage = useFormatMessage();
|
||||
const { data, isLoading: isPermissionCatalogLoading } =
|
||||
usePermissionCatalog();
|
||||
const permissionCatalog = data?.data;
|
||||
const [dialogName, setDialogName] = React.useState();
|
||||
|
||||
if (isPermissionCatalogLoading || loading)
|
||||
return <PermissionCatalogFieldLoader />;
|
||||
@@ -39,24 +37,44 @@ const PermissionCatalogField = ({
|
||||
<TableCell component="th" />
|
||||
|
||||
{permissionCatalog?.actions.map((action) => (
|
||||
<TableCell component="th" key={action.key}>
|
||||
<Typography
|
||||
component="div"
|
||||
variant="subtitle1"
|
||||
align="center"
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{action.label}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
))}
|
||||
<React.Fragment key={action.key}>
|
||||
<TableCell component="th" key={action.key}>
|
||||
<Typography
|
||||
component="div"
|
||||
variant="subtitle2"
|
||||
align="center"
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{action.label}{' '}
|
||||
{formatMessage('permissionCatalogField.ownEntitiesLabel')}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell component="th" />
|
||||
<TableCell
|
||||
component="th"
|
||||
key={`${action.key}-isCreator-condition`}
|
||||
>
|
||||
<Typography
|
||||
component="div"
|
||||
variant="subtitle2"
|
||||
align="center"
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{action.label}{' '}
|
||||
{formatMessage('permissionCatalogField.allEntitiesLabel')}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<TableBody>
|
||||
{permissionCatalog?.subjects.map((subject) => (
|
||||
<TableRow
|
||||
@@ -71,44 +89,43 @@ const PermissionCatalogField = ({
|
||||
</TableCell>
|
||||
|
||||
{permissionCatalog?.actions.map((action) => (
|
||||
<TableCell key={`${subject.key}.${action.key}`} align="center">
|
||||
<Typography variant="subtitle2" component="div">
|
||||
{action.subjects.includes(subject.key) && (
|
||||
<ActionField
|
||||
action={action}
|
||||
subject={subject}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
syncIsCreator={syncIsCreator}
|
||||
/>
|
||||
)}
|
||||
{!action.subjects.includes(subject.key) && '-'}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
<TableCell>
|
||||
<Stack direction="row" gap={1} justifyContent="right">
|
||||
<IconButton
|
||||
color="info"
|
||||
size="small"
|
||||
onClick={() => setDialogName(subject.key)}
|
||||
disabled={disabled}
|
||||
data-test="permission-settings-button"
|
||||
<React.Fragment key={`${subject.key}.${action.key}`}>
|
||||
<TableCell
|
||||
key={`${subject.key}.${action.key}-isCreator-condition`}
|
||||
align="center"
|
||||
>
|
||||
<SettingsIcon />
|
||||
</IconButton>
|
||||
<Typography variant="subtitle2" component="div">
|
||||
{action.subjects.includes(subject.key) && (
|
||||
<ConditionField
|
||||
action={action}
|
||||
subject={subject}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
/>
|
||||
)}
|
||||
{!action.subjects.includes(subject.key) && '-'}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<PermissionSettings
|
||||
open={dialogName === subject.key}
|
||||
onClose={() => setDialogName('')}
|
||||
fieldPrefix={`${name}.${subject.key}`}
|
||||
subject={subject.key}
|
||||
actions={permissionCatalog?.actions}
|
||||
conditions={permissionCatalog?.conditions}
|
||||
/>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
key={`${subject.key}.${action.key}`}
|
||||
align="center"
|
||||
>
|
||||
<Typography variant="subtitle2" component="div">
|
||||
{action.subjects.includes(subject.key) && (
|
||||
<AllEntitiesPermissions
|
||||
action={action}
|
||||
subject={subject}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
syncIsCreator={syncIsCreator}
|
||||
/>
|
||||
)}
|
||||
{!action.subjects.includes(subject.key) && '-'}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
@@ -116,6 +133,7 @@ const PermissionCatalogField = ({
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
|
||||
PermissionCatalogField.propTypes = {
|
||||
name: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
|
||||
@@ -6,10 +6,8 @@ export function getRoleWithComputedPermissions(role) {
|
||||
[permission.subject]: {
|
||||
...(computedPermissions[permission.subject] || {}),
|
||||
[permission.action]: {
|
||||
conditions: Object.fromEntries(
|
||||
permission.conditions.map((condition) => [condition, true]),
|
||||
),
|
||||
value: true,
|
||||
allEntities: permission.conditions.includes('isCreator') === false,
|
||||
ownEntities: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -28,15 +26,19 @@ export function getPermissions(computedPermissions) {
|
||||
(permissions, computedPermissionEntry) => {
|
||||
const [subject, actionsWithConditions] = computedPermissionEntry;
|
||||
for (const action in actionsWithConditions) {
|
||||
const { value: permitted, conditions = {} } =
|
||||
actionsWithConditions[action];
|
||||
if (permitted) {
|
||||
const { ownEntities, allEntities } = actionsWithConditions[action];
|
||||
|
||||
if (ownEntities && !allEntities) {
|
||||
permissions.push({
|
||||
action,
|
||||
subject,
|
||||
conditions: Object.entries(conditions)
|
||||
.filter(([, enabled]) => enabled)
|
||||
.map(([condition]) => condition),
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
} else if (ownEntities && allEntities) {
|
||||
permissions.push({
|
||||
action,
|
||||
subject,
|
||||
conditions: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -46,18 +48,9 @@ export function getPermissions(computedPermissions) {
|
||||
);
|
||||
}
|
||||
|
||||
export const getComputedPermissionsDefaultValues = (
|
||||
data,
|
||||
conditionsInitialValues,
|
||||
) => {
|
||||
export const getComputedPermissionsDefaultValues = (data) => {
|
||||
if (!data) return {};
|
||||
|
||||
const conditions = {};
|
||||
data.conditions.forEach((condition) => {
|
||||
conditions[condition.key] =
|
||||
conditionsInitialValues?.[condition.key] || false;
|
||||
});
|
||||
|
||||
const result = {};
|
||||
|
||||
data.subjects.forEach((subject) => {
|
||||
@@ -69,8 +62,8 @@ export const getComputedPermissionsDefaultValues = (
|
||||
|
||||
if (action.subjects.includes(subjectKey)) {
|
||||
result[subjectKey][actionKey] = {
|
||||
value: false,
|
||||
conditions: { ...conditions },
|
||||
ownEntities: false,
|
||||
allEntities: false,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -403,5 +403,7 @@
|
||||
"executionFilters.statusFilterSuccessfulOption": "Successful",
|
||||
"executionFilters.statusFilterFailedOption": "Failed",
|
||||
"executionFilters.startDateLabel": "Start Date",
|
||||
"executionFilters.endDateLabel": "End Date"
|
||||
"executionFilters.endDateLabel": "End Date",
|
||||
"permissionCatalogField.ownEntitiesLabel": "(own entities)",
|
||||
"permissionCatalogField.allEntitiesLabel": "(all entities)"
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function Application() {
|
||||
'data-test': 'add-connection-button',
|
||||
to: URLS.APP_ADD_CONNECTION(appKey, false),
|
||||
disabled:
|
||||
!currentUserAbility.can('create', 'Connection') ||
|
||||
!currentUserAbility.can('manage', 'Connection') ||
|
||||
appConfig?.data?.useOnlyPredefinedAuthClients === true ||
|
||||
appConfig?.data?.disabled === true,
|
||||
};
|
||||
@@ -92,7 +92,7 @@ export default function Application() {
|
||||
'data-test': 'add-connection-with-auth-client-button',
|
||||
to: URLS.APP_ADD_CONNECTION(appKey, true),
|
||||
disabled:
|
||||
!currentUserAbility.can('create', 'Connection') ||
|
||||
!currentUserAbility.can('manage', 'Connection') ||
|
||||
appOAuthClients?.data?.length === 0 ||
|
||||
appConfig?.data?.disabled === true,
|
||||
};
|
||||
@@ -139,7 +139,7 @@ export default function Application() {
|
||||
<Route
|
||||
path={`${URLS.FLOWS}/*`}
|
||||
element={
|
||||
<Can I="create" a="Flow" passThrough>
|
||||
<Can I="manage" a="Flow" passThrough>
|
||||
{(allowed) => (
|
||||
<ConditionalIconButton
|
||||
type="submit"
|
||||
@@ -162,7 +162,7 @@ export default function Application() {
|
||||
<Route
|
||||
path={`${URLS.CONNECTIONS}/*`}
|
||||
element={
|
||||
<Can I="create" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<SplitButton
|
||||
disabled={!allowed}
|
||||
@@ -248,7 +248,7 @@ export default function Application() {
|
||||
<Route
|
||||
path="/connections/add"
|
||||
element={
|
||||
<Can I="create" a="Connection">
|
||||
<Can I="manage" a="Connection">
|
||||
<AddAppConnection
|
||||
onClose={goToApplicationPage}
|
||||
application={app}
|
||||
@@ -260,7 +260,7 @@ export default function Application() {
|
||||
<Route
|
||||
path="/connections/:connectionId/reconnect"
|
||||
element={
|
||||
<Can I="create" a="Connection">
|
||||
<Can I="manage" a="Connection">
|
||||
<ReconnectConnection
|
||||
application={app}
|
||||
onClose={goToApplicationPage}
|
||||
|
||||
@@ -53,7 +53,7 @@ export default function Applications() {
|
||||
alignItems="center"
|
||||
order={{ xs: 1, sm: 2 }}
|
||||
>
|
||||
<Can I="create" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<ConditionalIconButton
|
||||
type="submit"
|
||||
@@ -84,7 +84,7 @@ export default function Applications() {
|
||||
)}
|
||||
|
||||
{!isLoading && !hasApps && (
|
||||
<Can I="create" a="Connection" passThrough>
|
||||
<Can I="manage" a="Connection" passThrough>
|
||||
{(allowed) => (
|
||||
<NoResultFound
|
||||
text={formatMessage('apps.noConnections')}
|
||||
|
||||
@@ -73,9 +73,6 @@ export default function CreateRole() {
|
||||
description: '',
|
||||
computedPermissions: getComputedPermissionsDefaultValues(
|
||||
permissionCatalogData?.data,
|
||||
{
|
||||
isCreator: true,
|
||||
},
|
||||
),
|
||||
}),
|
||||
[permissionCatalogData],
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function CreateUser() {
|
||||
const roles = rolesData?.data;
|
||||
const queryClient = useQueryClient();
|
||||
const currentUserAbility = useCurrentUserAbility();
|
||||
const canUpdateRole = currentUserAbility.can('update', 'Role');
|
||||
const canUpdateRole = currentUserAbility.can('manage', 'Role');
|
||||
|
||||
const handleUserCreation = async (userData) => {
|
||||
try {
|
||||
@@ -125,7 +125,7 @@ export default function CreateUser() {
|
||||
helperText={errors?.email?.message}
|
||||
/>
|
||||
|
||||
<Can I="update" a="Role">
|
||||
<Can I="manage" a="Role">
|
||||
<ControlledAutocomplete
|
||||
name="roleId"
|
||||
fullWidth
|
||||
|
||||
@@ -78,6 +78,7 @@ export default function EditRole() {
|
||||
try {
|
||||
setPermissionError(null);
|
||||
const newPermissions = getPermissions(roleData.computedPermissions);
|
||||
|
||||
await updateRole({
|
||||
name: roleData.name,
|
||||
description: roleData.description,
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function EditUser() {
|
||||
const enqueueSnackbar = useEnqueueSnackbar();
|
||||
const navigate = useNavigate();
|
||||
const currentUserAbility = useCurrentUserAbility();
|
||||
const canUpdateRole = currentUserAbility.can('update', 'Role');
|
||||
const canUpdateRole = currentUserAbility.can('manage', 'Role');
|
||||
|
||||
const handleUserUpdate = async (userDataToUpdate) => {
|
||||
try {
|
||||
@@ -169,7 +169,7 @@ export default function EditUser() {
|
||||
helperText={errors?.email?.message}
|
||||
/>
|
||||
|
||||
<Can I="update" a="Role">
|
||||
<Can I="manage" a="Role">
|
||||
<ControlledAutocomplete
|
||||
name="roleId"
|
||||
fullWidth
|
||||
|
||||
@@ -168,7 +168,7 @@ export default function Flows() {
|
||||
{!isLoading && !navigateToLastPage && !hasFlows && (
|
||||
<NoResultFound
|
||||
text={formatMessage('flows.noFlows')}
|
||||
{...(currentUserAbility.can('create', 'Flow') && {
|
||||
{...(currentUserAbility.can('manage', 'Flow') && {
|
||||
to: URLS.CREATE_FLOW,
|
||||
})}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user