From ac2e87dab37d1e660ca021873bfa5926aca190e2 Mon Sep 17 00:00:00 2001 From: ALGLAVE Ivan <ivan.alglave8@etu.univ-lorraine.fr> Date: Thu, 9 Feb 2023 14:29:17 +0100 Subject: [PATCH] Added the ability to import multiple people at once using JSON format. --- src/groups/dao/groups.dao.ts | 47 ++++++++++++++++++++++++++ src/groups/groups.controller.ts | 28 ++++++++++++++- src/groups/groups.module.ts | 6 +++- src/groups/groups.service.ts | 8 +++++ src/internships/dao/internships.dao.ts | 2 -- src/people/dao/people.dao.ts | 37 ++++++++++++++++++++ src/people/dto/create-people.dto.ts | 10 +++--- src/people/entities/people.entity.ts | 2 +- src/people/people.controller.ts | 2 +- src/people/people.service.ts | 4 +++ src/shared/Roles.ts | 15 ++++++++ 11 files changed, 149 insertions(+), 12 deletions(-) diff --git a/src/groups/dao/groups.dao.ts b/src/groups/dao/groups.dao.ts index 5be7864..52e31cc 100644 --- a/src/groups/dao/groups.dao.ts +++ b/src/groups/dao/groups.dao.ts @@ -107,6 +107,53 @@ export class GroupsDao { ); }); + findByIdAndUpdateManyByRole = ( + id: string, + role: string, + peopleIds: string[], + action: string, + ): Promise<Group | void> => + new Promise((resolve, reject) => { + let query = {}; + if (action === 'post') { + switch (role) { + case Roles.ROLE_RESPONSIBLE: + query = { $addToSet: { responsibles: { $each: peopleIds } } }; + break; + case Roles.ROLE_SECRETARY: + query = { $addToSet: { secretaries: { $each: peopleIds } } }; + break; + case Roles.ROLE_STUDENT: + query = { $addToSet: { students: { $each: peopleIds } } }; + break; + default: + reject(new BadRequestException('Bad role')); + } + } else if (action === 'delete') { + switch (role) { + case Roles.ROLE_RESPONSIBLE: + query = { $pull: { responsibles: { $in: peopleIds } } }; + break; + case Roles.ROLE_SECRETARY: + query = { $pull: { secretaries: { $in: peopleIds } } }; + break; + case Roles.ROLE_STUDENT: + query = { $pull: { students: { $in: peopleIds } } }; + break; + default: + reject(new BadRequestException('Bad role')); + } + } else reject(new BadRequestException('Unknown action')); + this._groupModel.findByIdAndUpdate( + id, + query, + { new: true }, + (err, value) => { + if (err) reject(err.message); + resolve(value); + }); + }); + findByIdAndRemove = (id: string): Promise<Group | void> => new Promise((resolve, reject) => { this._groupModel.findByIdAndDelete(id, {}, (err) => { diff --git a/src/groups/groups.controller.ts b/src/groups/groups.controller.ts index 18cf22e..625f5cc 100644 --- a/src/groups/groups.controller.ts +++ b/src/groups/groups.controller.ts @@ -13,11 +13,17 @@ import { CreateGroupDto } from './dto/create-group.dto'; import { UpdateGroupDto } from './dto/update-group.dto'; import { GroupEntity } from './entities/group.entity'; import { GroupsService } from './groups.service'; +import { CreatePeopleDto } from 'src/people/dto/create-people.dto'; +import { PeopleService } from 'src/people/people.service'; +import { roleValue } from 'src/shared/Roles'; @Controller('groups') @UseInterceptors(HttpInterceptor) export class GroupsController { - constructor(private readonly _groupsService: GroupsService) {} + constructor( + private readonly _groupsService: GroupsService, + private readonly _peopleService: PeopleService, + ) {} @Get() findAll(): Promise<GroupEntity[] | void> { @@ -34,6 +40,26 @@ export class GroupsController { return this._groupsService.create(createGroupDto); } + @Post(':id/import/:role') + async importAsFile( + @Param() params: { id: string; role: string }, + @Body() people: CreatePeopleDto[], + ): Promise<GroupEntity | void> { + const peopleEntities = await this._peopleService.createMany( + people.map((person) => { + person.role = roleValue(params.role); + return person; + }), + ); + const peopleIds = peopleEntities.map((person) => person._id); + return this._groupsService.updateManyByRole( + params.id, + params.role, + peopleIds, + 'post', + ); + } + @Put(':id') update( @Param() params: { id: string }, diff --git a/src/groups/groups.module.ts b/src/groups/groups.module.ts index b8c3b67..3614a83 100644 --- a/src/groups/groups.module.ts +++ b/src/groups/groups.module.ts @@ -1,5 +1,8 @@ import { Module, Logger } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; +import { PeopleDao } from 'src/people/dao/people.dao'; +import { PeopleService } from 'src/people/people.service'; +import { People, PeopleSchema } from 'src/people/schemas/people.schema'; import { GroupsDao } from './dao/groups.dao'; import { GroupsController } from './groups.controller'; import { GroupsService } from './groups.service'; @@ -8,8 +11,9 @@ import { Group, GroupSchema } from './schemas/group.schema'; @Module({ imports: [ MongooseModule.forFeature([{ name: Group.name, schema: GroupSchema }]), + MongooseModule.forFeature([{ name: People.name, schema: PeopleSchema }]), ], controllers: [GroupsController], - providers: [GroupsService, GroupsDao, Logger], + providers: [GroupsService, GroupsDao, Logger, PeopleService, PeopleDao], }) export class GroupsModule {} diff --git a/src/groups/groups.service.ts b/src/groups/groups.service.ts index bf52da3..59b939e 100644 --- a/src/groups/groups.service.ts +++ b/src/groups/groups.service.ts @@ -27,6 +27,14 @@ export class GroupsService { ): Promise<GroupEntity | void> => this._groupsDao.findByIdAndUpdateRole(id, role, personId, action); + updateManyByRole = ( + id: string, + role: string, + peopleIds: string[], + action: string, + ): Promise<GroupEntity | void> => + this._groupsDao.findByIdAndUpdateManyByRole(id, role, peopleIds, action); + delete(id: string): Promise<GroupEntity | void> { return this._groupsDao.findById(id).then((res) => { if (res) { diff --git a/src/internships/dao/internships.dao.ts b/src/internships/dao/internships.dao.ts index 22a0817..c42d59e 100644 --- a/src/internships/dao/internships.dao.ts +++ b/src/internships/dao/internships.dao.ts @@ -120,9 +120,7 @@ export class InternshipDao { content: string | boolean, ): Promise<Internship | void> => new Promise((resolve, reject) => { - console.log('%s/%s: {%s}', studentId, state, content); if (!isStateValid(state)) reject(BAD_REQUEST); - console.log(content); let nextState: string, contentHolder: string; let valid = false; switch (state) { diff --git a/src/people/dao/people.dao.ts b/src/people/dao/people.dao.ts index 33fd035..bb03a1d 100644 --- a/src/people/dao/people.dao.ts +++ b/src/people/dao/people.dao.ts @@ -12,6 +12,8 @@ import { People } from '../schemas/people.schema'; import * as Mailgun from 'mailgun-js'; import config from 'src/config'; import * as bcrypt from 'bcrypt'; +import { PeopleEntity } from '../entities/people.entity'; +import { CONFLICT } from 'src/shared/HttpError'; @Injectable() export class PeopleDao { @@ -73,6 +75,41 @@ export class PeopleDao { }); }; + saveMany = async (people: CreatePeopleDto[]): Promise<PeopleEntity[]> => + Promise.all( + people.map( + (person): Promise<PeopleEntity> => + new Promise((resolve, reject) => { + this._peopleModel.findOne( + { email: person.email }, + {}, + {}, + (err, value) => { + if (err) { + reject(err.message); + } else if (!value) { + // Person does not exist -> create password + add to database + this.secret().then((value) => { + person.passwordHash = value; + new this._peopleModel(person).save((err, value) => { + if (err) reject(err.message); + if (!value) reject(new InternalServerErrorException()); + this.sendPassword(person.email, person.passwordHash); + resolve(value); + }); + }); + } else { + resolve(value); + } + }, + ); + }), + ), + ); + // Check for existing people in database based on email + // Add missing people + // Get all added people as PeopleEntity to have access to IDs + findByIdAndUpdate = ( id: string, people: UpdatePeopleDto, diff --git a/src/people/dto/create-people.dto.ts b/src/people/dto/create-people.dto.ts index c26bd35..00d43b8 100644 --- a/src/people/dto/create-people.dto.ts +++ b/src/people/dto/create-people.dto.ts @@ -1,7 +1,6 @@ -import { IsBoolean, IsString, IsNotEmpty, IsOptional } from 'class-validator'; +import { IsString, IsNotEmpty, IsOptional } from 'class-validator'; export class CreatePeopleDto { - @IsString() @IsNotEmpty() firstname: string; @@ -16,8 +15,7 @@ export class CreatePeopleDto { @IsString() @IsNotEmpty() email: string; - - @IsNotEmpty() - role: number; -} \ No newline at end of file + @IsOptional() + role: number; +} diff --git a/src/people/entities/people.entity.ts b/src/people/entities/people.entity.ts index 7f8bf24..38dc121 100644 --- a/src/people/entities/people.entity.ts +++ b/src/people/entities/people.entity.ts @@ -11,4 +11,4 @@ export class PeopleEntity { constructor(partial: Partial<People>) { Object.assign(this, partial); } -} \ No newline at end of file +} diff --git a/src/people/people.controller.ts b/src/people/people.controller.ts index 0837bc2..68b8d75 100644 --- a/src/people/people.controller.ts +++ b/src/people/people.controller.ts @@ -29,7 +29,7 @@ export class PeopleController { constructor(private readonly _peopleService: PeopleService) {} - @UseGuards(AuthGuard('jwt')) + //@UseGuards(AuthGuard('jwt')) @Get() findAll(): Promise<PeopleEntity[] | void> { return this._peopleService.findAll(); diff --git a/src/people/people.service.ts b/src/people/people.service.ts index 2c35819..10d3195 100644 --- a/src/people/people.service.ts +++ b/src/people/people.service.ts @@ -24,6 +24,10 @@ export class PeopleService { return this._peopleDao.save(people); } + createMany = (people: CreatePeopleDto[]): Promise<PeopleEntity[]> => { + return this._peopleDao.saveMany(people); + }; + update = ( id: string, people: UpdatePeopleDto, diff --git a/src/shared/Roles.ts b/src/shared/Roles.ts index 317633e..7911808 100644 --- a/src/shared/Roles.ts +++ b/src/shared/Roles.ts @@ -12,3 +12,18 @@ export const ROLES = [ export const isRoleValid = (potentialRole: string): boolean => ROLES.includes(potentialRole); + +export const roleValue = (role: string): number => { + switch (role) { + case ROLE_STUDENT: + return 0; + case ROLE_SECRETARY: + return 1; + case ROLE_RESPONSIBLE: + return 2; + case ROLE_ADMIN: + return 9999; + default: + return -1; + } +}; -- GitLab