diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts index cefcd5ef266116233ae267ae882d0728ecc06577..7ba449e7479cbbd21193cfb94f4719e5b04c3458 100644 --- a/src/structures/structures.controller.ts +++ b/src/structures/structures.controller.ts @@ -149,6 +149,7 @@ export class StructuresController { @Post(':id/claim') public async claim(@Param('id') idStructure: string, @Body() user: User): Promise<pendingStructuresLink[]> { + this.logger.debug(`claim structure ${idStructure} from ${user.email}`); const structure = await this.structureService.findOne(idStructure); return this.userService.updateStructureLinkedClaim(user.email, idStructure, structure); } @@ -233,7 +234,7 @@ export class StructuresController { @Param('id') id: string, @Body() user: CreateTempUserDto ): Promise<Types.ObjectId[] | TempUser> { - // Get structure name + this.logger.debug(`addOwner`); const structure = await this.structureService.findOne(id); if (!structure) { throw new HttpException('Invalid Structure', HttpStatus.NOT_FOUND); diff --git a/src/temp-user/temp-user.controller.spec.ts b/src/temp-user/temp-user.controller.spec.ts index eef9ce02bd051ca859edb7e3f07f8354e2267685..82aa0e68dd75e964de49859d6bf864c56ab41340 100644 --- a/src/temp-user/temp-user.controller.spec.ts +++ b/src/temp-user/temp-user.controller.spec.ts @@ -27,26 +27,23 @@ describe('TempUserService', () => { expect(tempUserController).toBeDefined(); }); + describe('findAll', () => { + it('should get all temporary users', async () => { + await tempUserController.findAll(); + expect(mockTempUserService.findAll).toHaveBeenCalled(); + }); + }); + describe('getTempUser', () => { it('should get a temporary user by ID', async () => { - const tmpUser = { email: 'test@test.com', structuresLink: [] }; - mockTempUserService.findById.mockReturnValueOnce(tmpUser); - expect(await tempUserController.getTempUser('addq651')).toEqual(tmpUser); - }); - it('should get all temporary users', async () => { - const tempUsers = [ - { email: 'test@test.com', structuresLink: [] }, - { email: 'test2@test.com', structuresLink: [] }, - ]; - mockTempUserService.findAll.mockReturnValueOnce(tempUsers); - const findAllTempUsers = await tempUserController.findAll(); - expect(findAllTempUsers.length).toBe(2); + mockTempUserService.findById.mockResolvedValueOnce('something'); + await tempUserController.getTempUser('Azerty651'); + expect(mockTempUserService.findById).toHaveBeenCalledWith('Azerty651'); }); it('should throw error in case of no users', async () => { - const tmpUser = null; - mockTempUserService.findById.mockReturnValueOnce(tmpUser); + mockTempUserService.findById.mockReturnValueOnce(null); try { - await tempUserController.getTempUser('addq651'); + await tempUserController.getTempUser('Azerty651'); expect(true).toBe(false); } catch (e) { expect(e.message).toEqual('Temp user does not exist'); diff --git a/src/temp-user/temp-user.controller.ts b/src/temp-user/temp-user.controller.ts index ffcf386187226480f79de1afce6fb147df96ec2c..166a6777acdbe036c36adb09b88046767a4b0c0c 100644 --- a/src/temp-user/temp-user.controller.ts +++ b/src/temp-user/temp-user.controller.ts @@ -1,20 +1,16 @@ import { Controller, Get, HttpException, HttpStatus, Param } from '@nestjs/common'; -import { ApiParam } from '@nestjs/swagger'; +import { ApiParam, ApiTags } from '@nestjs/swagger'; import { TempUser } from './temp-user.schema'; import { TempUserService } from './temp-user.service'; +@ApiTags('temp-user') @Controller('temp-user') export class TempUserController { constructor(private readonly tempUserService: TempUserService) {} @Get() public async findAll(): Promise<TempUser[]> { - try { - const tempUsers: TempUser[] = await this.tempUserService.findAll(); - return tempUsers; - } catch (error) { - throw new HttpException('An error occurred while fetching temp users.', HttpStatus.INTERNAL_SERVER_ERROR); - } + return await this.tempUserService.findAll(); } @Get(':id') diff --git a/src/temp-user/temp-user.service.spec.ts b/src/temp-user/temp-user.service.spec.ts index 69cb602e7ba32667a292caa52d9e28be214c68ba..4da9ccfdd0a53f64c0f28a8f03c8f40011ed95a6 100644 --- a/src/temp-user/temp-user.service.spec.ts +++ b/src/temp-user/temp-user.service.spec.ts @@ -7,6 +7,7 @@ import { MailerModule } from '../mailer/mailer.module'; import { MailerService } from '../mailer/mailer.service'; import { TempUserService } from './temp-user.service'; import { Types } from 'mongoose'; +import { CreateTempUserDto } from './dto/create-temp-user.dto'; const ejsSpy = jest.spyOn(ejs, 'renderFile'); @@ -15,14 +16,15 @@ describe('TempUserService', () => { const tempUserModelMock = { create: jest.fn(), - findOne: jest.fn(), + findOne: jest.fn().mockReturnThis(), findById: jest.fn(), findByIdAndUpdate: jest.fn(), - deleteOne: jest.fn(), + deleteOne: jest.fn().mockReturnThis(), find: jest.fn().mockReturnThis(), exec: jest.fn(), updateOne: jest.fn(), populate: jest.fn().mockReturnThis(), + select: jest.fn(), }; const mockMailService = { @@ -43,7 +45,6 @@ describe('TempUserService', () => { }, }; - // Set up the test module before each test beforeEach(async () => { const module = await Test.createTestingModule({ imports: [HttpModule, MailerModule], @@ -60,34 +61,38 @@ describe('TempUserService', () => { tempUserService = module.get<TempUserService>(TempUserService); }); - // Test whether the service is defined it('should be defined', () => { expect(tempUserService).toBeDefined(); }); - // Test related to the 'findAll' method describe('findAll', () => { it('should return a list of temp users', async () => { const tempUsers = [ { email: 'user1@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')] }, { email: 'user2@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')] }, ]; - tempUserModelMock.exec.mockResolvedValueOnce(tempUsers); - expect(await tempUserService.findAll()).toEqual(tempUsers); }); + it('should throw and error', async () => { + tempUserModelMock.exec.mockRejectedValueOnce(new Error('test')); + try { + await tempUserService.findAll(); + expect(true).toBe(false); + } catch (e) { + expect(e.message).toEqual('An error occurred while fetching temp users.'); + expect(e.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); + } + }); }); - // Tests related to the 'create' method describe('create', () => { - const tmpUser = { + const tmpUser: CreateTempUserDto = { email: 'test@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')], }; it('should not create temporary user if it already exists', async () => { - tempUserModelMock.findOne.mockReturnThis(); tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); try { await tempUserService.create(tmpUser, 'PIMMS Framboise'); @@ -99,7 +104,6 @@ describe('TempUserService', () => { }); it('should create a temporary user', async () => { - tempUserModelMock.findOne.mockReturnThis(); tempUserModelMock.exec.mockResolvedValueOnce(null); tempUserModelMock.create.mockResolvedValueOnce(tmpUser); tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); @@ -109,18 +113,15 @@ describe('TempUserService', () => { }); }); - // Test whether the 'findOne' method works it('should find one', async () => { const tmpUser = { email: 'test2@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')], }; - tempUserModelMock.findOne.mockReturnThis(); tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); expect(await tempUserService.findOne('test2@test.com')).toEqual(tmpUser); }); - // Test whether the 'findById' method works it('should find one by id', async () => { const tmpUser = { email: 'test2@test.com', @@ -131,22 +132,18 @@ describe('TempUserService', () => { expect(await tempUserService.findById('5fbb92e480a5c257dc0161f0')).toEqual(tmpUser); }); - // Tests related to the 'delete' method describe('delete', () => { it('should delete a temporary user', async () => { const tmpUser = { email: 'test2@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')], }; - tempUserModelMock.findOne.mockReturnThis(); tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); - tempUserModelMock.deleteOne.mockReturnThis(); tempUserModelMock.exec.mockImplementationOnce(() => ({})); expect(await tempUserService.delete('toto@test.com')).toEqual(tmpUser); }); it('should return an error if the user does not exist', async () => { - tempUserModelMock.findOne.mockReturnThis(); tempUserModelMock.exec.mockResolvedValueOnce(null); try { await tempUserService.delete('toto@test.com'); @@ -158,38 +155,53 @@ describe('TempUserService', () => { }); }); - // Tests related to the 'updateStructureLinked' method describe('updateStructureLinked', () => { - it('should update the linked structure', async () => { - const tmpUser = { + it('should not update the linked structure if the user is not found', async () => { + const createTempUserDto = { email: 'test2@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')], }; - tempUserModelMock.findOne.mockReturnThis(); - tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); + tempUserModelMock.exec.mockResolvedValueOnce(null); - const userInDb = { - structuresLink: [], + try { + await tempUserService.updateStructureLinked(createTempUserDto); + expect(true).toBe(false); + } catch (e) { + expect(e.message).toEqual('User not found'); + expect(e.status).toEqual(HttpStatus.NOT_FOUND); + } + }); + + it('should not update the linked structure if the user is already linked', async () => { + const tmpUser = { + email: 'test2@test.com', + structuresLink: ['653015f722f6c63019ab038d'], + } as any; + const existingUserInDb = { + structuresLink: ['653015f722f6c63019ab038d', '653015f722f6c63019ab038e'], save: jest.fn().mockResolvedValueOnce(tmpUser), }; - jest.spyOn(tempUserModelMock, 'findOne').mockReturnValue({ - exec: jest.fn().mockResolvedValueOnce(userInDb), - }); + tempUserModelMock.exec.mockResolvedValueOnce(existingUserInDb); - tempUserModelMock.findByIdAndUpdate.mockReturnThis(); - expect(await tempUserService.updateStructureLinked(tmpUser)).toEqual(tmpUser); + try { + await tempUserService.updateStructureLinked(tmpUser); + expect(true).toBe(false); + } catch (e) { + expect(e.message).toEqual('User already linked'); + expect(e.status).toEqual(HttpStatus.UNPROCESSABLE_ENTITY); + } }); - - it('should not update the linked structure if the user is already linked', async () => { + it('should update the linked structure', async () => { const tmpUser = { email: 'test2@test.com', structuresLink: [new Types.ObjectId('653015f722f6c63019ab038d')], }; tempUserModelMock.findOne.mockReturnThis(); + tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); const userInDb = { - structuresLink: [new Types.ObjectId()], + structuresLink: [], save: jest.fn().mockResolvedValueOnce(tmpUser), }; @@ -198,12 +210,41 @@ describe('TempUserService', () => { }); tempUserModelMock.findByIdAndUpdate.mockReturnThis(); + expect(await tempUserService.updateStructureLinked(tmpUser)).toEqual(tmpUser); + }); + }); + + describe('getStructureTempUsers', () => { + it('should return a list of temp users', async () => { + tempUserModelMock.select.mockReturnThis(); + await tempUserService.getStructureTempUsers('653015f722f6c63019ab038d'); + expect(tempUserModelMock.find).toHaveBeenCalled(); + }); + }); + describe('removeFromStructureLinked', () => { + it('should not find the user', async () => { + tempUserModelMock.findOne.mockReturnThis(); + tempUserModelMock.exec.mockResolvedValueOnce(null); try { - await tempUserService.updateStructureLinked(tmpUser); + await tempUserService.removeFromStructureLinked('jp@test.com', '653015f722f6c63019ab038d'); } catch (e) { - expect(e.message).toEqual('User is already linked'); - expect(e.status).toEqual(HttpStatus.UNPROCESSABLE_ENTITY); + expect(e.status).toEqual(HttpStatus.NOT_FOUND); + expect(e.message).toEqual('Invalid temp user'); + } + }); + it('should fail because temp user is not linked to the structure', async () => { + const tmpUser = { + email: 'test2@test.com', + structuresLink: [new Types.ObjectId('aaa015f722f6c63019ab038d')], + }; + tempUserModelMock.findOne.mockReturnThis(); + tempUserModelMock.exec.mockResolvedValueOnce(tmpUser); + try { + await tempUserService.removeFromStructureLinked('jp@test.com', '653015f722f6c63019ab038d'); + } catch (e) { + expect(e.status).toEqual(HttpStatus.NOT_FOUND); + expect(e.message).toEqual("Temp user doesn't belong to this structure"); } }); }); diff --git a/src/temp-user/temp-user.service.ts b/src/temp-user/temp-user.service.ts index 89e35da2ec1e81dea8e661c5e77388098b26e9a3..6dd2fb91d049d0cae86233c1c810e5ea5844d9b0 100644 --- a/src/temp-user/temp-user.service.ts +++ b/src/temp-user/temp-user.service.ts @@ -23,13 +23,13 @@ export class TempUserService { } const createUser = await this.tempUserModel.create(createTempUser); - this.logger.debug(`TempUsersService | tempUser created`); - // Send email + this.logger.debug('tempUser created'); this.sendUserMail(createUser, structureName); return this.findOne(createTempUser.email); } public async findAll(): Promise<ITempUser[]> { + this.logger.debug('findAll'); try { const tempUsers = await this.tempUserModel .find() @@ -41,19 +41,22 @@ export class TempUserService { return tempUsers; } catch (error) { - throw new Error('An error occurred while fetching temp users: ' + error.message); + throw new HttpException('An error occurred while fetching temp users.', HttpStatus.INTERNAL_SERVER_ERROR); } } public async findOne(mail: string): Promise<ITempUser> { + this.logger.debug('findOne'); return this.tempUserModel.findOne({ email: mail }).exec(); } public async findById(id: string): Promise<TempUser> { + this.logger.debug('findById'); return this.tempUserModel.findById(new Types.ObjectId(id)).exec(); } public async delete(mail: string): Promise<TempUser> { + this.logger.debug('delete'); const userInDb = await this.findOne(mail); if (!userInDb) { throw new HttpException('User does not exist', HttpStatus.BAD_REQUEST); @@ -63,24 +66,19 @@ export class TempUserService { } public async updateStructureLinked(createTempUser: CreateTempUserDto): Promise<TempUser> { - // Find the user by email - const userInDb = await this.tempUserModel.findOne({ email: createTempUser.email }).exec(); - - if (!userInDb) { + this.logger.debug('updateStructureLinked'); + const user = await this.tempUserModel.findOne({ email: createTempUser.email }).exec(); + if (!user) { throw new HttpException('User not found', HttpStatus.NOT_FOUND); } // Check if the structuresLink already contains the provided structure - if (userInDb.structuresLink.includes(createTempUser.structuresLink[0])) { + if (user.structuresLink.includes(createTempUser.structuresLink[0])) { throw new HttpException('User already linked', HttpStatus.UNPROCESSABLE_ENTITY); } - // Add the new structure to structuresLink - userInDb.structuresLink.push(createTempUser.structuresLink[0]); - - // Save the updated user - const updatedUser = await userInDb.save(); - + user.structuresLink.push(createTempUser.structuresLink[0]); + const updatedUser = await user.save(); return updatedUser; } @@ -134,7 +132,6 @@ export class TempUserService { // Save the updated user if there are remaining structures await user.save(); } - return user.structuresLink; } } diff --git a/src/users/services/users.service.ts b/src/users/services/users.service.ts index 81fd62d2153f2dd8fcf36df1cfa16e2cfd228667..fcd3e2d10bcbbb6833bc318b64d27a03673c73d0 100644 --- a/src/users/services/users.service.ts +++ b/src/users/services/users.service.ts @@ -504,10 +504,10 @@ export class UsersService { idStructure: string, structure: StructureDocument ): Promise<pendingStructuresLink[]> { - const stucturesLinked = this.updatePendingStructureLinked(userEmail, idStructure, structure.structureName); + this.logger.debug(`updateStructureLinkedClaim for structure ${idStructure} from ${userEmail}`); + const structuresLinked = this.updatePendingStructureLinked(userEmail, idStructure, structure.structureName); this.sendAdminStructureValidationMail(userEmail, structure); - - return stucturesLinked; + return structuresLinked; } /**