Files
ostandari/server/controllers/electionController.js
T
2024-10-21 10:22:26 +03:30

885 lines
24 KiB
JavaScript

const Category = require('../models/Category');
const Election = require('../models/Election');
const {body, validationResult} = require('express-validator');
const {_sr} = require('../plugins/serverResponses');
const {
res404,
res500,
checkValidations,
generateRandomDigits,
hasWhiteSpaces,
isLatinCharactersWithSymbol
} = require('../plugins/controllersHelperFunctions');
const fs = require('fs');
const sharp = require('sharp');
////// variables
const profileWidth = 300;
const profileHeight = 400;
const profileQuality = 100;
const limit = 20;
//// functions
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));
}
const _generatePass = async () => {
let pass = generateRandomDigits(8);
let checkPass = await Election.findOne({'voters.password': pass});
if (checkPass) return await _generatePass();
return pass;
}
/////////////////////////////////////////////////////////////////////// admin election
module.exports.addElection = [
[
body('title')
.notEmpty().withMessage(_sr['fa'].required.field),
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('startDate')
.notEmpty().withMessage(`لطفا یک تاریخ شروع تعیین کنید`),
body('endDate')
.notEmpty().withMessage(`لطفا یک تاریخ پایان تعیین کنید`),
body('publish')
.isBoolean().withMessage(_sr['fa'].format.boolean),
],
checkValidations(validationResult),
async (req, res) => {
try {
const {
title,
catId,
description,
startDate,
endDate,
publish
} = req.body;
const data = {
title: title.trim(),
catId,
description,
startDate,
endDate,
publish,
_creator: req.user._id,
_updatedBy: req.user._id
}
const category = await Category.findOne({
_id: catId
}).populate({
path: 'parent',
populate: {
path: 'parent',
model: 'Category'
}
});
if (!category) return res404(res, 'دسته بندی مورد نظر پیدا نشد');
/** check special permission */
if (req.user.specialPermissions.length && await _checkSpecPermission(req, category)) {
return res.status(403).json({
message: `شما نمیتوانید این دسته بندی را انتخاب کنید`
});
}
data.allCat = category.treeCat;
data.rootParent = category.rootParent || category._id;
const createElection = await Election.create(data);
if (!createElection) return res500(res, `مشکلی در اجرای درخواست شما پیش آمده است`);
return res.json(createElection);
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.updateElection = [
[
body('title')
.notEmpty().withMessage(_sr['fa'].required.field),
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('startDate')
.notEmpty().withMessage(`لطفا یک تاریخ شروع تعیین کنید`),
body('endDate')
.notEmpty().withMessage(`لطفا یک تاریخ پایان تعیین کنید`),
body('publish')
.isBoolean().withMessage(_sr['fa'].format.boolean),
],
checkValidations(validationResult),
async (req, res) => {
try {
const electionId = req.params.id;
const {
title,
catId,
description,
startDate,
endDate,
publish
} = req.body;
//// check election
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, `انتخابات مورد نظر پیدا نشد`);
if (catId && targetElection.catId !== catId) {
const category = await Category.findOne({
_id: catId
}).populate({
path: 'parent',
populate: {
path: 'parent',
model: 'Category'
}
});
if (!category) return res404(res, 'دسته بندی مورد نظر پیدا نشد');
/** check special permission */
if (req.user.specialPermissions.length && await _checkSpecPermission(req, category)) {
return res.status(403).json({
message: `شما نمیتوانید این دسته بندی را انتخاب کنید`
});
}
targetElection.catId = catId;
targetElection.allCat = category.treeCat;
targetElection.rootParent = category.rootParent || category._id;
}
targetElection.title = title;
targetElection.description = description;
targetElection.startDate = startDate;
targetElection.endDate = endDate;
targetElection.publish = publish;
targetElection._updatedBy = req.user._id;
await targetElection.save();
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.getAllElection = [
async (req, res) => {
try {
let findQuery = {};
if (req.user.specialPermissions.length) {
findQuery.catId = {$in: req.user.specialPermissions}
}
const allElection = await Election.paginate(findQuery, {
page: req.query.page || 1,
populate: [
{path: 'catId'},
{
path: '_creator',
select: {
firstName: 1,
lastName: 1,
profilePic: 1
}
}
],
limit,
sort: {created_at: -1}
});
if (!allElection) return res500(res, `مشکلی در گرفتن اطلاعات پیش آمده است`);
return res.json(allElection);
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.getOneElection = [
async (req, res) => {
try {
const electionId = req.params.id;
const findQuery = {
_id: electionId
};
const election = await Election.findOne(findQuery).populate('catId');
if (!election) return res404(res, `اطلاعات مورد نظر پیدا نشد`);
if (req.user.specialPermissions.length && await _checkSpecPermission(req, election.catId)) {
return res.status(403).json({
message: `شما مجاز به دیدن اطلاعات این انتخابات نمی باشید`
});
}
return res.json(election);
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.deletOneElection = [
async (req, res) => {
try {
const electionId = req.params.id;
const deleteElection = await Election.findById(electionId).populate('catId');
if (!deleteElection) return res404(res, `انتخابات مورد نظر پیدا نشد`);
if (req.user.specialPermissions.length && await _checkSpecPermission(req, deleteElection.catId)) {
return res.status(403).json({
message: `شما اجازه حذف این انتخابات را ندارید`
});
}
if (deleteElection.candidates.length) {
const targetDir = `./static/uploads/images/election/`;
const getFiles = fs.readdirSync(targetDir);
for (const file of getFiles) {
if (file.includes(deleteElection._id)) {
fs.unlink(`./static/uploads/images/election/${file}`, (err) => {
if (err) console.log(err)
});
}
}
}
await deleteElection.deleteOne();
return res.json({message: _sr['fa'].response.success_remove});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.search = [
async (req, res) => {
try {
let query = {};
let populate = [
{
path: '_creator',
select: {firstName: 1, lastName: 1, profilePic: 1}
},
{
path: 'catId'
}
];
query['$and'] = [];
const {
term,
catId,
publish,
date
} = req.body;
/** search by term */
if (term && !_.isEmpty(term)) {
query['$and'].push({
$or: [{
title: {
$regex: '.*' + term + '.*'
}
}]
});
}
if (req.user.specialPermissions.length) {
query.catId = {$in: req.user.specialPermissions}
} else if (catId && !_.isEmpty(catId)) {
query['$and'].push({
catId
});
}
/** search by publish */
if (!_.isUndefined(publish) && _.isBoolean(publish)) {
query['$and'].push({
publish
});
}
/** search by date */
if (date && !_.isEmpty(date)) {
if (date.length === 1) {
query['$and'].push({
startDate: {$lte: new Date(date[0])},
endDate: {$gte: new Date(date[0])}
});
} else {
query['$and'].push({
startDate: {$lte: new Date(date[0])},
endDate: {$gte: new Date(date[1])}
});
}
}
_.isEmpty(query['$and']) && delete query['$and'];
// _.isEmpty(input['$or']) && delete input['$or'];
/** get elections */
const elections = await Election.paginate(query, {
page: req.query.page || 1,
limit,
populate,
sort: {_id: -1}
});
/** show result */
return res.json(elections);
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
///////////////////////////////////////////////////////////////////// admin candidate
module.exports.addCandidate = [
[
body('firstName')
.notEmpty().withMessage(_sr['fa'].required.first_name),
body('lastName')
.notEmpty().withMessage(_sr['fa'].required.last_name),
body('nationalCode')
.optional().isNumeric().withMessage(_sr['fa'].required.national_code)
.bail()
.isLength({min: 10, max: 10}).withMessage('کد ملی 10 رقمی می باشد'),
],
checkValidations(validationResult),
async (req, res) => {
try {
const electionId = req.params.id;
const {
firstName,
lastName,
bornDate,
education,
nationalCode,
resume
} = req.body;
const data = {
firstName,
lastName,
bornDate,
education,
nationalCode,
resume,
_creator: req.user._id,
_updatedBy: req.user._id
}
if (!req?.files?.profilePic) {
return res.status(422).json({
validation: {profilePic: {msg: `لطفا یک فایل ارسال کنید`}}
});
}
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
/////// add pic
const image = req.files.profilePic;
if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) {
return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}});
}
const imageName = 'candidate_' + Date.now() + '_' + targetElection._id + '.jpg';
data.profilePic = imageName;
const target = sharp(image.data)
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.toFormat('jpg')
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/election/${imageName}`)
targetElection.candidates.push(data);
await targetElection.save();
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
console.log(error.message)
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.updateCandidate = [
[
body('candidateId')
.notEmpty().withMessage(_sr['fa'].required.field),
body('firstName')
.notEmpty().withMessage(_sr['fa'].required.first_name),
body('lastName')
.notEmpty().withMessage(_sr['fa'].required.last_name),
body('nationalCode')
.optional().isNumeric().withMessage(_sr['fa'].required.national_code)
.bail()
.isLength({min: 10, max: 10}).withMessage('کد ملی 10 رقمی می باشد'),
],
checkValidations(validationResult),
async (req, res) => {
try {
const electionId = req.params.id;
const {
candidateId,
firstName,
lastName,
bornDate,
education,
nationalCode,
resume
} = req.body;
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
let candidate = targetElection.candidates.id(candidateId);
if (!candidate) return res404(res, `کاندید مورد نظر پیدا نشد`);
if (req?.files?.profilePic) {
const image = req.files.profilePic;
if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) {
return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}});
}
const imageName = 'candidate_' + Date.now() + '_' + targetElection._id + '.jpg';
const target = sharp(image.data)
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.toFormat('jpg')
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/election/${imageName}`)
/**
* if exist old pic delete it from file
*/
if (candidate.profilePic) {
const oldPic = `./static${candidate.profilePic}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
candidate.profilePic = imageName;
}
candidate.firstName = firstName;
candidate.lastName = lastName;
candidate.bornDate = bornDate;
candidate.education = education;
candidate.nationalCode = nationalCode;
candidate.resume = resume;
candidate._updatedBy = req.user._id;
await targetElection.save();
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.deleteCandidate = [
async (req, res) => {
try {
const electionId = req.params.id;
const candidateId = req.params.canId;
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
let candidate = targetElection.candidates.id(candidateId);
if (!candidate) return res404(res, `کاندید مورد نظر پیدا نشد`);
if (candidate.profilePic) {
const oldPic = `./static${candidate.profilePic}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
await targetElection.candidates.id(candidateId).remove();
await targetElection.save();
return res.json({message: _sr['fa'].response.success_remove});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
///////////////////////////////////////////////////////////////////// admin voter
module.exports.addVoter = [
[
body('firstName')
.notEmpty().withMessage(_sr['fa'].required.first_name),
body('lastName')
.notEmpty().withMessage(_sr['fa'].required.last_name),
body('nationalCode')
.notEmpty().withMessage(_sr['fa'].required.national_code)
.bail()
.isLength({min: 10, max: 10}).withMessage('کد ملی 10 رقمی می باشد'),
body('username')
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4)
.bail()
.custom((value, {req}) => {
if (hasWhiteSpaces(value)) return Promise.reject(_sr['fa'].response.whiteSpace)
else return true
})
.bail()
.custom((value, {req}) => {
if (!isLatinCharactersWithSymbol(value)) return Promise.reject(_sr['fa'].response.latinChar)
else return true
})
.bail()
.custom((value, {req}) => {
return Election.findOne({'voters.username': value})
.then(user => {
if (user) return Promise.reject(_sr['fa'].duplicated.username)
else return true
})
}),
],
checkValidations(validationResult),
async (req, res) => {
try {
const electionId = req.params.id;
const {
firstName,
lastName,
username,
nationalCode,
mobileNumber,
job
} = req.body;
//// generate password
// async function generatePass(){
// let pass = generateRandomDigits(8);
// let checkPass = Election.findOne({'voters.password' : pass});
//
// console.log(checkPass)
//
// if (checkPass) return await generatePass();
//
// return pass;
// }
const data = {
firstName,
lastName,
username,
password: await _generatePass(),
mobileNumber,
nationalCode,
job,
_creator: req.user._id,
_updatedBy: req.user._id
}
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
targetElection.voters.push(data);
await targetElection.save();
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
console.log(error.message)
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.updateVoter = [
[
body('voterId')
.notEmpty().withMessage(_sr['fa'].required.field),
body('firstName')
.notEmpty().withMessage(_sr['fa'].required.first_name),
body('lastName')
.notEmpty().withMessage(_sr['fa'].required.last_name),
body('nationalCode')
.notEmpty().withMessage(_sr['fa'].required.national_code),
],
checkValidations(validationResult),
async (req, res) => {
try {
const electionId = req.params.id;
const {
voterId,
firstName,
lastName,
nationalCode,
mobileNumber,
job
} = req.body;
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
let voter = targetElection.voters.id(voterId);
if (!voter) return res404(res, `رای دهنده مورد نظر پیدا نشد`);
voter.firstName = firstName;
voter.lastName = lastName;
voter.mobileNumber = mobileNumber;
voter.job = job;
voter.nationalCode = nationalCode;
voter._updatedBy = req.user._id;
await targetElection.save();
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.deleteVoter = [
async (req, res) => {
try {
const electionId = req.params.id;
const voterId = req.params.voterId;
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
let voter = targetElection.voters.id(voterId);
if (!voter) return res404(res, `کاربر مورد نظر پیدا نشد`);
await targetElection.voters.id(voterId).remove();
await targetElection.save();
return res.json({message: _sr['fa'].response.success_remove});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
//////////////////////////////////////////////////////////////////// auth voter
module.exports.voterLogin = [
[
body('username')
.notEmpty().withMessage(_sr['fa'].required.username),
body('password')
.notEmpty().withMessage(_sr['fa'].required.password)
],
checkValidations(validationResult),
async (req, res) => {
try {
const {username, password} = req.body;
const user = await Election.findOne({voters: {$elemMatch: {username, password, voted: false}}})
if (!user) return res.status(422).json({validation: {username: {msg: _sr['fa'].not_found.password}}});
return res.json({token: user.voters.find(item => item.password === password)._id});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.getVoterUser = [
async (req, res) => {
try {
const token = req.headers.authorization?.replace(/^Bearer\s/, '');
const election = await Election.findOne({'voters._id': token});
if (!election) return res.status(422).json({validation: {username: {msg: _sr['fa'].not_found.password}}});
const user = await election.voters.id(token);
return res.json({user});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
/////////////////////////////////////////////////////////////////////// public
module.exports.getElectionByUser = [
async (req, res) => {
try {
if (!req.voter) return res.status(403).json({message: 'شما اجازه دیدن این صفحه را ندارید'});
const targetElection = await Election.findOne({voters: {$elemMatch: {_id: req.voter._id, voted: false}}})
return res.json(targetElection);
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]
module.exports.addVote = [
[
body('electionId')
.notEmpty().withMessage(_sr['fa'].required.field),
body('candidateId')
.notEmpty().withMessage(_sr['fa'].required.field)
],
checkValidations(validationResult),
async (req, res) => {
try {
if (!req.voter) return res.status(403).json({message: 'شما اجازه رای دادن ندارید'});
const {electionId, candidateId} = req.body;
const targetElection = await Election.findById(electionId);
if (!targetElection) return res404(res, 'انتخابات مورد نظر پیدا نشد');
const voter = await targetElection.voters.id(req.voter._id);
if (!voter) return res.status(403).json({message: 'شما اجازه رای دادن ندارید'});
voter.voted = true;
const candidate = await targetElection.candidates.id(candidateId);
if (!candidate) return res404(res, 'کاندیدای انتخاب شده وجود ندارد');
const voteObj = {
voter: voter._id,
candidate: candidate._id
}
targetElection.votes.push(voteObj);
await targetElection.save();
return res.json({message: 'رای شما با موفقیت ثبت شد'});
} catch (error) {
return res500(res, `مشکلی در اجرای درخواست شما بوجود آمده است`);
}
}
]