const NewsFile = require('../models/NewsFile') const {body, validationResult} = require('express-validator') const {_sr} = require('../plugins/serverResponses') const {res404, res500} = require('../plugins/controllersHelperFunctions') const News = require('../models/News') const Category = require('../models/Category') const { deleteNewsImage, uploadProcessedImage, } = require('../plugins/newsImageStorage') ////// variables const limit = 5; const limitDetails = 11; const titleFilterRegex = new RegExp('/', 'g') ////// variables const coverNewsWidth = 1000; const coverNewsHeight = 600; const coverQuality = 100; const thumbCoverNewsWidth = 600; const thumbCoverNewsHeight = 300; const thumbCoverQuality = 200; ////// functions const changePriority = async (catId, modelType) => { try { const getAllNews = await News.find({ catId, modelType, priority: true }); for (const item of getAllNews) { item.priority = false; await item.save(); } return true } catch (error) { console.log(error) } } 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.addNewsFile = [ [ body('title') .notEmpty().withMessage(_sr['fa'].required.title) .custom((value, {req}) => { return NewsFile.findOne({title: value}) .then(newsFile => { if (newsFile) return Promise.reject(_sr['fa'].duplicated.title); else return true }) }), body('description') .optional().isString().withMessage(`نوع مقدار ارسال شده صحیح نمی باشد`), 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('index') .isNumeric().withMessage(`لطفا ترتیب نمایش را مشخص کنید`), body('showInHome') .optional().isBoolean().withMessage(_sr['fa'].format.boolean), body('siteMap') .optional().isBoolean().withMessage(_sr['fa'].format.boolean), 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 } }) ], async (req, res) => { const errors = validationResult(req) if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { let { title, description, catId, index, showInHome, siteMap, modelType } = req.body; /** set portals */ modelType = (req.user.portals.join() === portal.join()) ? modelType : req.user.portals[0]; let newsFileData = { title: title.trim().replace(titleFilterRegex, '-'), description: description.trim(), catId, index, showInHome, siteMap, _creator: req.user._id, _updatedBy: req.user._id, modelType }; 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: `شما اجازه استفاده از این دسته بندی را ندارید` }); } newsFileData.allCat = category.treeCat; newsFileData.rootParent = category.rootParent || category._id; } const createNewsFile = await NewsFile.create(newsFileData); if (!createNewsFile) res500(res, `مشکلی در اضافه کردن پرونده پرونده خبریی پیش آمده است`) /** * if we have pic upload to server */ if (req.files?.cover) { const image = req.files.cover; if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) return res.status(422).json({ validation: { cover: { msg: _sr['fa'].format.image } } }) const imageName = `news_${Date.now()}_${createNewsFile._id}.${image.mimetype.split('/')[1]}`; try { await uploadProcessedImage( image.data, imageName, coverNewsWidth, coverNewsHeight, coverQuality ); await uploadProcessedImage( image.data, `thumb_${imageName}`, thumbCoverNewsWidth, thumbCoverNewsHeight, thumbCoverQuality ); createNewsFile.cover = imageName; createNewsFile.thumbCover = `thumb_${imageName}`; await createNewsFile.save(); } catch (e) { return res500(res, e?.message); } } /** * show result */ return res.json(createNewsFile); } catch (error) { res500(res, error.message); } } ] module.exports.updateNewsFile = [ [ body('title') .notEmpty().withMessage(_sr['fa'].required.title), 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('description') .optional().isString().withMessage(`نوع مقدار ارسال شده صحیح نمی باشد`), body('index') .isNumeric().withMessage(`لطفا ترتیب نمایش را مشخص کنید`), body('showInHome') .optional().isBoolean().withMessage(_sr['fa'].format.boolean), body('siteMap') .optional().isBoolean().withMessage(_sr['fa'].format.boolean), 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 } }) ], async (req, res) => { const errors = validationResult(req) if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { /** * get data from input */ const { title, description, catId, index, showInHome, siteMap, modelType } = req.body; /** * get id */ var newsFileId = req.params.id; var targetNewsFile = await NewsFile.findById(newsFileId); /** check newsFile exist or not */ if (!targetNewsFile) return res404(res, `پرونده خبری مورد نظر پیدا نشد`); /** check access portal */ if (!req.user.portals.includes(targetNewsFile.modelType)) return res.status(403).json({message: `شما اجازه آپدیت این پرونده خبری را ندارید`}); if (targetNewsFile.title !== title) { var checkDuppTitle = await NewsFile.findOne({ title: title }); if (checkDuppTitle) { return res.status(422).json({validation: {title: {msg: _sr['fa'].duplicated.title}}}); } } if (modelType !== targetNewsFile.modelType) { /** check have news or not */ var checkNews = await News.find({newsFileId: targetNewsFile._id}); if (checkNews.length) { return res.status(403).json({message: `این پرونده خبری دارای خبر می باشد و شما نمی توانید نوع آن را تغییر دهید`}); } } /** 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 && targetNewsFile.catId !== catId) { targetNewsFile.allCat = category.treeCat; targetNewsFile.rootParent = category.rootParent || category._id; } targetNewsFile.title = title.trim().replace(titleFilterRegex, '-') targetNewsFile.description = description.trim(); targetNewsFile.catId = catId; targetNewsFile.index = index; targetNewsFile.showInHome = showInHome; targetNewsFile.siteMap = siteMap; targetNewsFile.modelType = modelType; /** * if we have pic upload to server */ if (req.files?.cover) { const image = req.files.cover; if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) { return res.status(422).json({ validation: { cover: { msg: _sr['fa'].format.image } } }); } const imageName = `news_${Date.now()}_${targetNewsFile._id}.${image.mimetype.split('/')[1]}`; try { await deleteNewsImage(targetNewsFile, "cover"); await deleteNewsImage(targetNewsFile, "thumbCover"); await uploadProcessedImage( image.data, imageName, coverNewsWidth, coverNewsHeight, coverQuality ); await uploadProcessedImage( image.data, `thumb_${imageName}`, thumbCoverNewsWidth, thumbCoverNewsHeight, thumbCoverQuality ); targetNewsFile.cover = imageName; targetNewsFile.thumbCover = `thumb_${imageName}`; } catch (e) { return res500(res, e?.message); } } await targetNewsFile.save(); /** * show result */ return res.json(targetNewsFile); } catch (error) { return res500(res, error.message); } } ] module.exports.deletOneNewsFile = [ async (req, res) => { try { var newsFileId = req.params.id; var targetNewsFile = await NewsFile.findOne({_id: newsFileId}); /** check newsFile exist or not */ if (!targetNewsFile) { return res404(res, `پرونده خبری مورد نظر پیدا نشد`); } /** check access portal */ if (!req.user.portals.includes(targetNewsFile.modelType)) { return res.status(403).json({message: `شما اجازه حذف این پرونده خبری را ندارید`}); } /** check have news or not */ var checkNews = await News.find({newsFileId: targetNewsFile._id}); if (checkNews.length) { return res.status(403).json({message: `این پرونده خبری دارای خبر می باشد و شما نمی توانید آن را حذف دهید`}); } /** delete newsFile */ await targetNewsFile.deleteOne(); /** * show result */ return res.json(targetNewsFile); } catch (error) { res500(res, error); } } ] module.exports.deleteAllNewsFile = [ async (req, res) => { try { } catch (error) { /** * if we got unkown error show to client */ res500(res, error); } } ] module.exports.getOneNewsFile = [ async (req, res) => { try { var newsFileId = req.params.id; var findQuery = {_id: newsFileId}; var newsFile = await NewsFile.findOne(findQuery).populate('catId'); if (!newsFile) { return res404(res, `پرونده خبری مورد نظر پیدا نشد`); } /** check access portal */ if (!req.user.portals.includes(newsFile.modelType)) { return res.status(403).json({message: `شما اجازه دسترسی به اطلاعات این پرونده خبری را ندارید`}); } /** * show result */ return res.json(newsFile); } catch (error) { res500(res, error); } } ] module.exports.getAll = [ async (req, res) => { try { var findQuery = {}; // @todo can change it if (req.user.specialPermissions.length) { findQuery.catId = {$in: req.user.specialPermissions} } if (req.user.portals.length) { findQuery.modelType = {$in: req.user.portals}; } /** get all newsFile */ const allNewsFile = await NewsFile.find(findQuery).populate('_creator', { firstName: 1, lastName: 1, profilePic: 1 }) .sort({created_at: -1}); /** if null we have error */ if (!allNewsFile) { return res500(res, `مشکلی در گرفتن اطلاعات پیش آمده است`); } /** show result to client */ return res.json(allNewsFile); } catch (error) { return res500(res, error?.message); } } ] module.exports.search = [ async (req, res) => { try { var query = {}; let populate = [{ path: '_creator', select: {firstName: 1, lastName: 1, profilePic: 1} }, { path: 'catId' }]; query['$and'] = []; var { term, showInHome, catId, portals } = req.body; ///////////// permissions /** search by catId */ if (req.user.specialPermissions.length) { query.catId = {$in: req.user.specialPermissions} } else if (catId && !_.isEmpty(catId)) { query['$and'].push({ catId }); } /** search by portals */ if (portals && !_.isEmpty(portals)) { query['$and'].push({ modelType: { $in: portals } }) } else { if (req.user.portals.length) { query.modelType = {$in: req.user.portals}; } } /** search by term */ if (term && !_.isEmpty(term)) { query['$and'].push({ $or: [{ title: { $regex: '.*' + term + '.*' } }] }); } /** search by showInHome */ if (!_.isUndefined(showInHome) && _.isBoolean(showInHome)) { query['$and'].push({ showInHome }); } _.isEmpty(query['$and']) && delete query['$and']; // _.isEmpty(input['$or']) && delete input['$or']; /** get news */ const news = await NewsFile.paginate(query, {page: req.query.page, limit, populate, sort: {_id: -1}}); /** show result */ return res.json(news); } catch (error) { return res500(res, error?.message) } } ] /////////////////////////////////////////////////////////////////////// public module.exports.viewNewsFile = [ async (req, res) => { try { const newsFileTitle = req.params.title; let targetNewsFile = await NewsFile.findOne({ title: newsFileTitle }) .populate('_creator', {firstName: 1, lastName: 1, profilePic: 1}); if (!targetNewsFile) { return res404(res, `پرونده خبری مورد نطر پیدا نشد`); } ++targetNewsFile.userViews; await targetNewsFile.save(); /** get news */ let getNews = await News.paginate({newsFileId: targetNewsFile._id}, {page: req.query.page || 1, limit: limitDetails , sort : {customDate : -1}}); let result = { newsFile: targetNewsFile, news: getNews }; return res.json(result); } catch (error) { return res500(res, `مشکلی در اجرای درخواست شما پیش آمده است`); } } ] module.exports.getAllNewsFile = [ async (req, res) => { try { const { portal, limit, skip } = req.query; const findQuery = {}; const setLimit = parseInt(limit) || 4; const setSort = {index: 1}; const setSkip = parseInt(skip) || 0; findQuery.modelType = portal; findQuery.publish = true; const getNewsFile = await NewsFile.find(findQuery).limit(setLimit).skip(setSkip).sort(setSort); return res.json(getNewsFile); } catch (error) { return res500(res, error?.message); } } ]