Skip to content

Commit bea5896

Browse files
committed
Refactor identity service methods for improved readability and maintainability
1 parent 62cb97e commit bea5896

File tree

2 files changed

+82
-62
lines changed

2 files changed

+82
-62
lines changed

src/management/identities/abstract-identities.service.ts

Lines changed: 74 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
import {BadRequestException, forwardRef, HttpException, Inject, Injectable} from '@nestjs/common';
2-
import {InjectModel} from '@nestjs/mongoose';
3-
import {Document, Model, ModifyResult, Query, Types} from 'mongoose';
4-
import {AbstractServiceSchema} from '~/_common/abstracts/abstract.service.schema';
5-
import {AbstractSchema} from '~/_common/abstracts/schemas/abstract.schema';
6-
import {ValidationConfigException, ValidationSchemaException} from '~/_common/errors/ValidationException';
7-
import {IdentitiesUpsertDto} from './_dto/identities.dto';
8-
import {IdentityState} from './_enums/states.enum';
9-
import {Identities} from './_schemas/identities.schema';
10-
import {IdentitiesValidationService} from './validations/identities.validation.service';
11-
import {FactorydriveService} from '@the-software-compagny/nestjs_module_factorydrive';
12-
import {BackendsService} from '~/core/backends/backends.service';
13-
import {construct, omit} from 'radash';
14-
import {toPlainAndCrush} from '~/_common/functions/to-plain-and-crush';
15-
import {createHash} from 'node:crypto';
16-
import {PasswdadmService} from "~/settings/passwdadm.service";
17-
import {DataStatusEnum} from "~/management/identities/_enums/data-status";
18-
import {JobState} from "~/core/jobs/_enums/state.enum";
1+
import { BadRequestException, forwardRef, HttpException, Inject, Injectable } from '@nestjs/common';
2+
import { InjectModel } from '@nestjs/mongoose';
3+
import { Document, Model, ModifyResult, Query, Types } from 'mongoose';
4+
import { AbstractServiceSchema } from '~/_common/abstracts/abstract.service.schema';
5+
import { AbstractSchema } from '~/_common/abstracts/schemas/abstract.schema';
6+
import { ValidationConfigException, ValidationSchemaException } from '~/_common/errors/ValidationException';
7+
import { IdentitiesUpsertDto } from './_dto/identities.dto';
8+
import { IdentityState } from './_enums/states.enum';
9+
import { Identities } from './_schemas/identities.schema';
10+
import { IdentitiesValidationService } from './validations/identities.validation.service';
11+
import { FactorydriveService } from '@the-software-compagny/nestjs_module_factorydrive';
12+
import { BackendsService } from '~/core/backends/backends.service';
13+
import { construct, omit } from 'radash';
14+
import { toPlainAndCrush } from '~/_common/functions/to-plain-and-crush';
15+
import { createHash } from 'node:crypto';
16+
import { PasswdadmService } from "~/settings/passwdadm.service";
17+
import { DataStatusEnum } from "~/management/identities/_enums/data-status";
18+
import { JobState } from "~/core/jobs/_enums/state.enum";
1919

2020
@Injectable()
2121
export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
@@ -121,27 +121,40 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
121121
return updated as unknown as ModifyResult<Query<T, T, any, T>>;
122122
}
123123

