Click here to Skip to main content
15,893,588 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
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:

JavaScript
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:


JavaScript
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);
            }
        
            // Create music video
            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();

            // update artist Times
            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 = {};

            // check video 
            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 }});

            // prev artist time update
            this.updateArtistTime(mv.artist);
            // now artist time update
            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;

            // delete music videos
            fs.unlinkSync(`./public${mv.videos}`);
            fs.unlinkSync(`./public${mv.images}`)
            mv.remove();

            // artist time update
            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:


JavaScript
<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


JavaScript
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:

JavaScript
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


JavaScript
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:



JavaScript
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.
Posted
Updated 9-Feb-21 19:43pm

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900