I'm uploading a video and an Image(to use as the thumbnail for video) from an
ejs form, using multer, they successfully upload and I have access to them however, I can't update/edit them properly, since I have to reupload both files every time I'm editing any of my fields and, the validator has also suddenly, stopped working.
this is a long question but I really appreciate it, if anyone can help me.
I'm using node, express, mongodb, multer for handling uploads and express-validator v.5.1.2 for validation
p.s. the validator was working fine when I was uploading a single file
The Routes:
router.get('/mvs', mvController.index);
router.get('/mvs/create', mvController.create);
router.post('/mvs/create',
uploadVideo.fields([{
name: 'videos', maxCount: 1
}, {
name: 'images', maxCount: 1
}]),
convertFileToField.videoHandle,
mvValidator.handle(),
mvController.store
);
router.get('/mvs/:id/edit', mvController.edit);
router.put('/mvs/:id',
uploadVideo.fields([{
name: 'videos', maxCount: 1
}, {
name: 'images', maxCount: 1
}]),
convertFileToField.videoHandle,
mvValidator.handle(),
mvController.update
);
router.delete('/mvs/:id', mvController.destroy);
videoController:
const fs = require('fs');
const path = require('path');
const controller = require('app/http/controllers/controller');
const Artist = require('app/models/artist');
const MV = require('app/models/mv');
class mvController extends controller {
async index(req , res) {
try {
let page = req.query.page || 1;
let mvs = await MV.paginate({} , { page , sort : { createdAt : 1 } , limit : 5 });
res.render('admin/mvs/index', { title : 'music-videos' , mvs });
} catch (err) {
next(err);
}
}
async create(req , res) {
let artists = await Artist.find({});
res.render('admin/mvs/create' , { artists });
}
async store(req , res , next) {
try {
let status = await this.validationData(req);
if(! status) {
if(req.file)
fs.unlinkSync(req.file.path);
return this.back(req,res);
}
let videos = this.videoPath(req.files['videos'][0]);
let images = this.videoPath(req.files['images'][0]);
let { title, artist} = req.body;
let newMV = new MV({
title,
slug : this.slug(title),
artist,
videos,
images
});
await newMV.save();
this.updateArtistTime(req.body.artist);
return res.redirect('/admin/mvs');
} catch(err) {
next(err);
}
}
async edit(req, res ,next) {
try {
this.isMongoId(req.params.id);
let mv = await MV.findById(req.params.id);
let artists = await Artist.find({});
if( ! mv ) this.error('video does not exist' , 404);
return res.render('admin/mvs/edit' , { mv , artists });
} catch (err) {
next(err);
}
}
async update(req, res , next) {
try {
let status = await this.validationData(req);
if(! status) {
if(req.files)
fs.unlinkSync(req.files.path);
return this.back(req,res);
}
let objForUpdate = {};
if(req.files) {
objForUpdate.videos = this.videoPath(req.files['videos'][0]);
objForUpdate.images = this.videoPath(req.files['images'][0]);
}
delete req.body.videos;
delete req.body.images;
objForUpdate.slug = this.slug(req.body.title);
let mv = await MV.findByIdAndUpdate(req.params.id , { $set : { ...req.body, ...objForUpdate }});
this.updateArtistTime(mv.artist);
this.updateArtistTime(req.body.artist);
return res.redirect('/admin/mvs');
} catch(err) {
next(err);
}
}
async destroy(req , res , next) {
try {
this.isMongoId(req.params.id);
let mv = await MV.findById(req.params.id);
if( ! mv ) this.error('video does not exist' , 404);
let artistId = mv.artist;
fs.unlinkSync(`./public${mv.videos}`);
fs.unlinkSync(`./public${mv.images}`)
mv.remove();
this.updateArtistTime(artistId);
return res.redirect('/admin/mvs');
} catch (err) {
next(err);
}
}
async updateArtistTime(artistId) {
let artist = await Artist.findById(artistId).populate('mvs').exec();
artist.set({ time : this.getTime(artist.mvs)});
await artist.save();
}
videoPath(video) {
let addressVideos = this.getUrlVideo(`${video.destination}/${video.filename}`);
return addressVideos;
}
getUrlVideo(dir) {
return dir.substring(8);
}
slug(title) {
return title.replace(/([^۰-۹آ-یa-z0-9]|-)+/g , "-")
}
}
module.exports = new mvController();
uploadVideo helper:
<pre>const multer = require('multer');
const mkdirp = require('mkdirp');
const fs = require('fs');
const getDirVideo = () => {
let year = new Date().getFullYear();
let month = new Date().getMonth() + 1;
let day = new Date().getDay();
return `./public/uploads/mvs/${year}/${month}/${day}`;
}
const videoStorage = multer.diskStorage({
destination : (req , file , cb) => {
let dir = getDirVideo();
mkdirp(dir , (err) => cb(null , dir))
},
filename : (req , file , cb) => {
let filePath = getDirVideo() + '/' + file.originalname;
console.log(filePath);
if(!fs.existsSync(filePath))
cb(null , file.originalname);
else
cb(null , Date.now() + '-' + file.originalname);
}
})
const uploadVideo = multer({
storage : videoStorage,
limits : {
fileSize : 1024 * 1024 * 40
}
});
module.exports = uploadVideo;
videoHandle middlware
videoHandle(req , res , next) {
if(! req.files) {
req.body.videos = undefined;
req.body.images = undefined;
}
else {
req.body.videos = req.files.videos[0].filename;
req.body.images = req.files.images[0].filename;
}
next();
}
validator:
const validator = require('./validator');
const { check } = require('express-validator/check');
const Artist = require('app/models/artist');
const MV = require('app/models/mv');
const path = require('path');
class mvValidator extends validator {
handle() {
return [
check('title')
.isLength({ min : 3 })
.withMessage('title can not be less than 3 characters'),
check('artist')
.not().isEmpty()
.withMessage('related artist can not remain empty'),
check('videos')
.custom(async (value , { req }) => {
if(req.query._method === 'put' && value === undefined) return;
if(! value)
throw new Error('video can not remain empty');
let fileExt = ['.webm' , '.mp4' , '.flv' , '.avi'];
if(! fileExt.includes(path.extname(value)))
throw new Error('file extention is not acceptable');
}),
check('images')
.custom(async (value , { req }) => {
if(req.query._method === 'put' && value === undefined) return;
if(! value)
throw new Error('video thumbnail can not remain empty');
let fileExt = ['.png' , '.jpg' , '.jpeg' , '.svg'];
if(! fileExt.includes(path.extname(value)))
throw new Error('file extention is not acceptable')
})
]
}
slug(title) {
return title.replace(/([^۰-۹آ-یa-z0-9]|-)+/g , "-")
}
}
module.exports = new mvValidator();
the error I'm getting when updating the form
TypeError: Cannot read property '0' of undefined
at convertFileToField.videoHandle (E:\Baritone_final - Copy\app\http\middleware\convertFileToField.js:22:47)
at Layer.handle [as handle_request] (E:\Baritone_final - Copy\node_modules\express\lib\router\layer.js:95:5)
at next (E:\Baritone_final - Copy\node_modules\express\lib\router\route.js:137:13)
at Immediate._onImmediate (E:\Baritone_final - Copy\node_modules\multer\lib\make-middleware.js:53:37)
at processImmediate (internal/timers.js:463:21)
the error I get from validator when I leave a field empty instead of the validator message:
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
What I have tried:
I've tried using both if(!req.file) and if(req.files) in videoHandle to update when files already exist and not having to reupload them.