I'm trying to upload a video using multer, I have a form and everything but when I click create, validator gives an error however, the file is saved in my directory as if validation was successful. I'm using mongoDB for database.
here's the validator
const { check } = require('express-validator/check');
const Video = require('app/models/VideoModel');
const path = require('path');
class videoValidator extends validator {
handle() {
return [
check('title')
.isLength({ min : 5 })
.withMessage('title should be at least 5 characters'),
check('artist')
.not().isEmpty()
.withMessage('artist field can not be empty'),
check('videos')
.custom(async (value , { req }) => {
if(req.query._method === 'put' && value === undefined) return;
if(! value)
throw new Error('the video field can not remain empty');
let fileExt = ['.webm' , '.ogg' , '.mp4' , '.avi'];
if(! fileExt.includes(path.extname(value)))
throw new Error('file extention is not supported')
}),
}
slug(title) {
return title.replace(/([^۰-۹آ-یa-z0-9]|-)+/g , "-")
}
}
module.exports = new videoValidator();
video Controller
async create(req , res) {
let artists = await Artist.find({});
res.render('admin/videos/create' , { artists });
}
async store(req , res , next) {
try {
let status = await this.validationData(req);
if(! status) return this.back(req,res);
let videos = req.file;
let { title , artist } = req.body;
let newVideo = new Video({
artist,
title,
slug : this.slug(title),
videos,
});
await newVideo.save();
return res.redirect('/admin/videos');
} catch(err) {
next(err);
}
}
Routes and upload helper
const videoUpload = require('app/helpers/uploadVideo');
// video Routes
router.get('/videos' , videoController.index);
router.get('/videos/create' , videoController.create);
router.post('/videos/create' ,
videoUpload.single('videos'),
videoValidator.handle(),
videoController.store
);
const multer = require('multer');
const path = require('path');
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/videos/${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;
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;
Model and ejs
const videoSchema = Schema({
artist: {
type : Schema.Types.ObjectId,
ref : 'Artist'
},
title: {
type : String,
required : true
},
videos: {
type : Object,
required : true
},
time: {
type: String,
default : '00:00:00'
},
videoUrl: {
type : String,
required : true
},
} , { timestamps : true });
module.exports = mongoose.model('Video' , videoSchema);
<div class="d-flex justify-content-between align-items-center mb-3 pb-2 border-bottom">
<h2>add Video</h2>
</div>
<form class="form-horizontal" action="/admin/videos/create" method="post" enctype="multipart/form-data">
<%- include(viewPath('layouts/error-messages')) -%>
<div class="form-group row">
<div class="col">
<label for="title" class="control-label font-weight-bold">Video Title </label>
<input type="text" class="form-control" name="title" id="title" placeholder="video title" value="<%= old('title') %>">
</div>
</div>
<div class="form-group row">
<div class="col">
<label for="artist" class="control-label font-weight-bold font-weight-bold">linked Artist</label>
<select name="artist" id="artist" class="form-control">
<% artists.forEach(artist => { %>
<option value="<%= artist._id %>" <%= String(old('artist')) == String(artist._id) ? 'selected' : '' %> ><%= artist.name %></option>
<% }) %>
</select>
</div>
<div class="col">
<label for="time" class="control-label font-weight-bold">Video Length</label>
<input type="text" class="form-control" name="time" id="time" placeholder="enter video length" value="<%= old('time') %>">
</div>
</div>
<div class="form-group row">
<div class="col">
<label for="videos" class="control-label font-weight-bold">Video File</label>
<input type="file" class="form-control" name="videos" id="videos" placeholder="Enter video file" >
</div>
</div>
<div class="form-group row">
<div class="col">
<button type="submit" class="btn btn-danger">Create</button>
</div>
</div>
</form>
and here's a screen shot of my upload folder that has the video correctly saved in it and it's playable
I just realized I've forgotten to add convertFileToField middleware. it's working fine now
handle(req , res , next) {
if(! req.file)
req.body.videos = undefined;
else
req.body.videos = req.file.filename;
next();
}