diff --git a/scripts/data/structures.js b/scripts/data/structures.js index 9af53b20216b4443551de9848cf9979ef9a75acb..24366938bd7d8f87f4f3155493041724e8963476 100644 --- a/scripts/data/structures.js +++ b/scripts/data/structures.js @@ -759,5 +759,79 @@ module.exports = { nbScanners: 1, otherDescription: null, }, + { + _id: ObjectId('61e9260c2ac971550065e262'), + coord: [4.88428, 45.727292], + equipmentsAndServices: [], + digitalCultureSecurity: ['2', '5', '9', '28', '34', '39', '42', '51', '52', '54', '65', '96', '97', '98'], + parentingHelp: ['3', '22', '82', '94'], + socialAndProfessional: ['6', '20', '66', '67', '68', '69', '124', '125', '127'], + accessRight: ['84', '85', '86', '87', '88', '89', '93', '95'], + baseSkills: ['1', '11', '38', '48', '74', '77'], + proceduresAccompaniment: [], + publicsAccompaniment: [], + publics: ['toutPublic'], + labelsQualifications: ['passNumerique'], + accessModality: ['accesLibre'], + structureName: "Maison Lyon pour l'Emploi - Lyon 8", + contactPhone: '04 04 04 04 04', + contactMail: 'a@a.com', + structureType: 'autre', + pmrAccess: false, + remoteAccompaniment: false, + accountVerified: true, + freeWorkShop: false, + nbComputers: 0, + nbPrinters: 0, + nbScanners: 0, + nbTablets: 0, + nbNumericTerminal: 0, + address: { + numero: '172', + street: 'Avenue Général Frère', + commune: 'Lyon', + }, + createdAt: 'Thu Jan 20 2022 10:06:20 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:20 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: null, + __v: 0, + }, + { + _id: ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + equipmentsAndServices: [], + digitalCultureSecurity: ['2', '5', '9', '28', '34', '39', '42', '51', '52', '54', '65', '96', '97', '98'], + parentingHelp: ['3', '22', '82', '94'], + socialAndProfessional: ['6', '20', '66', '67', '68', '69', '124', '125', '127'], + accessRight: ['84', '85', '86', '87', '88', '89', '93', '95'], + baseSkills: ['1', '11', '38', '48', '74', '77'], + proceduresAccompaniment: [], + publicsAccompaniment: [], + publics: ['toutPublic'], + labelsQualifications: ['passNumerique'], + accessModality: ['accesLibre'], + structureName: 'mon assistant numérique val de saone', + contactPhone: '04 04 04 04 04', + contactMail: 'a@a.com', + structureType: 'autre', + pmrAccess: false, + remoteAccompaniment: false, + accountVerified: true, + freeWorkShop: false, + nbComputers: 0, + nbPrinters: 0, + nbScanners: 0, + nbTablets: 0, + nbNumericTerminal: 0, + address: { + numero: '2', + street: 'Rue Neuve', + commune: 'Fleurieu-sur-Saône', + }, + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + __v: 0, + }, ], }; diff --git a/scripts/data/users.js b/scripts/data/users.js index beb7b1c359c6a90721a8aa14304f57c71fa570ef..fb5ebc814ed025c1c234f379aa67412d9f4f7be2 100644 --- a/scripts/data/users.js +++ b/scripts/data/users.js @@ -39,6 +39,8 @@ module.exports = { structuresLink: [ mongoose.Types.ObjectId('6001a38516b08100062e4161'), mongoose.Types.ObjectId('6001a3aa16b08100062e4166'), + mongoose.Types.ObjectId('61e9260c2ac971550065e262'), + mongoose.Types.ObjectId('61e9260b2ac971550065e261'), ], newEmail: null, changeEmailToken: null, diff --git a/src/structures/dto/structure.dto.ts b/src/structures/dto/structure.dto.ts index 12cd9f6078251651726e001f405bedeffe733101..4299a0cbfdf0e3fd739660ac60d70c55797dd661 100644 --- a/src/structures/dto/structure.dto.ts +++ b/src/structures/dto/structure.dto.ts @@ -69,4 +69,5 @@ export class structureDto { digitalCultureSecurity: string[]; coord: number[]; accountVerified: boolean; + dataShareConsentDate: Date; } diff --git a/src/structures/schemas/structure.schema.ts b/src/structures/schemas/structure.schema.ts index 1ac967167569fdb89c4ba11b87309363f4c4ad7e..f3bf4067964fda6870797e854b0735183cc7d8b4 100644 --- a/src/structures/schemas/structure.schema.ts +++ b/src/structures/schemas/structure.schema.ts @@ -51,6 +51,7 @@ export class Structure { this.coord = data.coord; this.deletedAt = data.deletedAt; this.accountVerified = data.accountVerified; + this.dataShareConsentDate = data.dataShareConsentDate; } @Prop() @@ -187,6 +188,9 @@ export class Structure { @Prop() accountVerified: boolean; + + @Prop() + dataShareConsentDate: Date; } export const StructureSchema = SchemaFactory.createForClass(Structure); diff --git a/src/structures/services/structure.service.spec.ts b/src/structures/services/structure.service.spec.ts index a3521419a7ad8f94b5f5f19455bb5c5bff83c674..567946859a7ffc47c1e1f3d2fad064dfda6c068b 100644 --- a/src/structures/services/structure.service.spec.ts +++ b/src/structures/services/structure.service.spec.ts @@ -2,7 +2,7 @@ import { HttpModule } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { getModelToken } from '@nestjs/mongoose'; import { Test, TestingModule } from '@nestjs/testing'; -import { CategoriesFormationsServiceMock } from '../../../test/mock/services/categoriesFormations.mock.service'; +import { Types } from 'mongoose'; import { UsersServiceMock } from '../../../test/mock/services/user.mock.service'; import { CategoriesFormationsService } from '../../categories/services/categories-formations.service'; import { ConfigurationService } from '../../configuration/configuration.service'; @@ -13,6 +13,12 @@ import { structureDto } from '../dto/structure.dto'; import { Structure, StructureDocument } from '../schemas/structure.schema'; import { StructuresSearchService } from './structures-search.service'; import { StructuresService } from './structures.service'; +import { IUser } from '../../users/interfaces/user.interface'; +import * as bcrypt from 'bcrypt'; + +function hashPassword() { + return bcrypt.hashSync(process.env.USER_PWD, process.env.SALT); +} describe('StructuresService', () => { let service: StructuresService; @@ -375,6 +381,108 @@ describe('StructuresService', () => { expect(res).toBeTruthy(); }); + describe('getAllDataConsentPendingStructures', () => { + it('should get one empty consent', async () => { + const user = { + _id: '123', + validationToken: + 'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42', + emailVerified: false, + email: 'jacques.dupont@mii.com', + password: hashPassword(), + role: 0, + newEmail: '', + changeEmailToken: '', + resetPasswordToken: null, + structuresLink: [ + Types.ObjectId('620e510b7d8f26712c386be7'), + Types.ObjectId('620e51247d8f26712c386be9'), + Types.ObjectId('620e5236f25755550cb86dfd'), + ], + pendingStructuresLink: [], + structureOutdatedMailSent: [], + name: 'Jacques', + surname: 'Dupont', + phone: '06 06 06 06 06', + } as IUser; + jest + .spyOn(service, 'findOne') + .mockResolvedValueOnce({ + _id: Types.ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + __v: 0, + } as StructureDocument) + .mockResolvedValueOnce({ + _id: Types.ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: null, + } as StructureDocument) + .mockResolvedValueOnce({ + _id: Types.ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: new Date(), + } as StructureDocument); + let res = await service.getAllDataConsentPendingStructures(user); + expect(res.length).toBe(1); + }); + it('should get no consent', async () => { + const user = { + _id: '123', + validationToken: + 'cf1c74c22cedb6b575945098db42d2f493fb759c9142c6aff7980f252886f36ee086574ee99a06bc99119079257116c959c8ec870949cebdef2b293666dbca42', + emailVerified: false, + email: 'jacques.dupont@mii.com', + password: hashPassword(), + role: 0, + newEmail: '', + changeEmailToken: '', + resetPasswordToken: null, + structuresLink: [ + Types.ObjectId('620e510b7d8f26712c386be7'), + Types.ObjectId('620e51247d8f26712c386be9'), + Types.ObjectId('620e5236f25755550cb86dfd'), + ], + pendingStructuresLink: [], + structureOutdatedMailSent: [], + name: 'Jacques', + surname: 'Dupont', + phone: '06 06 06 06 06', + } as IUser; + jest + .spyOn(service, 'findOne') + .mockResolvedValueOnce({ + _id: Types.ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: null, + __v: 0, + } as StructureDocument) + .mockResolvedValueOnce({ + _id: Types.ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: null, + } as StructureDocument) + .mockResolvedValueOnce({ + _id: Types.ObjectId('61e9260b2ac971550065e261'), + coord: [4.844309, 45.865288], + createdAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + updatedAt: 'Thu Jan 20 2022 10:06:19 GMT+0100 (heure normale d’Europe centrale)', + dataShareConsentDate: new Date(), + } as StructureDocument); + let res = await service.getAllDataConsentPendingStructures(user); + expect(res.length).toBe(0); + }); + }); + it('should report structure Error', () => { let res = service.reportStructureError('6093ba0e2ab5775cfc01ed3e', ''); expect(res).toBeTruthy(); diff --git a/src/structures/services/structures.service.ts b/src/structures/services/structures.service.ts index bd590256d66b573335226eaaf6c599579ed1bde9..b16568d30ce962f5a49e793ba01935bc21e1427a 100644 --- a/src/structures/services/structures.service.ts +++ b/src/structures/services/structures.service.ts @@ -672,4 +672,24 @@ export class StructuresService { }) ); } + + /** + * Retrieve all structure pending for data.grandlyon consent sharing. + * Case 1 : null value stands for 'no' + * Case 2: a date stands for 'yes' + * Case 3: no key in document when there is no reply to consent + * @param users {IUser} + * @returns {Structure[]} + */ + public async getAllDataConsentPendingStructures(users: IUser): Promise<Structure[]> { + const data = await Promise.all( + users.structuresLink.map(async (structureId: Types.ObjectId) => { + const structure = await this.findOne(structureId.toHexString()); + if (structure && structure.dataShareConsentDate === undefined) { + return structure; + } + }) + ); + return data.filter((value) => value); + } } diff --git a/src/structures/structures.controller.spec.ts b/src/structures/structures.controller.spec.ts index 6762f14c34fca751913f7ded03c94dff3fcf3b96..6404d10cfc171e8fb445d71d1025788a0c7ca78d 100644 --- a/src/structures/structures.controller.spec.ts +++ b/src/structures/structures.controller.spec.ts @@ -90,6 +90,7 @@ describe('AuthController', () => { numero: null, deletedAt: null, remoteAccompaniment: null, + dataShareConsentDate: null, ...structure, }); expect(res.structureName).toBe('a'); diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts index 0de71acb333cecc431c4f85786235dc4efe89b15..24b25f37daa728f15f970c6a4fff115edd57d9e0 100644 --- a/src/structures/structures.controller.ts +++ b/src/structures/structures.controller.ts @@ -273,6 +273,6 @@ export class StructuresController { @Post('reportStructureError') public async reportStructureError(@Body() data: { structureId: string; content: string }): Promise<void> { - return await this.structureService.reportStructureError(data.structureId, data.content); + return this.structureService.reportStructureError(data.structureId, data.content); } } diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 6830094ce1b7bc71510a2a2fc597cdfb9e824eaf..5baea90e9af13ef24bf1fd6cf34d5380362d64cc 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -10,6 +10,7 @@ import { UsersService } from './users.service'; import { StructuresService } from '../structures/services/structures.service'; import { TempUserService } from '../temp-user/temp-user.service'; import { ConfigurationService } from '../configuration/configuration.service'; +import { Structure } from '../structures/schemas/structure.schema'; @Controller('users') export class UsersController { constructor( @@ -124,4 +125,10 @@ export class UsersController { }); return user; } + + @Get('dataConsentValidation') + @UseGuards(JwtAuthGuard) + public async dataConsentValidation(@Request() req): Promise<Structure[]> { + return this.structureService.getAllDataConsentPendingStructures(req.user); + } }