1- import { Injectable , Logger , OnApplicationBootstrap } from '@nestjs/common' ;
2- import { parse } from 'yaml' ;
3- import { existsSync , readFileSync , readdirSync , writeFileSync } from 'fs' ;
4- import { ConfigObjectSchemaDTO } from './_dto/config.dto' ;
5- import { diff } from 'radash' ;
6- import { AdditionalFieldsPart } from '../_schemas/_parts/additionalFields.part.schema' ;
1+ import { Injectable , Logger , OnApplicationBootstrap } from '@nestjs/common' ;
2+ import { parse } from 'yaml' ;
3+ import { existsSync , readFileSync , readdirSync , writeFileSync } from 'fs' ;
4+ import { ConfigObjectSchemaDTO } from './_dto/config.dto' ;
5+ import { diff } from 'radash' ;
6+ import { AdditionalFieldsPart } from '../_schemas/_parts/additionalFields.part.schema' ;
77import Ajv from 'ajv' ;
8- import { buildYup } from 'schema-to-yup' ;
8+ import { buildYup } from 'schema-to-yup' ;
99import validSchema from './_config/validSchema' ;
1010import ajvErrors from 'ajv-errors' ;
11- import { ValidationConfigException , ValidationSchemaException } from '~/_common/errors/ValidationException' ;
12- import { additionalFieldsPartDto } from '../_dto/_parts/additionalFields.dto' ;
11+ import { ValidationConfigException , ValidationSchemaException } from '~/_common/errors/ValidationException' ;
12+ import { additionalFieldsPartDto } from '../_dto/_parts/additionalFields.dto' ;
1313
1414
1515/**
1616 * Service responsible for validating identities.
1717 */
1818@Injectable ( )
1919export class IdentitiesValidationService implements OnApplicationBootstrap {
20- private ajv : Ajv = new Ajv ( { allErrors : true } ) ;
20+ private ajv : Ajv = new Ajv ( { allErrors : true } ) ;
2121 private validateSchema ;
2222 private logger : Logger ;
2323
@@ -66,7 +66,8 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
6666 }
6767 return null ;
6868 }
69- public async transform ( data : AdditionalFieldsPart | additionalFieldsPartDto ) : Promise < AdditionalFieldsPart | additionalFieldsPartDto > {
69+
70+ public async transform ( data : AdditionalFieldsPart | additionalFieldsPartDto ) : Promise < AdditionalFieldsPart | additionalFieldsPartDto > {
7071 if ( ! data . objectClasses ) {
7172 data . objectClasses = [ ] ;
7273 }
@@ -79,9 +80,87 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
7980 const attributes = data . attributes || { } ;
8081 const attributesKeys = Object . keys ( attributes ) ;
8182 const validations = { } ;
82-
83+ for ( const key of attributesKeys ) {
84+ await this . transformAttribute ( key , attributes [ key ] , attributes ) ;
85+ }
8386 return data
8487 }
88+
89+ /**
90+ * Transform data following schema validation
91+ * @param key
92+ * @param attribute
93+ * @param data
94+ */
95+ public async transformAttribute ( key : string , attribute : any , data : any ) {
96+
97+ const path = this . resolveConfigPath ( key ) ;
98+ const schema : any = parse ( readFileSync ( path , 'utf8' ) ) ;
99+ this . logger . debug ( `Additionalfields object transformation: ${ JSON . stringify ( data [ key ] ) } ` ) ;
100+ for ( const [ index , def ] of Object . entries ( schema ?. properties || { } ) ) {
101+ switch ( ( def as any ) . type ) {
102+ case 'array' :
103+ if ( typeof data [ key ] [ index ] === 'undefined' || data [ key ] [ index ] === null ) {
104+ data [ key ] [ index ] = [ ] ;
105+ }
106+ if ( ! ( data [ key ] [ index ] instanceof Array ) ) {
107+ data [ key ] [ index ] = [ data [ key ] [ index ] ] ;
108+ }
109+ if ( typeof def [ 'items' ] !== 'undefined' ) {
110+ //test si toutes les valeurs sont du bon type
111+ for ( const elems in data [ key ] [ index ] ) {
112+ if ( typeof data [ key ] [ index ] [ elems ] !== def [ 'items' ] [ 'type' ] ) {
113+ switch ( def [ 'items' ] [ 'type' ] ) {
114+ case 'string' :
115+ data [ key ] [ index ] [ elems ] = String ( data [ key ] [ index ] [ elems ] ) ;
116+ break ;
117+ case 'number' :
118+ data [ key ] [ index ] [ elems ] = await this . transformNumber ( data [ key ] [ index ] [ elems ] )
119+ break ;
120+ }
121+ }
122+ }
123+ }
124+ break ;
125+ case 'number' :
126+ if ( typeof data [ key ] [ index ] === 'undefined' || data [ key ] [ index ] === null ) {
127+ data [ key ] [ index ] = 0 ;
128+ }
129+ if ( typeof data [ key ] [ index ] !== 'number' ) {
130+ //on ne convertit pas si la chaine est vide
131+ if ( typeof data [ key ] [ index ] === 'string' && data [ key ] [ index ] !== "" ) {
132+ data [ key ] [ index ] = await this . transformNumber ( data [ key ] [ index ] )
133+ }
134+ }
135+ break ;
136+ case 'string' :
137+ if ( typeof data [ key ] [ index ] === 'undefined' || data [ key ] [ index ] === null ) {
138+ data [ key ] [ index ] = "" ;
139+ }
140+ if ( typeof data [ key ] [ index ] !== 'string' ) {
141+ data [ key ] [ index ] = String ( data [ key ] [ index ] ) ;
142+ }
143+ break ;
144+ }
145+ }
146+ }
147+
148+ /**
149+ * transform string in number if it is possible
150+ * @param value
151+ * @private
152+ */
153+ private async transformNumber ( value ) {
154+ if ( typeof value === 'string' ) {
155+ const tr = parseFloat ( value )
156+ if ( ! isNaN ( tr ) ) {
157+ return tr
158+ } else {
159+ return 0
160+ }
161+ }
162+ return value
163+ }
85164 /**
86165 * Validates additional fields for identities.
87166 * @param data - The additional fields data to validate.
@@ -137,7 +216,7 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
137216 }
138217
139218 if ( reject ) {
140- throw new ValidationConfigException ( { validations } ) ;
219+ throw new ValidationConfigException ( { validations} ) ;
141220 }
142221
143222 // Validate each attribute
@@ -152,9 +231,9 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
152231 }
153232
154233 if ( reject ) {
155- throw new ValidationSchemaException ( { validations } ) ;
234+ throw new ValidationSchemaException ( { validations} ) ;
156235 }
157- return Promise . resolve ( { message : 'Validation succeeded' } ) ;
236+ return Promise . resolve ( { message : 'Validation succeeded' } ) ;
158237 }
159238
160239 /**
@@ -191,9 +270,9 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
191270
192271 this . logger . debug ( `Additionalfields object validation: ${ JSON . stringify ( data [ key ] ) } ` ) ;
193272
194- const yupSchema = buildYup ( schema , { noSortEdges : true } ) ;
273+ const yupSchema = buildYup ( schema , { noSortEdges : true } ) ;
195274 try {
196- await yupSchema . validate ( attribute , { strict : true , abortEarly : false } ) ;
275+ await yupSchema . validate ( attribute , { strict : true , abortEarly : false } ) ;
197276 return null ;
198277 } catch ( error ) {
199278 return error . inner . reduce ( ( acc , err ) => {
@@ -204,7 +283,7 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
204283 }
205284
206285 public async findAll ( ) : Promise < any > {
207- this . logger . debug ( [ 'findAll' , JSON . stringify ( Object . values ( { ...arguments } ) ) ] . join ( ' ' ) ) ;
286+ this . logger . debug ( [ 'findAll' , JSON . stringify ( Object . values ( { ...arguments } ) ) ] . join ( ' ' ) ) ;
208287 const hardConfigPath = './src/management/identities/validations/_config' ;
209288 const dynamicConfigPath = './configs/identities/validations' ;
210289 // Retrieve files from each directory and tag them with their source
@@ -253,7 +332,7 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
253332 const filePath = `${ fileObj . path } /${ fileObj . file } ` ;
254333 const data = parse ( readFileSync ( filePath , 'utf-8' ) ) ;
255334 const key = fileObj . file . replace ( '.yml' , '' ) ;
256- result . push ( { [ key ] : data , source : fileObj . source , name : key } ) ;
335+ result . push ( { [ key ] : data , source : fileObj . source , name : key } ) ;
257336 }
258337 return [ result , files . length ] ;
259338 }
@@ -265,13 +344,13 @@ export class IdentitiesValidationService implements OnApplicationBootstrap {
265344 filePath = './validation/inetorgperson.json' ;
266345 if ( ! existsSync ( filePath ) ) {
267346 const message = `File not found /validation/inetorgperson.json` ;
268- throw new ValidationConfigException ( { message } ) ;
347+ throw new ValidationConfigException ( { message} ) ;
269348 }
270349 } else {
271350 filePath = this . resolveConfigPath ( schema ) ;
272351 if ( ! existsSync ( filePath ) ) {
273352 const message = `File not found: ${ filePath } ` ;
274- throw new ValidationConfigException ( { message } ) ;
353+ throw new ValidationConfigException ( { message} ) ;
275354 }
276355 }
277356 return parse ( readFileSync ( filePath , 'utf-8' ) ) ;
0 commit comments