Files
clube67_newwhats.local/clube67/newwhats.local/plugins/uploads/backend/routes.js
T
VPS 4 Deploy Agent 45b7b91b04 fix(plugins): use conditional require for production Docker compatibility
Replace static require('backend/src/...') with NODE_ENV-conditional
requires in compiled plugin JS and TypeScript sources.
In production Docker /app/backend/src/ does not exist — only /app/dist/.
Fixes MODULE_NOT_FOUND errors on UnifiedStorageProvider, ext-api,
leads, nanobana, and uploads plugins.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 08:34:34 +02:00

153 lines
7.2 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUploadRoutes = createUploadRoutes;
const express_1 = require("express");
const multer_1 = __importDefault(require("multer"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
function createUploadRoutes(ctx) {
const router = (0, express_1.Router)();
const uploadDir = process.env.UPLOAD_DIR || path_1.default.join(process.cwd(), 'uploads');
if (!fs_1.default.existsSync(uploadDir))
fs_1.default.mkdirSync(uploadDir, { recursive: true });
const storage = multer_1.default.diskStorage({
destination: (_req, _file, cb) => cb(null, uploadDir),
filename: (_req, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
});
const upload = (0, multer_1.default)({ storage, limits: { fileSize: 5 * 1024 * 1024 } });
// POST / — Upload file
router.post('/', upload.single('file'), async (req, res) => {
try {
if (!req.file)
return res.status(400).json({ error: 'Nenhum arquivo enviado' });
const destination = req.query.destination;
const category = req.query.category || 'media';
let fileBuffer = fs_1.default.readFileSync(req.file.path);
let mimetype = req.file.mimetype;
// Emit transformation hook
const transformResults = await ctx.hooks.emit('upload:transform', {
buffer: fileBuffer,
mimetype: mimetype,
category: category,
originalname: req.file.originalname,
partnerId: req.body.partnerId
});
// If a plugin transformed the file, use the last result
if (transformResults && transformResults.length > 0) {
const lastResult = transformResults[transformResults.length - 1];
if (lastResult && lastResult.buffer) {
fileBuffer = lastResult.buffer;
mimetype = lastResult.mimetype || mimetype;
}
}
if (destination === 'cloud') {
if (fs_1.default.existsSync(req.file.path))
fs_1.default.unlinkSync(req.file.path);
// Use a more robust import for the singleton (conditional for production Docker)
const storageCore = process.env.NODE_ENV === 'production'
? require('../../../../dist/core/StorageProvider')
: require('../../../../backend/src/core/StorageProvider');
const provider = storageCore.storageProvider || (storageCore.default && storageCore.default.storageProvider);
if (!provider) {
ctx.logger.error('[Uploads] StorageProvider not found in core');
return res.status(500).json({ error: 'Storage core unavailable' });
}
const cloudResult = await provider.uploadFile({
category,
partnerId: req.body.partnerId,
benefitId: req.body.benefitId,
postId: req.body.postId,
whatsappId: req.body.whatsappId,
file: {
originalname: req.file.originalname,
buffer: fileBuffer,
mimetype: mimetype
}
});
return res.json({
url: `https://${process.env.WASABI_BUCKET}.s3.wasabisys.com/${cloudResult.path}`,
filename: req.file.filename,
provider: 'wasabi'
});
}
// Local storage fallback: save the potentially transformed buffer
if (transformResults && transformResults.length > 0) {
fs_1.default.writeFileSync(req.file.path, fileBuffer);
}
const url = `/uploads/${req.file.filename}`;
await ctx.hooks.emit('upload:completed', { filename: req.file.filename, url });
res.json({ url, filename: req.file.filename, size: fileBuffer.length });
}
catch (err) {
console.error('[Uploads] Error:', err);
res.status(500).json({ error: 'Erro no upload' });
}
});
// POST /logo — Upload partner logo
router.post('/logo', upload.single('logo'), async (req, res) => {
try {
if (!req.file)
return res.status(400).json({ error: 'Nenhum logo enviado' });
let fileBuffer = fs_1.default.readFileSync(req.file.path);
let mimetype = req.file.mimetype;
// Emit transformation hook
const transformResults = await ctx.hooks.emit('upload:transform', {
buffer: fileBuffer,
mimetype: mimetype,
category: 'partners',
originalname: req.file.originalname
});
if (transformResults && transformResults.length > 0) {
const lastResult = transformResults[transformResults.length - 1];
if (lastResult && lastResult.buffer) {
fileBuffer = lastResult.buffer;
mimetype = lastResult.mimetype || mimetype;
// Overwrite local file with optimized version
fs_1.default.writeFileSync(req.file.path, fileBuffer);
}
}
const url = `/uploads/${req.file.filename}`;
res.json({ url, filename: req.file.filename });
}
catch (err) {
console.error('[Uploads] Logo Error:', err);
res.status(500).json({ error: 'Erro no upload do logo' });
}
});
// DELETE /:filename — Delete file
router.delete('/:filename', async (req, res) => {
try {
const filePath = path_1.default.join(uploadDir, req.params.filename);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
await ctx.hooks.emit('upload:deleted', { filename: req.params.filename });
res.json({ message: 'Arquivo removido' });
}
else {
res.status(404).json({ error: 'Arquivo não encontrado' });
}
}
catch (err) {
res.status(500).json({ error: 'Erro ao remover' });
}
});
// GET /:filename — Legacy access with Washabi Fallback 🛡️
router.get('/:filename', async (req, res) => {
const { filename } = req.params;
const localPath = path_1.default.join(uploadDir, filename);
// 🛡️ If exists locally, serve normally
if (fs_1.default.existsSync(localPath)) {
return res.sendFile(localPath);
}
// 🚀 If NOT local, redirect or proxy to UnifiedStorageProvider
// We know most legacy uploads go to the 'media' category in the proxy
const storageProxyUrl = `/api/storage/view/media/${filename}`;
ctx.logger.info(`[Uploads:Fallback] Redirecting legacy file ${filename} -> ${storageProxyUrl}`);
res.redirect(storageProxyUrl);
});
return router;
}
//# sourceMappingURL=routes.js.map