Skip to content

Commit a314a96

Browse files
Merge pull request #29 from Libertech-FR/25-gestion-ui-jsonschema
25 gestion UI jsonschema
2 parents 041b3f8 + 5806c31 commit a314a96

20 files changed

+2047
-2048
lines changed

Dockerfile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ RUN yarn install \
1616
--non-interactive \
1717
--production=false
1818

19-
RUN apt-get update -y \
20-
&& apt-get install -y python3
21-
2219
RUN yarn run build
2320

2421
FROM node:18-bookworm-slim AS production
@@ -51,7 +48,9 @@ RUN apt clean -y \
5148
git \
5249
jq \
5350
nano \
54-
openssl
51+
openssl \
52+
python3 \
53+
build-essential
5554

5655
RUN yarn install \
5756
--prefer-offline \

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
include .env
21
APP_PORT = 4002
32
IMG_NAME = "ghcr.io/libertech-fr/sesame-orchestrator"
43
BASE_NAME = "sesame"
54
APP_NAME = "sesame-orchestrator"
65
PLATFORM = "linux/amd64"
6+
include .env
77

88
.DEFAULT_GOAL := help
99
help:
@@ -76,7 +76,7 @@ dbs: ## Start databases
7676
--health-retries=3 \
7777
--health-cmd="redis-cli ping || exit 1" \
7878
redis || true
79-
@docker exec -it $(BASE_NAME)-mongodb mongosh --eval "rs.initiate({_id: 'rs0', members: [{_id: 0, host: '127.0.0.1:27017'}]})" || true
79+
@docker exec -it $(BASE_NAME)-mongodb mongosh --eval "rs.initiate({_id: \"rs0\", members: [{_id: 0, host: \"$(BASE_NAME)-mongodb\"}]})" || true
8080

8181
stop: ## Stop the container
8282
@docker stop $(APP_NAME) || true

src/_common/abstracts/abstract.queue.processor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Queue, QueueEvents } from 'bullmq';
22
import { AbstractService, AbstractServiceContext } from './abstract.service';
3-
import { Redis, getRedisConnectionToken } from '@nestjs-modules/ioredis';
3+
import { getRedisConnectionToken } from '@nestjs-modules/ioredis';
4+
import { Redis } from 'ioredis';
45
import { OnModuleInit } from '@nestjs/common';
56
import { ConfigService } from '@nestjs/config';
67

src/_common/abstracts/abstract.service.schema.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
FilterQuery,
55
Model,
66
ModifyResult,
7+
MongooseBaseQueryOptions,
78
ProjectionType,
89
Query,
910
QueryOptions,
@@ -15,6 +16,7 @@ import { EventEmitterSeparator } from '~/_common/constants/event-emitter.constan
1516
import { AbstractService, AbstractServiceContext } from './abstract.service';
1617
import { ServiceSchemaInterface } from './interfaces/service.schema.interface';
1718
import { AbstractSchema } from './schemas/abstract.schema';
19+
import mongodb from 'mongodb';
1820

1921
@Injectable()
2022
export abstract class AbstractServiceSchema extends AbstractService implements ServiceSchemaInterface {
@@ -39,7 +41,7 @@ export abstract class AbstractServiceSchema extends AbstractService implements S
3941
return await this._model.find<Query<Array<T>, T, any, T>>(filter, projection, options).exec()
4042
}
4143

42-
public async count<T extends AbstractSchema | Document>(filter?: FilterQuery<T>, options?: QueryOptions<T>): Promise<number> {
44+
public async count<T extends AbstractSchema | Document>(filter?: FilterQuery<T>, options?: (mongodb.CountOptions & MongooseBaseQueryOptions<T>) | null): Promise<number> {
4345
//TODO: add event emitter
4446
this.logger.debug(['count', JSON.stringify(Object.values(arguments))].join(' '))
4547
return await this._model.countDocuments(filter, options).exec()
@@ -243,7 +245,7 @@ export abstract class AbstractServiceSchema extends AbstractService implements S
243245
}
244246
}
245247
return updated
246-
}
248+
}
247249

