Files
ostandari/server/controllers/newsFileController.js
T
2026-06-19 12:11:18 +03:30

675 lines
18 KiB
JavaScript

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);
}
}
]