diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index b84d9d146871a6c631cb69a3c7301fab82cc01e1..460744ec2b219c6cc1d4e8332ceb451031b955e1 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -12,4 +12,9 @@ export class AuthController { async login(@Body() loginDto: LoginDto) { return this.authService.login(loginDto); } + + @Post('resendEmail') + async resendEmail(@Body() loginDto: LoginDto) { + return this.authService.resendEmail(loginDto); + } } diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index a8784080413008e5be0f0dd37be15f5281c0851d..318fa3659d7c05eb4b5eed7fabfbc071d61e9751 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -94,9 +94,9 @@ describe('AuthService', () => { try { await authService.login(loginDto); } catch (e) { - expect(e.response).toBe('Invalid credentials'); - expect(e.message).toBe('Invalid credentials'); - expect(e.status).toBe(401); + expect(e.response).toBe('Unverified user'); + expect(e.message).toBe('Unverified user'); + expect(e.status).toBe(418); } }); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 818dac0fc413fae3382e02613548e746d42f0170..9bf5abbb0e5166baaca0a5a14d3376d3dcab2999 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -19,10 +19,10 @@ export class AuthService { } async login(loginDto: LoginDto) { - // find user in db - const user: User = await this.usersService.findByLogin(loginDto); + // check user auth in db + const user = await this.usersService.checkLogin(loginDto); if (!user.emailVerified) { - throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED); + throw new HttpException('Unverified user', HttpStatus.I_AM_A_TEAPOT); } // generate and sign token @@ -36,6 +36,15 @@ export class AuthService { }; } + async resendEmail(loginDto: LoginDto) { + // check user auth in db + const user = await this.usersService.checkLogin(loginDto); + if (user.emailVerified) { + throw new HttpException('User already verified', HttpStatus.UNPROCESSABLE_ENTITY); + } + return this.usersService.sendVerifyUserMail(user); + } + private _createToken(user: User) { const local = DateTime.local().setZone('Europe/Paris'); return { diff --git a/src/structures/services/structures.service.ts b/src/structures/services/structures.service.ts index 83572d2a18738d16fadb0aeeb9cf9a24a5a0b664..48e219ae492831098e2b37ab36ca3f3f2b68ee92 100644 --- a/src/structures/services/structures.service.ts +++ b/src/structures/services/structures.service.ts @@ -989,17 +989,6 @@ export class StructuresService { return this.userService.getStructureOwners(structureId); } - public async updateAccountVerified(idStructure: string): Promise<Structure> { - const structureLinked = await this.findOne(idStructure); - const structure = new this.structureModel(structureLinked); - if (!structure) { - throw new HttpException('Invalid structure', HttpStatus.NOT_FOUND); - } - structure.accountVerified = true; - structure.save(); - return structure; - } - public async findWithOwners(idStructure: string): Promise<{ structure: Structure; owners: IUser[] }> { const structure = await this.findOne(idStructure); if (!structure) { diff --git a/src/structures/structures.controller.spec.ts b/src/structures/structures.controller.spec.ts index 7ab3ff58118c54f8c78228a3521e257510b4f11f..789e96c74650d95a5a1a764ec005180025adfbfd 100644 --- a/src/structures/structures.controller.spec.ts +++ b/src/structures/structures.controller.spec.ts @@ -48,7 +48,6 @@ describe('StructuresController', () => { searchAddress: jest.fn(), searchForStructures: jest.fn(), update: jest.fn(), - updateAccountVerified: jest.fn(), updateAllDenormalizedFields: jest.fn(), }; @@ -134,12 +133,6 @@ describe('StructuresController', () => { expect(mockStructureService.create).toBeCalled(); }); - it('should update structure after ownerVerify', async () => { - const structureId = '1'; - const res = structuresController.updateAfterOwnerVerify(structureId); - expect(res).toBeTruthy(); - }); - it('should update structure', async () => { await structuresController.update('azerty', { deletedAt: null, diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts index 7f467b9b7b4e7c085d6978352be2c729b74a96a9..95a41a15c3de0097d4f2decc01baa458b36d1c2b 100644 --- a/src/structures/structures.controller.ts +++ b/src/structures/structures.controller.ts @@ -129,12 +129,6 @@ export class StructuresController { return this.structureService.updateAllDenormalizedFields(); } - @Put('updateAfterOwnerVerify/:id') - public async updateAfterOwnerVerify(@Param('id') id: string): Promise<Structure> { - Logger.debug(`updateAfterOwnerVerify | structure ${id}`, StructuresController.name); - return this.structureService.updateAccountVerified(id); - } - @ApiOperation({ summary: 'Patch one value or more of a structure' }) @Patch(':id') @UseGuards(JwtAuthGuard, IsStructureOwnerGuard) diff --git a/src/users/services/users.service.spec.ts b/src/users/services/users.service.spec.ts index f3e695b9d69c4a0a3e522d05bfb16c9ca810c399..8392130f003e194a72c9aa62f52a0a697d948556 100644 --- a/src/users/services/users.service.spec.ts +++ b/src/users/services/users.service.spec.ts @@ -242,12 +242,12 @@ describe('UsersService', () => { }); }); - describe('findByLogin', () => { + describe('checkLogin', () => { const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; it('should fail, no user found', async () => { jest.spyOn(usersService, 'findOne').mockResolvedValue(null); try { - await usersService.findByLogin(loginDto); + await usersService.checkLogin(loginDto); expect(true).toBe(false); } catch (error) { expect(error.status).toBe(HttpStatus.UNAUTHORIZED); @@ -260,7 +260,7 @@ describe('UsersService', () => { //TODO mock private function comparePassword ? -> false return true; try { - await usersService.findByLogin(loginDto); + await usersService.checkLogin(loginDto); expect(true).toBe(false); } catch (error) { expect(error.status).toBe(HttpStatus.UNAUTHORIZED); @@ -273,7 +273,7 @@ describe('UsersService', () => { jest.spyOn(usersService, 'findOne').mockResolvedValue(mockUser as IUser); //TODO mock private function comparePassword ? -> true return true; - expect(await usersService.findByLogin(loginDto)).toBe(mockUser); + expect(await usersService.checkLogin(loginDto)).toBe(mockUser); }); it('wrong password, should be unauthorized issue', async () => { @@ -281,7 +281,7 @@ describe('UsersService', () => { const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!!' }; //NOSONAR jest.spyOn(usersService, 'findOne').mockResolvedValue(null); try { - await usersService.findByLogin(loginDto); + await usersService.checkLogin(loginDto); expect(true).toBe(false); } catch (error) { expect(error.status).toBe(HttpStatus.UNAUTHORIZED); diff --git a/src/users/services/users.service.ts b/src/users/services/users.service.ts index f4100c58eb6b15bca86b58549dbd98f90f279ca3..ded27b31d8d510d8db3a31d0bd391fd71253d1cb 100644 --- a/src/users/services/users.service.ts +++ b/src/users/services/users.service.ts @@ -26,6 +26,7 @@ import { User } from '../schemas/user.schema'; import { JobsService } from './jobs.service'; import { UserRegistrySearchService } from './userRegistry-search.service'; import { StructuresService } from '../../structures/services/structures.service'; +import { AxiosResponse } from 'axios'; @Injectable() export class UsersService { @@ -191,8 +192,7 @@ export class UsersService { * Use for login action * @param param LoginDto */ - // TODO update method name - public async findByLogin({ email, password }: LoginDto): Promise<User> { + public async checkLogin({ email, password }: LoginDto): Promise<IUser> { const user = await this.findOne(email, true); if (!user) { @@ -216,21 +216,33 @@ export class UsersService { * @param user User */ private async verifyUserMail(user: IUser): Promise<IUser> { + const token = crypto.randomBytes(64).toString('hex'); + + // Save token + user.validationToken = token; + + // Send email + this.sendVerifyUserMail(user); + + return user; + } + + /** + * Send verification email to user + * @param user User + */ + public async sendVerifyUserMail(user: IUser): Promise<AxiosResponse> { const config = this.mailerService.config; const ejsPath = this.mailerService.getTemplateLocation(config.templates.verify.ejs); const jsonConfig = this.mailerService.loadJsonConfig(config.templates.verify.json); - const token = crypto.randomBytes(64).toString('hex'); const html = await ejs.renderFile(ejsPath, { config, - token: token, + token: user.validationToken, userId: user._id, }); - this.mailerService.send(user.email, jsonConfig.subject, html); - // Save token - user.validationToken = token; - return user; + return this.mailerService.send(user.email, jsonConfig.subject, html); } /** diff --git a/test/mock/services/structures.mock.service.ts b/test/mock/services/structures.mock.service.ts index 46b2b12c0badb401292181902d6848fa8bea692b..45f15b879079b6cf6ef2e0ba54e2d3f9e4ba47dc 100644 --- a/test/mock/services/structures.mock.service.ts +++ b/test/mock/services/structures.mock.service.ts @@ -1339,10 +1339,6 @@ export class StructuresServiceMock { return; } - async updateAccountVerified() { - return; - } - async updateAllDenormalizedFields() { return; } diff --git a/test/mock/services/user.mock.service.ts b/test/mock/services/user.mock.service.ts index 7173ecb0dcbbc11f39222129ef2ce7ab782abdf7..d8b6e2fca5205b1a94f5e43d695f7abdb750d8b6 100644 --- a/test/mock/services/user.mock.service.ts +++ b/test/mock/services/user.mock.service.ts @@ -50,7 +50,7 @@ export class UsersServiceMock { return null; } - findByLogin({ email, password }: LoginDto) { + checkLogin({ email, password }: LoginDto) { const user = this.findOne(email, true); if (!user) {