562 lines
18 KiB
TypeScript
562 lines
18 KiB
TypeScript
import BaseService from "@Services/BaseService";
|
|
import { BackendVariables } from "@Common/config/variables/Variables";
|
|
import { Service } from "typedi";
|
|
import jwt from "jsonwebtoken";
|
|
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
|
import { IdNotJwtPayload } from "../AuthService/AuthService";
|
|
import User, { DeedType, Office, OfficeRole, Role, DocumentType } from "le-coffre-resources/dist/SuperAdmin";
|
|
import RolesService from "@Services/super-admin/RolesService/RolesService";
|
|
import OfficesService from "@Services/super-admin/OfficesService/OfficesService";
|
|
import { EOfficeStatus } from "@prisma/client";
|
|
import OfficeRolesService from "@Services/super-admin/OfficeRolesService/OfficeRolesService";
|
|
import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesService";
|
|
import DocumentTypesService from "@Services/super-admin/DocumentTypesService/DocumentTypesService";
|
|
import * as Sentry from "@sentry/node";
|
|
|
|
interface IIdNotToken {
|
|
access_token: string;
|
|
expires_in: number;
|
|
id_token: string;
|
|
token_type: string;
|
|
}
|
|
|
|
interface IRattachementData {
|
|
entiteUrl: string;
|
|
personneUrl: string;
|
|
entite: {
|
|
codeCrpcen: string;
|
|
typeEntite: {
|
|
name: string;
|
|
};
|
|
ou: string;
|
|
denominationSociale: string;
|
|
statutEntite: {
|
|
name: string;
|
|
};
|
|
locationsUrl: string;
|
|
};
|
|
personne: {
|
|
numeroTelephonePro: string;
|
|
prenom: string;
|
|
nomUsuel: string;
|
|
mobilePro: string;
|
|
numeroAdherentCrpcen: string;
|
|
civilite: string;
|
|
};
|
|
typeLien: {
|
|
name: string;
|
|
};
|
|
numeroMobile: string;
|
|
numeroTelephone: string;
|
|
statutDuRattachement: boolean;
|
|
mailRattachement: string;
|
|
deleted: boolean;
|
|
}
|
|
|
|
interface IOfficeData {
|
|
ou: string;
|
|
intitule: string;
|
|
denominationSociale: string;
|
|
departementResidence: {
|
|
libelle: string;
|
|
code: string;
|
|
}[];
|
|
libelle: string;
|
|
codeCrpcen: string;
|
|
locationsUrl: string;
|
|
statutEntite: {
|
|
name: string;
|
|
};
|
|
typeEntite: {
|
|
name: string;
|
|
};
|
|
}
|
|
|
|
interface IOfficeLocation {
|
|
totalResultCount: number;
|
|
page: number;
|
|
size: number;
|
|
result: {
|
|
mail: string;
|
|
numeroTelephone: string;
|
|
adrGeo4: string;
|
|
adrGeoCodePostal: string;
|
|
adrGeoVille: string;
|
|
ou: string;
|
|
lastModified: string;
|
|
deleted: boolean;
|
|
}[];
|
|
}
|
|
|
|
enum EIdnotRole {
|
|
DIRECTEUR = "Directeur général du CSN",
|
|
NOTAIRE_TITULAIRE = "Notaire titulaire",
|
|
NOTAIRE_ASSOCIE = "Notaire associé",
|
|
NOTAIRE_SALARIE = "Notaire salarié",
|
|
COLLABORATEUR = "Collaborateur",
|
|
SECRETAIRE_GENERAL = "Secrétaire général",
|
|
SUPPLEANT = "Suppléant",
|
|
ADMINISTRATEUR = "Administrateur",
|
|
RESPONSABLE = "Responsable",
|
|
CURATEUR = "Curateur",
|
|
}
|
|
|
|
@Service()
|
|
export default class IdNotService extends BaseService {
|
|
constructor(
|
|
protected variables: BackendVariables,
|
|
private userService: UsersService,
|
|
private officeService: OfficesService,
|
|
private rolesService: RolesService,
|
|
private officeRolesService: OfficeRolesService,
|
|
private deedTypesService: DeedTypesService,
|
|
private documentTypesService: DocumentTypesService,
|
|
) {
|
|
super();
|
|
}
|
|
|
|
public async getIdNotToken(code: string) {
|
|
const query = new URLSearchParams({
|
|
client_id: this.variables.IDNOT_CLIENT_ID,
|
|
client_secret: this.variables.IDNOT_CLIENT_SECRET,
|
|
redirect_uri: this.variables.IDNOT_REDIRECT_URL,
|
|
code: code,
|
|
grant_type: "authorization_code",
|
|
});
|
|
|
|
try {
|
|
const token = await fetch(this.variables.IDNOT_BASE_URL + this.variables.IDNOT_CONNEXION_URL + "?" + query, { method: "POST" });
|
|
if (token.status !== 200) console.error(await token.text());
|
|
const decodedToken = (await token.json()) as IIdNotToken;
|
|
const decodedIdToken = jwt.decode(decodedToken.id_token) as IdNotJwtPayload;
|
|
return decodedIdToken;
|
|
} catch (error) {
|
|
console.error("Error fetching " + this.variables.IDNOT_BASE_URL + this.variables.IDNOT_CONNEXION_URL ,error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async getRole(roleName: string): Promise<Role> {
|
|
switch (roleName) {
|
|
case EIdnotRole.NOTAIRE_TITULAIRE:
|
|
return (await this.rolesService.get({ where: { name: "admin" } }))[0]!;
|
|
case EIdnotRole.NOTAIRE_ASSOCIE:
|
|
return (await this.rolesService.get({ where: { name: "admin" } }))[0]!;
|
|
case EIdnotRole.NOTAIRE_SALARIE:
|
|
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
|
case EIdnotRole.COLLABORATEUR:
|
|
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
|
case EIdnotRole.SUPPLEANT:
|
|
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
|
case EIdnotRole.ADMINISTRATEUR:
|
|
return (await this.rolesService.get({ where: { name: "admin" } }))[0]!;
|
|
case EIdnotRole.CURATEUR:
|
|
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
|
default:
|
|
return (await this.rolesService.get({ where: { name: "default" } }))[0]!;
|
|
}
|
|
}
|
|
|
|
public async getOfficeRole(roleName: string, officeUid: string) {
|
|
switch (roleName) {
|
|
case EIdnotRole.NOTAIRE_TITULAIRE:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Notaire" }, { office_uid: officeUid }] } }))[0]!;
|
|
case EIdnotRole.NOTAIRE_ASSOCIE:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Notaire" }, { office_uid: officeUid }] } }))[0]!;
|
|
case EIdnotRole.NOTAIRE_SALARIE:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Notaire" }, { office_uid: officeUid }] } }))[0]!;
|
|
case EIdnotRole.COLLABORATEUR:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!;
|
|
case EIdnotRole.SUPPLEANT:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!;
|
|
case EIdnotRole.ADMINISTRATEUR:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!;
|
|
case EIdnotRole.CURATEUR:
|
|
return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
public async getOfficeMemberships(officeId: string) {
|
|
const officeInfos = await this.officeService.getByUid(officeId);
|
|
const office = Office.hydrate<Office>(officeInfos!);
|
|
const searchParams = new URLSearchParams({
|
|
key: this.variables.IDNOT_API_KEY,
|
|
});
|
|
|
|
console.log("getOfficeMemberships");
|
|
|
|
const url = `${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/entites/${office.idNot}/personnes?` + searchParams;
|
|
|
|
try {
|
|
console.log("Tentative de connexion à l'URL :", url);
|
|
const response = await fetch(url, {
|
|
method: "GET",
|
|
});
|
|
|
|
return (await response.json()) as any;
|
|
} catch (error) {
|
|
console.error("Erreur lors de l'appel à fetch :", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public getOfficeStatus(statusName: string) {
|
|
switch (statusName) {
|
|
case "Pourvu":
|
|
return EOfficeStatus.ACTIVATED;
|
|
case "Pourvu mais décédé":
|
|
return EOfficeStatus.ACTIVATED;
|
|
case "Sans titulaire":
|
|
return EOfficeStatus.ACTIVATED;
|
|
case "Vacance":
|
|
return EOfficeStatus.ACTIVATED;
|
|
case "En activité":
|
|
return EOfficeStatus.ACTIVATED;
|
|
default:
|
|
return EOfficeStatus.DESACTIVATED;
|
|
}
|
|
}
|
|
|
|
public async updateUser(userId: string) {
|
|
const userInfos = await this.userService.getByUid(userId, { contact: true, role: true, office_membership: true });
|
|
const user = User.hydrate<User>(userInfos!);
|
|
console.log("Got user from db:", JSON.stringify(user));
|
|
const searchParams = new URLSearchParams({
|
|
key: this.variables.IDNOT_API_KEY,
|
|
});
|
|
|
|
let userData: IRattachementData;
|
|
try {
|
|
userData = (await (
|
|
await fetch(
|
|
`${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${user.idNot}_${user.office_membership!.idNot}?` +
|
|
searchParams,
|
|
{
|
|
method: "GET",
|
|
},
|
|
)
|
|
).json()) as IRattachementData;
|
|
} catch (error) {
|
|
console.error(`Error fetching user data for ${user.uid}: ${error}`);
|
|
return;
|
|
}
|
|
|
|
console.log("Got userData from idnot", JSON.stringify(userData));
|
|
|
|
if (userData.deleted) {
|
|
let rattachements: any;
|
|
|
|
try {
|
|
rattachements = (await (
|
|
await fetch(`${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/personnes/${user.idNot}/rattachements?deleted=false` + searchParams, {
|
|
method: "GET",
|
|
})
|
|
).json()) as any;
|
|
} catch (error) {
|
|
console.error("Error fetching rattachements", error);
|
|
return;
|
|
}
|
|
|
|
if (rattachements.totalResultCount === 0) {
|
|
console.warn("User has no valid rattachements", user.uid);
|
|
await this.userService.updateCheckedAt(user.uid!);
|
|
return;
|
|
}
|
|
const rattachementsResults = rattachements.result as IRattachementData[];
|
|
if (!rattachementsResults) return;
|
|
rattachementsResults.forEach(async (rattachement) => {
|
|
if (rattachement.statutDuRattachement && !rattachement.deleted) {
|
|
let officeData: IOfficeData;
|
|
|
|
try {
|
|
officeData = (await (
|
|
await fetch(`${this.variables.IDNOT_API_BASE_URL + rattachement.entiteUrl}?` + searchParams, {
|
|
method: "GET",
|
|
})
|
|
).json()) as IOfficeData;
|
|
} catch (error) {
|
|
console.error("Error fetching office data", error);
|
|
return;
|
|
}
|
|
|
|
if (officeData.typeEntite.name === "office") {
|
|
userData = rattachement;
|
|
console.log("Updated userData", JSON.stringify(userData));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
let updates = 0;
|
|
|
|
|
|
if (user.office_membership!.idNot !== userData.entite.ou) {
|
|
updates++;
|
|
let officeData = (await this.officeService.get({ where: { idNot: userData.entite.ou } }))[0];
|
|
if (!officeData) {
|
|
let officeLocationData: IOfficeLocation;
|
|
|
|
try {
|
|
officeLocationData = (await (
|
|
await fetch(`${this.variables.IDNOT_API_BASE_URL + userData.entite.locationsUrl}?` + searchParams, {
|
|
method: "GET",
|
|
})
|
|
).json()) as IOfficeLocation;
|
|
} catch (error) {
|
|
console.error("Error fetching office location data", error);
|
|
return;
|
|
}
|
|
|
|
const office = {
|
|
idNot: userData.entite.ou,
|
|
name: userData.entite.denominationSociale ?? userData.entite.codeCrpcen,
|
|
crpcen: userData.entite.codeCrpcen,
|
|
office_status: this.getOfficeStatus(userData.entite.statutEntite.name),
|
|
address: {
|
|
address: officeLocationData.result[0]!.adrGeo4,
|
|
city: officeLocationData.result[0]!.adrGeoVille.split(" ")[0] ?? officeLocationData.result[0]!.adrGeoVille,
|
|
zip_code: Number(officeLocationData.result[0]!.adrGeoCodePostal),
|
|
created_at: null,
|
|
updated_at: null,
|
|
},
|
|
created_at: null,
|
|
updated_at: null,
|
|
};
|
|
officeData = await this.officeService.create(office);
|
|
}
|
|
user.office_membership = officeData;
|
|
}
|
|
|
|
if (user.contact!.email !== userData.mailRattachement) {
|
|
updates++;
|
|
user.contact!.email = userData.mailRattachement;
|
|
}
|
|
if (user.contact!.cell_phone_number !== userData.numeroMobile) {
|
|
updates++;
|
|
user.contact!.cell_phone_number = userData.numeroMobile;
|
|
}
|
|
if (updates != 0) await this.userService.update(user.uid!, user);
|
|
await this.userService.updateCheckedAt(user.uid!);
|
|
}
|
|
|
|
public async updateOffice(officeId: string) {
|
|
const officeInfos = await this.officeService.getByUid(officeId, { address: true });
|
|
const office = Office.hydrate<Office>(officeInfos!);
|
|
const searchParams = new URLSearchParams({
|
|
key: this.variables.IDNOT_API_KEY,
|
|
});
|
|
|
|
let officeRawData;
|
|
try {
|
|
officeRawData = await fetch(`${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/entites/${office.idNot}?` + searchParams, {
|
|
method: "GET",
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching office data", error);
|
|
return;
|
|
}
|
|
|
|
if (officeRawData.status === 404) {
|
|
console.error("Fetching office raw data failed with status 404");
|
|
await this.officeService.updateCheckedAt(office.uid!);
|
|
//await this.officeService.delete(office.uid!);
|
|
return;
|
|
}
|
|
const officeData = (await officeRawData.json()) as IOfficeData;
|
|
|
|
let updates = 0;
|
|
//093051 = demo
|
|
if (office.name !== officeData.denominationSociale && office.name !== officeData.codeCrpcen && office.crpcen !== "029178" && office.crpcen !== "035010" && office.crpcen !== "093051") {
|
|
updates++;
|
|
office.name = officeData.denominationSociale ?? officeData.codeCrpcen;
|
|
}
|
|
if (office.office_status !== this.getOfficeStatus(officeData.statutEntite.name)) {
|
|
updates++;
|
|
office.office_status = this.getOfficeStatus(officeData.statutEntite.name);
|
|
}
|
|
console.log(`Updating office: ${office.uid} - ${office.name} - ${office.crpcen}`);
|
|
if (updates != 0) await this.officeService.update(office.uid!, office);
|
|
await this.officeService.updateCheckedAt(office.uid!);
|
|
}
|
|
|
|
public async getOrCreateUser(decodedToken: IdNotJwtPayload) {
|
|
let user = await this.userService.getByProvider("idNot", decodedToken.sub);
|
|
if (!user) {
|
|
const searchParams = new URLSearchParams({
|
|
key: this.variables.IDNOT_API_KEY,
|
|
});
|
|
|
|
let userData: IRattachementData;
|
|
|
|
try {
|
|
userData = (await (
|
|
await fetch(
|
|
`${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${decodedToken.profile_idn}?` + searchParams,
|
|
{
|
|
method: "GET",
|
|
},
|
|
)
|
|
).json()) as IRattachementData;
|
|
console.log("userData", userData);
|
|
} catch (error) {
|
|
console.error("Error fetching " + `${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${decodedToken.profile_idn}?`, error);
|
|
Sentry.captureException(error);
|
|
return null;
|
|
}
|
|
|
|
if (!userData.statutDuRattachement || userData.entite.typeEntite.name !== "office") {
|
|
console.info("User not attached to an office (May be a partner)");
|
|
return null;
|
|
}
|
|
|
|
let officeLocationData: IOfficeLocation;
|
|
|
|
try {
|
|
officeLocationData = (await (
|
|
await fetch(`${this.variables.IDNOT_API_BASE_URL + userData.entite.locationsUrl}?` + searchParams, { method: "GET" })
|
|
).json()) as IOfficeLocation;
|
|
} catch (error) {
|
|
console.error("Error fetching" + `${this.variables.IDNOT_API_BASE_URL + userData.entite.locationsUrl}` , error);
|
|
Sentry.captureException(error);
|
|
return null;
|
|
}
|
|
|
|
console.log("officeLocationData", officeLocationData);
|
|
|
|
const office = await this.officeService.get({ where: { idNot: decodedToken.entity_idn } });
|
|
|
|
// if(officeLocationData.result[0]!.adrGeoCodePostal.slice(0,2) !== "35") {
|
|
// return null;
|
|
// }
|
|
|
|
const role = await this.getRole(userData.typeLien.name);
|
|
|
|
const userToAdd = {
|
|
idNot: decodedToken.sub,
|
|
office_membership: {
|
|
idNot: decodedToken.entity_idn,
|
|
name: userData.entite.denominationSociale ?? userData.entite.codeCrpcen,
|
|
crpcen: userData.entite.codeCrpcen,
|
|
office_status: this.getOfficeStatus(userData.entite.statutEntite.name),
|
|
address: {
|
|
address: officeLocationData.result[0]!.adrGeo4,
|
|
city: officeLocationData.result[0]!.adrGeoVille.split(" ")[0] ?? officeLocationData.result[0]!.adrGeoVille, //officeLocationData.result[0]!.adrPostaleVille,
|
|
zip_code: Number(officeLocationData.result[0]!.adrGeoCodePostal),
|
|
created_at: null,
|
|
updated_at: null,
|
|
},
|
|
created_at: null,
|
|
updated_at: null,
|
|
status: "ACTIVE",
|
|
},
|
|
role: role,
|
|
contact: {
|
|
first_name: userData.personne.prenom,
|
|
last_name: userData.personne.nomUsuel,
|
|
email: userData.mailRattachement,
|
|
phone_number: userData.numeroTelephone,
|
|
cell_phone_number: userData.numeroMobile ?? userData.numeroTelephone,
|
|
civility: userData.personne.civilite,
|
|
created_at: null,
|
|
updated_at: null,
|
|
},
|
|
};
|
|
|
|
if (!userToAdd.contact.email) {
|
|
console.error("User pro email empty");
|
|
return null;
|
|
}
|
|
|
|
let userHydrated = User.hydrate<User>(userToAdd);
|
|
const user = await this.userService.create(userHydrated);
|
|
const userOffice = await this.officeService.getByUid(user.office_uid);
|
|
userHydrated = User.hydrate<User>(user);
|
|
const userOfficeHydrated = Office.hydrate<Office>(userOffice!);
|
|
|
|
if (office.length === 0) {
|
|
const officeRoles = await this.officeRolesService.get({
|
|
where: { office: { idNot: "0000" } },
|
|
include: { office: true, rules: true },
|
|
});
|
|
const deedTypes = await this.deedTypesService.get({
|
|
where: { office: { idNot: "0000" } },
|
|
include: { office: true, document_types: { include: { office: true } } },
|
|
});
|
|
const documentTypes = await this.documentTypesService.get({
|
|
where: { office: { idNot: "0000" } },
|
|
include: { office: true },
|
|
});
|
|
|
|
const officeRolesHydrated = OfficeRole.hydrateArray<OfficeRole>(officeRoles);
|
|
const deedTypesHydrated = DeedType.hydrateArray<DeedType>(deedTypes);
|
|
const documentTypesHydrated = DocumentType.hydrateArray<DocumentType>(documentTypes);
|
|
|
|
await this.duplicateOfficeRoles(officeRolesHydrated, userOfficeHydrated);
|
|
const documentTypesCreated = await this.duplicateDocumentTypes(documentTypesHydrated, userOfficeHydrated);
|
|
await this.duplicateDeedTypes(deedTypesHydrated, documentTypesCreated, userOfficeHydrated);
|
|
}
|
|
|
|
const officeRole = await this.getOfficeRole(userData.typeLien.name, user.office_uid);
|
|
|
|
if (officeRole) {
|
|
const officeRoleHydrated = OfficeRole.hydrate<OfficeRole>(officeRole!);
|
|
userHydrated.office_role = officeRoleHydrated;
|
|
await this.userService.update(user.uid, userHydrated);
|
|
}
|
|
|
|
return user;
|
|
}
|
|
return user;
|
|
}
|
|
|
|
public async duplicateDocumentTypes(documentTypes: DocumentType[], office: Office): Promise<DocumentType[]> {
|
|
let newDocumentTypes: DocumentType[] = [];
|
|
for (const documentType of documentTypes) {
|
|
documentType.office = office;
|
|
const documentTypeCreated = await this.documentTypesService.create(documentType);
|
|
newDocumentTypes.push(DocumentType.hydrate<DocumentType>(documentTypeCreated));
|
|
}
|
|
return newDocumentTypes;
|
|
}
|
|
|
|
public async duplicateDeedTypes(deedTypes: DeedType[], documentTypes: DocumentType[], office: Office) {
|
|
for (const deedType of deedTypes) {
|
|
let newDocumentTypes: DocumentType[] = [];
|
|
for (const document of deedType.document_types!) {
|
|
const newDocumentType = documentTypes.find((documentType) => documentType.name === document.name);
|
|
if (!newDocumentType) continue;
|
|
newDocumentTypes.push(newDocumentType!);
|
|
}
|
|
deedType.document_types = newDocumentTypes;
|
|
deedType.office = office;
|
|
await this.deedTypesService.create(deedType);
|
|
}
|
|
}
|
|
|
|
public async duplicateOfficeRoles(officeRoles: OfficeRole[], office: Office) {
|
|
for (const officeRole of officeRoles) {
|
|
officeRole.office = office;
|
|
await this.officeRolesService.create(officeRole);
|
|
}
|
|
}
|
|
|
|
public async updateUsers() {
|
|
const usersReq = await this.userService.getUsersToBeChecked();
|
|
const users = User.hydrateArray<User>(usersReq);
|
|
users.forEach(async (user) => {
|
|
await this.updateUser(user.uid!);
|
|
});
|
|
}
|
|
|
|
public async updateOffices() {
|
|
const officesReq = await this.officeService.getOfficesToBeChecked();
|
|
const offices = Office.hydrateArray<Office>(officesReq);
|
|
console.log(`Updating ${offices.length} offices`);
|
|
offices.forEach(async (office) => {
|
|
await this.updateOffice(office.uid!);
|
|
});
|
|
}
|
|
}
|