Skip to content

Commit

Permalink
feat: ajout du type de l'organisation (#3933)
Browse files Browse the repository at this point in the history
Co-authored-by: Paul Gaucher <[email protected]>
  • Loading branch information
Pomarom and Pomarom authored Dec 17, 2024
1 parent 6ed0e20 commit cdaef24
Show file tree
Hide file tree
Showing 18 changed files with 331 additions and 17 deletions.
18 changes: 13 additions & 5 deletions server/src/common/actions/account.actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Boom from "boom";
import { STATUT_FIABILISATION_ORGANISME } from "shared";
import { IOrganisme, STATUT_FIABILISATION_ORGANISME } from "shared";

import logger from "@/common/logger";
import { auditLogsDb, invitationsDb, organisationsDb, usersMigrationDb } from "@/common/model/collections";
Expand All @@ -23,36 +23,44 @@ export async function register(registration: RegistrationSchema): Promise<{
account_status: "PENDING_EMAIL_VALIDATION" | "CONFIRMED";
}> {
const alreadyExists = await getUserByEmail(registration.user.email);
let registrationExtraData: { organisme_id?: string } = {};
if (alreadyExists) {
throw Boom.conflict("Cet email est déjà utilisé.");
}

// on s'assure que l'organisme existe pour un OF
const type = registration.organisation.type;
if (type === "ORGANISME_FORMATION") {
let organisme: IOrganisme | undefined;
const { uai, siret } = registration.organisation;
try {
await getOrganismeByUAIAndSIRET(uai, siret);
organisme = await getOrganismeByUAIAndSIRET(uai, siret);
} catch (err) {
// si pas d'organisme en base (et donc le référentiel), on en crée un à partir depuis API entreprise
logger.warn({ action: "register", uai, siret }, "organisme inconnu créé");
// Récupération des infos depuis API Entreprise si option active, sinon renvoi des nom / adresse passé en paramètres
const data = await getOrganismeInfosFromSiret(siret);

// si aucun champ ferme fourni en entrée on récupère celui de l'organisme trouvé par son id
await createOrganisme({
organisme = await createOrganisme({
...data,
...(uai ? { uai } : {}),
siret,
fiabilisation_statut: STATUT_FIABILISATION_ORGANISME.NON_FIABLE,
organismesFormateurs: [],
organismesResponsables: [],
});
} finally {
registrationExtraData = { organisme_id: organisme?._id.toString() };
}
}

const organisation = await organisationsDb().findOne(registration.organisation);
const organisationId = organisation ? organisation._id : await createOrganisation(registration.organisation);
const organisationId = organisation
? organisation._id
: await createOrganisation({
...registration.organisation,
...registrationExtraData,
});

const userId = await createUser(registration.user, organisationId);

Expand Down
32 changes: 31 additions & 1 deletion server/src/common/actions/effectifs.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ICertification } from "api-alternance-sdk";
import Boom from "boom";
import { cloneDeep, isObject, merge, mergeWith, reduce, set, uniqBy } from "lodash-es";
import { ObjectId, type WithoutId } from "mongodb";
import { IOpcos, IRncp } from "shared/models";
import { IOpcos, IOrganisation, IRncp, IUsersMigration } from "shared/models";
import { IEffectif } from "shared/models/data/effectifs.model";
import { IEffectifDECA } from "shared/models/data/effectifsDECA.model";
import { IOrganisme } from "shared/models/data/organismes.model";
Expand Down Expand Up @@ -466,3 +466,33 @@ export const updateEffectifComputedFromRNCP = async (rncp: IRncp, opco: IOpcos)
)
);
};

