Skip to content

Commit 4de1bb0

Browse files
committed
divers pour la validation
1 parent a9b47db commit 4de1bb0

File tree

12 files changed

+217
-107
lines changed

12 files changed

+217
-107
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"ajv": "^8.16.0",
6565
"ajv-errors": "^3.0.0",
6666
"ajv-formats": "^3.0.1",
67+
"ajv-i18n": "^4.2.0",
6768
"argon2": "^0.41.1",
6869
"awesome-phonenumber": "^6.10.0",
6970
"bullmq": "^5.8.2",

src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface MongoosePlugin {
1515
}
1616
export interface ConfigInstance {
1717
application: {
18+
lang: string
1819
logLevel: string;
1920
nameQueue: string;
2021
bodyParser: {
@@ -80,6 +81,7 @@ export interface ConfigInstance {
8081

8182
export default (): ConfigInstance => ({
8283
application: {
84+
lang: process.env['LANG'] || 'en',
8385
logLevel: process.env['SESAME_LOG_LEVEL'] || 'info',
8486
nameQueue: process.env['SESAME_NAME_QUEUE'] || 'sesame',
8587
bodyParser: {

src/management/identities/_dto/_parts/inetOrgPerson.dto.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApiProperty, PartialType } from '@nestjs/swagger';
22
import { Type } from 'class-transformer';
3-
import { IsString, IsEmail, IsOptional, IsArray } from 'class-validator';
3+
import {IsString, IsEmail, IsOptional, IsArray, ValidateIf} from 'class-validator';
44

55
export class inetOrgPersonCreateDto {
66
@IsString()
@@ -56,6 +56,9 @@ export class inetOrgPersonCreateDto {
5656
@IsOptional()
5757
public labeledURI?: string;
5858

59+
@ValidateIf(o => {
60+
return o.mail && o.mail.length > 0;
61+
})
5962
@IsEmail()
6063
@ApiProperty({ required: false })
6164
@IsOptional()

src/management/identities/_dto/identities.dto.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export class IdentitiesCreateDto extends IntersectionType(CustomFieldsDto, Metad
3535
public lifecycle: number;
3636

3737
@IsObject()
38-
@ValidateNested()
3938
@Type(() => inetOrgPersonDto)
4039
@ApiProperty({ type: inetOrgPersonDto })
4140
public inetOrgPerson: inetOrgPersonDto;

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,4 +189,50 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
189189
throw new HttpException('Id not found', 400);
190190
}
191191
}
192+
/**
193+
* Check if mail and uid are unique. If mail is empty it is not checked
194+
* @param data
195+
* @private
196+
*/
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 }] };
202+
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 };
206+
dataDup = await this._model.find(f).exec()
207+
}
208+
if (dataDup.length > 0) {
209+
return false
210+
}else{
211+
return true
212+
}
213+
}
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 };
219+
dataDup = await this._model.countDocuments(f).exec()
220+
}
221+
if (dataDup> 0) {
222+
return false
223+
}else{
224+
return true
225+
}
226+
}
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 };
231+
dataDup = await this._model.countDocuments(f).exec()
232+
if (dataDup > 0) {
233+
return false
234+
}else{
235+
return true
236+
}
237+
}
192238
}

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

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@ export class IdentitiesCrudService extends AbstractIdentitiesService {
1414
): Promise<Document<T, any, T>> {
1515
data = this.transformNullsToString(data);
1616
await this.checkInetOrgPersonJpegPhoto(data);
17-
//recherche si email oy uid deja present
18-
const f: any = { $or: [{ 'inetOrgPerson.uid': data.inetOrgPerson.uid }, { 'inetOrgPerson.mail': data.inetOrgPerson.mail }] };
19-
let dataDup = await this._model.countDocuments(f).exec()
20-
if (dataDup > 0) {
21-
this.logger.error('Identité existante');
17+
if(await this.checkMailAndUid(data) === false){
18+
this.logger.error('Uid ou mail déjà présent dans une autre identité');
2219
throw new HttpException("Uid ou mail déjà présent dans une autre identité", 400);
2320
}
21+
const logPrefix = `Validation [${data.inetOrgPerson.cn}]:`;
22+
this.logger.log(`${logPrefix} Starting inetOrgPerson validation.`);
23+
const check={
24+
objectClasses: ['inetorgperson'],
25+
attributes:{ 'inetorgperson':data.inetOrgPerson}
26+
}
27+
//pour la validation le employeeNumber doit exister on en met un avec une valeur par defaut
28+
check.attributes.inetorgperson.employeeNumber=["1"];
29+
let validations = await this._validation.validate(check);
2430
const created: Document<T, any, T> = await super.create(data, options);
2531
return created;
2632
}
@@ -31,15 +37,29 @@ export class IdentitiesCrudService extends AbstractIdentitiesService {
3137
): Promise<ModifyResult<Query<T, T, any, T>>> {
3238
update = this.transformNullsToString(update);
3339
// noinspection UnnecessaryLocalVariableJS
40+
3441
//TODO : add validation logic here
3542
const logPrefix = `Validation [${update.inetOrgPerson.cn}]:`;
3643
try {
3744
this.logger.log(`${logPrefix} Starting additionalFields transformation.`);
45+
if(update.hasOwnProperty('metadata')){
46+
//suppresion de la clé metadata
47+
delete(update.metadata);
48+
}
49+
3850
await this._validation.transform(update.additionalFields);
39-
this.logger.log(`${logPrefix} Starting additionalFields validation.`);
40-
const validations = await this._validation.validate(update.additionalFields);
51+
52+
this.logger.log(`${logPrefix} Starting inetOrgPerson validation.`);
53+
const check={
54+
objectClasses: ['inetorgperson'],
55+
attributes:{ 'inetorgperson':update.inetOrgPerson}
56+
}
57+
let validationsInetOrg = await this._validation.validate(check);
58+
let validationsAdFields = await this._validation.validate(update.additionalFields);
59+
4160
this.logger.log(`${logPrefix} AdditionalFields validation successful.`);
42-
this.logger.log(`Validations : ${validations}`);
61+
this.logger.log(`Validations InetOrgPerson: ${validationsInetOrg}`);
62+
this.logger.log(`Validations Additional fields: ${validationsAdFields}`);
4363
} catch (error) {
4464
console.log(error);
4565
if (error instanceof ValidationConfigException) {
@@ -55,7 +75,11 @@ export class IdentitiesCrudService extends AbstractIdentitiesService {
5575
throw error; // Rethrow the original error if it's not one of the handled types.
5676
}
5777
}
58-
78+
// check mail and Uid
79+
if(await this.checkMailAndUid(update) === false){
80+
this.logger.error('Uid ou mail déjà présent dans une autre identité');
81+
throw new HttpException("Uid ou mail déjà présent dans une autre identité", 400);
82+
}
5983
// if (update.state === IdentityState.TO_COMPLETE) {
6084
update = { ...update, state: IdentityState.TO_VALIDATE };
6185

@@ -110,4 +134,6 @@ export class IdentitiesCrudService extends AbstractIdentitiesService {
110134
const deleted = await super.delete(_id, options);
111135
return deleted;
112136
}
137+
138+
113139
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +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-
const validations = await this._validation.validate(data.additionalFields);
58+
let validations = await this._validation.validate(data.additionalFields);
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+
}
5966
this.logger.log(`${logPrefix} AdditionalFields validation successful.`);
6067
this.logger.log(`Validations : ${JSON.stringify(validations)}`);
6168
crushedUpdate['state'] = IdentityState.TO_VALIDATE;

src/management/identities/validations/_config/validSchema.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ const validSchema = {
3131
enum: ['date', 'email','number','time','date-time','duration','uri','uri-reference','hostname','ipv4','ipv6','regex','uuid'],
3232
errorMessage: "Format invalide",
3333
},
34+
contains: {
35+
type: 'object',
36+
errorMessage: "Le champ 'required' doit être un booléen.",
37+
},
3438
items: {
3539
type: 'object',
3640
errorMessage: "Le champ 'required' doit être un booléen.",

src/management/identities/validations/identities.validation.service.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import { diff } from 'radash';
66
import { AdditionalFieldsPart } from '../_schemas/_parts/additionalFields.part.schema';
77
import Ajv from 'ajv';
88
import addFormats from 'ajv-formats';
9+
import localize from 'ajv-i18n';
910
import validSchema from './_config/validSchema';
1011
import ajvErrors from 'ajv-errors';
1112
import { ValidationConfigException, ValidationSchemaException } from '~/_common/errors/ValidationException';
1213
import { additionalFieldsPartDto } from '../_dto/_parts/additionalFields.dto';
14+
import {ConfigService} from "@nestjs/config";
1315

1416
/**
1517
* Service responsible for validating identities.
@@ -20,12 +22,13 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
2022
private validateSchema;
2123
private logger: Logger;
2224

23-
public constructor() {
25+
public constructor(protected config: ConfigService) {
2426
addFormats(this.ajv);
2527
ajvErrors(this.ajv);
2628
this.ajv.addFormat('number', /^\d*$/);
2729
this.validateSchema = this.ajv.compile(validSchema);
2830
this.logger = new Logger(IdentitiesValidationService.name);
31+
2932
}
3033

3134
public onApplicationBootstrap(): void {
@@ -57,14 +60,15 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
5760
}
5861

5962
private resolveConfigPath(key: string): string | null {
60-
const hardConfigPath = `./src/management/identities/validations/_config/${key}.yml`;
63+
//lecture deja dans le repertoire /validation pour les schemas non modifiables
64+
const hardConfigPath = `./validation/${key}.yml`;
6165
const dynamicConfigPath = `./configs/identities/validations/${key}.yml`;
62-
if (existsSync(dynamicConfigPath)) {
63-
return dynamicConfigPath;
64-
}
6566
if (existsSync(hardConfigPath)) {
6667
return hardConfigPath;
6768
}
69+
if (existsSync(dynamicConfigPath)) {
70+
return dynamicConfigPath;
71+
}
6872
return null;
6973
}
7074

@@ -309,7 +313,23 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
309313
throw new BadRequestException('schema for ' + key + ' does not exist');
310314
}
311315
const schema: any = parse(readFileSync(path, 'utf8'));
312-
316+
// mise de min length et minItems dans les champs requis
317+
if (schema.hasOwnProperty('required')) {
318+
for (const required of schema['required']) {
319+
switch(schema['properties'][required]['type']){
320+
case 'array':
321+
if (!schema['properties'][required]['minItems']){
322+
schema['properties'][required]['minItems']=1
323+
}
324+
break;
325+
case 'string':
326+
if (!schema['properties'][required]['minLength']){
327+
schema['properties'][required]['minLength']=1
328+
}
329+
break;
330+
}
331+
}
332+
}
313333
for (const [index, def] of Object.entries(schema?.properties || {})) {
314334
if (typeof data[key][index] === 'undefined' || data[key][index] === null) {
315335
switch ((def as any).type) {
@@ -342,6 +362,7 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
342362
const ok = await this.ajv.validate(schema, data[key]);
343363
if (ok === false) {
344364
const retErrors = {};
365+
await this.translateAjv(this.ajv.errors)
345366
for (const err of this.ajv.errors) {
346367
retErrors[err['instancePath'].substring(1)] = err['instancePath'].substring(1) + ' ' + err['message']
347368
}
@@ -409,9 +430,9 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
409430
this.logger.debug(['findOne', JSON.stringify(Object.values(arguments))].join(' '));
410431
let filePath = '';
411432
if (schema === 'inetorgperson') {
412-
filePath = './validation/inetorgperson.json';
433+
filePath = './validation/inetorgperson.yml';
413434
if (!existsSync(filePath)) {
414-
const message = `File not found /validation/inetorgperson.json`;
435+
const message = `File not found /validation/inetorgperson.yml`;
415436
throw new ValidationConfigException({ message });
416437
}
417438
} else {
@@ -423,4 +444,15 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
423444
}
424445
return parse(readFileSync(filePath, 'utf-8'));
425446
}
447+
private async translateAjv(messages){
448+
switch(this.config.get('application.lang')){
449+
case 'en':
450+
break
451+
case 'fr':
452+
case 'fr_FR.UTF-8':
453+
case 'fr_FR':
454+
localize.fr(messages)
455+
break
456+
}
457+
}
426458
}

0 commit comments

Comments
 (0)