"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = require("express"); const client_1 = require("@prisma/client"); const multer_1 = __importDefault(require("multer")); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const config_1 = require("../config/config"); const router = (0, express_1.Router)(); const prisma = new client_1.PrismaClient(); const getUploadsDir = (subPath) => { const localUploadsDir = path_1.default.join(process.cwd(), 'uploads'); const legacyUploadsDir = path_1.default.join(process.cwd(), '../../uploads'); const baseDir = fs_1.default.existsSync(localUploadsDir) ? localUploadsDir : legacyUploadsDir; return subPath ? path_1.default.join(baseDir, subPath) : baseDir; }; const storage = multer_1.default.diskStorage({ destination: (req, file, cb) => { const recipeNumber = req.body.recipeNumber || req.params.recipeNumber; if (!recipeNumber) { return cb(new Error('Recipe number is required'), ''); } const uploadDir = getUploadsDir(recipeNumber); if (!fs_1.default.existsSync(uploadDir)) { fs_1.default.mkdirSync(uploadDir, { recursive: true }); } cb(null, uploadDir); }, filename: (req, file, cb) => { const recipeNumber = req.body.recipeNumber || req.params.recipeNumber; if (!recipeNumber) { return cb(new Error('Recipe number is required'), ''); } const uploadDir = getUploadsDir(recipeNumber); const existingFiles = fs_1.default.existsSync(uploadDir) ? fs_1.default.readdirSync(uploadDir).filter(f => f.match(new RegExp(`^${recipeNumber}_\\d+\\.jpg$`))) : []; const nextIndex = existingFiles.length; const filename = `${recipeNumber}_${nextIndex}.jpg`; cb(null, filename); } }); const upload = (0, multer_1.default)({ storage, limits: { fileSize: config_1.config.upload.maxFileSize, }, fileFilter: (req, file, cb) => { const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']; if (allowedTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new Error('Invalid file type. Only JPEG, PNG and WebP are allowed.')); } }, }); router.post('/upload/:recipeId', upload.array('images', 10), async (req, res, next) => { try { const { recipeId } = req.params; const files = req.files; if (!recipeId) { return res.status(400).json({ success: false, message: 'Recipe ID is required', }); } if (!files || files.length === 0) { return res.status(400).json({ success: false, message: 'No files uploaded', }); } const recipe = await prisma.recipe.findUnique({ where: { id: parseInt(recipeId) } }); if (!recipe) { return res.status(404).json({ success: false, message: 'Recipe not found', }); } const imagePromises = files.map(file => { const relativePath = `uploads/${recipe.recipeNumber}/${file.filename}`; return prisma.recipeImage.create({ data: { recipeId: parseInt(recipeId), filePath: relativePath, } }); }); const images = await Promise.all(imagePromises); return res.status(201).json({ success: true, data: images, message: `${files.length} images uploaded successfully`, }); } catch (error) { if (req.files) { const files = req.files; files.forEach(file => { if (fs_1.default.existsSync(file.path)) { fs_1.default.unlinkSync(file.path); } }); } next(error); } }); router.delete('/:id', async (req, res, next) => { try { const { id } = req.params; if (!id) { return res.status(400).json({ success: false, message: 'Image ID is required', }); } const image = await prisma.recipeImage.findUnique({ where: { id: parseInt(id) } }); if (!image) { return res.status(404).json({ success: false, message: 'Image not found', }); } const fullPath = path_1.default.join(process.cwd(), '../..', image.filePath); if (fs_1.default.existsSync(fullPath)) { fs_1.default.unlinkSync(fullPath); } await prisma.recipeImage.delete({ where: { id: parseInt(id) } }); return res.json({ success: true, message: 'Image deleted successfully', }); } catch (error) { next(error); } }); router.get('/recipe/:recipeId', async (req, res, next) => { try { const { recipeId } = req.params; if (!recipeId) { return res.status(400).json({ success: false, message: 'Recipe ID is required', }); } const images = await prisma.recipeImage.findMany({ where: { recipeId: parseInt(recipeId) }, orderBy: { id: 'asc' } }); return res.json({ success: true, data: images, }); } catch (error) { next(error); } }); router.get('/serve/:imagePath(*)', (req, res, next) => { try { const imagePath = req.params.imagePath; if (!imagePath) { return res.status(400).json({ success: false, message: 'Image path is required', }); } const cleanPath = imagePath.replace(/^uploads\//, ''); const fullPath = path_1.default.join(getUploadsDir(), cleanPath); console.log(`Serving image: ${imagePath} -> ${fullPath}`); if (!fs_1.default.existsSync(fullPath)) { console.log(`Image not found: ${fullPath}`); return res.status(404).json({ success: false, message: 'Image not found', requestedPath: imagePath, resolvedPath: fullPath }); } const allowedOrigins = ['http://localhost:5173', 'http://localhost:3000']; const origin = req.headers.origin; const corsOrigin = process.env.CORS_ORIGIN === '*' ? (origin || '*') : (origin && allowedOrigins.includes(origin)) ? origin : 'http://localhost:3000'; res.set({ 'Access-Control-Allow-Origin': corsOrigin, 'Access-Control-Allow-Credentials': 'true', 'Cache-Control': 'public, max-age=31536000', }); return res.sendFile(path_1.default.resolve(fullPath)); } catch (error) { console.error('Error serving image:', error); next(error); } }); router.get('/:id', async (req, res, next) => { try { const { id } = req.params; if (!id) { return res.status(400).json({ success: false, message: 'Image ID is required', }); } const image = await prisma.recipeImage.findUnique({ where: { id: parseInt(id) } }); if (!image) { return res.status(404).json({ success: false, message: 'Image not found', }); } return res.json({ success: true, data: image, }); } catch (error) { next(error); } }); exports.default = router; //# sourceMappingURL=images.js.map