From df687d7044c94d0fe74b60003a1b4865b4697fbd Mon Sep 17 00:00:00 2001 From: Lixian Zhou Date: Thu, 12 Mar 2026 18:19:22 -0400 Subject: [PATCH] fix --- app/controllers/upload.controller.js | 98 ++++++++++++++++++- .../components/signature/DriverSignature.js | 4 +- client/src/services/CustomerService.js | 6 +- 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/app/controllers/upload.controller.js b/app/controllers/upload.controller.js index 827a138..6968cf8 100644 --- a/app/controllers/upload.controller.js +++ b/app/controllers/upload.controller.js @@ -10,12 +10,88 @@ const path = require("path"); const url = dbConfig.url; const baseUrl = dbConfig.fileUrl; const mongoClient = new MongoClient(url); +const BASE_UPLOAD_DIR = `/www/wwwroot/upload/`; +const DRIVER_SIGNATURE_DIR = path.join(BASE_UPLOAD_DIR, 'driver', 'sig'); +const uploadToMemory = multer({ + storage: multer.memoryStorage(), + limits: { fileSize: 10 * 1024 * 1024 } +}).single("file"); +const uploadToMemoryAsync = util.promisify(uploadToMemory); const readdir = util.promisify(fs.readdir); const stat = util.promisify(fs.stat); +const isDriverSignatureFileName = (name = '') => { + const safeName = `${name || ''}`.trim(); + return /^.+_.+_\d{2}_\d{2}$/.test(safeName); +}; + +const getDriverSignatureYear = (req) => { + const queryYear = `${req?.query?.year || ''}`.trim(); + if (/^\d{4}$/.test(queryYear)) { + return queryYear; + } + return `${new Date().getFullYear()}`; +}; + +const resolveSignatureExt = (mimetype = '', originalName = '') => { + const safeMimetype = `${mimetype || ''}`.toLowerCase(); + if (safeMimetype.includes('png')) return '.png'; + if (safeMimetype.includes('jpeg') || safeMimetype.includes('jpg')) return '.jpg'; + const ext = path.extname(`${originalName || ''}`.toLowerCase()); + if (ext === '.png' || ext === '.jpg' || ext === '.jpeg') return ext; + return '.jpg'; +}; + +const findDriverSignatureFilePath = async (fileBaseName = '') => { + const safeName = `${fileBaseName || ''}`.trim(); + if (!safeName) return null; + if (!fs.existsSync(DRIVER_SIGNATURE_DIR)) return null; + + const yearFolders = await readdir(DRIVER_SIGNATURE_DIR, { withFileTypes: true }); + const yearDirs = yearFolders.filter((entry) => entry.isDirectory()).map((entry) => path.join(DRIVER_SIGNATURE_DIR, entry.name)); + for (const yearDir of yearDirs) { + const candidates = [ + path.join(yearDir, safeName), + path.join(yearDir, `${safeName}.jpg`), + path.join(yearDir, `${safeName}.jpeg`), + path.join(yearDir, `${safeName}.png`) + ]; + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + } + return null; +}; + const uploadFiles = async (req, res) => { try { + const fileName = `${req?.params?.filename || ''}`.trim(); + if (!fileName) { + return res.status(400).send({ message: "Invalid filename." }); + } + // Driver signature upload now stores to shared server files. + if (isDriverSignatureFileName(fileName)) { + await uploadToMemoryAsync(req, res); + if (!req.file) { + return res.status(400).send({ message: "You must select a file." }); + } + const year = getDriverSignatureYear(req); + const targetDir = path.join(DRIVER_SIGNATURE_DIR, year); + if (!fs.existsSync(targetDir)) { + fs.mkdirSync(targetDir, { recursive: true }); + } + const ext = resolveSignatureExt(req.file?.mimetype, req.file?.originalname); + const targetFilePath = path.join(targetDir, `${fileName}${ext}`); + fs.writeFileSync(targetFilePath, req.file.buffer); + return res.send({ + message: "Driver signature has been uploaded.", + path: targetFilePath + }); + } + await upload(req, res); if (req.file == undefined) { return res.send({ @@ -34,11 +110,20 @@ const uploadFiles = async (req, res) => { }; const getFile = async (req, res) => { try { + const fileName = decodeURIComponent(`${req?.params?.name || ''}`.trim()); + if (isDriverSignatureFileName(fileName)) { + const signaturePath = await findDriverSignatureFilePath(fileName); + if (signaturePath) { + const fileBuffer = await fs.promises.readFile(signaturePath); + return res.status(200).send(fileBuffer.toString('base64')); + } + } + await mongoClient.connect(); const database = mongoClient.db(dbConfig.database); const images = database.collection(dbConfig.imgBucket + ".files"); const chunks = database.collection(dbConfig.imgBucket + ".chunks"); - const cursor = await (images.find({filename: req.params.name}).toArray()); + const cursor = await (images.find({filename: fileName}).toArray()); if (cursor.length === 0) { return res.status(500).send({ message: "No files found!", @@ -55,14 +140,21 @@ const getFile = async (req, res) => { const deleteFile = async (req, res) => { try { + const targetName = `${req?.body?.name || ''}`.trim(); + if (isDriverSignatureFileName(targetName)) { + const signaturePath = await findDriverSignatureFilePath(targetName); + if (signaturePath && fs.existsSync(signaturePath)) { + await fs.promises.unlink(signaturePath); + } + } await mongoClient.connect(); const database = mongoClient.db(dbConfig.database); const images = database.collection(dbConfig.imgBucket + ".files"); const chunks = database.collection(dbConfig.imgBucket + ".chunks"); - const cursor = await (images.find({filename: req.body.name}).toArray()); + const cursor = await (images.find({filename: targetName}).toArray()); if (cursor.length > 0) { await chunks.deleteMany({files_id: cursor[cursor.length-1]._id}); - await images.deleteMany({filename: req.body.name}); + await images.deleteMany({filename: targetName}); } return res.status(200).send({ message: 'Delete Image Succeed'}); } catch (error) { diff --git a/client/src/components/signature/DriverSignature.js b/client/src/components/signature/DriverSignature.js index 03ed419..38180f3 100644 --- a/client/src/components/signature/DriverSignature.js +++ b/client/src/components/signature/DriverSignature.js @@ -48,7 +48,9 @@ const DriverSignature = () => { const formData = new FormData(); formData.append('file', blob, `${fileName}.jpg`); - CustomerService.uploadAvatar(fileName, formData).then(() => { + CustomerService.uploadAvatar(fileName, formData, { + year: moment(signatureRequest?.route_date).format('YYYY') + }).then(() => { SignatureRequestService.updateSignatureRequest(signatureRequest?.id, { status: 'done'}).then(() => { SignatureRequestService.getSignatureRequestById(urlParams.id).then((data) => { setSignatureRequest(data?.data); diff --git a/client/src/services/CustomerService.js b/client/src/services/CustomerService.js index 5f94abd..5608851 100644 --- a/client/src/services/CustomerService.js +++ b/client/src/services/CustomerService.js @@ -36,12 +36,14 @@ const deleteClient = (id, data) => { return http.put(`/clients/${id}`, data); } -const uploadAvatar = (filename, data) => { +const uploadAvatar = (filename, data, options = {}) => { const safeFilename = `${filename || ''}`.trim(); if (!safeFilename || safeFilename.includes('undefined') || safeFilename.includes('null')) { throw new Error('Invalid upload filename for avatar/signature.'); } - return http.post(`/files/upload/${encodeURIComponent(safeFilename)}`, data) + return http.post(`/files/upload/${encodeURIComponent(safeFilename)}`, data, { + params: options + }) } const getAvatar = (filename) => {