-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(core): Update invitation endpoints to use DTOs (#12377)
- Loading branch information
Showing
14 changed files
with
282 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
packages/@n8n/api-types/src/dto/invitation/__tests__/accept-invitation-request.dto.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { AcceptInvitationRequestDto } from '../accept-invitation-request.dto'; | ||
|
||
describe('AcceptInvitationRequestDto', () => { | ||
const validUuid = '123e4567-e89b-12d3-a456-426614174000'; | ||
|
||
describe('Valid requests', () => { | ||
test.each([ | ||
{ | ||
name: 'complete valid invitation acceptance', | ||
request: { | ||
inviterId: validUuid, | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
password: 'SecurePassword123', | ||
}, | ||
}, | ||
])('should validate $name', ({ request }) => { | ||
const result = AcceptInvitationRequestDto.safeParse(request); | ||
expect(result.success).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('Invalid requests', () => { | ||
test.each([ | ||
{ | ||
name: 'missing inviterId', | ||
request: { | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
password: 'SecurePassword123', | ||
}, | ||
expectedErrorPath: ['inviterId'], | ||
}, | ||
{ | ||
name: 'invalid inviterId', | ||
request: { | ||
inviterId: 'not-a-valid-uuid', | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
password: 'SecurePassword123', | ||
}, | ||
expectedErrorPath: ['inviterId'], | ||
}, | ||
{ | ||
name: 'missing first name', | ||
request: { | ||
inviterId: validUuid, | ||
firstName: '', | ||
lastName: 'Doe', | ||
password: 'SecurePassword123', | ||
}, | ||
expectedErrorPath: ['firstName'], | ||
}, | ||
{ | ||
name: 'missing last name', | ||
request: { | ||
inviterId: validUuid, | ||
firstName: 'John', | ||
lastName: '', | ||
password: 'SecurePassword123', | ||
}, | ||
expectedErrorPath: ['lastName'], | ||
}, | ||
{ | ||
name: 'password too short', | ||
request: { | ||
inviterId: validUuid, | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
password: 'short', | ||
}, | ||
expectedErrorPath: ['password'], | ||
}, | ||
{ | ||
name: 'password without number', | ||
request: { | ||
inviterId: validUuid, | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
password: 'NoNumberPassword', | ||
}, | ||
expectedErrorPath: ['password'], | ||
}, | ||
])('should fail validation for $name', ({ request, expectedErrorPath }) => { | ||
const result = AcceptInvitationRequestDto.safeParse(request); | ||
|
||
expect(result.success).toBe(false); | ||
|
||
if (expectedErrorPath) { | ||
expect(result.error?.issues[0].path).toEqual(expectedErrorPath); | ||
} | ||
}); | ||
}); | ||
}); |
60 changes: 60 additions & 0 deletions
60
packages/@n8n/api-types/src/dto/invitation/__tests__/invite-users-request.dto.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { InviteUsersRequestDto } from '../invite-users-request.dto'; | ||
|
||
describe('InviteUsersRequestDto', () => { | ||
describe('Valid requests', () => { | ||
test.each([ | ||
{ | ||
name: 'empty array', | ||
request: [], | ||
}, | ||
{ | ||
name: 'single user invitation with default role', | ||
request: [{ email: '[email protected]' }], | ||
}, | ||
{ | ||
name: 'multiple user invitations with different roles', | ||
request: [ | ||
{ email: '[email protected]', role: 'global:member' }, | ||
{ email: '[email protected]', role: 'global:admin' }, | ||
], | ||
}, | ||
])('should validate $name', ({ request }) => { | ||
const result = InviteUsersRequestDto.safeParse(request); | ||
expect(result.success).toBe(true); | ||
}); | ||
|
||
it('should default role to global:member', () => { | ||
const result = InviteUsersRequestDto.safeParse([{ email: '[email protected]' }]); | ||
expect(result.success).toBe(true); | ||
expect(result.data?.[0].role).toBe('global:member'); | ||
}); | ||
}); | ||
|
||
describe('Invalid requests', () => { | ||
test.each([ | ||
{ | ||
name: 'invalid email', | ||
request: [{ email: 'invalid-email' }], | ||
expectedErrorPath: [0, 'email'], | ||
}, | ||
{ | ||
name: 'invalid role', | ||
request: [ | ||
{ | ||
email: '[email protected]', | ||
role: 'invalid-role', | ||
}, | ||
], | ||
expectedErrorPath: [0, 'role'], | ||
}, | ||
])('should fail validation for $name', ({ request, expectedErrorPath }) => { | ||
const result = InviteUsersRequestDto.safeParse(request); | ||
|
||
expect(result.success).toBe(false); | ||
|
||
if (expectedErrorPath) { | ||
expect(result.error?.issues[0].path).toEqual(expectedErrorPath); | ||
} | ||
}); | ||
}); | ||
}); |
11 changes: 11 additions & 0 deletions
11
packages/@n8n/api-types/src/dto/invitation/accept-invitation-request.dto.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { z } from 'zod'; | ||
import { Z } from 'zod-class'; | ||
|
||
import { passwordSchema } from '../../schemas/password.schema'; | ||
|
||
export class AcceptInvitationRequestDto extends Z.class({ | ||
inviterId: z.string().uuid(), | ||
firstName: z.string().min(1, 'First name is required'), | ||
lastName: z.string().min(1, 'Last name is required'), | ||
password: passwordSchema, | ||
}) {} |
16 changes: 16 additions & 0 deletions
16
packages/@n8n/api-types/src/dto/invitation/invite-users-request.dto.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
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'), | ||
}); | ||
|
||
const invitationsSchema = z.array(invitedUserSchema); | ||
|
||
export class InviteUsersRequestDto extends Array<z.infer<typeof invitedUserSchema>> { | ||
static safeParse(data: unknown) { | ||
return invitationsSchema.safeParse(data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
packages/@n8n/api-types/src/schemas/__tests__/paswword.schema.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { passwordSchema } from '../password.schema'; | ||
|
||
describe('passwordSchema', () => { | ||
test('should throw on empty password', () => { | ||
const check = () => passwordSchema.parse(''); | ||
|
||
expect(check).toThrowError('Password must be 8 to 64 characters long'); | ||
}); | ||
|
||
test('should return same password if valid', () => { | ||
const validPassword = 'abcd1234X'; | ||
|
||
const validated = passwordSchema.parse(validPassword); | ||
|
||
expect(validated).toBe(validPassword); | ||
}); | ||
|
||
test('should require at least one uppercase letter', () => { | ||
const invalidPassword = 'abcd1234'; | ||
|
||
const failingCheck = () => passwordSchema.parse(invalidPassword); | ||
|
||
expect(failingCheck).toThrowError('Password must contain at least 1 uppercase letter.'); | ||
}); | ||
|
||
test('should require at least one number', () => { | ||
const validPassword = 'abcd1234X'; | ||
const invalidPassword = 'abcdEFGH'; | ||
|
||
const validated = passwordSchema.parse(validPassword); | ||
|
||
expect(validated).toBe(validPassword); | ||
|
||
const check = () => passwordSchema.parse(invalidPassword); | ||
|
||
expect(check).toThrowError('Password must contain at least 1 number.'); | ||
}); | ||
|
||
test('should require a minimum length of 8 characters', () => { | ||
const invalidPassword = 'a'.repeat(7); | ||
|
||
const check = () => passwordSchema.parse(invalidPassword); | ||
|
||
expect(check).toThrowError('Password must be 8 to 64 characters long.'); | ||
}); | ||
|
||
test('should require a maximum length of 64 characters', () => { | ||
const invalidPassword = 'a'.repeat(65); | ||
|
||
const check = () => passwordSchema.parse(invalidPassword); | ||
|
||
expect(check).toThrowError('Password must be 8 to 64 characters long.'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.