From 6b6df1fb16be381383b007a54a335f1d0db2c8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marl=C3=A8ne=20SIMONDANT?= <msimondant@grandlyon.com> Date: Mon, 24 Oct 2022 12:53:34 +0000 Subject: [PATCH] feat : add unattachedSince date to users without any structure --- scripts/init-db.js | 1 + src/admin/admin.controller.ts | 1 + .../1666104879255-add-unattachedSince.ts | 29 +++++++++++++++++++ src/structures/services/structures.service.ts | 7 +++-- src/structures/structures.controller.spec.ts | 2 ++ src/structures/structures.controller.ts | 2 +- src/users/dto/create-user.dto.ts | 3 ++ src/users/schemas/user.schema.ts | 3 ++ src/users/services/users.service.spec.ts | 3 ++ src/users/services/users.service.ts | 16 +++++----- 10 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 src/migrations/scripts/1666104879255-add-unattachedSince.ts diff --git a/scripts/init-db.js b/scripts/init-db.js index 2041dc256..910179178 100644 --- a/scripts/init-db.js +++ b/scripts/init-db.js @@ -58,6 +58,7 @@ const usersSchema = mongoose.Schema({ structuresLink: [], structureOutdatedMailSent: [], pendingStructuresLink: [], + unattachedSince: Date, password: String, phone: String, employer: String, diff --git a/src/admin/admin.controller.ts b/src/admin/admin.controller.ts index f803d1f6b..0369680c3 100644 --- a/src/admin/admin.controller.ts +++ b/src/admin/admin.controller.ts @@ -219,6 +219,7 @@ export class AdminController { return { id: user._id, createdAt: user.createdAt ? user.createdAt.toLocaleDateString() : '', + unattachedSince: user.unattachedSince ? user.unattachedSince.toLocaleDateString() : '', surname: user.surname, name: user.name, email: user.email, diff --git a/src/migrations/scripts/1666104879255-add-unattachedSince.ts b/src/migrations/scripts/1666104879255-add-unattachedSince.ts new file mode 100644 index 000000000..5d75bf607 --- /dev/null +++ b/src/migrations/scripts/1666104879255-add-unattachedSince.ts @@ -0,0 +1,29 @@ +import { Db } from 'mongodb'; +import { getDb } from '../migrations-utils/db'; +import { DateTime } from 'luxon'; + +export const up = async () => { + const db: Db = await getDb(); + const cursor = db.collection('users').find({}); + let document; + while ((document = await cursor.next())) { + let value: Date; + if (!document.structuresLink || document.structuresLink.length == 0) { + value = DateTime.local(); + } else { + value = null; + } + await db.collection('users').updateOne({ _id: document._id }, [{ $set: { unattachedSince: value } }]); + } + console.log(`Update done : unattachedSince added to users`); +}; + +export const down = async () => { + const db: Db = await getDb(); + const cursor = db.collection('users').find({}); + let document; + while ((document = await cursor.next())) { + await db.collection('users').updateOne({ _id: document._id }, [{ $unset: 'unattachedSince' }]); + } + console.log(`Downgrade done : unattachedSince removed from users`); +}; diff --git a/src/structures/services/structures.service.ts b/src/structures/services/structures.service.ts index 3407a3d5f..f638e0edf 100644 --- a/src/structures/services/structures.service.ts +++ b/src/structures/services/structures.service.ts @@ -583,8 +583,11 @@ export class StructuresService { structure.structureType = null; structure.deletedAt = DateTime.local().setZone('Europe/Paris').toString(); this.anonymizeStructure(structure).save(); - // Remove structure from userModel - this.userService.removeStructureIdFromUsers(structure._id); + // Remove structure from owners (and check if there is a newly unattached user) + const owners = await this.getOwners(structure._id); + owners.forEach((owner) => { + this.userService.removeFromStructureLinked(owner, id); + }); this.sendAdminStructureNotification( structure, this.mailerService.config.templates.structureDeletionNotification.ejs, diff --git a/src/structures/structures.controller.spec.ts b/src/structures/structures.controller.spec.ts index 2e77f0918..8338823da 100644 --- a/src/structures/structures.controller.spec.ts +++ b/src/structures/structures.controller.spec.ts @@ -151,6 +151,7 @@ describe('AuthController', () => { validated: true, hasPersonalOffer: false, }, + unattachedSince: null, }); expect(res).toBeTruthy(); }); @@ -229,6 +230,7 @@ describe('AuthController', () => { validated: true, hasPersonalOffer: false, }, + unattachedSince: null, }); expect(res).toBeTruthy(); res = controller.join('', null); diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts index d62bf74ab..73ddd47df 100644 --- a/src/structures/structures.controller.ts +++ b/src/structures/structures.controller.ts @@ -221,7 +221,7 @@ export class StructuresController { if (!userFromDb || !userFromDb.structuresLink.includes(Types.ObjectId(id))) { throw new HttpException('Invalid User', HttpStatus.NOT_FOUND); } - this.userService.removeFromStructureLinked(userFromDb.email, id); + this.userService.removeFromStructureLinked(userFromDb, id); } @Delete(':id/tempUser/:userId') diff --git a/src/users/dto/create-user.dto.ts b/src/users/dto/create-user.dto.ts index b0bbda7ad..f304639c2 100644 --- a/src/users/dto/create-user.dto.ts +++ b/src/users/dto/create-user.dto.ts @@ -33,6 +33,9 @@ export class CreateUserDto { @IsOptional() structuresLink?: Array<string>; + @IsOptional() + unattachedSince?: Date; + @IsArray() @IsOptional() personalOffers?: PersonalOffer[]; diff --git a/src/users/schemas/user.schema.ts b/src/users/schemas/user.schema.ts index 3c1b9da92..08c9213fa 100644 --- a/src/users/schemas/user.schema.ts +++ b/src/users/schemas/user.schema.ts @@ -52,6 +52,9 @@ export class User { @Prop({ default: null }) structureOutdatedMailSent: Types.ObjectId[]; + @Prop({ default: null }) + unattachedSince: Date; + @Prop({ type: [{ type: Types.ObjectId, ref: 'PersonalOffer' }] }) personalOffers: PersonalOfferDocument[]; diff --git a/src/users/services/users.service.spec.ts b/src/users/services/users.service.spec.ts index 49d9bb9d4..9fbaf7c55 100644 --- a/src/users/services/users.service.spec.ts +++ b/src/users/services/users.service.spec.ts @@ -108,6 +108,7 @@ const mockUser: User = { validated: true, hasPersonalOffer: false, }, + unattachedSince: null, }; describe('UsersService', () => { @@ -311,6 +312,7 @@ describe('UsersService', () => { validated: true, hasPersonalOffer: false, }, + unattachedSince: null, }; const emailDto: EmailChangeDto = { newEmail: 'test.dupont@mail.com', oldEmail: 'jacques.dupont@mii.com' }; //NOSONAR jest.spyOn(service, 'changeUserEmail').mockImplementation(async (): Promise<User> => result); @@ -355,6 +357,7 @@ describe('UsersService', () => { validated: true, hasPersonalOffer: false, }, + unattachedSince: null, }; const token = '9bb3542bdc5ca8801ad4cee00403c1052bc95dee768dcbb65b1f719870578ed79f71f52fdc3e6bf02fd200a72b8b6f56fc26950df30c8cd7e427a485f80181b9'; //NOSONAR diff --git a/src/users/services/users.service.ts b/src/users/services/users.service.ts index edfc5eda6..d2d5b80b5 100644 --- a/src/users/services/users.service.ts +++ b/src/users/services/users.service.ts @@ -20,6 +20,7 @@ import { UpdateDetailsDto } from '../dto/update-details.dto'; import { DescriptionDto } from '../dto/description.dto'; import { IUserRegistry } from '../interfaces/userRegistry.interface'; import { UserRegistrySearchService } from './userRegistry-search.service'; +import { DateTime } from 'luxon'; @Injectable() export class UsersService { @@ -55,7 +56,7 @@ export class UsersService { }); } createUser.password = await this.hashPassword(createUser.password); - + createUser.unattachedSince = DateTime.local(); // Send verification email createUser = await this.verifyUserMail(createUser); await createUser.save(); @@ -150,12 +151,6 @@ export class UsersService { return this.userModel.findById(id).populate('employer').populate('job').select('-password').exec(); } - public async removeStructureIdFromUsers(structureId: Types.ObjectId): Promise<IUser[] | undefined> { - return this.userModel - .updateMany({ structuresLink: { $in: [structureId] } }, { $pull: { structuresLink: structureId } }) - .exec(); - } - public async replaceEmployers( sourceEmployer: EmployerDocument, targetEmployer: EmployerDocument @@ -543,6 +538,7 @@ export class UsersService { if (user) { if (!user.structuresLink.includes(Types.ObjectId(idStructure))) { user.structuresLink.push(Types.ObjectId(idStructure)); + user.unattachedSince = null; await user.save(); return user.structuresLink; } @@ -551,8 +547,7 @@ export class UsersService { throw new HttpException('Invalid user', HttpStatus.NOT_FOUND); } - public async removeFromStructureLinked(userEmail: string, idStructure: string): Promise<Types.ObjectId[]> { - const user = await this.findOne(userEmail, true); + public async removeFromStructureLinked(user: IUser, idStructure: string): Promise<Types.ObjectId[]> { if (!user) { throw new HttpException('Invalid user', HttpStatus.NOT_FOUND); } @@ -562,6 +557,9 @@ export class UsersService { user.structuresLink = user.structuresLink.filter((structureId) => { return !structureId.equals(idStructure); }); + if (user.structuresLink.length == 0) { + user.unattachedSince = DateTime.local(); + } await user.save(); return user.structuresLink; } -- GitLab