const Gallery = require("../models/Gallery"); const { body, validationResult } = require("express-validator"); const sharp = require("sharp"); const crypto = require("crypto"); const { _sr } = require("../plugins/serverResponses"); const { res404, res500 } = require("../plugins/controllersHelperFunctions"); const fs = require("fs"); const moment = require("moment-jalaali"); const Category = require("./../models/Category"); ////// variables const picsWidth = 1920; const picsHeight = 1080; const picsQuality = 100; const limit = 5; const thumbPicsWidth = 600; const thumbPicsHeight = 300; const thumbPicsQuality = 80; const coverQuality = 100; const coverWidth = 800; const coverHeight = 600; const thumbCoverWidth = 350; const thumbCoverHeight = 262; const thumbCoverQuality = 100; const graphicWidth = 1920; const graphicHeight = 1080; const graphicQuality = 100; const thumbGraphicWidth = 600; const thumbGraphicHeight = 300; const thumbGraphicQuality = 80; const shortTitleFront = 150; const shortTitlePanel = 20; const shortSumTitle = 250; const titleFilterRegex = new RegExp("/", "g"); /////// limit const imageLimit = 2; const graphicLimit = 5; const videoLimit = 20; ////// functions const _upload = async (fileType, file, galleryId, Hash) => { try { const fileName = `gallery_${galleryId}_${Date.now()}.${ file.mimetype.split("/")[1] }`; const uploadPath = `./static/uploads/${fileType}s/gallery/${fileName}`; const thumbUploadPath = `./static/uploads/${fileType}s/gallery/thumb_${fileName}`; switch (fileType) { case "image": try { const target = sharp(file.data); await target .resize(picsWidth, picsHeight, { fit: "cover", }) .toFormat("jpg") .jpeg({ quality: picsQuality, }) .toFile(uploadPath); await target .resize(thumbPicsWidth, thumbPicsHeight, { fit: "cover", }) .toFormat("jpg") .jpeg({ quality: thumbPicsQuality, }) .toFile(thumbUploadPath); } catch (error) { console.log(error); } break; case "graphic": try { const target = sharp(file.data); await target // .resize(graphicWidth, graphicHeight, { // fit: 'cover' // }) .toFormat("jpg") .jpeg({ quality: graphicQuality, }) .toFile(uploadPath); await target .resize(thumbGraphicWidth, thumbGraphicHeight, { fit: "cover", }) .toFormat("jpg") .jpeg({ quality: thumbGraphicQuality, }) .toFile(thumbUploadPath); } catch (error) { console.log(error); } break; case "video": await file.mv(uploadPath); break; } return fileName; } catch (error) { console.log(error); return null; } }; const _deleteOne = async (fileType, name) => { try { let targetFile = `./static/uploads/${fileType}s/gallery/${name}`; let thumbTargetFile = `./static/uploads/${fileType}s/gallery/thumb_${name}`; if (fs.existsSync(targetFile)) { fs.unlink(targetFile, (err) => { if (err) console.log(err); }); if (fileType !== "video") { fs.unlink(thumbTargetFile, (err) => { if (err) console.log(err); }); } return name; } else { return null; } } catch (error) { console.log(error); return null; } }; const _deleteAll = async (galleryId, galleryType) => { try { const targetDir = `./static/uploads/${galleryType}s/gallery/`; const getFiles = fs.readdirSync(targetDir); for (const file of getFiles) { if (file.includes(galleryId)) { fs.unlink(`./static/uploads/${galleryType}s/gallery/${file}`, (err) => { if (err) console.log(err); }); } } } catch (error) { console.log(error); } }; const _deleteCover = async (galleryId) => { try { const targetDir = `./static/uploads/images/gallery/`; const getFiles = fs.readdirSync(targetDir); for (const file of getFiles) { if (file.includes(galleryId) && file.includes("cover")) { fs.unlink(`./static/uploads/images/gallery/${file}`, (err) => { if (err) console.log(err); }); } } } catch (error) { console.log(err); } }; const _randomGallery = async (queryObject) => { let setSkip; try { let temp = []; const result = []; /** total of gallery */ const count = await Gallery.countDocuments(queryObject); if (count < 4) { return await Gallery.find(queryObject); } /** get random index number */ while (temp.length < 4) { setSkip = Math.floor(Math.random() * count); temp.push(setSkip); /** remove duplicate numbers */ temp = [...new Set(temp)]; } /** get news and push to result */ for (let i = 0; i < 4; i++) { const getGalley = await Gallery.findOne(queryObject).skip(temp[i]); if (getGalley) { result.push(getGalley); } } /** return result */ return result; } catch (error) { console.log(error); /** return error */ return []; } }; const _checkSpecPermission = async (req, category) => { return ( !req.user.specialPermissions.includes(category._id) && //check parent id exist in special permissions or not !req.user.specialPermissions.some((item) => category?.treeCat?.join().includes(item) ) ); }; /////////////////////////////////////////////////////////////////////// admin module.exports.addGallery = [ [ body("title") .notEmpty() .withMessage(_sr["fa"].required.title) .custom((value, { req }) => { return Gallery.findOne({ title: value }).then((gallery) => { if (gallery) return Promise.reject(_sr["fa"].duplicated.title); else return true; }); }), // body('summaryTitle') // .notEmpty().withMessage(_sr['fa'].required.caption), body("leadTitle").notEmpty().withMessage(_sr["fa"].required.caption), body("catId") .isMongoId() .withMessage(_sr["fa"].required.field) .if((value, { req }) => { return req.body.catId; }) .custom((value) => { return Category.findOne({ _id: value, }).then((category) => { if (!category) return Promise.reject(_sr["fa"].not_found.category); else return true; }); }), body("priority").isNumeric().withMessage(_sr["fa"].format.number), body("showInHome").isBoolean().withMessage(_sr["fa"].format.boolean), body("special").isBoolean().withMessage(_sr["fa"].format.boolean), body("siteMap") .optional() .isBoolean() .withMessage(_sr["fa"].format.boolean), body("isEmbedded").isBoolean().withMessage(_sr["fa"].format.boolean), body("publish").isBoolean().withMessage(_sr["fa"].format.boolean), body("galleryType") .notEmpty() .withMessage(_sr["fa"].required.field) .bail() .isIn(["image", "video", "graphic"]) .withMessage( `${_sr["fa"].optional.onlyValid} => 'image' , 'video' , 'graphic` ), body("keywords") .if((value) => { return value; }) .custom((value) => { const keywords = _.isString(value) ? JSON.parse(value) : value; if (!_.isArray(keywords)) { return Promise.reject(`این فیلد باید به صورت آرایه فرستاده شود`); } return true; }), body("modelType").custom((value, { req }) => { if (req.user.portals.join() === portal.join()) { if (!portal.includes(value)) { return Promise.reject(_sr["fa"].required.field); } else { return true; } } else { return true; } }), // body('metaTagDesc') // .notEmpty().withMessage(_sr['fa'].required.field), body("newsFileId") .optional() .isMongoId() .withMessage(`لطفا یک ای دی صحیح ارسال کنید`), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped(), }); try { let { title, summaryTitle, leadTitle, isEmbedded, catId, priority, showInHome, special, siteMap, publish, galleryType, modelType, keywords, metaTagDesc, newsFileId, favorite, } = req.body; /** this code fix problem with array in form data */ keywords = _.isString(keywords) ? JSON.parse(keywords) : keywords; /** set portals */ modelType = req.user.portals.join() === portal.join() ? modelType : req.user.portals[0]; const galleryData = { title: title?.trim()?.replace(titleFilterRegex, "-"), summaryTitle: summaryTitle?.trim(), leadTitle, catId, isEmbedded, newsFileId, priority, showInHome, special, siteMap, publish, galleryType, keywords, metaTagDesc: metaTagDesc ? metaTagDesc?.trim() : leadTitle?.trim(), favorite, _creator: req.user._id, modelType, shortTitleFront: title?.trim()?.slice(0, shortTitleFront), shortTitlePanel: title?.trim()?.slice(0, shortTitlePanel), shortSummaryTitle: summaryTitle?.trim()?.slice(0, shortSumTitle), }; if (catId) { /** get category with populate parent */ const category = await Category.findOne({ _id: catId, }).populate({ path: "parent", populate: { path: "parent", model: "Category", }, }); /** if undefined we have error from database */ if (!category) return res404(res, `دسته بندی انتخاب شده برای این خبر پیدا نشد`); /** check special permission */ if ( req.user.specialPermissions.length && (await _checkSpecPermission(req, category)) ) { return res.status(403).json({ message: `شما نمیتوانید این دسته بندی را انتخاب کنید`, }); } if (category.modelType !== modelType) { return res.status(403).json({ message: `شما اجازه استفاده از این دسته بندی را ندارید`, }); } galleryData.allCat = category.treeCat; galleryData.rootParent = category.rootParent || category._id; } if (special) { const getSpecGallery = await Gallery.find({ special, modelType }); if (getSpecGallery.length) { for (const item of getSpecGallery) { item.special = false; await item.save(); } } } var createGallery = await Gallery.create(galleryData); if (!createGallery) { return res500(res, `مشکلی در اجرای درخواست شما پیش آمده است`); } /** * show result */ return res.json(createGallery); } catch (error) { console.log(error); /** * if we got unkown error show to client */ res500(res, error.message); } }, ]; module.exports.updateGallery = [ [ body("title").notEmpty().withMessage(_sr["fa"].required.title), // body('summaryTitle') // .notEmpty().withMessage(_sr['fa'].required.caption), body("leadTitle").notEmpty().withMessage(_sr["fa"].required.caption), body("catId") .isMongoId() .withMessage(_sr["fa"].required.field) .if((value, { req }) => { return req.body.catId; }) .custom((value) => { return Category.findOne({ _id: value, }).then((category) => { if (!category) return Promise.reject(_sr["fa"].not_found.category); else return true; }); }), // body('priority') // .isNumeric().withMessage(_sr['fa'].format.number), body("showInHome").isBoolean().withMessage(_sr["fa"].format.boolean), body("special").isBoolean().withMessage(_sr["fa"].format.boolean), body("isEmbedded").isBoolean().withMessage(_sr["fa"].format.boolean), body("embeddedCode").custom((value, { req }) => { if (JSON.parse(req.body.isEmbedded) && _.isEmpty(value)) { return Promise.reject(_sr["fa"].required.field); } else { return true; } }), body("siteMap") .optional() .isBoolean() .withMessage(_sr["fa"].format.boolean), body("publish").isBoolean().withMessage(_sr["fa"].format.boolean), body("newsFileId") .optional() .isMongoId() .withMessage(`لطفا یک ای دی صحیح ارسال کنید`), body("galleryType") .notEmpty() .withMessage(_sr["fa"].required.field) .bail() .isIn(["image", "video", "graphic"]) .withMessage( `${_sr["fa"].optional.onlyValid} => 'image' , 'video' , 'graphic` ), body("keywords") .if((value) => { return value; }) .custom((value) => { const keywords = _.isString(value) ? JSON.parse(value) : value; if (!_.isArray(keywords)) { return Promise.reject(`این فیلد باید به صورت آرایه فرستاده شود`); } return true; }), // body('metaTagDesc') // .notEmpty().withMessage(_sr['fa'].required.field), body("modelType").custom((value, { req }) => { if (req.user.portals.join() === portal.join()) { if (!portal.includes(value)) { return Promise.reject(_sr["fa"].required.field); } else { return true; } } else { return true; } }), body("customDate") .optional() .isString() .withMessage(`لطفا یک تاریخ صحیح وارد نمایید`), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped(), }); try { /** * get data from input */ let { title, summaryTitle, leadTitle, catId, isEmbedded, embeddedCode, priority, showInHome, special, siteMap, publish, galleryType, modelType, keywords, metaTagDesc, customDate, newsFileId, favorite, } = req.body; /** this code fix problem with array in form data */ keywords = _.isString(keywords) ? JSON.parse(keywords) : keywords; /** * get id */ let galleryId = req.params.id; let targetGallery = await Gallery.findOne({ _id: galleryId }); if (!targetGallery) { return res404(res, `گالری مورد نظر پیدا نشد`); } if (!req.user.portals.includes(targetGallery.modelType)) { return res500(res, `شما اجازه آپدیت این گالری را ندارید`); } if (targetGallery.title !== title) { var checkDuppTitle = await Gallery.findOne({ title: title, }); if (checkDuppTitle) { return res.status(422).json({ validation: { title: { msg: _sr["fa"].duplicated.title } }, }); } } if (targetGallery.galleryType !== galleryType) { await _deleteAll(targetGallery._id, targetGallery.galleryType); targetGallery.images = []; targetGallery.thumbImages = []; targetGallery.video = null; targetGallery.graphic = null; targetGallery.thumbGraphic = null; targetGallery.galleryType = galleryType; targetGallery.galleryStatus = false; } /** get category with populate parent */ var category = await Category.findOne({ _id: catId, }).populate({ path: "parent", populate: { path: "parent", model: "Category", }, }); /** if undefined we have error from database */ if (!category) return res404(res, `دسته بندی انتخاب شده برای این رسانه پیدا نشد`); /** check special permission */ if ( req.user.specialPermissions.length && (await _checkSpecPermission(req, category)) ) { return res.status(403).json({ message: `شما مجاز به انتخاب این دسته بندی نمی باشید`, }); } if (category.modelType !== modelType) { return res.status(403).json({ message: `محدوده انتخاب شده شما با محدوده دسته بندی همخوانی ندارد`, }); } if (catId && targetGallery.catId !== catId) { targetGallery.allCat = category.treeCat; targetGallery.rootParent = category.rootParent || category._id; } if (isEmbedded === "true" && galleryType === "video") { await _deleteOne(galleryType, targetGallery.video); targetGallery.video = null; targetGallery.galleryStatus = false; } if (special) { const getSpecGallery = await Gallery.find({ special, modelType }); if (getSpecGallery.length) { for (const item of getSpecGallery) { item.special = false; await item.save(); } } } targetGallery.title = title?.trim()?.replace(titleFilterRegex, "-"); targetGallery.summaryTitle = summaryTitle?.trim(); targetGallery.leadTitle = leadTitle; targetGallery.isEmbedded = isEmbedded; targetGallery.embeddedCode = embeddedCode; if (!_.isEmpty(embeddedCode) && targetGallery.galleryType === "video") targetGallery.galleryStatus = true; targetGallery.catId = catId; // targetGallery.priority = priority; targetGallery.showInHome = showInHome; targetGallery.special = special; targetGallery.siteMap = siteMap; targetGallery.publish = publish; targetGallery.modelType = modelType; targetGallery.keywords = keywords; targetGallery.metaTagDesc = metaTagDesc?.trim() || leadTitle?.trim(); targetGallery.favorite = favorite; targetGallery.shortTitleFront = title?.slice(0, shortTitleFront); targetGallery.shortTitlePanel = title?.slice(0, shortTitlePanel); targetGallery.shortSummaryTitle = summaryTitle ?.trim() .slice(0, shortSumTitle); targetGallery.customDate = customDate || targetGallery.created_at; targetGallery.newsFileId = newsFileId; targetGallery._updatedBy = req.user._id; if (customDate) targetGallery.customDateHistory.push({ customDate, _updatedBy: req.user._id, }); await targetGallery.save(); /** * show result */ return res.json(targetGallery); } catch (error) { return res500(res, error.message); } }, ]; module.exports.deletOneGallery = [ async (req, res) => { try { var galleryId = req.params.id; var targetGallery = await Gallery.findOne({ _id: galleryId }); /** check gallery exist or not */ if (!targetGallery) { return res404(res, `گالری مورد نظر پیدا نشد`); } if (!req.user.portals.includes(targetGallery.modelType)) { return res500(res, `شما اجازه پاک کردن این گالری را ندارید`); } await _deleteAll(targetGallery._id, targetGallery.galleryType); await _deleteCover(targetGallery._id); /** delete gallery */ await targetGallery.deleteOne(); /** * show result */ return res.json(targetGallery); } catch (error) { /** * if we got unkown error show to client */ return res500(res, error); } }, ]; module.exports.getOneGallery = [ async (req, res) => { try { var galleryId = req.params.id; // var findQuery = req.user.portals.length == 2 ? {_id : galleryId} : {_id : galleryId , modelType : req.user.portals[0]}; var gallery = await Gallery.findOne({ _id: galleryId }).populate("catId"); if (!gallery) { return res404(res, `گالری مورد نظر پیدا نشد`); } if (!req.user.portals.includes(gallery.modelType)) { return res500(res, `شما اجازه دسترسی به اطلاعات این گالری را ندارید`); } /** * show result */ return res.json(gallery); } catch (error) { /** * if we got unkown error show to client */ res500(res, error); } }, ]; module.exports.getAll = [ async (req, res) => { try { var findQuery = req.user.portals.join() === portal.join() ? {} : { modelType: req.user.portals[0] }; // @todo can change it if (req.user.specialPermissions.length) { findQuery.catId = { $in: req.user.specialPermissions }; } /** get all gallery */ var allGallery = await Gallery.paginate(findQuery, { page: req.query.page, limit, populate: [ { path: "_creator", select: { firstName: 1, lastName: 1, profilePic: 1, }, }, { path: "catId" }, ], sort: { customDate: -1, }, }); /** if null we have error */ if (!allGallery) { return res500( res, `مشکلی در گرفتن گالری ها پیش آمده لطفا با پشتیبانی تماس بگیرید` ); } /** show result to client */ return res.json(allGallery); } catch (error) { /** if we have unknown error show it */ return res500(res, error.message); } }, ]; module.exports.search = [ async (req, res) => { try { let findQuery = {}; findQuery["$and"] = []; findQuery["$or"] = []; if (req.user.portals.length) { findQuery.modelType = { $in: req.user.portals, }; } var { term, catId, showInHome, portals, galleryStatus, publish, galleryType, date, } = req.body; /** search by term */ if (term && !_.isEmpty(term)) { findQuery["$or"].push({ title: { $regex: ".*" + term + ".*", }, }); } /** search by catId */ if (req.user.specialPermissions.length) { findQuery.catId = { $in: req.user.specialPermissions }; } else if (catId && !_.isEmpty(catId)) { findQuery["$and"].push({ catId, }); } /** search by galleryType */ if (galleryType && !_.isEmpty(galleryType)) { findQuery["$and"].push({ galleryType, }); } /** search by publish */ if (!_.isUndefined(publish) && _.isBoolean(publish)) { findQuery["$and"].push({ publish, }); } /** search by portals */ if (req.user.portals.length) { findQuery.modelType = { $in: req.user.portals, }; } else if (portals && !_.isEmpty(portals)) { findQuery["$and"].push({ modelType: { $in: portals, }, }); } /** search by galleryStatus */ if (!_.isUndefined(galleryStatus) && _.isBoolean(galleryStatus)) { findQuery["$and"].push({ galleryStatus, }); } /** search by date */ if (date && !_.isEmpty(date)) { if (date.length === 1) { findQuery["$and"].push({ created_at: { $gte: moment(date[0]).startOf("days"), $lt: moment(date[0]).endOf("days"), }, }); } else { findQuery["$and"].push({ created_at: { $gte: new Date(date[0]), $lt: new Date(date[1]), }, }); } } _.isEmpty(findQuery["$and"]) && delete findQuery["$and"]; _.isEmpty(findQuery["$or"]) && delete findQuery["$or"]; /** get gallery */ var gallery = await Gallery.paginate(findQuery, { page: req.query.page, limit, populate: [ { path: "_creator", select: { firstName: 1, lastName: 1, profilePic: 1, }, }, { path: "catId" }, ], sort: { customDate: -1, }, }); /** show result */ return res.json(gallery); } catch (error) { return res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// manage gallery files /// Develope module.exports.uploadPDF = [ [ body("title").notEmpty().withMessage(_sr["fa"].required.title).bail(), body("pdf").notEmpty().withMessage(_sr["fa"].required.field).bail(), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(422).json({ validation: errors.mapped(), }); } try { const { title, pdf } = req.body; if (!req.files || !req.files.file) { return res.status(422).json({ validation: { file: { msg: `لطفا یک فایل ارسال کنید` } }, }); } const file = req.files.file; const mb = file.size / (1024 * 1024); if (fileType === "image" && mb > imageLimit) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 5 مگابایت` }, }, }); } if (fileType === "graphic" && mb > graphicLimit) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 10 مگابایت` }, }, }); } if (fileType === "video" && mb > videoLimit) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 50 مگابایت` }, }, }); } if ( fileType === "image" && !_sr.supportedImageFormats.includes(file.mimetype.split("/")[1]) ) { return res.status(422).json({ validation: { file: { msg: _sr["fa"].format.image } }, }); } if ( fileType === "video" && !_sr.supportedVideoFormats.includes(file.mimetype.split("/")[1]) ) { return res.status(422).json({ validation: { file: { msg: _sr["fa"].format.video } }, }); } if (!req.user.portals.includes(targetGallery.modelType)) { return res .status(500) .json({ msg: `شما اجازه آپلود فایل برای این گالری را ندارید` }); } if (targetGallery.galleryType !== fileType) { return res.status(422).json({ validation: { file: { msg: `شما اجازه آپلود فایل با تایپ متفاوت از گالری ندارید`, }, }, }); } const fileName = await _upload(fileType, file, targetGallery._id); switch (fileType) { case "image": targetGallery.uidImage.push(fileHash); targetGallery.images.push(fileName); targetGallery.thumbImages.push(`thumb_${fileName}`); break; case "video": if ( targetGallery.video && (await fs.existsSync(`./static/${targetGallery?.video}`)) ) { fs.unlink(`./static/${targetGallery.video}`, (err) => { if (err) return res.status(500).json({ msg: err.message }); }); } targetGallery.video = fileName; break; case "graphic": if ( targetGallery.graphic && (await fs.existsSync(`./static/${targetGallery?.graphic}`)) ) { fs.unlink(`./static/${targetGallery.graphic}`, (err) => { if (err) return res.status(500).json({ msg: err.message }); }); fs.unlink(`./static/${targetGallery.thumbGraphic}`, (err) => { if (err) return res.status(500).json({ msg: err.message }); }); } targetGallery.graphic = fileName; targetGallery.thumbGraphic = `thumb_${fileName}`; break; } targetGallery.galleryStatus = Boolean(targetGallery.cover); targetGallery._updatedBy = req.user._id; targetGallery.imageNames = req.files.file; await targetGallery.save(); const gallery = await Gallery.findById(targetGallery._id); return res.json(gallery); } catch (error) { console.log(error.message); return res.status(500).json({ msg: error.message }); } }, ]; module.exports.uploadFile = [ [ body("galleryId") .notEmpty() .withMessage(_sr["fa"].required.title) .bail() .custom((value, { req }) => { return Gallery.findOne({ _id: value }).then((gallery) => { if (!gallery) return Promise.reject(_sr["fa"].not_found.item_id); else return true; }); }), body("fileType") .notEmpty() .withMessage(_sr["fa"].required.field) .bail() .isIn(["image", "video", "graphic"]) .withMessage( `${_sr["fa"].optional.onlyValid} => 'image' , 'video' , 'graphic'` ), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(422).json({ validation: errors.mapped(), }); } try { const { galleryId, fileType } = req.body; if (!req.files || !req.files.file) { return res.status(422).json({ validation: { file: { msg: `لطفا یک فایل ارسال کنید` } }, }); } const file = req.files.file; const fileBuffer = file.data; const fileHash = crypto .createHash("md5") .update(fileBuffer) .digest("hex"); const targetGallery = await Gallery.findOne({ _id: galleryId }); if (!targetGallery) { return res.status(404).json({ msg: `گالری پیدا نشد` }); } const Hash = targetGallery.uidImage.map((path) => path.replace("/uploads/images/gallery/", "") ); if (Hash.includes(fileHash)) { return res.status(200).json({ msg: `این فایل قبلا بارگذاری شده` }); } const mb = file.size / (1024 * 1024); if (fileType === "image" && mb > imageLimit) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 5 مگابایت` }, }, }); } if (fileType === "graphic" && mb > graphicLimit) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 10 مگابایت` }, }, }); } if (fileType === "video" && mb > videoLimit) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 50 مگابایت` }, }, }); } if ( fileType === "image" && !_sr.supportedImageFormats.includes(file.mimetype.split("/")[1]) ) { return res.status(422).json({ validation: { file: { msg: _sr["fa"].format.image } }, }); } if ( fileType === "video" && !_sr.supportedVideoFormats.includes(file.mimetype.split("/")[1]) ) { return res.status(422).json({ validation: { file: { msg: _sr["fa"].format.video } }, }); } if (!req.user.portals.includes(targetGallery.modelType)) { return res .status(500) .json({ msg: `شما اجازه آپلود فایل برای این گالری را ندارید` }); } if (targetGallery.galleryType !== fileType) { return res.status(422).json({ validation: { file: { msg: `شما اجازه آپلود فایل با تایپ متفاوت از گالری ندارید`, }, }, }); } const fileName = await _upload(fileType, file, targetGallery._id); switch (fileType) { case "image": targetGallery.uidImage.push(fileHash); targetGallery.images.push(fileName); targetGallery.thumbImages.push(`thumb_${fileName}`); break; case "video": if ( targetGallery.video && (await fs.existsSync(`./static/${targetGallery?.video}`)) ) { fs.unlink(`./static/${targetGallery.video}`, (err) => { if (err) return res.status(500).json({ msg: err.message }); }); } targetGallery.video = fileName; break; case "graphic": if ( targetGallery.graphic && (await fs.existsSync(`./static/${targetGallery?.graphic}`)) ) { fs.unlink(`./static/${targetGallery.graphic}`, (err) => { if (err) return res.status(500).json({ msg: err.message }); }); fs.unlink(`./static/${targetGallery.thumbGraphic}`, (err) => { if (err) return res.status(500).json({ msg: err.message }); }); } targetGallery.graphic = fileName; targetGallery.thumbGraphic = `thumb_${fileName}`; break; } // Update the uidImage with the new fileHash targetGallery.galleryStatus = Boolean(targetGallery.cover); targetGallery._updatedBy = req.user._id; targetGallery.imageNames = req.files.file; await targetGallery.save(); const gallery = await Gallery.findById(targetGallery._id); /** * show result */ return res.json(gallery); } catch (error) { console.log(error.message); /** * if we got unknown error show to client */ return res.status(500).json({ msg: error.message }); } }, ]; // module.exports.uploadFile = [ // [ // body('galleryId') // .notEmpty().withMessage(_sr['fa'].required.title) // .bail() // .custom((value, {req}) => { // return Gallery.findOne({_id: value}) // .then(gallery => { // if (!gallery) return Promise.reject(_sr['fa'].not_found.item_id); // else return true // }) // }), // body('fileType') // .notEmpty().withMessage(_sr['fa'].required.field) // .bail() // .isIn(['image', 'video', 'graphic']).withMessage(`${_sr['fa'].optional.onlyValid} => 'image' , 'video' , 'graphic'`), // // ], // async (req, res) => { // // const errors = validationResult(req) // if (!errors.isEmpty()) return res.status(422).json({ // validation: errors.mapped() // }); // // try { // let { // galleryId, // fileType, // } = req.body; // // if (!req.files || !req.files.file) { // return res.status(422).json({ // validation: {file: {msg: `لطفا یک فایل ارسال کنید`}} // }); // } // // var file = req.files.file; // const fileBuffer = file.data; // const fileHash = crypto.createHash('md5').update(fileBuffer).digest('hex'); // // const ImageValid = await Gallery.findOne({ _id: galleryId }); // if (!ImageValid) return res404(res, `گالری پیدا نشد`); // // const existingFileHashes = ImageValid.fileHashes || []; // if (existingFileHashes.includes(fileHash)) { // return res.status(422).json({ // validation: { file: { msg: `این فایل قبلاً آپلود شده است` } } // }); // } // /** start convert byte to mb */ // var mb = file.size / (1024 * 1024); // // /** check limit size of image */ // if (fileType === 'image' && mb > imageLimit) { // return res.status(422).json({ // validation: {file: {msg: `${_sr['fa'].max_char.data_size} 5 مگابایت`}} // }); // } // // /** check limit size of graphics */ // if (fileType === 'graphic' && mb > graphicLimit) { // return res.status(422).json({ // validation: {file: {msg: `${_sr['fa'].max_char.data_size} 10 مگابایت`}} // }); // } // // /** check limit size of video */ // if (fileType === 'video' && mb > videoLimit) { // return res.status(422).json({ // validation: {file: {msg: `${_sr['fa'].max_char.data_size} 50 مگابایت`}} // }); // } // // /** check format of image */ // if (fileType === 'image' && !_sr.supportedImageFormats.includes(file.mimetype.split('/')[1])) { // return res.status(422).json({ // validation: {file: {msg: _sr['fa'].format.image}} // }); // } // // /** check format of video */ // if (fileType === 'video' && !_sr.supportedVideoFormats.includes(file.mimetype.split('/')[1])) { // return res.status(422).json({ // validation: {file: {msg: _sr['fa'].format.video}} // }); // } // // var targetGallery = await Gallery.findOne({_id: galleryId}); // // // if (!targetGallery) return res404(res, `گالری پیدا نشد`); // // /** check portal type */ // if (!req.user.portals.includes(targetGallery.modelType)) { // return res500(res, `شما اجازه آپلود فایل برای این گالری را ندارید`); // } // // /** check type of input with gallery type */ // if (targetGallery.galleryType !== fileType) { // return res.status(422).json({ // validation: {file: {msg: `شما اجازه آپلود فایل با تایپ متفاوت از گالری ندارید`}} // }); // } // // /** upload pic or video get name */ // var fileName = await _upload(fileType, file, targetGallery._id); // // // // if(fileType == 'image'){ // // targetGallery.images.push(fileName); // // targetGallery.thumbImages.push(`thumb_${fileName}`); // // }else{ // // if(targetGallery.video){ // // fs.unlink(`./static/${targetGallery.video}`, (err) => { // // if (err) res500(res , err.message); // // }); // // } // // targetGallery.video = fileName; // // } // // switch (fileType) { // case 'image': // targetGallery.images.push(fileName); // targetGallery.thumbImages.push(`thumb_${fileName}`); // break; // case 'video': // if (targetGallery.video && await fs.existsSync(`./static/${targetGallery?.video}`)) { // fs.unlink(`./static/${targetGallery.video}`, (err) => { // if (err) return res500(res, err.message); // }); // } // targetGallery.video = fileName; // break; // case 'graphic': // if (targetGallery.graphic && await fs.existsSync(`./static/${targetGallery?.graphic}`)) { // fs.unlink(`./static/${targetGallery.graphic}`, (err) => { // if (err) return res500(res, err.message); // }); // fs.unlink(`./static/${targetGallery.thumbGraphic}`, (err) => { // if (err) return res500(res, err.message); // }); // } // targetGallery.graphic = fileName; // targetGallery.thumbGraphic = `thumb_${fileName}`; // break; // } // // targetGallery.galleryStatus = Boolean(targetGallery.cover); // targetGallery._updatedBy = req.user._id; // targetGallery.imageNames = req.files.file // await targetGallery.save(); // // var gallery = await Gallery.findById(targetGallery._id); // // /** // * show result // */ // return res.json(gallery); // } catch (error) { // console.log(error.message); // /** // * if we got unkown error show to client // */ // return res500(res, error.message); // } // } // ] module.exports.deleteFile = [ [ body("galleryId") .notEmpty() .withMessage(_sr["fa"].required.title) .bail() .custom((value, { req }) => { return Gallery.findOne({ _id: value }).then((gallery) => { if (!gallery) return Promise.reject(_sr["fa"].not_found.item_id); else return true; }); }), body("name").notEmpty().withMessage(_sr["fa"].required.field), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped(), }); try { const { galleryId, name } = req.body; const targetGallery = await Gallery.findOne({ _id: galleryId }).lean(); if (!targetGallery) return res404(res, `گالری مورد نظر پیدا نشد`); /** check portal type */ if (!req.user.portals.includes(targetGallery.modelType)) return res500(res, `شما اجازه حذف فایل برای این گالری را ندارید`); if ( (targetGallery.images.length === 0 && targetGallery.galleryType === "image") || (!targetGallery.video && targetGallery.galleryType === "video") ) return res404(res, `عکس یا فیلم درخواست شده پیدا نشد`); let deleteFile = await _deleteOne(targetGallery.galleryType, name); // if (!deleteFile) return res404(res, `عکس درخواست شده پیدا نشد`); /** update gallery after delete file */ let imageArr = []; if ( targetGallery.galleryType === "image" || targetGallery.galleryType === "graphic" ) { let index = targetGallery.images.findIndex((item) => { return item.includes(deleteFile || name); }); if (index > -1) { targetGallery.images.splice(index, 1); targetGallery.thumbImages.splice(index, 1); } } else { targetGallery.video = null; } targetGallery.galleryStatus = !!targetGallery.images.length; var gallery = await Gallery.findByIdAndUpdate( targetGallery._id, targetGallery, { new: true } ); /** * show result */ return res.json(gallery); } catch (error) { console.log(error); /** * if we got unkown error show to client */ return res500(res, error.message); } }, ]; // module.exports.uploadCover = [ // [ // body('galleryId') // .notEmpty().withMessage(_sr['fa'].required.title) // .bail() // .custom((value, {req}) => { // return Gallery.findOne({_id: value}) // .then(gallery => { // if (!gallery) return Promise.reject(_sr['fa'].not_found.item_id); // else return true // }) // }), // ], // async (req, res) => { // // const errors = validationResult(req) // if (!errors.isEmpty()) return res.status(422).json({ // validation: errors.mapped() // }); // // try { // const { // galleryId, // } = req.body; // // if (!req.files || !req.files.file) { // return res.status(422).json({ // validation: {file: {msg: `لطفا یک فایل ارسال کنید`}} // }); // } // // const file = req.files.file; // // /** start convert byte to mb */ // const mb = file.size ; // // /** check limit size of image */ // if (mb > 5) { // return res.status(422).json({ // validation: {file: {msg: `${_sr['fa'].max_char.data_size} 5 مگابایت`}} // }); // } // // /** check format of image */ // if (!_sr.supportedImageFormats.includes(file.mimetype.split('/')[1])) { // return res.status(422).json({ // validation: {file: {msg: _sr['fa'].format.image}} // }); // } // // let targetGallery = await Gallery.findOne({_id: galleryId}); // // // if (!targetGallery) { // return res404(res, `گالری پیدا نشد`); // } // // /** check portal type */ // if (!req.user.portals.includes(targetGallery.modelType)) { // return res500(res, `شما اجازه آپلود فایل برای این گالری را ندارید`); // } // // const imageName = `cover_gallery_${Date.now()}_${targetGallery._id}.jpg`; // const thumbImg = `thumb_${imageName}`; // try { // const target = sharp(file.data) // await target // .resize(coverWidth, coverHeight, { // fit: 'cover' // }) // .toFormat('jpg') // .jpeg({ // quality: coverQuality // }) // .toFile(`./static/uploads/images/gallery/${imageName}`); // // await target // .resize(thumbCoverWidth, thumbCoverHeight, { // fit: 'cover' // }) // .toFormat('jpg') // .jpeg({ // quality: thumbCoverQuality // }) // .toFile(`./static/uploads/images/gallery/${thumbImg}`); // // // /** // * if exist old pic delete it from file // */ // if (targetGallery.cover) { // let oldPic = `./static${targetGallery.cover}`; // // if (fs.existsSync(oldPic)) { // fs.unlink(oldPic, (err) => { // if (err) return res500(res, err?.message); // }); // } // } // // if (targetGallery.thumbCover) { // let oldPic = `./static${targetGallery.thumbCover}`; // // if (fs.existsSync(oldPic)) { // fs.unlink(oldPic, (err) => { // if (err) return res500(res, err?.message); // }); // } // } // // targetGallery.cover = imageName; // targetGallery.thumbCover = thumbImg; // // targetGallery.galleryStatus = targetGallery.images.length || // targetGallery.video || // targetGallery.graphic ? true : false; // // } catch (e) { // return res500(res, e?.message); // } // // await targetGallery.save(); // // const gallery = await Gallery.findById(targetGallery._id); // // /** // * show result // */ // return res.json(gallery); // } catch (error) { // console.log(error); // /** // * if we got unkown error show to client // */ // return res500(res, error.message); // } // } // ] // Prod //Develope module.exports.uploadCover = [ [ body("galleryId") .notEmpty() .withMessage(_sr["fa"].required.title) .bail() .isMongoId() .withMessage("آی دی گالری نامعتبر است") .bail() .custom(async (value, { req }) => { try { const gallery = await Gallery.findById(value); if (!gallery) { return Promise.reject(_sr["fa"].not_found.item_id); } return true; } catch (error) { return Promise.reject("آی دی گالری نامعتبر است"); } }), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(422).json({ validation: errors.mapped(), }); } try { const { galleryId } = req.body; // Debug logging console.log("galleryId received:", galleryId); console.log("req.body:", req.body); if (!galleryId) { return res.status(422).json({ validation: { galleryId: { msg: `آی دی گالری الزامی است` } }, }); } if (!req.files || !req.files.file) { return res.status(422).json({ validation: { file: { msg: `لطفا یک فایل ارسال کنید` } }, }); } const file = req.files.file; // Find the gallery record with better error handling let targetGallery; try { targetGallery = await Gallery.findById(galleryId); console.log("targetGallery found:", !!targetGallery); } catch (dbError) { console.error("Database error:", dbError); return res.status(422).json({ validation: { galleryId: { msg: `آی دی گالری نامعتبر است` } }, }); } if (!targetGallery) { return res404(res, `گالری پیدا نشد`); } // Check if user object exists and has portals if (!req.user || !req.user.portals) { return res.status(401).json({ message: `اطلاعات کاربری نامعتبر است` }); } /** check portal type */ if (!req.user.portals.includes(targetGallery.modelType)) { return res500(res, `شما اجازه آپلود فایل برای این گالری را ندارید`); } /** start convert byte to mb */ const mb = file.size / (1024 * 1024); // Convert bytes to megabytes /** check limit size of image */ if (mb > 5) { return res.status(422).json({ validation: { file: { msg: `${_sr["fa"].max_char.data_size} 5 مگابایت` }, }, }); } /** check format of image */ if (!_sr.supportedImageFormats.includes(file.mimetype.split("/")[1])) { return res.status(422).json({ validation: { file: { msg: _sr["fa"].format.image } }, }); } const imageName = `cover_gallery_${Date.now()}_${targetGallery._id}.jpg`; const thumbImg = `thumb_${imageName}`; try { const target = sharp(file.data); await target .resize(coverWidth, coverHeight, { fit: "cover", }) .toFormat("jpg") .jpeg({ quality: coverQuality, }) .toFile(`./static/uploads/images/gallery/${imageName}`); await target .resize(thumbCoverWidth, thumbCoverHeight, { fit: "cover", }) .toFormat("jpg") .jpeg({ quality: thumbCoverQuality, }) .toFile(`./static/uploads/images/gallery/${thumbImg}`); /** * if exist old pic delete it from file */ if (targetGallery.cover) { let oldPic = `./static/uploads/images/gallery/${targetGallery.cover}`; if (fs.existsSync(oldPic)) { fs.unlink(oldPic, (err) => { if (err) console.log("Error deleting old cover:", err); }); } } if (targetGallery.thumbCover) { let oldThumbPic = `./static/uploads/images/gallery/${targetGallery.thumbCover}`; if (fs.existsSync(oldThumbPic)) { fs.unlink(oldThumbPic, (err) => { if (err) console.log("Error deleting old thumb cover:", err); }); } } // Update gallery record with new cover images targetGallery.cover = imageName; targetGallery.thumbCover = thumbImg; targetGallery.galleryStatus = Boolean(targetGallery.cover) || Boolean(targetGallery.images?.length) || Boolean(targetGallery.video) || Boolean(targetGallery.graphic); targetGallery._updatedBy = req.user._id; await targetGallery.save(); // Return the updated gallery const gallery = await Gallery.findById(targetGallery._id); return res.json(gallery); } catch (e) { return res500(res, e?.message); } } catch (error) { console.log(error); return res500(res, error.message); } }, ]; ////////////////////////////////////////////////////////////////////// get gallery module.exports.getGalleryPublic = [ async (req, res) => { try { const { type, page } = req.query; const catId = req.params.catId; const findQuery = {}; findQuery.galleryType = type; findQuery.galleryStatus = true; findQuery.catId = catId; let setLimit = 9; const getGallery = await Gallery.paginate(findQuery, { page: page || 1, limit: setLimit, populate: { path: "_creator", select: "firstName lastName", }, sort: { customDate: -1 }, }); const favorites = await Gallery.find({ ...findQuery, favorite: true }); const result = { all: getGallery, favorites: favorites, }; return res.json(result); } catch (error) { return res500(res, error?.message); } }, ]; module.exports.GetArchive = [ async (req, res) => { try { const Archive = await Gallery.find({ images: { $exists: true } }); res.status(200).json(Archive); } catch (e) { res.status(500).json({ msg: e.message }); } }, ]; module.exports.getAllGallery = [ async (req, res) => { try { const { type, page, portal } = req.query; let findQuery = {}; findQuery.galleryType = type; findQuery.galleryStatus = true; findQuery.publish = true; findQuery.modelType = portal; let setLimit = 13; const getGallery = await Gallery.paginate(findQuery, { page: page || 1, limit: setLimit, populate: { path: "_creator", select: "firstName lastName", }, sort: { customDate: -1 }, }); const favorites = await Gallery.find({ ...findQuery, favorite: true, }).sort({ customDate: -1 }); const hero = await Gallery.findOne({ ...findQuery, special: true }).sort({ customDate: -1, }); const result = { all: getGallery, hero: hero, favorites: favorites, }; return res.json(result); } catch (error) { return res500(res, error?.message); } }, ]; module.exports.viewGallery = [ async (req, res) => { try { const galleryTitle = req.params.title; let targetGallery = await Gallery.findOne({ _id: galleryTitle, galleryStatus: true, publish: true, }).populate("_creator", { firstName: 1, lastName: 1, profilePic: 1 }); if (!targetGallery) { return res404(res, `گالری مورد نطر پیدا نشد`); } ++targetGallery.userViews; await targetGallery.save(); return res.json(targetGallery); } catch (error) { return res500(res, error?.message); } }, ]; module.exports.getRelated = [ async (req, res) => { try { const { type, title } = req.query; const targetGallery = await Gallery.findById(title); if (!targetGallery) { return res.json([]); } let findQuery = {}; findQuery.galleryType = type; findQuery._id = { $ne: title, }; findQuery.galleryStatus = true; findQuery.publish = true; const getGallery = await Gallery.find(findQuery) .populate({ path: "_creator", select: "firstName lastName", }) .limit(4) .sort({ customDate: -1, }); return res.json(getGallery); } catch (error) { return res500(res, error?.message); } }, ];