const multer = require("multer"); const { UPLOAD_DIR } = require("../config/upload.config"); const CSV_UPLOAD_FIELD = "file"; const upload = multer({ dest: UPLOAD_DIR, limits: { fileSize: 10 * 1024 * 1024 }, }); function respondCsvUploadError(res, statusCode, message, extra = {}) { return res.status(statusCode).json({ status: "failed", message, ...extra, }); } /** * Parses multipart upload and sets req.file from form field "file". * Returns helpful errors when Swagger/Postman sends the wrong shape. */ function handleCsvUpload(req, res, next) { upload.any()(req, res, (err) => { if (err) { if (err.code === "LIMIT_FILE_SIZE") { return respondCsvUploadError( res, 400, "CSV file is too large. Maximum allowed size is 10 MB." ); } if (err.code === "LIMIT_UNEXPECTED_FILE") { return respondCsvUploadError( res, 400, `Unexpected file field "${err.field}". Use form field name "${CSV_UPLOAD_FIELD}" for the CSV.`, { expected_field: CSV_UPLOAD_FIELD, received_field: err.field } ); } return respondCsvUploadError( res, 400, "Could not read uploaded file. Please upload a valid .csv file.", { detail: err.message } ); } const files = Array.isArray(req.files) ? req.files : []; if (files.length === 0) { const contentType = req.headers["content-type"] || ""; if (!contentType.includes("multipart/form-data")) { return respondCsvUploadError( res, 400, "CSV upload must use multipart/form-data, not JSON.", { hint: `Send your .csv in form field "${CSV_UPLOAD_FIELD}". In Swagger: choose the file under "${CSV_UPLOAD_FIELD}" before Execute.`, expected_field: CSV_UPLOAD_FIELD, received_content_type: contentType || "(missing)", } ); } return respondCsvUploadError( res, 400, `No CSV file received. Attach a .csv file to form field "${CSV_UPLOAD_FIELD}".`, { hint: 'In Swagger UI: click "Try it out" → use the file picker for "' + CSV_UPLOAD_FIELD + '" (e.g. hs-codes-sample.csv) → then Execute. Do not leave the file field empty.', expected_field: CSV_UPLOAD_FIELD, example_curl: 'curl -F "file=@hs-codes-sample.csv;type=text/csv" ...', } ); } const csvFile = files.find((f) => f.fieldname === CSV_UPLOAD_FIELD); if (!csvFile) { const receivedFields = [...new Set(files.map((f) => f.fieldname))]; return respondCsvUploadError( res, 400, `CSV must use form field "${CSV_UPLOAD_FIELD}", but received: ${receivedFields.join(", ")}.`, { hint: `Change the form field name to "${CSV_UPLOAD_FIELD}" and upload again.`, expected_field: CSV_UPLOAD_FIELD, received_fields: receivedFields, } ); } if (files.length > 1) { return respondCsvUploadError( res, 400, "Only one CSV file can be uploaded per request.", { hint: `Send a single file in field "${CSV_UPLOAD_FIELD}".`, received_file_count: files.length, } ); } req.file = csvFile; return next(); }); } module.exports = { handleCsvUpload, CSV_UPLOAD_FIELD };