225 lines
7.3 KiB
JavaScript
225 lines
7.3 KiB
JavaScript
"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 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 = path_1.default.join(process.cwd(), '../../uploads', 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 = path_1.default.join(process.cwd(), '../../uploads', 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(process.cwd(), '../../uploads', 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
|
|
});
|
|
}
|
|
res.set({
|
|
'Access-Control-Allow-Origin': 'http://localhost:5173',
|
|
'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
|