export const buildEffectifForMissionLocale = (
effectif: IEffectif & { organisation: IOrganisation } & { cfa_users: IUsersMigration }
) => {
const result = {
_id: effectif._id,
apprenant: {
nom: effectif.apprenant.nom,
prenom: effectif.apprenant.prenom,
date_de_naissance: effectif.apprenant.date_de_naissance,
adresse: effectif.apprenant.adresse,
telephone: effectif.apprenant.telephone,
courriel: effectif.apprenant.courriel,
rqth: effectif.apprenant.rqth,
},
parcours: effectif._computed?.statut,
formation: effectif.formation,
organisme: effectif._computed?.organisme,
user: {
nom: effectif.cfa_users?.nom,
fonction: effectif.cfa_users?.prenom,
email: effectif.cfa_users?.email,
telephone: effectif.cfa_users?.telephone,
},
organisme_id: effectif.organisme_id,
annee_scolaire: effectif.annee_scolaire,
source: effectif.source,
};
return result;
};
61 changes: 61 additions & 0 deletions server/src/common/actions/effectifs/effectifs.actions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ObjectId } from "mongodb";
import { IEffectif, IOrganisation, IUsersMigration } from "shared/models";
import { getAnneesScolaireListFromDate } from "shared/utils";

import { organismeLookup } from "@/common/actions/helpers/filters";
import { effectifsDb } from "@/common/model/collections";

import { buildEffectifForMissionLocale } from "../effectifs.actions";

