diff --git a/packages/server/src/auth/__tests__/auth.controller.login.spec.ts b/packages/server/src/auth/__tests__/auth.controller.login.spec.ts deleted file mode 100644 index 18d35ed..0000000 --- a/packages/server/src/auth/__tests__/auth.controller.login.spec.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { JwtService } from '@nestjs/jwt'; -import { Project } from '@prisma/client'; -import { PrismaService } from '../../prisma/prisma.service'; -import { UserService } from '../../user/user.service'; -import { LoginController } from '../auth.controller'; -import { AuthService } from '../auth.service'; -import { EmailLoginDto, UsernameLoginDto } from '../dto/auth.dto'; -import { JwtAuthGuard } from '../jwt-auth.guard'; -import { UserTestUtil } from '../../user/__tests__/utils/user.test.util'; -import { ProjectService } from '../../project/project.service'; - -describe('LoginController', () => { - let jwtAuthGuard: JwtAuthGuard; - - beforeEach(async () => { - jwtAuthGuard = new JwtAuthGuard(); - }); - - it('should be define', () => { - expect(jwtAuthGuard).toBeDefined(); - }); -}); - -describe('LoginController', () => { - let userTestUtil: UserTestUtil; - - let dummyProjects: Project[]; - - let validProjectId: string; - const validUsername = 'test'; - const validEmail = 'test@example.com'; - const validPassword = 'pw'; - - let loginController: LoginController; - let authService: AuthService; - let userService: UserService; - let projectService: ProjectService; - let prismaService: PrismaService; - let jwtService: JwtService; - - beforeAll(async () => { - try { - userTestUtil = new UserTestUtil(); - - const moduleRef = await userTestUtil.setup(); - - prismaService = moduleRef.get(PrismaService); - jwtService = moduleRef.get(JwtService); - userService = new UserService(prismaService); - projectService = new ProjectService(prismaService); - authService = new AuthService(userService, jwtService, projectService); - loginController = new LoginController(authService); - - dummyProjects = await userTestUtil.createDummyProjects(); - validProjectId = dummyProjects[0].id; - } catch (error) { - console.log(error); - } - }); - - afterAll(async () => { - await userTestUtil.tearDown(); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - // /login/username tests - - it('/login/username valid', async () => { - const userInput: UsernameLoginDto = { - projectId: validProjectId, - username: validUsername, - password: validPassword - }; - - const result = { - accessToken: 'valid-token' - }; - - const spy = jest.spyOn(authService, 'validateUsername').mockImplementation(async () => result); - expect(await loginController.loginUsername(userInput)).toEqual(result); - - spy.mockRestore(); - }); - - it('/login/username ablate projectId', async () => { - const user: UsernameLoginDto = { - projectId: undefined, - username: validUsername, - password: validPassword - }; - - await expect(loginController.loginUsername(user)).rejects.toThrowError('Bad request'); - }); - - it('/login/username ablate password', async () => { - const user: UsernameLoginDto = { - projectId: '123', - username: 'john', - password: undefined - }; - - const loginController = new LoginController(authService); - await expect(loginController.loginUsername(user)).rejects.toThrowError('Bad request'); - }); - - it('/login/username ablate username', async () => { - const user: UsernameLoginDto = { - projectId: '12345', - username: undefined, - password: 'password' - }; - - const loginController = new LoginController(authService); - await expect(loginController.loginUsername(user)).rejects.toThrowError('Bad request'); - }); - - it('/login/username incorrect projectId', async () => { - const user: UsernameLoginDto = { - projectId: 'incorrectprojectId', - username: validUsername, - password: validPassword - }; - - await expect(loginController.loginUsername(user)).rejects.toThrowError('Unauthorized'); - }); - - it('/login/username incorrect password', async () => { - const user: UsernameLoginDto = { - projectId: validProjectId, - username: validUsername, - password: 'incorrectPassword' - }; - - await expect(loginController.loginUsername(user)).rejects.toThrowError('Unauthorized'); - }); - - it('login/username incorrect username', async () => { - const userDto = new UsernameLoginDto(); - userDto.projectId = validProjectId; - userDto.username = 'incorrectusername'; - userDto.password = validPassword; - const expectedResult = { accessToken: 'token' }; - - const spy = jest.spyOn(authService, 'validateUsername').mockImplementation(() => Promise.resolve(expectedResult)); - expect(await loginController.loginUsername(userDto)).toBe(expectedResult); - - spy.mockRestore(); - }); - - // /login/email tests - - it('/login/email valid', async () => { - const userInput: EmailLoginDto = { - projectId: validProjectId, - email: validEmail, - password: validPassword - }; - - const result = { - accessToken: 'valid-token' - }; - - const spy = jest.spyOn(authService, 'validateEmail').mockImplementation(async () => result); - expect(await loginController.loginEmail(userInput)).toEqual(result); - - spy.mockRestore(); - }); - - it('/login/email ablate projectId', async () => { - const user: EmailLoginDto = { - projectId: undefined, - email: 'test@example.com', - password: 'test' - }; - - await expect(loginController.loginEmail(user)).rejects.toThrowError('Bad request'); - }); - - it('/login/email ablate password', async () => { - const user: EmailLoginDto = { - projectId: validProjectId, - email: validEmail, - password: undefined - }; - - const loginController = new LoginController(authService); - await expect(loginController.loginEmail(user)).rejects.toThrowError('Bad request'); - }); - - it('/login/email ablate email', async () => { - const user: EmailLoginDto = { - projectId: validProjectId, - email: undefined, - password: validPassword - }; - - const loginController = new LoginController(authService); - await expect(loginController.loginEmail(user)).rejects.toThrowError('Bad request'); - }); - - it('/login/email incorrect projectId', async () => { - const user: EmailLoginDto = { - projectId: 'incorrectprojectId', - email: validEmail, - password: validPassword - }; - - await expect(loginController.loginEmail(user)).rejects.toThrowError('Unauthorized'); - }); - - it('/login/email incorrect password', async () => { - const user: EmailLoginDto = { - projectId: validProjectId, - email: validEmail, - password: 'incorrectPassword' - }; - - await expect(loginController.loginEmail(user)).rejects.toThrowError('Unauthorized'); - }); - - it('login/username incorrect email', async () => { - const userDto = new EmailLoginDto(); - userDto.projectId = validProjectId; - userDto.email = 'incorrectEmail'; - userDto.password = validPassword; - const expectedResult = { accessToken: 'token' }; - - const spy = jest.spyOn(authService, 'validateEmail').mockImplementation(() => Promise.resolve(expectedResult)); - expect(await loginController.loginEmail(userDto)).toBe(expectedResult); - - spy.mockRestore(); - }); -}); diff --git a/packages/server/src/auth/__tests__/auth.controller.recover.spec.ts b/packages/server/src/auth/__tests__/auth.controller.recover.spec.ts deleted file mode 100644 index 18e16e5..0000000 --- a/packages/server/src/auth/__tests__/auth.controller.recover.spec.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { JwtService } from '@nestjs/jwt'; -import { Project } from '@prisma/client'; -import { PrismaService } from '../../prisma/prisma.service'; -import { RecoveryController } from '../auth.controller'; -import { UserTestUtil } from '../../user/__tests__/utils/user.test.util'; -import { UserService } from '../../user/user.service'; -import { AuthService } from '../auth.service'; -import { ResetDto } from '../dto/auth.dto'; -import { ProjectService } from '../../project/project.service'; - -describe('RecoveryController', () => { - let userTestUtil: UserTestUtil; - - let dummyProjects: Project[]; - - let validProjectId: string; - let validEmail: string; - let validPassword: string; - let validResetCode: string; - - let recoveryController: RecoveryController; - let prismaService: PrismaService; - let userService: UserService; - let projectService: ProjectService; - let authService: AuthService; - let jwtService: JwtService; - - beforeAll(async () => { - userTestUtil = new UserTestUtil(); - - const moduleRef = await userTestUtil.setup(); - - prismaService = moduleRef.get(PrismaService); - jwtService = moduleRef.get(JwtService); - userService = new UserService(prismaService); - projectService = new ProjectService(prismaService); - authService = new AuthService(userService, jwtService, projectService); - recoveryController = new RecoveryController(authService); - - dummyProjects = await userTestUtil.createDummyProjects(); - - validProjectId = dummyProjects[0].id; - validEmail = 'test@gmail.com'; - validPassword = 'pw'; - validResetCode = '123456'; - }); - - afterAll(async () => { - await userTestUtil.tearDown(); - }); - - afterEach(async () => { - jest.clearAllMocks(); - }); - - // recover/forgot - - it('/recover/forgot ablate projectId', async () => { - const user = { - projectId: undefined, - email: validEmail - }; - - expect(await recoveryController.forgotPassword(user)).toBeUndefined(); - }); - - it('/recover/forgot ablate email', async () => { - const user = { - projectId: validProjectId, - email: undefined - }; - - expect(await recoveryController.forgotPassword(user)).toBeUndefined(); - }); - - it('/recover/forgot incorrect projectId', async () => { - const user = { - projectId: 'incorrectProjectId', - email: validEmail - }; - - expect(await recoveryController.forgotPassword(user)).toBeUndefined(); - }); - - // recover/reset - - it('/recover/password ablate projectId', async () => { - const user: ResetDto = { - projectId: undefined, - email: validEmail, - password: validPassword, - code: validResetCode - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Password unsuccessfully updated. Project id, email, password and reset code are all required.', - status: 400 - }); - }); - - it('/recover/password ablate email', async () => { - const user: ResetDto = { - projectId: validProjectId, - email: undefined, - password: validPassword, - code: validResetCode - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Password unsuccessfully updated. Project id, email, password and reset code are all required.', - status: 400 - }); - }); - - it('/recover/password ablate password', async () => { - const user: ResetDto = { - projectId: validProjectId, - email: validEmail, - password: undefined, - code: validResetCode - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Password unsuccessfully updated. Project id, email, password and reset code are all required.', - status: 400 - }); - }); - - it('/recover/password ablate code', async () => { - const user: ResetDto = { - projectId: validProjectId, - email: validEmail, - password: validPassword, - code: undefined - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Password unsuccessfully updated. Project id, email, password and reset code are all required.', - status: 400 - }); - }); - - it('/recover/password incorrect projectId', async () => { - const user: ResetDto = { - projectId: 'incorrectProjectId', - email: validEmail, - password: validPassword, - code: validResetCode - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Unauthorized', - status: 401 - }); - }); - - it('/recover/password incorrect email', async () => { - const user: ResetDto = { - projectId: validProjectId, - email: 'incorrectEmail', - password: validPassword, - code: validResetCode - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Unauthorized', - status: 401 - }); - }); - - it('/recover/password incorrect code', async () => { - const user: ResetDto = { - projectId: validProjectId, - email: validEmail, - password: validPassword, - code: 'incorrectCode' - }; - - expect(await recoveryController.resetPassword(user)).toEqual({ - message: 'Unauthorized', - status: 401 - }); - }); -}); diff --git a/packages/server/src/auth/__tests__/auth.controller.signup.spec.ts b/packages/server/src/auth/__tests__/auth.controller.signup.spec.ts deleted file mode 100644 index 737235f..0000000 --- a/packages/server/src/auth/__tests__/auth.controller.signup.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { JwtService } from '@nestjs/jwt'; -import { Project } from '@prisma/client'; -import { PrismaService } from '../../prisma/prisma.service'; -import { UserService } from '../../user/user.service'; -import { SignupController } from '../auth.controller'; -import { AuthService } from '../auth.service'; -import { UserSignupDto } from '../dto/auth.dto'; -import { UserTestUtil } from '../../user/__tests__/utils/user.test.util'; -import { ProjectService } from '../../project/project.service'; - -describe('SignupController', () => { - let userTestUtil: UserTestUtil; - - let dummyProjects: Project[]; - - let validProjectId: string; - let validUsername: string; - let validEmail: string; - let validPassword: string; - - let signupController: SignupController; - let authService: AuthService; - let projectService: ProjectService; - let userService: UserService; - let prismaService: PrismaService; - let jwtService: JwtService; - - beforeAll(async () => { - userTestUtil = new UserTestUtil(); - - const moduleRef = await userTestUtil.setup(); - - prismaService = moduleRef.get(PrismaService); - jwtService = moduleRef.get(JwtService); - userService = new UserService(prismaService); - projectService = new ProjectService(prismaService); - authService = new AuthService(userService, jwtService, projectService); - signupController = new SignupController(authService); - - dummyProjects = await userTestUtil.createDummyProjects(); - validProjectId = dummyProjects[0].id; - validUsername = 'test'; - validPassword = 'test@gmail.com'; - validPassword = 'pw'; - }); - - afterAll(async () => { - await userTestUtil.tearDown(); - }); - - afterEach(async () => { - jest.clearAllMocks(); - }); - - it('/signup valid', async () => { - const userInput: UserSignupDto = { - projectId: validProjectId, - username: validUsername, - email: validEmail, - password: validPassword - }; - - const result = { - accessToken: 'valid-token' - }; - - const spy = jest.spyOn(authService, 'signup').mockImplementation(async () => result); - expect(await signupController.signup(userInput)).toEqual(result); - - spy.mockRestore(); - }); -}); diff --git a/packages/server/src/auth/__tests__/auth.resolver.spec.ts b/packages/server/src/auth/__tests__/auth.resolver.spec.ts new file mode 100644 index 0000000..9148b7d --- /dev/null +++ b/packages/server/src/auth/__tests__/auth.resolver.spec.ts @@ -0,0 +1,383 @@ +import * as sinon from 'sinon'; + +import { AuthService } from '../auth.service'; +import { AuthResolver } from '../auth.resolver'; +import { UserService } from 'src/user/user.service'; +import { NotificationService } from 'src/notification/notification.service'; +import { ConfigService } from '@nestjs/config'; +import { ProjectService } from '../../project/project.service'; +import { JwtService } from '@nestjs/jwt'; +import { HttpService } from '@nestjs/axios'; + +const sandbox: sinon.Sandbox = sinon.createSandbox(); + +// Fixtures + +const PROJECT_ID = '1'; +const USER_ID = '1'; +const EMAIL = 'email@sail.codes'; +const USERNAME = 'username'; +const PASSWORD = 'password'; +const HASHED_PASSWORD = '$2a$12$CZyhclA1jHP.mi8izmC/N.HMs5vUEw5NR.AQqUj7vj/VTcxkN3dRS'; + +const MOCK_USER = { + id: USER_ID, + password: HASHED_PASSWORD +}; + +const MOCK_PROJECT = { + id: PROJECT_ID, + name: 'Test Project', + allowSignup: true +}; + +describe('Auth Module Integration Test (service)', () => { + let authService: AuthService; + let authResolver: AuthResolver; + let mockUserService: sinon.SinonStubbedInstance; + let mockJwtService: sinon.SinonStubbedInstance; + + let mockProjectService: sinon.SinonStubbedInstance; + let mockNotificationService: sinon.SinonStubbedInstance; + let mockConfigService: sinon.SinonStubbedInstance; + let mockHttpService: sinon.SinonStubbedInstance; + + beforeEach(async () => { + mockUserService = { + findUserByEmail: sandbox.stub(), + findUserByUsername: sandbox.stub(), + createUser: sandbox.stub(), + setResetToken: sandbox.stub(), + updateUserPassword: sandbox.stub() + }; + mockJwtService = { + sign: sandbox.stub(), + verify: sandbox.stub() + }; + mockProjectService = { + getProject: sandbox.stub() + }; + mockConfigService = { + get: sandbox.stub().returns('secret') + }; + mockNotificationService = { + sendPasswordResetEmail: sandbox.stub(), + sendPasswordUpdatedEmail: sandbox.stub() + }; + authService = new AuthService(mockUserService, mockJwtService, mockProjectService, mockConfigService, mockNotificationService, mockHttpService); + authResolver = new AuthResolver(authService); + }); + + describe('login', () => { + it('it should login user by username', async () => { + // Arrange + mockUserService.findUserByUsername.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver.loginUsername({ + projectId: PROJECT_ID, + username: USERNAME, + password: PASSWORD + }); + + // Assert + expect(result.accessToken).toBe('access-token'); + expect(result.refreshToken).toBe('refresh-token'); + }); + + it('it should login user by email', async () => { + // Arrange + mockUserService.findUserByEmail.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver.loginEmail({ + projectId: PROJECT_ID, + email: EMAIL, + password: PASSWORD + }); + + // Assert + expect(result.accessToken).toBe('access-token'); + expect(result.refreshToken).toBe('refresh-token'); + }); + + it('it should throw an error if missing username', async () => { + // Arrange + mockUserService.findUserByUsername.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginUsername({ + projectId: PROJECT_ID, + password: PASSWORD + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if missing projectId', async () => { + // Arrange + mockUserService.findUserByUsername.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginUsername({ + username: USERNAME, + password: PASSWORD + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if missing password', async () => { + // Arrange + mockUserService.findUserByUsername.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginUsername({ + username: USERNAME, + projectId: PROJECT_ID + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if password is incorrect', async () => { + // Arrange + mockUserService.findUserByUsername.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginUsername({ + username: USERNAME, + projectId: PROJECT_ID, + password: 'wrong-password' + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if missing email', async () => { + // Arrange + mockUserService.findUserByEmail.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginEmail({ + projectId: PROJECT_ID, + password: PASSWORD + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if missing projectId via logging via email', async () => { + // Arrange + mockUserService.findUserByEmail.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginEmail({ + email: EMAIL, + password: PASSWORD + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if missing password logging in via email', async () => { + // Arrange + mockUserService.findUserByEmail.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginEmail({ + email: EMAIL, + projectId: PROJECT_ID + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + + it('it should throw an error if password is incorrect logging in via email', async () => { + // Arrange + mockUserService.findUserByEmail.resolves(MOCK_USER); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .loginEmail({ + email: EMAIL, + projectId: PROJECT_ID, + password: 'wrong-password' + } as any) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + }); + + describe('signup', () => { + it('it should signup user via email', async () => { + // Arrange + mockUserService.createUser.resolves(MOCK_USER); + mockProjectService.getProject.resolves(MOCK_PROJECT); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver.signup({ + projectId: PROJECT_ID, + email: EMAIL, + password: PASSWORD + }); + + // Assert + expect(result.accessToken).toBe('access-token'); + expect(result.refreshToken).toBe('refresh-token'); + }); + + it("it should block signup if project doesn't allow signup", async () => { + // Arrange + mockUserService.createUser.resolves(MOCK_USER); + mockProjectService.getProject.resolves({ + ...MOCK_PROJECT, + allowSignup: false + }); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver + .signup({ + projectId: PROJECT_ID, + email: EMAIL, + password: PASSWORD + }) + .catch((e) => { + expect(e).toBeDefined(); + }); + + // Assert + expect(result).toBeUndefined(); + }); + }); + + describe('forgotPassword', () => { + it('it should send password reset email', async () => { + // Arrange + mockUserService.setResetToken.resolves(true); + mockNotificationService.sendPasswordResetEmail.returns(true); + + // Act + const result = await authResolver.forgotPassword({ + projectId: PROJECT_ID, + email: EMAIL + }); + + // Assert + expect(result).toBeTruthy(); + }); + }); + + describe('resetPassword', () => { + it('it should reset the users password', async () => { + // Arrange + mockUserService.updateUserPassword.resolves({ + message: 'Password successfully updated', + status: 200 + }); + mockNotificationService.sendPasswordUpdatedEmail.returns(true); + + // Act + const result = await authResolver.resetPassword({ + projectId: PROJECT_ID, + email: EMAIL, + password: PASSWORD, + code: 'reset-code' + }); + + // Assert + expect(result).toBeTruthy(); + }); + }); + + describe('refresh', () => { + it('it should refresh the users token', async () => { + // Arrange + mockJwtService.verify.returns({ + id: USER_ID, + projectId: PROJECT_ID, + type: 'refresh' + }); + mockJwtService.sign.onFirstCall().returns('access-token'); + mockJwtService.sign.onSecondCall().returns('refresh-token'); + + // Act + const result = await authResolver.refresh('refresh-token'); + + // Assert + expect(result.accessToken).toBe('access-token'); + expect(result.refreshToken).toBe('refresh-token'); + }); + }); + + describe('publicKey', () => { + it('it should return the public key', async () => { + const result = authResolver.publicKey(); + + expect(result).toEqual(['secret', 'secret']); + }); + }); +}); diff --git a/packages/server/src/auth/auth.service.ts b/packages/server/src/auth/auth.service.ts index b3cf677..b39bdfc 100644 --- a/packages/server/src/auth/auth.service.ts +++ b/packages/server/src/auth/auth.service.ts @@ -168,6 +168,15 @@ export class AuthService { */ async signup(user: UserSignupDto): Promise { const data = user; + const project = await this.projectService.getProject(data.projectId); + + if (project == null) { + throw new HttpException('Project not found', HttpStatus.NOT_FOUND); + } + + if (!project.allowSignup) { + throw new HttpException('Signup is not allowed for this project', HttpStatus.FORBIDDEN); + } if (data == null || (data && Object.keys(data).length == 0)) { return { accessToken: '', refreshToken: '' }; diff --git a/packages/server/src/auth/dto/auth.dto.ts b/packages/server/src/auth/dto/auth.dto.ts index b19e39a..aa1167c 100644 --- a/packages/server/src/auth/dto/auth.dto.ts +++ b/packages/server/src/auth/dto/auth.dto.ts @@ -16,7 +16,7 @@ export class UserSignupDto { @IsOptional() @IsString() @Field() - fullname: string; + fullname?: string; @IsDefined() @IsEmail() @@ -141,6 +141,7 @@ export class SignupTransformPipe implements PipeTransform { user.username = body.username?.toString(); user.email = body.email?.toString().toLowerCase(); user.password = body.password; + user.fullname = body.fullname; return user; } diff --git a/packages/server/src/auth/types/auth.types.ts b/packages/server/src/auth/types/auth.types.ts index 6357bfc..91be2b3 100644 --- a/packages/server/src/auth/types/auth.types.ts +++ b/packages/server/src/auth/types/auth.types.ts @@ -6,6 +6,7 @@ export type UserSignup = { password: string; email?: string; username?: string; + fullname?: string; }; export type UsernameLogin = {