Efijoon
Efijoon

Reputation: 7

Multer doesnt upload but it wont give me any errors

I'm using multer for uploading images for creating courses in my application and my courses have images and I have a form for getting the data from user. I use multer in middleware and add it to my route with upload.single('images') and my field which I get the image from user is named images and that means I have got the image from the user. When I just click on the save button, I won't get any errors and my server will work like it is stuck in a middleware and when I go to my upload folder, I don't see any images loaded! And if I load the image I will save the course in my database which is mongo. But I don't find the course saved too.
I have checked the enctype="multipart/form-data" and it was in my form. And this is my multer middleware code

const multer = require("multer");
const mkdirp = require("mkdirp");
const fs = require("fs");

const getDirImage = () => {
  let year = new Date().getFullYear();
  let month = new Date().getMonth() + 1;
  let day = new Date().getDay();

  return `./public/uploads/images/${year}/${month}/${day}`;
};

const ImageStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    let dir = getDirImage();
    mkdirp(dir).then(made => {
        console.log(`File made on ${made}`);   
    });
  },
  filename: (req, file, cb) => {
    let filePath = getDirImage() + "/" + file.originalname;
    if (!fs.existsSync(filePath)) cb(null, file.originalname);
    else cb(null, Date.now() + "-" + file.originalname);
  },
});

const uploadImage = multer({
  storage: ImageStorage,
  limits: {
    fileSize: 1024 * 1024 * 10,
  },
});

module.exports = uploadImage;

and this is the middlewares which I referenced it to my handler of route controller

router.post("/courses/create", upload.single("images"), convertFileToField.handle, courseValidator.handle(), courseController.storeCourse);

and this is the convertFileToField Code

const middleware = require('./middleware');

class ConvertFiletoField extends middleware {
  handle(req, res, next) {
    if (!req.file)
        req.body.images = undefined;
    else 
        req.body.images = req.file.filename;

    next();
  }
}

module.exports = new ConvertFiletoField();

And this is the courseValidator Middleware Code

const validator = require('./validator');
const Course = require("app/models/Course");
const path = require("path");
const { check } = require("express-validator/check");

class courseValidator extends validator {
  handle() {
    return [
      check("title")
        .not()
        .isEmpty()
        .withMessage("فیلد عنوان نمیتواند خالی بماند")
        .custom(async (value) => {
          const course = await Course.findOne({ slug: this.slug(value)});
          if (course) {
            throw new Error('we have this course on our site !!!!')
          }
        }),

      check('images')
        .custom(async value => {
          if (! value) {
            throw new Error('You need to enter a course !');
          }
          let fileExt = ['.png', '.jpg', 'jpeg', '.svg'];

          if (! fileExt.includes(path.extname(value)))
            throw new Error('the course extention is not valid !'); 
        }),

    ];
  }

  slug(title) {
    return title.replace(/([^۰-۹آ-یa-z0-9]|-)+/g, "-");
  }
}

module.exports = new courseValidator();

And Finally this is the post route handler

const controller = require("app/http/controllers/controller");
const Course = require("app/models/Course");
const fs = require('fs');
const path = require("path");
const sharp = require("sharp");

class courseController extends controller {
  showCourses(req, res) {
    const courses = Course.find({}).sort({ createdAt: -1 });
    res.render("admin/courses/index", { courses: courses });
  }

  createCourse(req, res) {
    res.render("admin/courses/create");
  }

  async storeCourse(req, res) {
    let status = await this.validationData(req);
    if (!status) {
      // For Deleting the saved image because of having validation error
      if (req.file)
        fs.unlink(req.file.path, (err) => {
          console.log(err);
        });
      return this.back(req, res);
    }

    // Create the Course
    let images = this.imageResize(req.file);
    const { title, type, body, price, tags } = req.body;

    const newCourse = new Course({
      user: req.user._id,
      title,
      type,
      slug: this.slug(),
      body,
      images: JSON.stringify(images),
      price,
      tags,
    });
    await newCourse.save();
    return res.redirect("/admin/courses");
  }

  imageResize(image) {
    let imageInfo = path.parse(image.path);

    let addressImage = {};
    addressImage["original"] = `${imageInfo}/${image.filename}`;

    const resize = (size) => {
      let imageName = `${imageInfo.name}-${size}${imageInfo.ext}`;

      addressImage[size] = this.getUrlImage(`${image.destination}/${imageName}`);

      sharp(image.path)
        .resize(size, null)
        .toFile(`${image.destination}/${imageName}`)
    };

    [1080, 720, 480].map(resize);
  }

  getUrlImage(dir) {
    return dir.substr(8);
  }

  slug(title) {
    return title.replace(/([^۰-۹آ-یa-z0-9]|-)+/g, "-");
  }
}

module.exports = new courseController();

I had done everything I could and I had tried all the solutions for loading the image but I get error at my courseValidation middleware.

Please say any solution that is related to multer. I will try it out.

Upvotes: 0

Views: 1081

Answers (2)

Mahdi Hashemi
Mahdi Hashemi

Reputation: 127

in the destination section of the diskStorage you must be return name of the directory in the callback function. your middleware stoped in this section because you don't call cb function.

 destination: (req, file, cb) => {
    let dir = getDirImage();
    mkdirp(dir).then(made => {
        console.log(`File made on ${made}`);
        cb(made)
    });
  }

Upvotes: 1

user3014595
user3014595

Reputation: 124

here middleware function need to be defined

router.post("/courses/create", multerMiddleWare,..{...});

    const multerMiddleWare = (req, res, next) => {
      uploadImage(req, res,
          (error) => {
            if (!error) return next();
            return next('error');
          });
    };

const uploadImage = multer({
  storage: ImageStorage,
  limits: {
    fileSize: 1024 * 1024 * 10,
  },
}).single("images");

Upvotes: 0

Related Questions