// Méthode de récupération de la liste des effectifs en base
export const getAllEffectifs = async (
query = {},
Expand Down Expand Up @@ -132,3 +136,60 @@ export const getDetailedEffectifById = async (_id: any) => {

return organisme;
};

export const getPaginatedEffectifsByMissionLocaleId = async (
missionLocaleId: string,
page: number = 1,
limit: number = 20
) => {
const aggregation = [
{
$match: {
"_computed.missionLocale.id": missionLocaleId,
annee_scolaire: { $in: getAnneesScolaireListFromDate(new Date()) },
},
},
{ $addFields: { stringify_organisme_id: { $toString: "$organisme_id" } } },
{
$lookup: {
from: "organisations",
localField: "stringify_organisme_id",
foreignField: "organisme_id",
as: "organisation",
},
},
{
$unwind: {
path: "$organisation",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "usersMigration",
localField: "organisation._id",
foreignField: "organisation_id",
as: "cfa_users",
},
},
{
$unwind: {
path: "$cfa_users",
preserveNullAndEmptyArrays: true,
},
},
{
$facet: {
pagination: [{ $count: "total" }, { $addFields: { page, limit } }],
data: [{ $skip: (page - 1) * limit }, { $limit: limit }],
},
},
{ $unwind: { path: "$pagination" } },
];
const { pagination, data } = (await effectifsDb().aggregate(aggregation).next()) as {
pagination: any;
data: Array<IEffectif & { organisation: IOrganisation } & { cfa_users: IUsersMigration }>;
};
const effectifs = data.map((effectif) => buildEffectifForMissionLocale(effectif));
return { pagination, data: effectifs };
};
20 changes: 20 additions & 0 deletions server/src/common/actions/helpers/permissions-organisme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ export type OrganismeWithPermissions = IOrganisme & { permissions: PermissionsOr
};
export async function getAcl(organisation: IOrganisation): Promise<Acl> {
switch (organisation.type) {
// Tout a false pour les missions locales
// Cela assure aucun accès potentiels aux autres apis

case "MISSION_LOCALE": {
return {
viewContacts: false,
infoTransmissionEffectifs: false,
indicateursEffectifs: false,
effectifsNominatifs: {
apprenant: false,
apprenti: false,
inscritSansContrat: false,
rupturant: false,
abandon: false,
inconnu: false,
},
manageEffectifs: false,
configurerModeTransmission: false,
};
}
case "ORGANISME_FORMATION": {
const userOrganisme = await organismesDb().findOne({
siret: organisation.siret,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { effectifsDb } from "@/common/model/collections";

import { DateFilters } from "../helpers/filters";

import { buildIndicateursEffectifsPipeline } from "./indicateurs.actions";

export const getEffectifIndicateursForMissionLocaleId = async (filters: DateFilters, missionLocaleId: string) => {
const aggregation = [
{
$match: {
"_computed.missionLocale.id": missionLocaleId,
},
},
...buildIndicateursEffectifsPipeline(null, filters.date),
{
$project: {
_id: 0,
inscrits: 1,
abandons: 1,
rupturants: 1,
},
},
];
const indicateurs = await effectifsDb().aggregate(aggregation).toArray();
return indicateurs ?? { inscrits: 0, abandons: 0, rupturants: 0 };
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { buildEffectifMongoFilters } from "./effectifs/effectifs-filters";
import { buildDECAFilter } from "./indicateurs-with-deca.actions";
import { buildOrganismeMongoFilters } from "./organismes/organismes-filters";

function buildIndicateursEffectifsPipeline(groupBy: string | null, currentDate: Date) {
export function buildIndicateursEffectifsPipeline(groupBy: string | null, currentDate: Date) {
return [
{
$addFields: {
Expand Down
2 changes: 2 additions & 0 deletions server/src/common/actions/organisations.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ async function getInvitationById(ctx: AuthContext, invitationId: ObjectId): Prom
export async function buildOrganisationLabel(organisationId: ObjectId): Promise<string> {
const organisation = await getOrganisationById(organisationId);
switch (organisation.type) {
case "MISSION_LOCALE":
return `Mission locale ${organisation.nom}`;
case "ORGANISME_FORMATION": {
const organisme = await organismesDb().findOne({
siret: organisation.siret,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,25 @@ exports[`validation-schema > should create validation schema for effectifs > eff
},
],
},
"missionLocale": {
"anyOf": [
{
"additionalProperties": false,
"bsonType": "object",
"properties": {
"id": {
"bsonType": "string",
},
},
"required": [
"id",
],
},
{
"bsonType": "null",
},
],
},
"organisme": {
"anyOf": [
{
Expand Down Expand Up @@ -2700,6 +2719,25 @@ exports[`validation-schema > should create validation schema for effectifsArchiv
},
],
},
"missionLocale": {
"anyOf": [
{
"additionalProperties": false,
"bsonType": "object",
"properties": {
"id": {
"bsonType": "string",
},
},
"required": [
"id",
],
},
{
"bsonType": "null",
},
],
},
"organisme": {
"anyOf": [
{
Expand Down Expand Up @@ -8947,6 +8985,43 @@ exports[`validation-schema > should create validation schema for opcos > opcos 1
exports[`validation-schema > should create validation schema for organisations > organisations 1`] = `
{
"anyOf": [
{
"additionalProperties": false,
"bsonType": "object",
"properties": {
"_id": {
"bsonType": "objectId",
},
"created_at": {
"bsonType": "date",
"description": "Date de création en base de données",
},
"ml_id": {
"bsonType": "number",
"description": "Identifiant de la mission locale",
},
"nom": {
"bsonType": "string",
"description": "Nom de la mission locale",
},
"siret": {
"bsonType": "string",
"description": "N° SIRET",
"pattern": "^[0-9]{14}$",
},
"type": {
"bsonType": "string",
},
},
"required": [
"_id",
"created_at",
"type",
"nom",
"siret",
"ml_id",
],
},
{
"additionalProperties": false,
"bsonType": "object",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { addJob } from "job-processor";

export const up = async () => {
await addJob({
name: "tmp:migration:organisation-organisme",
queued: true,
});
};
15 changes: 14 additions & 1 deletion server/src/http/middlewares/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Boom from "boom";
import { NextFunction, Request, RequestHandler, Response } from "express";
import { ObjectId } from "mongodb";
import { IEffectif, ORGANISATION_TYPE, PermissionOrganisme } from "shared";
import { IEffectif, IOrganisationMissionLocale, ORGANISATION_TYPE, PermissionOrganisme } from "shared";
import { IEffectifDECA } from "shared/models/data/effectifsDECA.model";

import { getOrganismePermission } from "@/common/actions/helpers/permissions-organisme";
Expand Down Expand Up @@ -41,6 +41,19 @@ export function requireAdministrator(req: Request, _res: Response, next: NextFun
next();
}

export function requireMissionLocale(req: Request, res: Response, next: NextFunction) {
const user = req.user as AuthContext;
ensureValidUser(user);
if (user.organisation.type !== "MISSION_LOCALE") {
throw Boom.forbidden("Accès non autorisé");
}

const orga = user.organisation as IOrganisationMissionLocale;

res.locals.missionLocale = orga;
next();
}

interface MyLocals {
organismeId: ObjectId;
}
Expand Down
Loading

0 comments on commit cdaef24

Please sign in to comment.