**Motivations:** - Intégrer les notifications relais (polling, auto-process hashes) dans ServiceSyncScreen - Valider conformité CNIL des contrats/champs à l’ajout au graphe - Accéder à la sync par service depuis SyncScreen **Root causes:** - N/A (évolutions + petits correctifs) **Correctifs:** - relayNotificationService: suppression import inutilisé RelayConfig **Evolutions:** - useRelayNotifications: hook (RelayNotificationService, start/stop polling, auto-process hash) - cnilValidation: validateContractCNIL, validateChampCNIL (valid, errors, warnings) - graphResolver: addContrat/addChamp appellent validation CNIL (async, logs warnings/errors, non bloquant) - ServiceSyncScreen: useRelayNotifications, GraphResolver ref, polling selon configs (fréquence min), sync result (hasMessages, « Aucun nouveau message »), useBloom mention - SyncScreen: bouton « Sync par service » vers /service-sync **Pages affectées:** - userwallet: useRelayNotifications, cnilValidation, ServiceSyncScreen, SyncScreen, graphResolver, relayNotificationService
164 lines
4.7 KiB
TypeScript
164 lines
4.7 KiB
TypeScript
import type { Contrat, Champ } from '../types/contract';
|
|
import type { DataJson } from '../types/message';
|
|
|
|
/**
|
|
* CNIL validation result.
|
|
*/
|
|
export interface CNILValidationResult {
|
|
valid: boolean;
|
|
errors: string[];
|
|
warnings: string[];
|
|
}
|
|
|
|
/**
|
|
* Check if a contract requires CNIL fields based on its type.
|
|
*/
|
|
function contractRequiresCNIL(_contrat: Contrat): boolean {
|
|
// Tous les contrats nécessitent les champs CNIL selon la politique métier
|
|
// Peut être ajusté selon les besoins spécifiques
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Validate CNIL fields in datajson.
|
|
*/
|
|
function validateCNILFields(datajson?: DataJson): {
|
|
valid: boolean;
|
|
errors: string[];
|
|
warnings: string[];
|
|
} {
|
|
const errors: string[] = [];
|
|
const warnings: string[] = [];
|
|
|
|
if (datajson === undefined || datajson === null) {
|
|
errors.push('datajson manquant');
|
|
return { valid: false, errors, warnings };
|
|
}
|
|
|
|
// Vérifier raisons_usage_tiers
|
|
if (datajson.raisons_usage_tiers !== undefined) {
|
|
if (!Array.isArray(datajson.raisons_usage_tiers)) {
|
|
errors.push('raisons_usage_tiers doit être un tableau');
|
|
} else {
|
|
for (const item of datajson.raisons_usage_tiers) {
|
|
if (
|
|
typeof item !== 'object' ||
|
|
item === null ||
|
|
!Array.isArray(item.raisons) ||
|
|
typeof item.tiers !== 'string'
|
|
) {
|
|
errors.push(
|
|
'raisons_usage_tiers: chaque élément doit avoir raisons (string[]) et tiers (string)',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Vérifier raisons_partage_tiers
|
|
if (datajson.raisons_partage_tiers !== undefined) {
|
|
if (!Array.isArray(datajson.raisons_partage_tiers)) {
|
|
errors.push('raisons_partage_tiers doit être un tableau');
|
|
} else {
|
|
for (const item of datajson.raisons_partage_tiers) {
|
|
if (
|
|
typeof item !== 'object' ||
|
|
item === null ||
|
|
!Array.isArray(item.raisons) ||
|
|
typeof item.tiers !== 'string'
|
|
) {
|
|
errors.push(
|
|
'raisons_partage_tiers: chaque élément doit avoir raisons (string[]) et tiers (string)',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Vérifier conditions_conservation
|
|
if (datajson.conditions_conservation !== undefined) {
|
|
if (typeof datajson.conditions_conservation !== 'object' || datajson.conditions_conservation === null) {
|
|
errors.push('conditions_conservation doit être un objet');
|
|
} else {
|
|
const cc = datajson.conditions_conservation as Record<string, unknown>;
|
|
if (typeof cc.delai_expiration !== 'string' && typeof cc.delai_expiration !== 'number') {
|
|
errors.push('conditions_conservation.delai_expiration requis (string ou number)');
|
|
}
|
|
}
|
|
} else {
|
|
warnings.push('conditions_conservation non défini (recommandé pour conformité CNIL)');
|
|
}
|
|
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors,
|
|
warnings,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Validate CNIL compliance for a contract.
|
|
* Returns validation result with errors and warnings.
|
|
*/
|
|
export function validateContractCNIL(contrat: Contrat): CNILValidationResult {
|
|
const errors: string[] = [];
|
|
const warnings: string[] = [];
|
|
|
|
if (!contractRequiresCNIL(contrat)) {
|
|
return { valid: true, errors: [], warnings: [] };
|
|
}
|
|
|
|
const datajson = contrat.datajson;
|
|
const cnilValidation = validateCNILFields(datajson);
|
|
|
|
errors.push(...cnilValidation.errors);
|
|
warnings.push(...cnilValidation.warnings);
|
|
|
|
// Vérifier que les champs obligatoires sont présents si requis par la politique
|
|
// Pour l'instant, on génère seulement des warnings, pas d'erreurs strictes
|
|
// La politique métier peut être ajustée ici
|
|
if (datajson?.raisons_usage_tiers === undefined) {
|
|
warnings.push('raisons_usage_tiers non défini (recommandé pour conformité CNIL)');
|
|
}
|
|
|
|
if (datajson?.raisons_partage_tiers === undefined) {
|
|
warnings.push('raisons_partage_tiers non défini (recommandé pour conformité CNIL)');
|
|
}
|
|
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors,
|
|
warnings,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Validate CNIL compliance for a field (Champ).
|
|
*/
|
|
export function validateChampCNIL(champ: Champ): CNILValidationResult {
|
|
const errors: string[] = [];
|
|
const warnings: string[] = [];
|
|
|
|
const datajson = champ.datajson;
|
|
const cnilValidation = validateCNILFields(datajson);
|
|
|
|
errors.push(...cnilValidation.errors);
|
|
warnings.push(...cnilValidation.warnings);
|
|
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors,
|
|
warnings,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check if CNIL fields are required for a contract type.
|
|
* Can be customized based on business policy.
|
|
*/
|
|
export function isCNILRequiredForContract(_contrat: Contrat): boolean {
|
|
// Politique métier : tous les contrats nécessitent les champs CNIL
|
|
// Peut être ajusté selon le type de contrat
|
|
return true;
|
|
}
|