implented multer to offer endpoints for upload and retrieval of images
This commit is contained in:
parent
31540d4d4b
commit
24f1ca4350
|
|
@ -0,0 +1,80 @@
|
||||||
|
import multer from 'multer';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import config from '../config/index.js';
|
||||||
|
|
||||||
|
const uploadDir = path.resolve(process.cwd(), config.uploadDir);
|
||||||
|
if (!fs.existsSync(uploadDir)) {
|
||||||
|
fs.mkdirSync(uploadDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage = multer.diskStorage({
|
||||||
|
destination: (req, file, cb) => {
|
||||||
|
let userPath = req.body.path || '';
|
||||||
|
|
||||||
|
userPath = path.normalize(userPath).replace(/^(\.\.[\/\\])+/, '');
|
||||||
|
|
||||||
|
const targetPath = path.join(uploadDir, userPath);
|
||||||
|
|
||||||
|
if (!targetPath.startsWith(uploadDir)) {
|
||||||
|
return cb(new Error('Invalid path.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(targetPath)) {
|
||||||
|
fs.mkdirSync(targetPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(null, targetPath);
|
||||||
|
},
|
||||||
|
|
||||||
|
filename: (req, file, cb) => {
|
||||||
|
const randomName = crypto.randomBytes(16).toString('hex');
|
||||||
|
const ext = path.extname(file.originalname);
|
||||||
|
cb(null, randomName + ext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileFilter = (req, file, cb) => {
|
||||||
|
const allowedExtensions = /jpeg|jpg|png|gif/;
|
||||||
|
const allowedMimeTypes = /image\/jpeg|image\/jpg|image\/png|image\/gif/;
|
||||||
|
|
||||||
|
const extname = allowedExtensions.test(path.extname(file.originalname).toLowerCase());
|
||||||
|
const mimetype = allowedMimeTypes.test(file.mimetype);
|
||||||
|
|
||||||
|
if (extname && mimetype) {
|
||||||
|
cb(null, true);
|
||||||
|
} else {
|
||||||
|
cb(new multer.MulterError('LIMIT_UNEXPECTED_FILE', file.fieldname));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const multerUpload = multer({
|
||||||
|
storage,
|
||||||
|
fileFilter,
|
||||||
|
limits: { fileSize: 1024 * 1024 * 1024 } // 1GB
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadMiddleware = (fieldName, multiple = false) => (req, res, next) => {
|
||||||
|
const uploader = multiple ? multerUpload.array(fieldName) : multerUpload.single(fieldName);
|
||||||
|
|
||||||
|
uploader(req, res, (err) => {
|
||||||
|
if (err instanceof multer.MulterError) {
|
||||||
|
return res.status(400).json({ error: err.message });
|
||||||
|
} else if (err) {
|
||||||
|
return res.status(500).json({ error: 'Internal server error during file upload.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!multiple && !req.file) {
|
||||||
|
return res.status(400).json({ error: `No file uploaded under field "${fieldName}"` });
|
||||||
|
}
|
||||||
|
const result = req.file
|
||||||
|
|
||||||
|
next(result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
fileFilter,
|
||||||
|
uploadMiddleware
|
||||||
|
};
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
sendOkResponse,
|
sendOkResponse,
|
||||||
sendResponseNoContent,
|
sendResponseNoContent,
|
||||||
} from '../utils/responses.js'
|
} from '../utils/responses.js'
|
||||||
import { latitudeRange, longitudeRange, uuid, varChar } from '../validators/expressValidator/customValidators.js'
|
import { json, latitudeRange, longitudeRange, uuid, varChar } from '../validators/expressValidator/customValidators.js'
|
||||||
import { integerRange } from '../validators/expressValidator/customValidators.js'
|
import { integerRange } from '../validators/expressValidator/customValidators.js'
|
||||||
import {payloadExpressValidator} from '../validators/expressValidator/payloadExpressValidator.js'
|
import {payloadExpressValidator} from '../validators/expressValidator/payloadExpressValidator.js'
|
||||||
import { authorizePermission, setToken, authenticateToken, refreshAuthenticate} from '../middlewares/auth.js'
|
import { authorizePermission, setToken, authenticateToken, refreshAuthenticate} from '../middlewares/auth.js'
|
||||||
|
|
@ -86,7 +86,7 @@ export default(config) => {
|
||||||
(req, res, next) => indexController(req, res, next),
|
(req, res, next) => indexController(req, res, next),
|
||||||
(result, req, res, next) => addLinks(result, req, res, next, hasAddLinks, linkRoutes),
|
(result, req, res, next) => addLinks(result, req, res, next, hasAddLinks, linkRoutes),
|
||||||
(result, req, res, _) => sendOkResponse(result, req, res)
|
(result, req, res, _) => sendOkResponse(result, req, res)
|
||||||
)
|
);
|
||||||
|
|
||||||
// User Routes
|
// User Routes
|
||||||
/**
|
/**
|
||||||
|
|
@ -974,7 +974,8 @@ export default(config) => {
|
||||||
varChar('address').optional({ nullable: true, values: 'falsy' }),
|
varChar('address').optional({ nullable: true, values: 'falsy' }),
|
||||||
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
||||||
latitudeRange('latitude'),
|
latitudeRange('latitude'),
|
||||||
longitudeRange('longitude')
|
longitudeRange('longitude'),
|
||||||
|
json('images').optional({ nullable: true, values: 'falsy' }),
|
||||||
],
|
],
|
||||||
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
||||||
(req, res, next) => insertPlaceController(req, res, next, config),
|
(req, res, next) => insertPlaceController(req, res, next, config),
|
||||||
|
|
@ -1012,7 +1013,8 @@ export default(config) => {
|
||||||
varChar('address').optional({ nullable: true, values: 'falsy' }),
|
varChar('address').optional({ nullable: true, values: 'falsy' }),
|
||||||
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
||||||
latitudeRange('latitude').optional({ nullable: false, values: 'falsy' }),
|
latitudeRange('latitude').optional({ nullable: false, values: 'falsy' }),
|
||||||
longitudeRange('longitude').optional({nullable: false, values: 'falsy'})
|
longitudeRange('longitude').optional({nullable: false, values: 'falsy'}),
|
||||||
|
json('images').optional({ nullable: true, values: 'falsy' }),
|
||||||
],
|
],
|
||||||
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
||||||
(req, res, next) => modifyPlaceController(req, res, next, config),
|
(req, res, next) => modifyPlaceController(req, res, next, config),
|
||||||
|
|
@ -1221,6 +1223,7 @@ export default(config) => {
|
||||||
uuid('user_uuid'),
|
uuid('user_uuid'),
|
||||||
uuid('report_type_uuid').optional({ nullable: false, values: 'falsy' }),
|
uuid('report_type_uuid').optional({ nullable: false, values: 'falsy' }),
|
||||||
integerRange('rating', {min: 1, max: 3}),
|
integerRange('rating', {min: 1, max: 3}),
|
||||||
|
json('images').optional({ nullable: true, values: 'falsy' }),
|
||||||
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
||||||
],
|
],
|
||||||
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
||||||
|
|
@ -1258,6 +1261,7 @@ export default(config) => {
|
||||||
uuid('user_uuid').optional({ nullable: false, values: 'falsy' }),
|
uuid('user_uuid').optional({ nullable: false, values: 'falsy' }),
|
||||||
uuid('report_type_uuid').optional({ nullable: false, values: 'falsy' }),
|
uuid('report_type_uuid').optional({ nullable: false, values: 'falsy' }),
|
||||||
integerRange('rating', {min: 1, max: 3}).optional({ nullable: false, values: 'falsy' }),
|
integerRange('rating', {min: 1, max: 3}).optional({ nullable: false, values: 'falsy' }),
|
||||||
|
json('images').optional({ nullable: true, values: 'falsy' }),
|
||||||
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
varChar('description').optional({ nullable: true, values: 'falsy' }),
|
||||||
],
|
],
|
||||||
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
(req, res, next) => payloadExpressValidator(req, res, next, config),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { uploadMiddleware } from '../middlewares/upload.js'; // tu middleware multer
|
||||||
|
import { Router } from 'express'
|
||||||
|
|
||||||
|
export default(config) => {
|
||||||
|
/**
|
||||||
|
* Express router to mount user related functions on.
|
||||||
|
* @type {Object}
|
||||||
|
* @const
|
||||||
|
* @namespace placeRouter
|
||||||
|
*/
|
||||||
|
const router = Router()
|
||||||
|
const hasAddLinks = config.environment !== 'production'
|
||||||
|
|
||||||
|
// Single file upload route
|
||||||
|
router.post(
|
||||||
|
'/upload',
|
||||||
|
uploadMiddleware('file'),
|
||||||
|
(result, req, res, next) => addLinks(result, req, res, next, hasAddLinks, linkRoutes),
|
||||||
|
(result, req, res, _) => sendOkResponse(result, req, res));
|
||||||
|
|
||||||
|
// Multiple file upload route
|
||||||
|
router.post(
|
||||||
|
'/upload-multiple',
|
||||||
|
uploadMiddleware('file', true),
|
||||||
|
(result, req, res, next) => addLinks(result, req, res, next, hasAddLinks, linkRoutes),
|
||||||
|
(result, req, res, _) => sendOkResponse(result, req, res)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue