From 8f1bc01010e3575a5fd53027be7bb9e680e8fc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20BRISON?= <ext.sopra.jbrison@grandlyon.com> Date: Mon, 11 Jan 2021 12:04:29 +0100 Subject: [PATCH] feat: claim structure --- src/structures/structures.controller.ts | 18 +++++++++++++++--- src/structures/structures.service.ts | 22 ++++++++++++++++------ src/users/create-user.dto.ts | 6 +++++- src/users/user.schema.ts | 1 + src/users/users.controller.ts | 12 +++++++++++- src/users/users.service.spec.ts | 16 ++++++++++++++++ src/users/users.service.ts | 15 +++++++++++++++ 7 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts index 5178d6376..eaa572291 100644 --- a/src/structures/structures.controller.ts +++ b/src/structures/structures.controller.ts @@ -1,4 +1,6 @@ -import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common'; +import { Body, Controller, Get, Param, ParseIntPipe, Post, Put, Query } from '@nestjs/common'; +import { User } from '../users/user.schema'; +import { UsersService } from '../users/users.service'; import { CreateStructureDto } from './dto/create-structure.dto'; import { QueryStructure } from './dto/query-structure.dto'; import { structureDto } from './dto/structure.dto'; @@ -7,7 +9,7 @@ import { StructuresService } from './structures.service'; @Controller('structures') export class StructuresController { - constructor(private readonly structureService: StructuresService) {} + constructor(private readonly structureService: StructuresService, private readonly userService: UsersService) {} @Post() public async create(@Body() createStructureDto: CreateStructureDto): Promise<Structure> { @@ -19,7 +21,7 @@ export class StructuresController { return this.structureService.search(query.query, body ? body.filters : null); } - @Post(':id') + @Put(':id') public async update(@Param('id') id: number, @Body() body: structureDto) { return this.structureService.update(id, body); } @@ -29,6 +31,16 @@ export class StructuresController { return this.structureService.findAll(); } + @Get(':id/isClaimed') + public async isClaimed(@Param('id') id: number): Promise<boolean> { + return this.structureService.isClaimed(id); + } + + @Post(':id/claim') + public async claim(@Param('id', new ParseIntPipe()) idStructure: number, @Body() user: User) { + return this.userService.updateStructureLinked(user.email, idStructure); + } + @Get('count') public async countCategories(): Promise<Array<{ id: string; count: number }>> { const data = await Promise.all([ diff --git a/src/structures/structures.service.ts b/src/structures/structures.service.ts index 3de8c1002..85d241a5f 100644 --- a/src/structures/structures.service.ts +++ b/src/structures/structures.service.ts @@ -12,16 +12,16 @@ import { UsersService } from '../users/users.service'; export class StructuresService { constructor( private readonly httpService: HttpService, - private readonly usersService: UsersService, + private readonly userService: UsersService, @InjectModel(Structure.name) private structureModel: Model<StructureDocument> ) {} public async create(idUser: string, structureDto: structureDto): Promise<Structure> { - const user = await this.usersService.findOne(idUser); + const user = await this.userService.findOne(idUser); if (!user) { throw new HttpException('Invalid profile', HttpStatus.NOT_FOUND); } - let createdStructure = new this.structureModel(structureDto); + const createdStructure = new this.structureModel(structureDto); createdStructure.id = (await this.getNumberStructures()) + 1; createdStructure.save(); user.structuresLink.push(createdStructure.id); @@ -87,11 +87,11 @@ export class StructuresService { } public async update(idStructure: number, structure: structureDto): Promise<Structure> { - const result = await this.structureModel.update({ id: idStructure }, structure); + const result = await this.structureModel.updateOne({ id: idStructure }, structure); //NOSONAR if (!result) { throw new HttpException('Invalid structure id', HttpStatus.BAD_REQUEST); } - return structure; + return this.structureModel.findOne({ id: idStructure }).exec(); } public findOne(idParam: number): Promise<Structure> { @@ -116,6 +116,16 @@ export class StructuresService { }); } + public async isClaimed(idStructure): Promise<boolean> { + const users = await this.userService.findAll(); + users.forEach((user) => { + if (user.structuresLink.includes(idStructure)) { + return true; + } + }); + return false; + } + /** * Count every value occurence of a given key * @param key structure key @@ -141,6 +151,6 @@ export class StructuresService { } public async getNumberStructures(): Promise<number> { - return await this.structureModel.countDocuments(); + return await this.structureModel.countDocuments(); //NOSONAR } } diff --git a/src/users/create-user.dto.ts b/src/users/create-user.dto.ts index 477d79a2a..acb92be7f 100644 --- a/src/users/create-user.dto.ts +++ b/src/users/create-user.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; +import { IsArray, IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator'; export class CreateUserDto { @ApiProperty({ type: String }) @@ -11,4 +11,8 @@ export class CreateUserDto { @IsEmail() @ApiProperty({ type: String }) email: string; + + @IsArray() + @IsOptional() + structuresLink?: Array<number>; } diff --git a/src/users/user.schema.ts b/src/users/user.schema.ts index 0c04dba82..490f7b424 100644 --- a/src/users/user.schema.ts +++ b/src/users/user.schema.ts @@ -25,6 +25,7 @@ export class User { @Prop({ default: null }) newEmail: string; + @Prop({ default: null }) structuresLink: number[]; } diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index e37378c59..1585ae1a3 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -24,7 +24,17 @@ export class UsersController { @Post() @ApiResponse({ status: 201, description: 'User created' }) public async create(@Body() createUserDto: CreateUserDto) { - return this.usersService.create(createUserDto); + // remove structureId for creation and add structure after + let structureId = null; + if (createUserDto.structuresLink.length > 0) { + structureId = createUserDto.structuresLink[0]; + delete createUserDto.structuresLink; + } + const user = await this.usersService.create(createUserDto); + if (structureId) { + this.usersService.updateStructureLinked(createUserDto.email, structureId); + } + return user; } @Post('verify/:id') diff --git a/src/users/users.service.spec.ts b/src/users/users.service.spec.ts index c8e1e0c15..e797c49a4 100644 --- a/src/users/users.service.spec.ts +++ b/src/users/users.service.spec.ts @@ -42,6 +42,7 @@ describe('UsersService', () => { newEmail: '', changeEmailToken: '', resetPasswordToken: null, + structuresLink: [], }; const userDto: CreateUserDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR jest.spyOn(service, 'create').mockImplementation(async (): Promise<User> => result); @@ -78,6 +79,7 @@ describe('UsersService', () => { newEmail: '', changeEmailToken: '', resetPasswordToken: null, + structuresLink: [], }; const loginDto: LoginDto = { email: 'jacques.dupont@mii.com', password: 'test1A!!' }; //NOSONAR jest.spyOn(service, 'findByLogin').mockImplementation(async (): Promise<User> => result); @@ -135,6 +137,7 @@ describe('UsersService', () => { role: 0, newEmail: 'test.dupont@mail.com', resetPasswordToken: '', + structuresLink: [], changeEmailToken: '9bb3542bdc5ca8801ad4cee00403c1052bc95dee768dcbb65b1f719870578ed79f71f52fdc3e6bf02fd200a72b8b6f56fc26950df30c8cd7e427a485f80181b9', }; @@ -164,6 +167,7 @@ describe('UsersService', () => { newEmail: '', resetPasswordToken: '', changeEmailToken: '', + structuresLink: [], }; const token = '9bb3542bdc5ca8801ad4cee00403c1052bc95dee768dcbb65b1f719870578ed79f71f52fdc3e6bf02fd200a72b8b6f56fc26950df30c8cd7e427a485f80181b9'; //NOSONAR @@ -228,5 +232,17 @@ describe('UsersService', () => { ) ).toBe(result); }); + + it('should return structureLink tab ', async () => { + const result = [53]; + jest.spyOn(service, 'updateStructureLinked').mockImplementation(async (): Promise<any> => result); + expect(await service.updateStructureLinked('test@mii.com', 53)).toBe(result); + }); + + it('should return invalid User ', async () => { + const result = new HttpException('Invalid user', HttpStatus.NOT_FOUND); + jest.spyOn(service, 'updateStructureLinked').mockImplementation(async (): Promise<any> => result); + expect(await service.updateStructureLinked('test@mii.com', 53)).toBe(result); + }); }); }); diff --git a/src/users/users.service.ts b/src/users/users.service.ts index d05f8d5de..a14e86643 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -31,6 +31,7 @@ export class UsersService { ); } let createUser = new this.userModel(createUserDto); + // createUser.email = createUserDto.email; createUser.password = await this.hashPassword(createUser.password); // Send verification email createUser = await this.verifyUserMail(createUser); @@ -67,6 +68,10 @@ export class UsersService { return this.userModel.findOne({ email: mail }).select('-password').exec(); } + public async findAll(): Promise<User[]> { + return await this.userModel.find().exec(); + } + public async findById(id: string, passwordQuery?: boolean): Promise<IUser | undefined> { if (passwordQuery) { return this.userModel.findById(id).exec(); @@ -235,4 +240,14 @@ export class UsersService { } throw new HttpException('Invalid token', HttpStatus.UNAUTHORIZED); } + + public async updateStructureLinked(userEmail: string, idStructure: number): Promise<any> { + const user = await this.findOne(userEmail, true); + if (user) { + user.structuresLink.push(idStructure); + user.save(); + return user.structuresLink; + } + throw new HttpException('Invalid user', HttpStatus.NOT_FOUND); + } } -- GitLab