248250
public async upsert<T extends AbstractSchema | Document>(
249251
filter: FilterQuery<T>,
@@ -299,7 +301,7 @@ export abstract class AbstractServiceSchema extends AbstractService implements S
299301

300302
return result;
301303
}
302-
304+
303305

304306
public async delete<T extends AbstractSchema | Document>(_id: Types.ObjectId | any, options?: QueryOptions<T> | null | undefined): Promise<Query<T, T, any, T>> {
305307
this.logger.debug(['delete', JSON.stringify(Object.values(arguments))].join(' '))

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,10 @@ export class additionalFieldsPartDto {
1414
name: 'attributes',
1515
})
1616
attributes: { [key: string]: any };
17+
18+
@ApiProperty({
19+
type: 'object',
20+
name: 'validations',
21+
})
22+
validations?: { [key: string]: { [key: string]: string } };
1723
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import { IdentityState } from '../_enums/states.enum';
55
import { IdentityLifecycle } from '../_enums/lifecycle.enum';
66
import { Type } from 'class-transformer';
77
import { additionalFieldsPartDto } from './_parts/additionalFields.dto';
8+
import { MetadataDto } from '~/_common/abstracts/dto/metadata.dto';
89

9-
export class IdentitiesCreateDto {
10+
export class IdentitiesCreateDto extends MetadataDto {
1011
@IsNumber()
1112
@IsEnum(IdentityState)
1213
@ApiProperty({ enum: IdentityState })

src/management/identities/identities.controller.ts

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -121,25 +121,28 @@ export class IdentitiesController extends AbstractController {
121121
@Res() res: Response,
122122
@SearchFilterSchema() searchFilterSchema: FilterSchema,
123123
@SearchFilterOptions() searchFilterOptions: FilterOptions,
124-
): Promise<Response> {
125-
try {
126-
const [data, total] = await this._service.findAndCount(
127-
searchFilterSchema,
128-
IdentitiesController.projection,
129-
searchFilterOptions,
130-
);
131-
return res.status(HttpStatus.OK).json({
132-
statusCode: HttpStatus.OK,
133-
total,
134-
data,
135-
});
136-
} catch (error) {
137-
return res.status(HttpStatus.BAD_REQUEST).json({
138-
statusCode: HttpStatus.BAD_REQUEST,
139-
message: error.message,
140-
validations: error.validations,
141-
});
142-
}
124+
): Promise<
125+
Response<
126+
{
127+
statusCode: number;
128+
data?: Document<Identities, any, Identities>;
129+
total?: number;
130+
message?: string;
131+
validations?: MixedValue;
132+
},
133+
any
134+
>
135+
> {
136+
const [data, total] = await this._service.findAndCount(
137+
searchFilterSchema,
138+
IdentitiesController.projection,
139+
searchFilterOptions,
140+
);
141+
return res.status(HttpStatus.OK).json({
142+
statusCode: HttpStatus.OK,
143+
total,
144+
data,
145+
});
143146
}
144147

145148
@Get(':_id([0-9a-fA-F]{24})')
Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { HttpException, Logger, Module } from '@nestjs/common';
1+
import { Module } from '@nestjs/common';
22
import { MongooseModule } from '@nestjs/mongoose';
3-
import { IdentitiesSchema, Identities } from './_schemas/identities.schema';
3+
import { Identities, IdentitiesSchema } from './_schemas/identities.schema';
44
import { IdentitiesService } from './identities.service';
55
import { IdentitiesController } from './identities.controller';
66
import { IdentitiesValidationService } from './validations/identities.validation.service';
77
import { IdentitiesValidationModule } from './validations/identities.validation.module';
8-
import { IdentityState } from './_enums/states.enum';
9-
import { ValidationConfigException, ValidationSchemaException } from '~/_common/errors/ValidationException';
8+
import { IdentitiesJsonformsService } from './jsonforms/identities.jsonforms.service';
9+
import { IdentitiesJsonformsModule } from './jsonforms/identities.jsonforms.module';
1010
import { APP_FILTER } from '@nestjs/core';
1111
import { IdentitiesValidationFilter } from '~/_common/filters/identities-validation.filter';
1212

@@ -15,32 +15,9 @@ import { IdentitiesValidationFilter } from '~/_common/filters/identities-validat
1515
MongooseModule.forFeatureAsync([
1616
{
1717
name: Identities.name,
18-
imports: [IdentitiesValidationModule],
19-
inject: [IdentitiesValidationService],
20-
useFactory: (validationService: IdentitiesValidationService) => {
21-
const schema = IdentitiesSchema;
22-
23-
schema.pre('validate', async function (next) {
24-
const logPrefix = `Validation [${this.inetOrgPerson.cn}]:`;
25-
try {
26-
Logger.log(`${logPrefix} Starting additionalFields validation.`);
27-
await validationService.validate(this.additionalFields);
28-
Logger.log(`${logPrefix} AdditionalFields validation successful.`);
29-
} catch (error) {
30-
handleValidationError(error, this, logPrefix);
31-
}
32-
next();
33-
});
34-
35-
schema.pre('save', async function (next) {
36-
if (this.state === IdentityState.TO_CREATE) {
37-
this.state = IdentityState.TO_VALIDATE;
38-
}
39-
next();
40-
});
41-
42-
return schema;
43-
},
18+
imports: [IdentitiesValidationModule, IdentitiesJsonformsModule],
19+
inject: [IdentitiesValidationService, IdentitiesJsonformsService],
20+
useFactory: () => IdentitiesSchema,
4421
},
4522
]),
4623
],
@@ -51,29 +28,8 @@ import { IdentitiesValidationFilter } from '~/_common/filters/identities-validat
5128
provide: APP_FILTER,
5229
useClass: IdentitiesValidationFilter,
5330
},
31+
IdentitiesJsonformsService,
5432
],
5533
controllers: [IdentitiesController],
5634
})
5735
export class IdentitiesModule {}
58-
59-
function handleValidationError(error: Error | HttpException, identity: Identities, logPrefix: string) {
60-
if (error instanceof ValidationConfigException) {
61-
Logger.error(`${logPrefix} Validation config error. ${JSON.stringify(error.getValidations())}`);
62-
throw new ValidationConfigException(error.getPayload());
63-
}
64-
65-
if (error instanceof ValidationSchemaException) {
66-
Logger.warn(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
67-
if (identity.state === IdentityState.TO_CREATE) {
68-
Logger.warn(`${logPrefix} State set to TO_COMPLETE.`);
69-
identity.state = IdentityState.TO_COMPLETE;
70-
identity.additionalFields.validations = error.getValidations();
71-
} else {
72-
Logger.error(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
73-
throw new ValidationSchemaException(error.getPayload());
74-
}
75-
} else {
76-
Logger.error(`${logPrefix} Unhandled error: ${error.message}`);
77-
throw error; // Rethrow the original error if it's not one of the handled types.
78-
}
79-
}

src/management/identities/identities.service.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ export class IdentitiesService extends AbstractServiceSchema {
3434
const logPrefix = `Validation [${data.inetOrgPerson.cn}]:`;
3535
data.additionalFields.validations = {};
3636
try {
37-
Logger.log(`${logPrefix} Starting additionalFields validation.`);
37+
this.logger.log(`${logPrefix} Starting additionalFields validation.`);
3838
const validations = await this._validation.validate(data.additionalFields);
39-
Logger.log(`${logPrefix} AdditionalFields validation successful.`);
40-
Logger.log(`Validations : ${validations}`);
39+
this.logger.log(`${logPrefix} AdditionalFields validation successful.`);
40+
this.logger.log(`Validations : ${validations}`);
4141
data.state = IdentityState.TO_VALIDATE;
4242
} catch (error) {
4343
data = this.handleValidationError(error, data, logPrefix);
@@ -46,7 +46,7 @@ export class IdentitiesService extends AbstractServiceSchema {
4646
//TODO: ameliorer la logique d'upsert
4747
const identity = await this._model.findOne({ 'inetOrgPerson.uid': data.inetOrgPerson.uid });
4848
if (identity) {
49-
Logger.log(`${logPrefix} Identity already exists. Updating.`);
49+
this.logger.log(`${logPrefix} Identity already exists. Updating.`);
5050
data.additionalFields.objectClasses = [
5151
...new Set([...identity.additionalFields.objectClasses, ...data.additionalFields.objectClasses]),
5252
];
@@ -71,6 +71,28 @@ export class IdentitiesService extends AbstractServiceSchema {
7171
options?: QueryOptions<T> & { rawResult: true },
7272
): Promise<ModifyResult<Query<T, T, any, T>>> {
7373
// noinspection UnnecessaryLocalVariableJS
74+
//TODO : add validation logic here
75+
const logPrefix = `Validation [${update.inetOrgPerson.cn}]:`;
76+
try {
77+
this.logger.log(`${logPrefix} Starting additionalFields validation.`);
78+
const validations = await this._validation.validate(update.additionalFields);
79+
this.logger.log(`${logPrefix} AdditionalFields validation successful.`);
80+
this.logger.log(`Validations : ${validations}`);
81+
} catch (error) {
82+
if (error instanceof ValidationConfigException) {
83+
this.logger.error(`${logPrefix} Validation config error. ${JSON.stringify(error.getValidations())}`);
84+
throw new ValidationConfigException(error.getPayload());
85+
}
86+
if (error instanceof ValidationSchemaException) {
87+
this.logger.warn(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
88+
update.additionalFields.validations = error.getValidations();
89+
throw new ValidationSchemaException(error.getPayload());
90+
} else {
91+
this.logger.error(`${logPrefix} Unhandled error: ${error.message}`);
92+
throw error; // Rethrow the original error if it's not one of the handled types.
93+
}
94+
}
95+
//update.state = IdentityState.TO_VALIDATE;
7496
const updated = await super.update(_id, update, options);
7597
//TODO: add backends service logic here (TO_SYNC)
7698
return updated;
@@ -89,23 +111,23 @@ export class IdentitiesService extends AbstractServiceSchema {
89111

90112
private handleValidationError(error: Error | HttpException, identity: Identities, logPrefix: string) {
91113
if (error instanceof ValidationConfigException) {
92-
Logger.error(`${logPrefix} Validation config error. ${JSON.stringify(error.getValidations())}`);
114+
this.logger.error(`${logPrefix} Validation config error. ${JSON.stringify(error.getValidations())}`);
93115
throw new ValidationConfigException(error.getPayload());
94116
}
95117

96118
if (error instanceof ValidationSchemaException) {
97-
Logger.warn(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
119+
this.logger.warn(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
98120
identity.additionalFields.validations = error.getValidations();
99121
if (identity.state === IdentityState.TO_CREATE) {
100-
Logger.warn(`${logPrefix} State set to TO_COMPLETE.`);
122+
this.logger.warn(`${logPrefix} State set to TO_COMPLETE.`);
101123
identity.state = IdentityState.TO_COMPLETE;
102124
return identity;
103125
} else {
104-
Logger.error(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
126+
this.logger.error(`${logPrefix} Validation schema error. ${JSON.stringify(error.getValidations())}`);
105127
throw new ValidationSchemaException(error.getPayload());
106128
}
107129
} else {
108-
Logger.error(`${logPrefix} Unhandled error: ${error.message}`);
130+
this.logger.error(`${logPrefix} Unhandled error: ${error.message}`);
109131
throw error; // Rethrow the original error if it's not one of the handled types.
110132
}
111133
}

0 commit comments

Comments
 (0)