0

Maybe the question is not very clear, so I will explain it better. I have created an application where I can create articles that have a title, content and an image. The image is uploaded with multer to the root folder in a directory called ../frontend/public/uploads/post. As I create posts, the images uploaded with these posts are saved in this folder. The problem is that when I delete the post, the image is not deleted with everything else in the post, but it remains in the same folder. Over time, this can become problematic, as the number of images keeps increasing during the lifetime of the application.

That's what I've tried so far, in the image deletion controller, I added this fs.unlinkmethod, but it doesn't work.

const token = req.cookies.jwt;
const decoded = jwtAuth.verify(token, process.env.TOKEN_SECRET);
const userId = decoded.id;

const { id } = req.params;

const user = await User.findByPk(userId);

try {

    await Post.findOne({
        where: { id: id }
    }).then((postFind) => {
        if (!postFind) return res.status(404).json('Utilisateur non trouvé.');
        
        if (postFind.UserId !== user.id && postFind.UserId !== user.isAdmin === true) return res.status(401).json('Vous ne pouvez pas supprimer cette publication.')

        //Si le UserId correspond à celui de la sauce supprimer de la db
        const filename = postFind.attachment.split(`/../frontend/public/uploads/post/`)[1];
        fs.unlink(`post/${filename}`, () => {
            console.log("test", filename);
            Post.destroy({ where: { id: postFind.id } })
                .then((post) => {
                    if (post === 0) throw new RequestError("Ce contenu n'existe pas !")

                    res.status(200).json('Ce contenu a été suppirmé avec succès !')
                })
                .catch(err => {
                    next(err)
                })
        })

How do I delete an image from disk when I delete the database image? Basically, when I delete a UI image, I want it to be deleted from disk as well.

Multer middleware configuration:

 const multer = require("multer");
    const MIME_TYPES = {
        'image/jpg': 'jpg',
        'image/jpeg': 'jpg',
        'image/png': 'png',
        'image/gif': 'gif'
    
    };
    const imageFilter = (req, file, cb) => {
        if (file.mimetype.startsWith("image")) {
            cb(null, true);
        } else {
            cb("Veuillez télécharger uniquement des images.", false);
        }
    };
    const storage = multer.diskStorage({
        destination: (req, file, cb) => {
            let directory = "";
            directory = "profil" ? "/profil" : "",
                directory = "post" ? "/post" : "";
    
            cb(null, `../frontend/public/uploads/${directory}`);
        },
        filename: (req, file, cb) => {
            let extension = MIME_TYPES[file.mimetype];
            let fileName = "";
            fileName = "profil" ? "profil" : file.originalname;
            fileName = "post" ? "post" + "." + extension : file.originalname + "." + extension;
            cb(null, `${Date.now()}_${fileName}`);
        },
    });
    module.exports = multer({ storage: storage, fileFilter: imageFilter });

The route to delete the image:

router.delete('/:id', PostController.deletePost);

Path Access

app.use('../frontend/public/uploads/post', express.static(path.join('../frontend/public/uploads/post')));

Oumar MAURET
  • 45
  • 1
  • 7
  • The line `directory = "profil" ? "/profil" : "", directory = "post" ? "/post" : "";` is almost certainly a bug. What is this expresion supposed to do? – Tomalak May 01 '22 at 08:06
  • Another bug is here `postFind.UserId !== user.id && postFind.UserId !== user.isAdmin === true` – Tomalak May 01 '22 at 08:16

2 Answers2

0

Basically unlinkSync comes with this facility in nodejs

try {
    //file removed
    var fs = require('fs');
    const directoryPath = join(process.cwd(), '/uploads/');
    fs.unlinkSync(filePath+body.name);
} catch(err) {
    console.error(err)
}

Click HERE for reference

Tanjin Alam
  • 1,728
  • 13
  • 15
0

Use path.resolve() to create an absolute path that fs.unlink() can handle.

Also, not using async/await consistently in your request handler is a wasted opportunity.

const fs = require('fs').promises;
const path = require('path');

async (req, res, next) => {
    try {
        const { id } = req.params;
        const token = jwtAuth.verify(req.cookies.jwt, process.env.TOKEN_SECRET);
        const user = await User.findByPk(token.id);

        const post = await Post.findOne({ where: { id: id } });
        if (!post) return res.status(404).json('Utilisateur non trouvé.');
        if (post.UserId !== user.id || !user.isAdmin) return res.status(401).json('Vous ne pouvez pas supprimer cette publication.');

        const result = await Post.destroy({ where: { id: post.id } });
        if (result === 0) throw new RequestError("Ce contenu n'existe pas !")

        const filename = post.attachment.split('/../frontend/public/uploads/post/')[1];
        const filepath = path.resolve(`post/${filename}`)
        await fs.unlink(filepath);

        res.status(200).json('Ce contenu a été suppirmé avec succès !')
    } catch (err) {
        next(err);
    }
}
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Thank you for your help, I had a problem with the middleware, during the creation I had put a default file name and that was the problem, so I changed the data so that during the creation the original file name is recorded in the disk – Oumar MAURET May 01 '22 at 14:36