Checkpoint: Amélioration de la page Paramètres avec :

- Ajout de 3 nouveaux paramètres globaux : délai d'expiration QR codes (minutes), durée de validité tokens (heures), notifications actives (boolean)
- Création de la table historiqueParametres pour tracer toutes les modifications avec userId, userName, champModifié, ancienneValeur, nouvelleValeur et dateModification
- Ajout d'un bouton "Tester l'URL" avec indicateur visuel de statut (vert si accessible, rouge si erreur)
- Affichage de l'historique des modifications dans un tableau avec toutes les informations de traçabilité
- Mise à jour automatique de l'historique lors de chaque modification de paramètre
This commit is contained in:
Manus
2026-01-12 03:34:33 -05:00
parent 44c1cd65fa
commit 182b39e78a
12 changed files with 719 additions and 431 deletions

View File

@@ -1,6 +1,6 @@
import { eq } from "drizzle-orm";
import { eq, sql } from "drizzle-orm";
import { getDb } from "./db";
import { parametres } from "../drizzle/schema";
import { parametres, historiqueParametres } from "../drizzle/schema";
/**
* Récupérer les paramètres de l'application
@@ -26,17 +26,108 @@ export async function getParametres() {
}
/**
* Mettre à jour l'URL publique
* Mettre à jour les paramètres de l'application
* Enregistre automatiquement l'historique des modifications
*/
export async function updateUrlPublique(urlPublique: string) {
export async function updateParametres(
updates: Partial<{
urlPublique: string;
delaiExpirationQR: number;
dureeValiditeToken: number;
notificationsActives: boolean;
}>,
userId: number,
userName: string
) {
const db = await getDb();
if (!db) throw new Error("Database not available");
const params = await getParametres();
// Enregistrer l'historique pour chaque champ modifié
for (const [key, value] of Object.entries(updates)) {
const oldValue = params[key as keyof typeof params];
if (oldValue !== value) {
await db.insert(historiqueParametres).values({
userId,
userName,
champModifie: key,
ancienneValeur: oldValue !== null && oldValue !== undefined ? String(oldValue) : null,
nouvelleValeur: value !== null && value !== undefined ? String(value) : null,
});
}
}
// Mettre à jour les paramètres
await db.update(parametres)
.set({ urlPublique })
.set(updates)
.where(eq(parametres.id, params.id));
return getParametres();
}
/**
* Mettre à jour l'URL publique (fonction de compatibilité)
*/
export async function updateUrlPublique(urlPublique: string, userId?: number, userName?: string) {
return updateParametres(
{ urlPublique },
userId || 1,
userName || "Système"
);
}
/**
* Récupérer l'historique des modifications des paramètres
*/
export async function getHistoriqueParametres(limit: number = 50) {
const db = await getDb();
if (!db) throw new Error("Database not available");
return db.select()
.from(historiqueParametres)
.orderBy(sql`${historiqueParametres.dateModification} DESC`)
.limit(limit);
}
/**
* Tester l'accessibilité d'une URL
*/
export async function testerUrl(url: string): Promise<{ accessible: boolean; message: string; statusCode?: number }> {
try {
// Vérifier le format de l'URL
const urlObj = new URL(url);
if (!['http:', 'https:'].includes(urlObj.protocol)) {
return {
accessible: false,
message: "L'URL doit commencer par http:// ou https://"
};
}
// Tenter une requête HEAD pour vérifier l'accessibilité
const response = await fetch(url, {
method: 'HEAD',
signal: AbortSignal.timeout(5000), // Timeout de 5 secondes
});
return {
accessible: response.ok,
message: response.ok
? "L'URL est accessible"
: `L'URL a retourné une erreur HTTP ${response.status}`,
statusCode: response.status
};
} catch (error) {
if (error instanceof TypeError && error.message.includes('Invalid URL')) {
return {
accessible: false,
message: "Format d'URL invalide"
};
}
return {
accessible: false,
message: `Erreur lors du test: ${error instanceof Error ? error.message : 'Erreur inconnue'}`
};
}
}