From 5356819ceb4aafe83e480621a72f91a35b228442 Mon Sep 17 00:00:00 2001 From: Manus Date: Tue, 27 Jan 2026 07:28:09 -0500 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20Modification=20du=20stockage=20de?= =?UTF-8?q?s=20signatures=20d'=C3=A9margement=20pour=20utiliser=20le=20sys?= =?UTF-8?q?t=C3=A8me=20de=20fichiers=20local=20au=20lieu=20de=20S3=20:=20-?= =?UTF-8?q?=20Remplacement=20de=20storagePut=20par=20fs.writeFileSync=20da?= =?UTF-8?q?ns=20routers.ts=20-=20Structure=20de=20dossiers=20:=20uploads/s?= =?UTF-8?q?ignatures/[formation-id]-[sequence-id]/=20-=20Noms=20de=20fichi?= =?UTF-8?q?ers=20uniques=20avec=20crypto.randomBytes=20-=20URLs=20publique?= =?UTF-8?q?s=20relatives=20:=20/uploads/signatures/[formation-id]-[sequenc?= =?UTF-8?q?e-id]/[fichier].png=20-=20Correction=20de=20l'erreur=20"fetch?= =?UTF-8?q?=20failed"=20caus=C3=A9e=20par=20l'inaccessibilit=C3=A9=20de=20?= =?UTF-8?q?forge.manus.im=20sur=20le=20VPS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/routers.ts | 39 ++++++++++++++++++++++++++++++++------- todo.md | 8 ++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/server/routers.ts b/server/routers.ts index e0dbed6..ca6d097 100644 --- a/server/routers.ts +++ b/server/routers.ts @@ -2503,18 +2503,43 @@ export const appRouter = router({ } } - // Uploader la signature en S3 si fournie + // Stocker la signature localement si fournie let signatureUrl: string | undefined; let signatureS3Key: string | undefined; if (input.signatureDataUrl) { - const { storagePut } = await import("./storage"); + const fs = await import("fs"); + const path = await import("path"); + const crypto = await import("crypto"); + + // Récupérer l'inscription pour obtenir la séquence + const inscriptionData = await db.select().from(inscriptions).where(eq(inscriptions.id, input.inscriptionId)).limit(1); + if (inscriptionData.length === 0) throw new Error("Inscription introuvable"); + + const sequenceData = await db.select().from(sequences).where(eq(sequences.id, inscriptionData[0].sequenceId)).limit(1); + if (sequenceData.length === 0) throw new Error("Séquence introuvable"); + + const formationId = sequenceData[0].formationId; + const sequenceId = sequenceData[0].id; + + // Créer la structure de dossiers + const uploadsDir = path.resolve(process.cwd(), "uploads", "signatures", `${formationId}-${sequenceId}`); + if (!fs.existsSync(uploadsDir)) { + fs.mkdirSync(uploadsDir, { recursive: true }); + } + + // Générer un nom de fichier unique + const randomSuffix = crypto.randomBytes(8).toString("hex"); + const fileName = `signature-${input.inscriptionId}-${input.dateFormationId}-${randomSuffix}.png`; + const filePath = path.join(uploadsDir, fileName); + + // Convertir le data URL en buffer et sauvegarder const base64Data = input.signatureDataUrl.split(",")[1]; const buffer = Buffer.from(base64Data, "base64"); - const randomSuffix = Math.random().toString(36).substring(7); - const s3Key = `signatures/presence-${input.inscriptionId}-${input.dateFormationId}-${randomSuffix}.png`; - const { url } = await storagePut(s3Key, buffer, "image/png"); - signatureUrl = url; - signatureS3Key = s3Key; + fs.writeFileSync(filePath, buffer); + + // Générer l'URL publique + signatureUrl = `/uploads/signatures/${formationId}-${sequenceId}/${fileName}`; + signatureS3Key = `signatures/${formationId}-${sequenceId}/${fileName}`; } const result = await validerPresence({ diff --git a/todo.md b/todo.md index c653322..e2fc04d 100644 --- a/todo.md +++ b/todo.md @@ -1303,3 +1303,11 @@ - [ ] Intégrer les signatures dans la feuille de présence PDF (optionnel) - [ ] Tester le flux complet sur smartphone - [ ] Déployer sur le VPS + +## Stockage local des signatures d'émargement + +- [ ] Modifier routers.ts pour stocker les signatures localement au lieu de S3 +- [ ] Créer la structure de dossiers uploads/signatures/[formation-id]-[sequence-id]/ +- [ ] Générer des noms de fichiers uniques pour chaque signature +- [ ] Configurer Nginx pour servir les fichiers de signatures +- [ ] Tester le flux complet sur le VPS