124+
private stableStringify(obj) {
125+
if (typeof obj !== "object" || obj === null) {
126+
return JSON.stringify(obj);
127+
}
128+
129+
if (Array.isArray(obj)) {
130+
return `[${obj.map(this.stableStringify).join(',')}]`;
131+
}
132+
133+
return `{${Object.keys(obj).sort().map(key =>
134+
JSON.stringify(key) + ':' + this.stableStringify(obj[key])
135+
).join(',')}}`;
136+
}
137+
124138
protected async previewFingerprint(identity: any): Promise<string> {
125139
const additionalFields = omit(identity.additionalFields, ['validations']);
126-
const data = JSON.stringify(
127-
construct(
128-
omit(
129-
toPlainAndCrush({
130-
inetOrgPerson: identity.inetOrgPerson,
131-
additionalFields,
132-
}) as any,
133-
[
134-
//TODO: add configurable fields to exclude
135-
/* 'additionalFields.attributes.supannPerson.supannOIDCGenre' */
136-
],
137-
),
140+
const data = construct(
141+
omit(
142+
toPlainAndCrush({
143+
inetOrgPerson: identity.inetOrgPerson,
144+
additionalFields,
145+
}) as any,
146+
[
147+
//TODO: add configurable fields to exclude
148+
/* 'additionalFields.attributes.supannPerson.supannOIDCGenre' */
149+
],
138150
),
139151
);
140152

141153
const hash = createHash('sha256');
142-
hash.update(data);
154+
hash.update(this.stableStringify(data));
143155
return hash.digest('hex').toString();
144156
}
157+
145158
public async activation(id: string, status: DataStatusEnum) {
146159
//recherche de l'identité
147160
let identity: Identities = null;
@@ -164,19 +177,20 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
164177
if (statusChanged) {
165178
// le dataStaus à changé on envoye l info aux backend et on enregistre l identité
166179
// Envoi du status au backend
167-
let statusBackend=true
168-
if (status == DataStatusEnum.INACTIVE || status == DataStatusEnum.PASSWORDNEEDTOBECHANGED){
169-
statusBackend= false
180+
let statusBackend = true
181+
if (status == DataStatusEnum.INACTIVE || status == DataStatusEnum.PASSWORDNEEDTOBECHANGED) {
182+
statusBackend = false
170183
}
171-
const result = await this.backends.activationIdentity(identity._id.toString(),statusBackend);
184+
const result = await this.backends.activationIdentity(identity._id.toString(), statusBackend);
172185
if (result.state === JobState.COMPLETED) {
173186
await super.update(identity._id, identity);
174187
} else {
175188
throw new HttpException('Backend failed', 400);
176189
}
177190
}
178191
}
179-
public async askToChangePassword(id: string){
192+
193+
public async askToChangePassword(id: string) {
180194
try {
181195
const identity = await this.findById<Identities>(id);
182196
if (identity.dataStatus === DataStatusEnum.ACTIVE) {
@@ -189,49 +203,52 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
189203
throw new HttpException('Id not found', 400);
190204
}
191205
}
206+
192207
/**
193208
* Check if mail and uid are unique. If mail is empty it is not checked
194209
* @param data
195210
* @private
196211
*/
197-
protected async checkMailAndUid(data): Promise <boolean> {
198-
let dataDup=[];
199-
if (data.inetOrgPerson.hasOwnProperty('mail') && data.inetOrgPerson.mail !== ''){
200-
const id=new Types.ObjectId(data['_id']);
201-
const f: any = { '_id': {$ne : id},$or: [{ 'inetOrgPerson.uid': data.inetOrgPerson.uid }, { 'inetOrgPerson.mail': data.inetOrgPerson.mail }] };
212+
protected async checkMailAndUid(data): Promise<boolean> {
213+
let dataDup = [];
214+
if (data.inetOrgPerson.hasOwnProperty('mail') && data.inetOrgPerson.mail !== '') {
215+
const id = new Types.ObjectId(data['_id']);
216+
const f: any = { '_id': { $ne: id }, $or: [{ 'inetOrgPerson.uid': data.inetOrgPerson.uid }, { 'inetOrgPerson.mail': data.inetOrgPerson.mail }] };
202217
dataDup = await this._model.find(f).exec()
203-
}else{
204-
const id=new Types.ObjectId(data['_id']);
205-
const f: any = { '_id': {$ne : id},'inetOrgPerson.uid': data.inetOrgPerson.uid };
218+
} else {
219+
const id = new Types.ObjectId(data['_id']);
220+
const f: any = { '_id': { $ne: id }, 'inetOrgPerson.uid': data.inetOrgPerson.uid };
206221
dataDup = await this._model.find(f).exec()
207222
}
208223
if (dataDup.length > 0) {
209224
return false
210-
}else{
225+
} else {
211226
return true
212227
}
213228
}
214-
protected async checkMail(data): Promise <boolean> {
215-
let dataDup=0;
216-
if (data.inetOrgPerson.hasOwnProperty('mail') && data.inetOrgPerson.mail !== ''){
217-
const id=new Types.ObjectId(data['_id']);
218-
const f: any = { '_id': {$ne : id},'inetOrgPerson.mail': data.inetOrgPerson.mail };
229+
230+
protected async checkMail(data): Promise<boolean> {
231+
let dataDup = 0;
232+
if (data.inetOrgPerson.hasOwnProperty('mail') && data.inetOrgPerson.mail !== '') {
233+
const id = new Types.ObjectId(data['_id']);
234+
const f: any = { '_id': { $ne: id }, 'inetOrgPerson.mail': data.inetOrgPerson.mail };
219235
dataDup = await this._model.countDocuments(f).exec()
220236
}
221-
if (dataDup> 0) {
237+
if (dataDup > 0) {
222238
return false
223-
}else{
239+
} else {
224240
return true
225241
}
226242
}
227-
protected async checkUid(data): Promise <boolean> {
228-
let dataDup=0;
229-
const id=new Types.ObjectId(data['_id']);
230-
const f: any = {'_id': {$ne : id}, 'inetOrgPerson.uid': data.inetOrgPerson.uid };
243+
244+
protected async checkUid(data): Promise<boolean> {
245+
let dataDup = 0;
246+
const id = new Types.ObjectId(data['_id']);
247+
const f: any = { '_id': { $ne: id }, 'inetOrgPerson.uid': data.inetOrgPerson.uid };
231248
dataDup = await this._model.countDocuments(f).exec()
232249
if (dataDup > 0) {
233250
return false
234-
}else{
251+
} else {
235252
return true
236253
}
237254
}

src/management/identities/identities-upsert.service.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@ export class IdentitiesUpsertService extends AbstractIdentitiesService {
5555
this.logger.log(`${logPrefix} Starting additionalFields transformation.`);
5656
await this._validation.transform(data.additionalFields);
5757
this.logger.log(`${logPrefix} Starting additionalFields validation.`);
58-
5958
let validations = await this._validation.validate(data.additionalFields,true);
59+
//validation email and uid
60+
if (await this.checkMail(data) === false) {
61+
validations['inetOrgPerson.mail'] = "Email déjà présent dans une autre identité"
62+
}
63+
if (await this.checkUid(data) === false) {
64+
validations['inetOrgPerson.uid'] = "Uid déjà présent dans une autre identité"
65+
}
6066
this.logger.log(`${logPrefix} AdditionalFields validation successful.`);
6167
this.logger.log(`Validations : ${JSON.stringify(validations)}`);
6268
crushedUpdate['state'] = IdentityState.TO_VALIDATE;
@@ -77,10 +83,7 @@ export class IdentitiesUpsertService extends AbstractIdentitiesService {
7783
}
7884

7985
const fingerprint = await this.previewFingerprint(
80-
construct({
81-
...toPlainAndCrush(identity?.toJSON()),
82-
...crushedUpdate,
83-
}),
86+
data,
8487
);
8588

8689
await this.checkFingerprint(filters, fingerprint, extra);

0 commit comments

Comments
 (0)