Skip to content

Commit

Permalink
feat(formation): transformation fiches formations initiales
Browse files Browse the repository at this point in the history
  • Loading branch information
Naorid committed Jul 25, 2023
1 parent 5d1e248 commit ce2ff41
Show file tree
Hide file tree
Showing 21 changed files with 806 additions and 4 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ FORMATIONS_INITIALES_ONISEP_DIRECTORY_NAME=
FORMATIONS_INITIALES_ONISEP_FLUX_URL=
FORMATIONS_INITIALES_ONISEP_RAW_FILE_EXTENSION=
FORMATIONS_INITIALES_EXTRACT_LOG_LEVEL=
FORMATIONS_INITIALES_MINIO_RAW_BUCKET_NAME=

FORMATIONS_INITIALES_MINIO_RAW_BUCKET_NAME=

Expand Down
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ FORMATIONS_INITIALES_ONISEP_DIRECTORY_NAME=onisep
FORMATIONS_INITIALES_ONISEP_FLUX_URL=https://some.url.com/onisep
FORMATIONS_INITIALES_ONISEP_RAW_FILE_EXTENSION=.xml
FORMATIONS_INITIALES_EXTRACT_LOG_LEVEL=debug
FORMATIONS_INITIALES_MINIO_RAW_BUCKET_NAME=formations-initiales-raw

FORMATIONS_INITIALES_MINIO_RAW_BUCKET_NAME=formations-initiales-raw

Expand Down
5 changes: 5 additions & 0 deletions apps/cli/src/command/transform.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import {
TransformFlowTousMobilisesSubCommand,
} from "@evenements/src/transformation/infrastructure/sub-command/transform-flow-tous-mobilises.sub-command";

import {
TransformFlowOnisepSubCommand,
} from "@formations-initiales/src/transformation/infrastructure/sub-command/transform-flow-onisep.sub-command";

