diff --git a/.replit b/.replit index 2e1a3ae..baa3edd 100644 --- a/.replit +++ b/.replit @@ -37,4 +37,4 @@ args = "npm run dev" waitForPort = 5000 [agent] -integrations = ["javascript_object_storage==1.0.0", "javascript_database==1.0.0", "javascript_log_in_with_replit==1.0.0"] +integrations = ["javascript_object_storage==1.0.0", "javascript_log_in_with_replit==1.0.0", "javascript_database==1.0.0"] diff --git a/attached_assets/Pasted--dbHost-logiflow-db-PRODUCTION-Using-standard-PostgreSQL-PostgreSQL-c-1756892354894_1756892354895.txt b/attached_assets/Pasted--dbHost-logiflow-db-PRODUCTION-Using-standard-PostgreSQL-PostgreSQL-c-1756892354894_1756892354895.txt new file mode 100644 index 0000000..386191f --- /dev/null +++ b/attached_assets/Pasted--dbHost-logiflow-db-PRODUCTION-Using-standard-PostgreSQL-PostgreSQL-c-1756892354894_1756892354895.txt @@ -0,0 +1,195 @@ + + + dbHost: 'logiflow-db' + +} + +🐳 PRODUCTION: Using standard PostgreSQL + +✅ PostgreSQL connection test successful + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db:5432' + +} + +✅ Using DatabaseStorage (production PostgreSQL) + +⏰ Automatic backup scheduled for daily 2:00 AM+ (native timer) + +file:///app/dist/index.js:11 + + throw Error('Dynamic require of "' + x2 + '" is not supported'); + + + +^ + +Error: Dynamic require of "stream" is not supported + + at file:///app/dist/index.js:11:9 + + at node_modules/busboy/lib/types/multipart.js (file:///app/dist/index.js:7398:34) + + at __require2 (file:///app/dist/index.js:17:50) + + at node_modules/busboy/lib/index.js (file:///app/dist/index.js:9024:7) + + at __require2 (file:///app/dist/index.js:17:50) + + at file:///app/dist/index.js:25027:29 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + +Node.js v20.19.4 + +Applying DLC migration... + +NOTICE: column "stock_epuise" of relation "dlc_products" already exists, skipping + +NOTICE: column "stock_epuise_by" of relation "dlc_products" already exists, skipping + +NOTICE: column "stock_epuise_at" of relation "dlc_products" already exists, skipping + +NOTICE: relation "idx_dlc_products_stock_epuise" already exists, skipping + +ALTER TABLE + + CREATE INDEX + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db' + +} + +🐳 PRODUCTION: Using standard PostgreSQL + +✅ PostgreSQL connection test successful + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db:5432' + +} + +✅ Using DatabaseStorage (production PostgreSQL) + +⏰ Automatic backup scheduled for daily 2:00 AM+ (native timer) + +file:///app/dist/index.js:11 + + throw Error('Dynamic require of "' + x2 + '" is not supported'); + + + +^ + +Error: Dynamic require of "stream" is not supported + + at file:///app/dist/index.js:11:9 + + at node_modules/busboy/lib/types/multipart.js (file:///app/dist/index.js:7398:34) + + at __require2 (file:///app/dist/index.js:17:50) + + at node_modules/busboy/lib/index.js (file:///app/dist/index.js:9024:7) + + at __require2 (file:///app/dist/index.js:17:50) + + at file:///app/dist/index.js:25027:29 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + +Node.js v20.19.4 + +Applying DLC migration... + +NOTICE: column "stock_epuise" of relation "dlc_products" already exists, skipping + +NOTICE: column "stock_epuise_by" of relation "dlc_products" already exists, skipping + +NOTICE: column "stock_epuise_at" of relation "dlc_products" already exists, skipping + +NOTICE: relation "idx_dlc_products_stock_epuise" already exists, skipping + +ALTER TABLE + + CREATE INDEX + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db' + +} + +🐳 PRODUCTION: Using standard PostgreSQL + +✅ PostgreSQL connection test successful + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db:5432' + +} + +✅ Using DatabaseStorage (production PostgreSQL) + +⏰ Automatic backup scheduled for daily 2:00 AM+ (native timer) + +file:///app/dist/index.js:11 + + throw Error('Dynamic require of "' + x2 + '" is not supported'); + + + +^ + +Error: Dynamic require of "stream" is not supported + + at file:///app/dist/index.js:11:9 + + at node_modules/busboy/lib/types/multipart.js (file:///app/dist/index.js:7398:34) + + at __require2 (file:///app/dist/index.js:17:50) + + at node_modules/busboy/lib/index.js (file:///app/dist/index.js:9024:7) + + at __require2 (file:///app/dist/index.js:17:50) + + at file:///app/dist/index.js:25027:29 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + +Node.js v20.19.4 \ No newline at end of file diff --git a/client/src/components/Sidebar.tsx b/client/src/components/Sidebar.tsx index 6ed53a8..fdfe746 100644 --- a/client/src/components/Sidebar.tsx +++ b/client/src/components/Sidebar.tsx @@ -102,9 +102,24 @@ export default function Sidebar() { startProcessingTimer(); try { - const formData = new FormData(); - formData.append('pdf', selectedFile); - formData.append('recipient', selectedRecipient); + // Convertir le fichier en base64 + const pdfBase64 = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const result = reader.result as string; + // Enlever le prĂ©fixe "data:application/pdf;base64," + const base64 = result.split(',')[1]; + resolve(base64); + }; + reader.onerror = () => reject(new Error('Erreur lors de la lecture du fichier')); + reader.readAsDataURL(selectedFile); + }); + + const requestBody = { + pdfBase64, + fileName: selectedFile.name, + recipient: selectedRecipient + }; // CrĂ©er un AbortController pour gĂ©rer le timeout const controller = new AbortController(); @@ -112,7 +127,10 @@ export default function Sidebar() { const response = await fetch('/api/bap/send-webhook', { method: 'POST', - body: formData, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), signal: controller.signal, credentials: 'include' }); diff --git a/package-lock.json b/package-lock.json index 43c4e45..8a3a249 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,13 +41,11 @@ "@radix-ui/react-tooltip": "^1.2.0", "@tanstack/react-query": "^5.60.5", "@types/bcrypt": "^6.0.0", - "@types/busboy": "^1.5.4", "@types/form-data": "^2.2.1", "@types/memoizee": "^0.4.12", "@types/node-fetch": "^2.6.13", "@types/pg": "^8.15.4", "bcrypt": "^6.0.0", - "busboy": "^1.6.0", "caniuse-lite": "^1.0.30001727", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -3625,15 +3623,6 @@ "@types/node": "*" } }, - "node_modules/@types/busboy": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.4.tgz", - "integrity": "sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -4232,17 +4221,6 @@ "node": ">=6.14.2" } }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -8450,14 +8428,6 @@ "node": ">= 0.8" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", diff --git a/package.json b/package.json index df234ac..8658697 100644 --- a/package.json +++ b/package.json @@ -43,13 +43,11 @@ "@radix-ui/react-tooltip": "^1.2.0", "@tanstack/react-query": "^5.60.5", "@types/bcrypt": "^6.0.0", - "@types/busboy": "^1.5.4", "@types/form-data": "^2.2.1", "@types/memoizee": "^0.4.12", "@types/node-fetch": "^2.6.13", "@types/pg": "^8.15.4", "bcrypt": "^6.0.0", - "busboy": "^1.6.0", "caniuse-lite": "^1.0.30001727", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/server/routes.ts b/server/routes.ts index 54d7587..b411d81 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -49,7 +49,6 @@ import { eq, desc, or, isNull } from "drizzle-orm"; import { invoiceVerificationService } from "./invoiceVerification"; import { backupService } from "./backupService"; import { weatherService } from "./weatherService.js"; -import Busboy from 'busboy'; import fetch from "node-fetch"; export async function registerRoutes(app: Express): Promise { @@ -78,69 +77,35 @@ export async function registerRoutes(app: Express): Promise { return res.status(403).json({ error: 'AccĂšs refusĂ© - Admin uniquement' }); } - // Parser le multipart/form-data avec busboy - const busboy = Busboy({ headers: req.headers }); - let fileBuffer: Buffer | null = null; - let fileName = ''; - let recipient = ''; - let mimeType = ''; - - const parsePromise = new Promise((resolve, reject) => { - busboy.on('file', (fieldname, file, info) => { - const { filename, mimeType: fileMimeType } = info; - - if (fieldname === 'pdf') { - fileName = filename; - mimeType = fileMimeType; - - const chunks: Buffer[] = []; - file.on('data', (chunk) => { - chunks.push(chunk); - }); - - file.on('end', () => { - fileBuffer = Buffer.concat(chunks); - }); - } else { - file.resume(); // Ignorer les autres fichiers - } - }); - - busboy.on('field', (fieldname, val) => { - if (fieldname === 'recipient') { - recipient = val; - } - }); - - busboy.on('finish', () => { - resolve(); - }); - - busboy.on('error', (err) => { - reject(err); - }); - }); - - req.pipe(busboy); - await parsePromise; + // RĂ©cupĂ©rer les donnĂ©es JSON du body + const { pdfBase64, fileName, recipient } = req.body; // Valider les donnĂ©es - if (!fileBuffer) { - return res.status(400).json({ error: 'Aucun fichier PDF fourni' }); + if (!pdfBase64 || !fileName || !recipient) { + return res.status(400).json({ error: 'DonnĂ©es manquantes: pdfBase64, fileName ou recipient' }); } - if (mimeType !== 'application/pdf') { + if (!['Prissela', 'CĂ©lia'].includes(recipient)) { + return res.status(400).json({ error: 'Destinataire invalide' }); + } + + // VĂ©rifier l'extension PDF + if (!fileName.toLowerCase().endsWith('.pdf')) { return res.status(400).json({ error: 'Le fichier doit ĂȘtre un PDF' }); } - if (!recipient || !['Prissela', 'CĂ©lia'].includes(recipient)) { - return res.status(400).json({ error: 'Destinataire invalide' }); + // DĂ©coder le base64 en buffer + let fileBuffer: Buffer; + try { + fileBuffer = Buffer.from(pdfBase64, 'base64'); + } catch (error) { + return res.status(400).json({ error: 'Format base64 invalide' }); } console.log('đŸ“€ BAP: Envoi webhook n8n', { recipient, fileName, - fileSize: fileBuffer?.length || 0, + fileSize: fileBuffer.length, userId: user.id });