mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(core): Allow custom project roles from being set to a user project relation (#18926)
This commit is contained in:
committed by
GitHub
parent
5b5f60212a
commit
027edbe89d
@@ -16,6 +16,7 @@ describe('InviteUsersRequestDto', () => {
|
||||
request: [
|
||||
{ email: 'user1@example.com', role: 'global:member' },
|
||||
{ email: 'user2@example.com', role: 'global:admin' },
|
||||
{ email: 'user3@example.com', role: 'custom:role' },
|
||||
],
|
||||
},
|
||||
])('should validate $name', ({ request }) => {
|
||||
@@ -42,7 +43,7 @@ describe('InviteUsersRequestDto', () => {
|
||||
request: [
|
||||
{
|
||||
email: 'user@example.com',
|
||||
role: 'invalid-role',
|
||||
role: 'global:owner',
|
||||
},
|
||||
],
|
||||
expectedErrorPath: [0, 'role'],
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { assignableGlobalRoleSchema } from '@n8n/permissions';
|
||||
import { z } from 'zod';
|
||||
|
||||
const roleSchema = z.enum(['global:member', 'global:admin']);
|
||||
|
||||
const invitedUserSchema = z.object({
|
||||
email: z.string().email(),
|
||||
role: roleSchema.default('global:member'),
|
||||
role: assignableGlobalRoleSchema.default('global:member'),
|
||||
});
|
||||
|
||||
const invitationsSchema = z.array(invitedUserSchema);
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('AddUsersToProjectDto', () => {
|
||||
relations: [
|
||||
{
|
||||
userId: 'user-123',
|
||||
role: 'invalid-role',
|
||||
role: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -31,13 +31,6 @@ describe('ChangeUserRoleInProject', () => {
|
||||
},
|
||||
expectedErrorPath: ['role'],
|
||||
},
|
||||
{
|
||||
name: 'invalid role value',
|
||||
request: {
|
||||
role: 'invalid-role',
|
||||
},
|
||||
expectedErrorPath: ['role'],
|
||||
},
|
||||
{
|
||||
name: 'personal owner role',
|
||||
request: { role: PROJECT_OWNER_ROLE_SLUG },
|
||||
|
||||
@@ -120,7 +120,7 @@ describe('UpdateProjectDto', () => {
|
||||
relations: [
|
||||
{
|
||||
userId: 'user-123',
|
||||
role: 'invalid-role',
|
||||
role: 'project:personalOwner',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { teamRoleSchema } from '@n8n/permissions';
|
||||
import { assignableProjectRoleSchema } from '@n8n/permissions';
|
||||
import { Z } from 'zod-class';
|
||||
|
||||
export class ChangeUserRoleInProject extends Z.class({
|
||||
role: teamRoleSchema,
|
||||
role: assignableProjectRoleSchema,
|
||||
}) {}
|
||||
|
||||
@@ -11,27 +11,28 @@ describe('RoleChangeRequestDto', () => {
|
||||
expect(result.error?.issues[0].message).toBe('New role is required');
|
||||
});
|
||||
|
||||
it('should fail validation with invalid newRoleName', () => {
|
||||
it('should fail validation with invalid newRoleName global:owner', () => {
|
||||
const data = {
|
||||
newRoleName: 'invalidRole',
|
||||
newRoleName: 'global:owner',
|
||||
};
|
||||
|
||||
const result = RoleChangeRequestDto.safeParse(data);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error?.issues[0].path[0]).toBe('newRoleName');
|
||||
expect(result.error?.issues[0].message).toBe(
|
||||
"Invalid enum value. Expected 'global:admin' | 'global:member', received 'invalidRole'",
|
||||
);
|
||||
expect(result.error?.issues[0].message).toBe('This global role value is not assignable');
|
||||
});
|
||||
|
||||
it('should pass validation with valid data', () => {
|
||||
const data = {
|
||||
newRoleName: 'global:admin',
|
||||
};
|
||||
it.each<string>(['global:admin', 'custom:role'])(
|
||||
'should pass validation with valid newRoleName %s',
|
||||
(role) => {
|
||||
const data = {
|
||||
newRoleName: role,
|
||||
};
|
||||
|
||||
const result = RoleChangeRequestDto.safeParse(data);
|
||||
const result = RoleChangeRequestDto.safeParse(data);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
import { assignableGlobalRoleSchema } from '@n8n/permissions';
|
||||
import { Z } from 'zod-class';
|
||||
|
||||
export class RoleChangeRequestDto extends Z.class({
|
||||
newRoleName: z.enum(['global:admin', 'global:member'], {
|
||||
required_error: 'New role is required',
|
||||
}),
|
||||
newRoleName: assignableGlobalRoleSchema
|
||||
// enforce required (non-nullable, non-optional) with custom error message on undefined
|
||||
.nullish()
|
||||
.refine((val): val is NonNullable<typeof val> => val !== null && typeof val !== 'undefined', {
|
||||
message: 'New role is required',
|
||||
}),
|
||||
}) {}
|
||||
|
||||
@@ -82,7 +82,7 @@ describe('project.schema', () => {
|
||||
},
|
||||
{
|
||||
name: 'invalid role',
|
||||
value: { userId: 'user-123', role: 'invalid-role' },
|
||||
value: { userId: 'user-123', role: 'project:personalOwner' },
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { teamRoleSchema } from '@n8n/permissions';
|
||||
import { assignableProjectRoleSchema } from '@n8n/permissions';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const projectNameSchema = z.string().min(1).max(255);
|
||||
@@ -16,6 +16,6 @@ export const projectDescriptionSchema = z.string().max(512);
|
||||
|
||||
export const projectRelationSchema = z.object({
|
||||
userId: z.string().min(1),
|
||||
role: teamRoleSchema,
|
||||
role: assignableProjectRoleSchema,
|
||||
});
|
||||
export type ProjectRelation = z.infer<typeof projectRelationSchema>;
|
||||
|
||||
Reference in New Issue
Block a user