Files
asan-service/server/controllers/lotteryController.js
T
2025-07-09 11:55:58 +03:30

357 lines
12 KiB
JavaScript

const fs = require('fs')
const jimp = require('jimp')
const { body, validationResult } = require('express-validator')
const moment = require('moment-jalaali')
const Lottery = require('../models/Lottery')
const { serialChecker } = require('../plugins/asanServiceSerialChecker')
const { _sr } = require('../plugins/serverResponses')
const {
res404,
res406,
res500,
checkValidations,
removeWhiteSpaces,
checkMobileNumber,
normalizeMobileNumber
} = require('../plugins/controllersHelperFunctions')
const sms = require('../plugins/SMS_Module')
///
const _faSr = _sr.fa
module.exports.addLottery = [
[
body('title').notEmpty().withMessage(_faSr.required.title),
body('winnersCount')
.notEmpty()
.withMessage('تعداد برندگان قرعه کشی را مشخص کنید')
.bail()
.isNumeric()
.withMessage(_faSr.format.number)
.bail()
.custom((value, { req }) => {
if (Number(value) < 1) return Promise.reject(new Error('تعداد برندگان نمیتواند کمتر از 1 باشد'))
else return Promise.resolve()
}),
body('expireDate')
.notEmpty()
.withMessage('تاریخ پایان قرعه کشی را مشخص کنید')
.bail()
.isNumeric()
.withMessage('فرمت صحیح نیست')
.bail()
.custom((value, { req }) => {
if (Number(value) < Date.now()) return Promise.reject(new Error('نمیتوان تاریخ روز جاری یا قبل تر انتخاب کرد.'))
else return Promise.resolve()
})
],
checkValidations(validationResult),
async (req, res) => {
const { title, winnersCount, expireDate } = req.body
const supportedImageFormats = ['png', 'jpg', 'jpeg', 'webp']
let entryBgImgName, resultBgImgName, entryWidth, entryHeight, resultWidth, resultHeight
try {
// check for other open lotteries
const openLotteries = await Lottery.find({ expired: false })
if (openLotteries.length) return res406(res, 'تا بسته شدن قرعه کشی قبلی نمیتوان قرعه کشی جدید ثبت کرد')
// required image validations
if (!req.files || !req.files.entryBgImg)
return res.status(422).json({ validation: { entryBgImg: { msg: 'عکس صفحه شرکت در قرعه کشی اجباری است' } } })
if (!req.files || !req.files.resultBgImg)
return res.status(422).json({
validation: {
resultBgImg: {
msg: 'عکس صفحه نتایج قرعه کشی اجباری است'
}
}
})
// save images
if (req.files) {
// save entry bg image
if (req.files.entryBgImg) {
const image = req.files.entryBgImg
// validate image format
if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
return res.status(422).json({ validation: { entryBgImg: { msg: _faSr.format.image } } })
}
entryBgImgName = 'lotteryEntryBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
const jimpImg = await jimp.read(image.data)
jimpImg.quality(100).write(`./static/uploads/images/lottery/${entryBgImgName}`)
entryWidth = jimpImg.bitmap.width
entryHeight = jimpImg.bitmap.height
}
// save result bg image
if (req.files.resultBgImg) {
const image = req.files.resultBgImg
// validate image format
if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
return res.status(422).json({ validation: { resultBgImg: { msg: _faSr.format.image } } })
}
resultBgImgName = 'lotteryResultBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
const jimpImg = await jimp.read(image.data)
jimpImg.quality(100).write(`./static/uploads/images/lottery/${resultBgImgName}`)
resultWidth = jimpImg.bitmap.width
resultHeight = jimpImg.bitmap.height
}
}
const data = {
title,
winnersCount,
expireDate
}
if (entryBgImgName) {
data.entryWidth = entryWidth
data.entryHeight = entryHeight
data.entryBgImg = entryBgImgName
}
if (resultBgImgName) {
data.resultWidth = resultWidth
data.resultHeight = resultHeight
data.resultBgImg = resultBgImgName
}
data.lotteryCode = 'L'.concat(moment(Date.now()).format('jMMMjDDjYYYY').toUpperCase())
const lottery = new Lottery(data)
await lottery.save()
return res.json({ message: _faSr.response.success_save })
} catch (e) {
return res500(res, `there is an error here --- ${e}`)
}
}
]
module.exports.updateLottery = [
[
body('title').notEmpty().withMessage(_faSr.required.title),
body('winnersCount')
.notEmpty()
.withMessage('تعداد برندگان قرعه کشی را مشخص کنید')
.bail()
.isNumeric()
.withMessage(_faSr.format.number)
.bail()
.custom((value, { req }) => {
if (Number(value) < 1) return Promise.reject(new Error('تعداد برندگان نمیتواند کمتر از 1 باشد'))
else return Promise.resolve()
}),
body('expireDate')
.notEmpty()
.withMessage('تاریخ پایان قرعه کشی را مشخص کنید')
.bail()
.isNumeric()
.withMessage('فرمت صحیح نیست')
.bail()
.custom((value, { req }) => {
if (Number(value) < Date.now()) return Promise.reject(new Error('نمیتوان تاریخ روز جاری یا قبل تر انتخاب کرد.'))
else return Promise.resolve()
})
],
checkValidations(validationResult),
async (req, res) => {
const { title, winnersCount, expireDate } = req.body
const supportedImageFormats = ['png', 'jpg', 'jpeg', 'webp']
let entryBgImgName, resultBgImgName, entryWidth, entryHeight, resultWidth, resultHeight
try {
// check lottery expiration
const lottery = await Lottery.findById(req.params?.lotteryId)
if (lottery.expired) return res406(res, 'نمیتوان قرعه کشی بسته شده را ویرایش کرد')
// save images
if (req.files) {
// save entry bg image
if (req.files.entryBgImg) {
const image = req.files.entryBgImg
// validate image format
if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
return res.status(422).json({ validation: { entryBgImg: { msg: _faSr.format.image } } })
}
entryBgImgName = 'lotteryEntryBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
const jimpImg = await jimp.read(image.data)
jimpImg.quality(100).write(`./static/uploads/images/lottery/${entryBgImgName}`)
entryWidth = jimpImg.bitmap.width
entryHeight = jimpImg.bitmap.height
lottery.entryBgImg &&
fs.unlink(`./static/${lottery.entryBgImg}`, err => {
if (err) console.log(err)
})
}
// save result bg image
if (req.files.resultBgImg) {
const image = req.files.resultBgImg
// validate image format
if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
return res.status(422).json({ validation: { resultBgImg: { msg: _faSr.format.image } } })
}
resultBgImgName = 'lotteryResultBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
const jimpImg = await jimp.read(image.data)
jimpImg.quality(100).write(`./static/uploads/images/lottery/${resultBgImgName}`)
resultWidth = jimpImg.bitmap.width
resultHeight = jimpImg.bitmap.height
lottery.resultBgImg &&
fs.unlink(`./static/${lottery.resultBgImg}`, err => {
if (err) console.log(err)
})
}
}
lottery.title = title
lottery.winnersCount = winnersCount
lottery.expireDate = expireDate
if (entryBgImgName) {
lottery.entryWidth = entryWidth
lottery.entryHeight = entryHeight
lottery.entryBgImg = entryBgImgName
}
if (resultBgImgName) {
lottery.resultWidth = resultWidth
lottery.resultHeight = resultHeight
lottery.resultBgImg = resultBgImgName
}
await lottery.save()
return res.json({ message: _faSr.response.success_save })
} catch (e) {
return res500(res, `there is an error here --- ${e}`)
}
}
]
module.exports.getAllLotteries = [
(req, res) => {
Lottery.find({})
.sort({ _id: -1 })
.exec((err, data) => {
if (err || !data) return res500(res, err)
else return res.json(data)
})
}
]
module.exports.getOneLottery = [
(req, res) => {
Lottery.findById(req.params?.lotteryId, (err, data) => {
if (err || !data) return res404(err)
else return res.json(data)
})
}
]
module.exports.getLastLottery = [
(req, res) => {
Lottery.find({})
.sort({ _id: -1 })
.select('-participants -winnersCount')
.exec((err, data) => {
if (err || !data?.length) return res404(res, 'هیچ قرعه کشی ای در دسترس نیست')
else return res.json(data[0])
})
}
]
module.exports.enrollParticipant = [
[
body('fullName')
.notEmpty()
.withMessage(_faSr.required.name)
.bail()
.isLength({ min: 4 })
.withMessage(_faSr.min_char.min4)
.bail()
.custom((value, { req }) => {
if (removeWhiteSpaces(value).length < 4) return Promise.reject(_faSr.min_char.min4)
if (removeWhiteSpaces(value).match(/^[A-Za-z]+$/g))
return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید.'))
else return true
}),
body('mobile')
.notEmpty()
.withMessage(_faSr.required.phone_number)
.bail()
.custom((value, { req }) => {
const mobileNStatus = checkMobileNumber(value)
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
else return Promise.resolve()
}),
body('serial')
.notEmpty()
.withMessage('شماره سریال گارانتی را وارد کنید')
.bail()
.custom(async (value, { req }) => {
try {
const serialStatus = await serialChecker(value)
if (!serialStatus) return Promise.reject(new Error('شماره سریال معتبر نمیباشد'))
else return Promise.resolve()
} catch (e) {
console.log('error in check serials for enrollLotteryController ---- error message: ', e)
return Promise.reject(new Error('مشکلی در بررسی شماره سریال پیش آمده'))
}
})
],
checkValidations(validationResult),
async (req, res) => {
const { fullName, mobile, serial, lotteryId } = req.body
try {
const lottery = await Lottery.findById(lotteryId)
if (!lottery) throw new Error('incorrect lottery id')
if (lottery.expired) return res404(res, 'مهلت شرکت در قرعه کشی به پایان رسیده')
for await (const item of lottery.participants) {
if (item.serial === serial) return res404(res, 'این شماره سریال از قبل توسط شخص دیگری ثبت شده است')
}
const enrollCode = lottery.lotteryCode
.concat(lottery.participants.length)
.concat((Math.random() * 100).toFixed(0))
const normalizedMN = normalizeMobileNumber(mobile)
const data = { fullName, mobile: normalizedMN, serial, enrollCode }
lottery.participants.push(data)
lottery.markModified('participants')
await lottery.save()
await sms.lottery.enrollment(normalizedMN, fullName, enrollCode, Date.now())
return res.json({ message: 'اطلاعات شما با موفیقت در سیستم ثبت شد. کد پیگیری به تلفن همراه شما ارسال گردید' })
} catch (e) {
return res500(res, `there is an error here --- ${e}`)
}
}
]
module.exports.deleteLottery = [
(req, res) => {
Lottery.findByIdAndDelete(req.params?.lotteryId, (err, oldData) => {
if (err || !oldData) return res404(res, err)
fs.unlink(`./static/${oldData.entryBgImg}`, err => {
if (err) console.log(err)
})
fs.unlink(`./static/${oldData.resultBgImg}`, err => {
if (err) console.log(err)
})
return res.json({ message: _faSr.response.success_remove })
})
}
]