import {
TransformFlowImmojeuneSubCommand,
} from "@logements/src/transformation/infrastructure/sub-command/transform-flow-immojeune.sub-command";
Expand All @@ -30,6 +34,7 @@ import {
TransformFlowJobteaserSubCommand,
TransformFlowStagefrCompressedSubCommand,
TransformFlowStagefrUncompressedSubCommand,
TransformFlowOnisepSubCommand,
],
})
export class TransformCommand extends CommandRunner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class ConfigurationFactory extends ConfigurationValidator {
const DEFAULT_HISTORY_DIRECTORY_NAME = "history";

return {
CONTEXT: "evenements/extraction",
CONTEXT: "evenements/transformation",
DOMAINE: "Évènements",
FLOWS: [
getOrError("EVENTS_TOUS_MOBILISES_NAME"),
Expand Down
7 changes: 4 additions & 3 deletions apps/formations-initiales/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Module } from "@nestjs/common";

import { Extraction } from "./extraction";
import { Extraction } from "@formations-initiales/src/extraction";
import { Transformation } from "@formations-initiales/src/transformation/infrastructure";

@Module({
imports: [Extraction],
exports: [Extraction],
imports: [Extraction, Transformation],
exports: [Extraction, Transformation],
})
export class FormationsInitiales {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Module } from "@nestjs/common";

import {
TransformerFluxOnisep,
} from "@formations-initiales/src/transformation/application-service/transformer-flux-onisep.usecase";
import {
FormationsInitialesRepository,
} from "@formations-initiales/src/transformation/domain/service/formations-initiales.repository";
import { Convertir } from "@formations-initiales/src/transformation/domain/service/onisep/convertir.domain-service";
import { Gateways } from "@formations-initiales/src/transformation/infrastructure/gateway";

import { Shared } from "@shared/src";

@Module({
imports: [Gateways, Shared],
providers: [{
provide: Convertir,
inject: [],
useFactory: (): Convertir => {
return new Convertir();
},
}, {
provide: TransformerFluxOnisep,
inject: [
"FormationsInitialesRepository",
Convertir,
],
useFactory: (formationsInitialesRepository: FormationsInitialesRepository, convertirDomainService: Convertir): TransformerFluxOnisep => {
return new TransformerFluxOnisep(formationsInitialesRepository, convertirDomainService);
},
}],
exports: [TransformerFluxOnisep],
})
export class Usecases {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FluxTransformation } from "@formations-initiales/src/transformation/domain/model/flux";
import { Onisep } from "@formations-initiales/src/transformation/domain/model/onisep";
import {
FormationsInitialesRepository,
} from "@formations-initiales/src/transformation/domain/service/formations-initiales.repository";
import { Convertir } from "@formations-initiales/src/transformation/domain/service/onisep/convertir.domain-service";

import { Usecase } from "@shared/src/application-service/usecase";

export class TransformerFluxOnisep implements Usecase {
constructor(
private readonly formationsInitialesRepository: FormationsInitialesRepository,
private readonly convertir: Convertir,
) {
}

public async executer(flux: FluxTransformation): Promise<void> {
const contenuDuFlux = await this.formationsInitialesRepository.recuperer<Onisep.Contenu>(flux);

await this.formationsInitialesRepository.sauvegarder(this.convertir.depuisOnisep(contenuDuFlux), flux);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export namespace UnJeuneUneSolution {
export type FormationInitiale = {
identifiant: string
intitule: string
duree: string
certification: string
niveauEtudesVise: string
description: string
attendusParcoursup: string
conditionsAcces: string
poursuiteEtudes: string
}
}
15 changes: 15 additions & 0 deletions apps/formations-initiales/src/transformation/domain/model/flux.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Flux } from "@shared/src/domain/model/flux";

export class FluxTransformation extends Flux {
constructor(
nom: string,
public readonly dossierHistorisation: string,
public readonly extensionFichierBrut: string,
public readonly extensionFichierTransforme: string
) {
super(nom, extensionFichierBrut);
this.dossierHistorisation = dossierHistorisation;
this.extensionFichierBrut = extensionFichierBrut;
this.extensionFichierTransforme = extensionFichierTransforme;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export namespace Onisep {
export type Contenu = {
formations: { formation: Array<Formation> }
}
export type Formation = {
identifiant: string
libelle_complet: string
duree_formation: string
niveau_certification: string
niveau_etudes: { libelle: string }
descriptif_format_court: string
attendus: string
descriptif_acces: string
descriptif_poursuite_etudes: string
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { UnJeuneUneSolution } from "@formations-initiales/src/transformation/domain/model/1jeune1solution";
import { FluxTransformation } from "@formations-initiales/src/transformation/domain/model/flux";

export interface FormationsInitialesRepository {
recuperer<T>(flux: FluxTransformation): Promise<T>;
sauvegarder(formationInitiales: Array<UnJeuneUneSolution.FormationInitiale>, flux: FluxTransformation): Promise<void>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { UnJeuneUneSolution } from "@formations-initiales//src/transformation/domain/model/1jeune1solution";
import { Onisep } from "@formations-initiales/src/transformation/domain/model/onisep";

export class Convertir {
public depuisOnisep(formations: Onisep.Contenu): Array<UnJeuneUneSolution.FormationInitiale> {
return formations.formations.formation.map((formation) => {
return {
identifiant: formation.identifiant,
intitule: formation.libelle_complet,
duree: formation.duree_formation,
certification: formation.niveau_certification,
niveauEtudesVise: formation.niveau_etudes.libelle,
description: formation.descriptif_format_court,
attendusParcoursup: formation.attendus,
conditionsAcces: formation.descriptif_acces,
poursuiteEtudes: formation.descriptif_poursuite_etudes,
};
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
ConfigurationValidator,
Environment,
SentryConfiguration,
} from "@shared/src/infrastructure/configuration/configuration";
import { Domaine, LogLevel } from "@shared/src/infrastructure/configuration/logger";

type MinioConfiguration = {
ACCESS_KEY: string
HISTORY_DIRECTORY_NAME: string
PORT: number
RAW_BUCKET_NAME: string
SECRET_KEY: string
URL: string
TRANSFORMED_BUCKET_NAME: string
}

type TaskConfiguration = {
DIRECTORY_NAME: string
FLUX_URL: string
NAME: string
RAW_FILE_EXTENSION: string
TRANSFORMED_FILE_EXTENSION: string
}

export type Configuration = {
CONTEXT: string
DOMAINE: Domaine
FLOWS: Array<string>
ONISEP: TaskConfiguration
LOGGER_LOG_LEVEL: LogLevel
MINIO: MinioConfiguration
NODE_ENV: Environment
SENTRY: SentryConfiguration
TEMPORARY_DIRECTORY_PATH: string
}

export class ConfigurationFactory extends ConfigurationValidator {
public static createRoot(): { formationsInitialesTransformation: Configuration } {
return { formationsInitialesTransformation: ConfigurationFactory.create() };
}

public static create(): Configuration {
const { getOrError, getOrDefault } = ConfigurationFactory;
const DEFAULT_RAW_BUCKET_NAME = "raw";
const DEFAULT_MINIO_PORT = "9000";
const DEFAULT_ONISEP_NAME = "onisep";
const DEFAULT_LOG_LEVEL = "debug";
const DEFAULT_HISTORY_DIRECTORY_NAME = "history";

return {
CONTEXT: "formations-initiales/transformation",
DOMAINE: "Formations initiales",
FLOWS: [
getOrError("FORMATIONS_INITIALES_ONISEP_NAME"),
],
ONISEP: {
DIRECTORY_NAME: getOrDefault("FORMATIONS_INITIALES_ONISEP_DIRECTORY_NAME", DEFAULT_ONISEP_NAME),
FLUX_URL: getOrError("FORMATIONS_INITIALES_ONISEP_FLUX_URL"),
NAME: getOrDefault("FORMATIONS_INITIALES_ONISEP_NAME", DEFAULT_ONISEP_NAME),
RAW_FILE_EXTENSION: getOrDefault("FORMATIONS_INITIALES_ONISEP_RAW_FILE_EXTENSION", "xml"),
TRANSFORMED_FILE_EXTENSION: getOrDefault("FORMATIONS_INITIALES_ONISEP_TRANSFORMED_FILE_EXTENSION", "json"),
},
LOGGER_LOG_LEVEL: getOrDefault("LOGGER_LOG_LEVEL", DEFAULT_LOG_LEVEL) as LogLevel,
MINIO: {
ACCESS_KEY: getOrError("MINIO_ACCESS_KEY"),
HISTORY_DIRECTORY_NAME: getOrDefault("MINIO_HISTORY_DIRECTORY_NAME", DEFAULT_HISTORY_DIRECTORY_NAME),
PORT: Number(getOrDefault("MINIO_PORT", DEFAULT_MINIO_PORT)),
RAW_BUCKET_NAME: getOrDefault("EVENTS_MINIO_RAW_BUCKET_NAME", DEFAULT_RAW_BUCKET_NAME),
SECRET_KEY: getOrError("MINIO_SECRET_KEY"),
URL: getOrError("MINIO_URL"),
TRANSFORMED_BUCKET_NAME: getOrError("EVENTS_MINIO_TRANSFORMED_BUCKET_NAME"),
},
NODE_ENV: getOrError("NODE_ENV") as Environment,
SENTRY: {
DSN: getOrError("SENTRY_DSN"),
PROJECT: getOrError("npm_package_name"),
RELEASE: getOrError("npm_package_version"),
},
TEMPORARY_DIRECTORY_PATH: getOrError("TEMPORARY_DIRECTORY_PATH"),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
ConfigurationFactory,
} from "@formations-initiales/src/transformation/infrastructure/configuration/configuration";
import {
FormationsInitialesTransformationLoggerStrategy,
} from "@formations-initiales/src/transformation/infrastructure/configuration/logger-strategy";

const configuration = ConfigurationFactory.create();
const loggerStrategy = new FormationsInitialesTransformationLoggerStrategy(configuration);

export function CommandLog(flowName: string): (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor {
return function (target: unknown, propertyKey: string, descriptor: TypedPropertyDescriptor<() => Promise<void>>): PropertyDescriptor {
const originalMethod = descriptor.value;

descriptor.value = async function (...args: []): Promise<void> {
try {
loggerStrategy.get(flowName).info(`Starting to transform [${flowName}] flow`);
await originalMethod.apply(this, args);
} catch (e) {
loggerStrategy.get(flowName).fatal({ msg: (<Error>e).message, extra: { stack: (<Error>e).stack } });
} finally {
loggerStrategy.get(flowName).info(`End of transforming from [${flowName}] flow`);
}
};

return descriptor;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Configuration } from "@formations-initiales/src/transformation/infrastructure/configuration/configuration";

import {
Logger,
LoggerFactory,
LoggerStrategy,
LoggerStrategyError,
} from "@shared/src/infrastructure/configuration/logger";

export class FormationsInitialesTransformationLoggerStrategy implements LoggerStrategy {
private readonly loggers: Map<string, Logger>;

constructor(configuration: Configuration) {
const loggerFactory = new LoggerFactory(
configuration.SENTRY.DSN,
configuration.SENTRY.PROJECT,
configuration.SENTRY.RELEASE,
configuration.NODE_ENV,
configuration.CONTEXT,
configuration.LOGGER_LOG_LEVEL,
configuration.DOMAINE,
);
this.loggers = new Map();
configuration.FLOWS.forEach((flow) => {
this.loggers.set(flow, loggerFactory.create({ name: flow }));
});
}

get(flowName: string): Logger {
const logger = this.loggers.get(flowName);
if (logger) {
return logger;
}
throw new LoggerStrategyError(flowName);
}
}
Loading

0 comments on commit ce2ff41

Please sign in to comment.