const sharp = require("sharp"); const config = require("../config/main.js"); const configIllustrations = require("../config/illustrations.js"); const tool = require("../tools/main"); const toolError = require("../tools/error"); const toolFile = require("../tools/file"); const questionnaireCtrl = require("./questionnaire"); const txt = require("../lang/"+config.adminLang+"/illustration"); const txtGeneral = require("../lang/"+config.adminLang+"/general"); exports.create = async (req, res, next) => { try { const db = require("../models/index"); const illustrationDatas = await checkHasFile(req); // Le fichier peut avoir été bloqué par multer : if(!illustrationDatas.url) res.status(400).json({ errors: [txt.needGoodFile] }); else { const questionnaire=await questionnaireCtrl.searchQuestionnaireById(illustrationDatas.QuestionnaireId); if(!questionnaire) { toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url); throw { message: txt.needQuestionnaireForIllustration }; } else if(configIllustrations.nbIllustrationsMax!==0 && questionnaire.Illustrations.length >= configIllustrations.nbIllustrationsMax) { toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url); res.status(400).json({ errors: [txt.needMaxIllustrationsForQuestionnaire] }); } else { const illustration=await db["Illustration"].create({ ...illustrationDatas }, { fields: ["url", "alt", "title", "caption", "QuestionnaireId"] }); const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(illustrationDatas.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher res.status(201).json({ message: txt.addedOkMessage, questionnaire: questionnaireDatas }); } } next(); } catch(e) { const returnAPI=toolError.returnSequelize(e); if(returnAPI.messages) { res.status(returnAPI.status).json({ errors : returnAPI.messages }); next(); } else next(e); } } exports.modify = async (req, res, next) => { try { const db = require("../models/index"); const illustration=await searchIllustrationById(req.params.id); if(!illustration) res.status(404).json({ errors: txt.notFound }); else { const questionnaire=await questionnaireCtrl.searchQuestionnaireById(illustration.QuestionnaireId); if(!questionnaire) { if(illustrationDatas.url) toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url); throw { message: txt.needQuestionnaireForIllustration }; } else if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.Questionnaire.CreatorId) { if(illustrationDatas.url) toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url); res.status(401).json({ errors: txtGeneral.notAllowed }); } else { if(!tool.isEmpty(req.body.fileError)) res.status(400).json({ errors: [req.body.fileError] }); else { const illustrationDatas = await checkHasFile(req); // Lors d'une mise à jour, un nouveau fichier n'a pas forcément été envoyé ou peut avoir été bloqué par multer // Mais si c'est le cas, on supprime l'ancien fichier : if(illustrationDatas.url) { toolFile.deleteFile(configIllustrations.dirIllustrations+"/min", illustration.url); } await db["Illustration"].update({ ...illustrationDatas }, { where: { id : req.params.id } , fields: ["url", "alt", "title", "caption"], limit:1 }); const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(illustrationDatas.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher res.status(200).json({ message: txt.updatedOkMessage, questionnaire: questionnaireDatas }); } } } next(); } catch(e) { const returnAPI=toolError.returnSequelize(e); if(returnAPI.messages) { res.status(returnAPI.status).json({ errors : returnAPI.messages }); next(); } else next(e); } } exports.delete = async (req, res, next) => { try { const db = require("../models/index"); const illustration=await searchIllustrationById(req.params.id); if(!illustration) throw { message: txt.notFound+req.params.id }; else { const questionnaire=await questionnaireCtrl.searchQuestionnaireById(illustration.QuestionnaireId); if(!questionnaire) throw { message: txt.needQuestionnaireForIllustration }; else if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.Questionnaire.CreatorId) res.status(401).json({ errors: txtGeneral.notAllowed }); else { const delIllus=await deleteIllustrationById(req.params.id); if(delIllus) { const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(illustration.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher res.status(200).json({ message: txt.deletedOkMessage, questionnaire: questionnaireDatas }); } else res.status(400).json({ errors: [txtGeneral.serverError] }); } } next(); } catch(e) { next(e); } } exports.getOneIllustrationById = async (req, res, next) => { try { const illustration=await searchIllustrationById(req.params.id); if(illustration) res.status(200).json(illustration); else res.status(404).json(null); } catch(e) { next(e); } } // cron de nettoyage des fichiers illustrations n'existant plus dans la bd exports.deleteOldFiles= async (req, res, next) => { try { const db = require("../models/index"); const illustrations=await db["Illustration"].findAll({ attributes: ["url"] }); let saveFiles=[]; for(let i in illustrations) saveFiles.push(illustrations[i].url); await toolFile.deleteFilesInDirectory(configIllustrations.dirIllustrations, saveFiles); await toolFile.deleteFilesInDirectory(configIllustrations.dirIllustrations+"/min", saveFiles); // + le répertoire temporaire où rien ne devrait traîner : const fileExpiration=new Date().getTime()-1000; await toolFile.deleteOldFilesInDirectory(configIllustrations.dirIllustrationsTmp, fileExpiration); res.status(200).json(deleteFiles); next(); } catch(e) { next(e); } } // FONCTIONS UTILITAIRES // Gère le redimensionnement de l'image si un fichier est envoyé. // c'est multer qui vérifie dans le middleware précédent que l'image a le bon format, puis lui donne un nom (filename) si c'est ok const checkHasFile = async (req) => { if(req.file) { // à revoir ? : là l'image est aggrandie si + petite que demandé await sharp(req.file.path).resize(configIllustrations.illustrationsWidthMaxInPx).toFile(configIllustrations.dirIllustrations+"/"+req.file.filename); await sharp(req.file.path).resize(configIllustrations.illustrationsMiniaturesWidthMaxInPx).toFile(configIllustrations.dirIllustrations+"/min/"+req.file.filename); await toolFile.deleteFile(configIllustrations.dirIllustrationsTmp, req.file.filename); } // La gestion du téléchargement du fichier de l'illustration fait que les données sont envoyées sous forme de chaîne de caractères (form-data), qu'il faut transformer en json const datas=req.file ? { ...req.body, url: req.file.filename } : { ...req.body }; return datas; } const searchIllustrationById = async (id) => { const db = require("../models/index"); const illustration=await db["Illustration"].findByPk(id); if(illustration) return illustration; else return false; } const deleteIllustrationById = async (id) => { const db = require("../models/index"); const illustration=await searchIllustrationById(id); if(!illustration) throw { message: txt.notFound+id }; else { const nb=await db["Illustration"].destroy( { where: { id : id }, limit:1 }); if(nb===1) { toolFile.deleteFile(configIllustrations.dirIllustrations, illustration.url); toolFile.deleteFile(configIllustrations.dirIllustrations+"/min", illustration.url); questionnaireCtrl.creaQuestionnaireJson(illustration.QuestionnaireId); } return true; } } exports.deleteIllustrationById = deleteIllustrationById;