S3 for other controolers

This commit is contained in:
2026-06-19 15:47:02 +03:30
parent c73027540a
commit e95883eb6a
32 changed files with 1073 additions and 650 deletions
+1 -1
View File
@@ -36,7 +36,7 @@
v-for="(item, i) in items" v-for="(item, i) in items"
:key="i" :key="i"
class="item"> class="item">
<img :src="`/uploads/images/category/shafafiat/${item.icon}`" alt="شفافیت" /> <img :src="item.icon" alt="شفافیت" />
<div class="parent"> <div class="parent">
<div class="right"></div> <div class="right"></div>
<div class="left"></div> <div class="left"></div>
+81 -133
View File
@@ -8,13 +8,19 @@ const {
checkValidations, checkValidations,
} = require("../plugins/controllersHelperFunctions"); } = require("../plugins/controllersHelperFunctions");
const News = require("../models/News"); const News = require("../models/News");
const sharp = require("sharp");
const fs = require("fs");
const { extname } = require("path"); const { extname } = require("path");
const {
deleteCategoryImage,
deleteShafafiatIcon,
uploadProcessedImage,
uploadShafafiatIcon,
uploadTermsFile,
deleteTermsFile,
getStoredImageName,
} = require("../plugins/categoryImageStorage");
// variables // variables
const titleFilterRegex = new RegExp("/", "g"); const titleFilterRegex = new RegExp("/", "g");
const noCover = "/img/no-cover.jpg";
const coverNewsWidth = 400; const coverNewsWidth = 400;
const coverNewsHeight = 400; const coverNewsHeight = 400;
const coverQuality = 100; const coverQuality = 100;
@@ -411,34 +417,13 @@ module.exports.addCategory = [
image.mimetype.split("/")[1] image.mimetype.split("/")[1]
}`; }`;
try { try {
const target = sharp(image.data); await uploadProcessedImage(
await target image.data,
.resize(coverNewsWidth, coverNewsHeight, { fit: "cover" }) imageName,
.jpeg({ quality: coverQuality }) coverNewsWidth,
.toFile(`./static/uploads/images/category/${imageName}`); coverNewsHeight,
coverQuality
/** );
* if exist old pic delete it from file
*/
// if (targetNews.cover !== noCover && !targetNews.imported) {
// let oldPic = `./static${targetNews.cover}`;
//
// if (await fs.existsSync(oldPic)) {
// fs.unlink(oldPic, (err) => {
// if (err) return res500(res, err?.message);
// });
// }
// }
// if (targetNews.thumbCover !== noCover && !targetNews.imported) {
// let oldPic = `./static${targetNews.thumbCover}`;
//
// if (await fs.existsSync(oldPic)) {
// fs.unlink(oldPic, (err) => {
// if (err) return res500(res, err?.message);
// });
// }
// }
create.managerCover = imageName; create.managerCover = imageName;
await create.save(); await create.save();
@@ -461,33 +446,12 @@ module.exports.addCategory = [
const ext = extname(image.name); const ext = extname(image.name);
const imageName = `shafafiat_icon_${Date.now()}${ext}`; const imageName = `shafafiat_icon_${Date.now()}${ext}`;
try { try {
await image.mv( await uploadShafafiatIcon(
`${process.cwd()}/static/uploads/images/category/shafafiat/${imageName}` image.data,
imageName,
image.mimetype
); );
/**
* if exist old pic delete it from file
*/
// if (targetNews.cover !== noCover && !targetNews.imported) {
// let oldPic = `./static${targetNews.cover}`;
//
// if (await fs.existsSync(oldPic)) {
// fs.unlink(oldPic, (err) => {
// if (err) return res500(res, err?.message);
// });
// }
// }
// if (targetNews.thumbCover !== noCover && !targetNews.imported) {
// let oldPic = `./static${targetNews.thumbCover}`;
//
// if (await fs.existsSync(oldPic)) {
// fs.unlink(oldPic, (err) => {
// if (err) return res500(res, err?.message);
// });
// }
// }
create.icon = imageName; create.icon = imageName;
await create.save(); await create.save();
} catch (e) { } catch (e) {
@@ -812,24 +776,15 @@ module.exports.updateCategory = [
image.mimetype.split("/")[1] image.mimetype.split("/")[1]
}`; }`;
try { try {
const target = sharp(image.data); await deleteCategoryImage(targetCategory, "managerCover");
await target
.resize(coverNewsWidth, coverNewsHeight, { fit: "cover" })
.jpeg({ quality: coverQuality })
.toFile(`./static/uploads/images/category/${imageName}`);
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (targetCategory.managerCover !== noCover) { coverNewsWidth,
let oldPic = `./static${targetCategory.managerCover}`; coverNewsHeight,
coverQuality
if (await fs.existsSync(oldPic)) { );
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
targetCategory.managerCover = imageName; targetCategory.managerCover = imageName;
} catch (e) { } catch (e) {
@@ -839,7 +794,6 @@ module.exports.updateCategory = [
if (req.files?.icon) { if (req.files?.icon) {
const image = req.files.icon; const image = req.files.icon;
console.log(image);
if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) { if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) {
return res.status(422).json({ return res.status(422).json({
validation: { validation: {
@@ -852,30 +806,17 @@ module.exports.updateCategory = [
const ext = extname(image.name); const ext = extname(image.name);
const imageName = `shafafiat_icon_${Date.now()}${ext}`; const imageName = `shafafiat_icon_${Date.now()}${ext}`;
try { try {
await image.mv( await deleteShafafiatIcon(
`${process.cwd()}/static/uploads/images/category/shafafiat/${imageName}` getStoredImageName(targetCategory, "icon")
); );
// const target = sharp(image.data)
// await target
// .resize(coverNewsWidth, coverNewsHeight, {fit: 'cover'})
// .jpeg({quality: coverQuality})
// .toFile(`./static/uploads/images/category/shafafiat/${imageName}`);
/** await uploadShafafiatIcon(
* if exist old pic delete it from file image.data,
*/ imageName,
if (targetCategory.icon !== noCover) { image.mimetype
let oldPic = `./static${targetCategory.icon}`; );
if (await fs.existsSync(oldPic)) {
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
targetCategory.icon = imageName; targetCategory.icon = imageName;
console.log(targetCategory);
} catch (e) { } catch (e) {
return res500(res, e?.message); return res500(res, e?.message);
} }
@@ -1223,52 +1164,59 @@ module.exports.getParent = [
module.exports.addTermsFileToCategory = [ module.exports.addTermsFileToCategory = [
[body("termsTitle").notEmpty().withMessage(_sr["fa"].required.title)], [body("termsTitle").notEmpty().withMessage(_sr["fa"].required.title)],
checkValidations(validationResult), checkValidations(validationResult),
(req, res) => { async (req, res) => {
if (!req.files?.file) try {
return res if (!req.files?.file)
.status(422) return res
.json({ validation: { file: { msg: _sr["fa"].required.file } } }); .status(422)
if (req.files?.file.mimetype.split("/")[1] !== "pdf") .json({ validation: { file: { msg: _sr["fa"].required.file } } });
return res if (req.files?.file.mimetype.split("/")[1] !== "pdf")
.status(422) return res
.json({ validation: { file: { msg: "فقط فرمت PDF قابل قبول است" } } }); .status(422)
.json({ validation: { file: { msg: "فقط فرمت PDF قابل قبول است" } } });
const data = { title: req.body.termsTitle }; const category = await Category.findById(req.params.categoryId);
const file = req.files.file; if (!category) return res404(res, "category not found");
const fileName =
req.body.termsTitle.replace(titleFilterRegex, "-") +
"_" +
Date.now() +
".pdf";
file.mv(`./static/uploads/files/terms/${fileName}`);
data.file = fileName;
Category.findById(req.params.categoryId, (err, category) => { const fileName =
if (err || !category) return res404(res, err); req.body.termsTitle.replace(titleFilterRegex, "-") +
category.terms.push(data); "_" +
category.save((err) => { Date.now() +
if (err) return res500(res, err); ".pdf";
else return res.json({ message: _sr["fa"].response.success_save });
await uploadTermsFile(req.files.file.data, fileName);
category.terms.push({
title: req.body.termsTitle,
file: fileName,
}); });
}); await category.save();
return res.json({ message: _sr["fa"].response.success_save });
} catch (err) {
return res500(res, err);
}
}, },
]; ];
module.exports.removeTermsFileFromCategory = [ module.exports.removeTermsFileFromCategory = [
(req, res) => { async (req, res) => {
Category.findOne({ "terms._id": req.params.fileId }, (err, category) => { try {
if (err || !category) return res404(res, err); const category = await Category.findOne({ "terms._id": req.params.fileId });
const file = category.terms.id(req.params.fileId); if (!category) return res404(res, "not found");
if (!file) return res404(res, "not found");
file.remove(); const termsFile = category.terms.id(req.params.fileId);
fs.unlink(`./static/${file.file}`, (err) => { if (!termsFile) return res404(res, "not found");
if (err) console.log(err);
}); const fileName = getStoredImageName(termsFile, "file");
category.save((err) => { termsFile.remove();
if (err) return res500(res, err); await deleteTermsFile(fileName);
else return res.json({ message: _sr["fa"].response.success_remove }); await category.save();
});
}); return res.json({ message: _sr["fa"].response.success_remove });
} catch (err) {
return res500(res, err);
}
}, },
]; ];
+34 -55
View File
@@ -1,9 +1,11 @@
const {body, validationResult} = require('express-validator'); const {body, validationResult} = require('express-validator');
const sharp = require('sharp');
const {_sr} = require('../plugins/serverResponses'); const {_sr} = require('../plugins/serverResponses');
const {res404, res500, hasWhiteSpaces, isLatinCharactersWithSymbol, generateRandomDigits} = require('../plugins/controllersHelperFunctions'); const {res404, res500, hasWhiteSpaces, isLatinCharactersWithSymbol, generateRandomDigits} = require('../plugins/controllersHelperFunctions');
const Content = require('../models/Content'); const Content = require('../models/Content');
const fs = require('fs'); const {
deleteContentImages,
uploadProcessedImage,
} = require('../plugins/contentImageStorage');
////// variables ////// variables
@@ -85,26 +87,23 @@ module.exports.addContent = [
const imageName = `manager_${Date.now()}_${create._id}.${image.mimetype.split('/')[1]}`; const imageName = `manager_${Date.now()}_${create._id}.${image.mimetype.split('/')[1]}`;
const thumbName = 'thumb_' + imageName const thumbName = 'thumb_' + imageName
try { try {
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(profileWidth, profileHeight, { imageName,
fit: 'cover' profileWidth,
}) profileHeight,
.jpeg({ profileQuality
quality: profileQuality );
}) await uploadProcessedImage(
.toFile(`./static/uploads/images/content/${imageName}`) image.data,
await target thumbName,
.resize(profileThumbWidth, profileThumbHeight, { profileThumbWidth,
fit: 'cover' profileThumbHeight,
}) profileThumbQuality
.jpeg({ );
quality: profileThumbQuality
})
.toFile(`./static/uploads/images/content/${thumbName}`)
create.cover = imageName; create.cover = imageName;
create.thumb = imageName; create.thumb = thumbName;
await create.save(); await create.save();
} catch (e) { } catch (e) {
@@ -180,42 +179,22 @@ module.exports.updateContent = [
const imageName = `manager_${Date.now()}_${targetContent._id}.${image.mimetype.split('/')[1]}`; const imageName = `manager_${Date.now()}_${targetContent._id}.${image.mimetype.split('/')[1]}`;
const thumbName = 'thumb_' + imageName const thumbName = 'thumb_' + imageName
try { try {
const target = sharp(image.data) await deleteContentImages(targetContent);
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/content/${imageName}`)
await target
.resize(profileThumbWidth, profileThumbHeight, {
fit: 'cover'
})
.jpeg({
quality: profileThumbQuality
})
.toFile(`./static/uploads/images/content/${thumbName}`)
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (targetContent.cover) { profileWidth,
const oldPic = `./static${targetContent.cover}` profileHeight,
const oldThumb = `./static${targetContent.thumb}` profileQuality
);
if (fs.existsSync(oldPic)) { await uploadProcessedImage(
fs.unlink(oldPic, (err) => { image.data,
if (err) return res500(res, err?.message); thumbName,
}); profileThumbWidth,
} profileThumbHeight,
if (fs.existsSync(oldThumb)) { profileThumbQuality
fs.unlink(oldThumb, (err) => { );
if (err) return res500(res, err?.message);
});
}
}
targetContent.cover = imageName; targetContent.cover = imageName;
targetContent.thumb = thumbName; targetContent.thumb = thumbName;
+63 -63
View File
@@ -1,9 +1,15 @@
const fs = require('fs') const fs = require('fs')
const {PassThrough} = require('stream')
const archiver = require('archiver') const archiver = require('archiver')
const moment = require('moment') const moment = require('moment')
const jwt = require('jsonwebtoken') const jwt = require('jsonwebtoken')
const {secretKey} = require('../authentication') const {secretKey} = require('../authentication')
const {_sr} = require('../plugins/serverResponses') const {_sr} = require('../plugins/serverResponses')
const {
appendS3UploadsToArchive,
uploadBackupArchive,
deleteOldBackups,
} = require('../plugins/backupStorage')
// models // models
const Category = require('../models/Category') const Category = require('../models/Category')
const Comment = require('../models/Comment') const Comment = require('../models/Comment')
@@ -21,6 +27,8 @@ const Slider = require('../models/Slider')
const User = require('../models/User') const User = require('../models/User')
const YearBanner = require('../models/YearBanner') const YearBanner = require('../models/YearBanner')
const hostFullError = '<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>'
module.exports.createBackUp = [ module.exports.createBackUp = [
// check user token and permission to backup // check user token and permission to backup
async (req, res, next) => { async (req, res, next) => {
@@ -85,86 +93,72 @@ module.exports.createBackUp = [
const [categories, comments, contactus, contents, galleries, homepage, links, meetings, news, newsFiles, services, sliders, users, yearBanner, occasion] = await Promise.all(dataBaseQueries) const [categories, comments, contactus, contents, galleries, homepage, links, meetings, news, newsFiles, services, sliders, users, yearBanner, occasion] = await Promise.all(dataBaseQueries)
if (await !fs.existsSync('./backup/database')) await fs.mkdirSync('./backup/database') const dateStr = moment(Date.now()).format('YYYY-MM-DD')
const backupName = `backup_${dateStr}.zip`
await Promise.all([
fs.writeFileSync(`./backup/database/categories_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(categories)),
fs.writeFileSync(`./backup/database/comments_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(comments)),
fs.writeFileSync(`./backup/database/contactus_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(contactus)),
fs.writeFileSync(`./backup/database/contents_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(contents)),
fs.writeFileSync(`./backup/database/galleries_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(galleries)),
fs.writeFileSync(`./backup/database/homepage_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(homepage)),
fs.writeFileSync(`./backup/database/links_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(links)),
fs.writeFileSync(`./backup/database/meetings_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(meetings)),
fs.writeFileSync(`./backup/database/news_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(news)),
fs.writeFileSync(`./backup/database/newsFiles_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(newsFiles)),
fs.writeFileSync(`./backup/database/services_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(services)),
fs.writeFileSync(`./backup/database/sliders_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(sliders)),
fs.writeFileSync(`./backup/database/users_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(users)),
fs.writeFileSync(`./backup/database/yearBanner_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(yearBanner)),
fs.writeFileSync(`./backup/database/occasion_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(occasion))
])
/////////////////// create backup zip file
const backupName = 'backup_' + moment(Date.now()).format('YYYY-MM-DD') + '.zip'
// create a file to stream archive data to.
const output = fs.createWriteStream(`./backup/${backupName}`)
const archive = archiver('zip', { const archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level. zlib: {level: 9}
}) })
const output = new PassThrough()
const chunks = []
output.on('data', (chunk) => chunks.push(chunk))
// listen for all archive data to be written
// 'close' event is fired only when a file descriptor is involved
output.on('close', function () {
console.log(archive.pointer() + ' total bytes')
console.log('archiver has been finalized and the output file descriptor has closed.')
return res.download(`./backup/${backupName}`)
})
// This event is fired when the data source is drained no matter what was the data source.
// It is not part of this library but rather from the NodeJS Stream API.
// @see: https://nodejs.org/api/stream.html#stream_event_end
output.on('end', function () {
console.log('Data has been drained')
return res.status(500).send('<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>')
})
// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function (err) { archive.on('warning', function (err) {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
// log warning
console.log('On archiver warning -- ENOENT error code', err) console.log('On archiver warning -- ENOENT error code', err)
} else { } else {
// throw error
console.log('On archiver warning -- other error codes ', err) console.log('On archiver warning -- other error codes ', err)
} }
return res.status(500).send('<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>') return res.status(500).send(hostFullError)
}) })
// good practice to catch this error explicitly
archive.on('error', function (err) { archive.on('error', function (err) {
// throw err
console.log(err) console.log(err)
return res.status(500).json({message: 'مشکلی پیش آمده'}) return res.status(500).json({message: 'مشکلی پیش آمده'})
}) })
// pipe archive data to the file archive.pipe(output)
await archive.pipe(output)
// append files from a sub-directory and naming it `new-subdir` within the archive const databaseExports = [
await archive.directory(`./static/uploads/`, 'uploads') ['categories', categories],
await archive.directory(`./backup/database/`, 'database') ['comments', comments],
['contactus', contactus],
['contents', contents],
['galleries', galleries],
['homepage', homepage],
['links', links],
['meetings', meetings],
['news', news],
['newsFiles', newsFiles],
['services', services],
['sliders', sliders],
['users', users],
['yearBanner', yearBanner],
['occasion', occasion],
]
for (const [name, data] of databaseExports) {
archive.append(JSON.stringify(data), {name: `database/${name}_${dateStr}.json`})
}
await appendS3UploadsToArchive(archive)
// finalize the archive (ie we are done appending files but streams have to finish yet)
// 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
await archive.finalize() await archive.finalize()
await fs.rmdirSync('./backup/database', {recursive: true}) await new Promise((resolve, reject) => {
output.on('end', resolve)
output.on('error', reject)
})
const buffer = Buffer.concat(chunks)
await uploadBackupArchive(buffer, backupName)
res.setHeader('Content-Type', 'application/zip')
res.setHeader('Content-Disposition', `attachment; filename="${backupName}"`)
return res.send(buffer)
} catch (e) { } catch (e) {
return res.status(500).send('<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>') return res.status(500).send(hostFullError)
} }
} }
] ]
@@ -173,12 +167,18 @@ module.exports.createBackUp = [
module.exports.removeOldBackups = [ module.exports.removeOldBackups = [
async (req, res) => { async (req, res) => {
try { try {
const files = await fs.readdirSync('./backup') await deleteOldBackups()
for await (const file of files) {
const isDirectory = await fs.statSync(`./backup/${file}`).isDirectory() if (fs.existsSync('./backup')) {
if (isDirectory) await fs.rmdirSync(`./backup/${file}`, {recursive: true}) const files = fs.readdirSync('./backup')
else await fs.unlinkSync(`./backup/${file}`) for (const file of files) {
const filePath = `./backup/${file}`
const isDirectory = fs.statSync(filePath).isDirectory()
if (isDirectory) fs.rmdirSync(filePath, {recursive: true})
else fs.unlinkSync(filePath)
}
} }
return res.json({message: _sr['fa'].response.success_remove}) return res.json({message: _sr['fa'].response.success_remove})
} catch (e) { } catch (e) {
return res.status(500).json({message: e}) return res.status(500).json({message: e})
+22 -53
View File
@@ -10,8 +10,11 @@ const {
hasWhiteSpaces, hasWhiteSpaces,
isLatinCharactersWithSymbol isLatinCharactersWithSymbol
} = require('../plugins/controllersHelperFunctions'); } = require('../plugins/controllersHelperFunctions');
const fs = require('fs'); const {
const sharp = require('sharp'); deleteCandidateImage,
deleteElectionCandidateImages,
uploadProcessedImage,
} = require('../plugins/electionImageStorage');
////// variables ////// variables
const profileWidth = 300; const profileWidth = 300;
@@ -292,17 +295,7 @@ module.exports.deletOneElection = [
} }
if (deleteElection.candidates.length) { if (deleteElection.candidates.length) {
const targetDir = `./static/uploads/images/election/`; await deleteElectionCandidateImages(deleteElection);
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(); await deleteElection.deleteOne();
@@ -457,16 +450,13 @@ module.exports.addCandidate = [
} }
const imageName = 'candidate_' + Date.now() + '_' + targetElection._id + '.jpg'; const imageName = 'candidate_' + Date.now() + '_' + targetElection._id + '.jpg';
data.profilePic = imageName; data.profilePic = imageName;
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(profileWidth, profileHeight, { imageName,
fit: 'cover' profileWidth,
}) profileHeight,
.toFormat('jpg') profileQuality
.jpeg({ );
quality: profileQuality
})
.toFile(`./static/uploads/images/election/${imageName}`)
targetElection.candidates.push(data); targetElection.candidates.push(data);
@@ -528,29 +518,16 @@ module.exports.updateCandidate = [
return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}}); return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}});
} }
const imageName = 'candidate_' + Date.now() + '_' + targetElection._id + '.jpg'; const imageName = 'candidate_' + Date.now() + '_' + targetElection._id + '.jpg';
const target = sharp(image.data) await deleteCandidateImage(candidate);
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.toFormat('jpg')
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/election/${imageName}`)
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (candidate.profilePic) { profileWidth,
const oldPic = `./static${candidate.profilePic}`; profileHeight,
profileQuality
);
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
candidate.profilePic = imageName; candidate.profilePic = imageName;
} }
@@ -586,15 +563,7 @@ module.exports.deleteCandidate = [
if (!candidate) return res404(res, `کاندید مورد نظر پیدا نشد`); if (!candidate) return res404(res, `کاندید مورد نظر پیدا نشد`);
if (candidate.profilePic) { await deleteCandidateImage(candidate);
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.candidates.id(candidateId).remove();
+20 -41
View File
@@ -3,7 +3,6 @@ const {
body, body,
validationResult validationResult
} = require('express-validator'); } = require('express-validator');
const sharp = require('sharp');
const { const {
_sr _sr
} = require('../plugins/serverResponses'); } = require('../plugins/serverResponses');
@@ -14,7 +13,10 @@ const {
isLatinCharactersWithSymbol, isLatinCharactersWithSymbol,
generateRandomDigits generateRandomDigits
} = require('../plugins/controllersHelperFunctions'); } = require('../plugins/controllersHelperFunctions');
const fs = require('fs'); const {
deleteLinksImage,
uploadProcessedImage,
} = require('../plugins/linksImageStorage');
////// variables ////// variables
const profileWidth = 50; const profileWidth = 50;
@@ -108,15 +110,13 @@ module.exports.addLinks = [
} }
const imageName = `links_${Date.now()}_${createLinks._id}.${image.mimetype.split('/')[1]}`; const imageName = `links_${Date.now()}_${createLinks._id}.${image.mimetype.split('/')[1]}`;
try { try {
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(profileWidth, profileHeight, { imageName,
fit: 'cover' profileWidth,
}) profileHeight,
.jpeg({ profileQuality
quality: profileQuality );
})
.toFile(`./static/uploads/images/links/${imageName}`);
createLinks.icon = imageName; createLinks.icon = imageName;
@@ -243,28 +243,15 @@ module.exports.updateLinks = [
} }
const imageName = `links_${Date.now()}_${targetLinks._id}.${image.mimetype.split('/')[1]}`; const imageName = `links_${Date.now()}_${targetLinks._id}.${image.mimetype.split('/')[1]}`;
try { try {
const target = sharp(image.data) await deleteLinksImage(targetLinks, 'icon');
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/links/${imageName}`);
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (targetLinks.icon) { profileWidth,
var oldPic = `./static${targetLinks.icon}`; profileHeight,
profileQuality
if (fs.existsSync(oldPic)) { );
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
targetLinks.icon = imageName; targetLinks.icon = imageName;
targetLinks.linksStatus = true; targetLinks.linksStatus = true;
@@ -312,15 +299,7 @@ module.exports.deletOneLinks = [
return res500(res, `شما اجازه حذف این پیوند را ندارید`); return res500(res, `شما اجازه حذف این پیوند را ندارید`);
} }
if (targetLinks.icon) { await deleteLinksImage(targetLinks, 'icon');
var oldPic = `./static${targetLinks.icon}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (error) => {
if (error) return res500(res, error?.message);
});
}
}
/** delete links */ /** delete links */
await targetLinks.deleteOne(); await targetLinks.deleteOne();
+20 -40
View File
@@ -2,8 +2,10 @@ const Occasion = require('../models/Occasion');
const {body, validationResult} = require('express-validator'); const {body, validationResult} = require('express-validator');
const {_sr} = require('../plugins/serverResponses'); const {_sr} = require('../plugins/serverResponses');
const {res404, res500} = require('../plugins/controllersHelperFunctions'); const {res404, res500} = require('../plugins/controllersHelperFunctions');
const fs = require('fs'); const {
const sharp = require('sharp'); deleteOccasionImage,
uploadProcessedImage,
} = require('../plugins/occasionImageStorage');
const moment = require('moment-jalaali'); const moment = require('moment-jalaali');
////// variables ////// variables
@@ -63,16 +65,13 @@ module.exports.addOccasion = [
} }
const imageName = `occasion_${addOccasion._id}_${Date.now()}.jpg`; const imageName = `occasion_${addOccasion._id}_${Date.now()}.jpg`;
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(occasionWidth, occasionHeight, { imageName,
fit: 'cover' occasionWidth,
}) occasionHeight,
.toFormat('jpg') occasionQuality
.jpeg({ );
quality: occasionQuality
})
.toFile(`./static/uploads/images/occasion/${imageName}`);
addOccasion.status = true; addOccasion.status = true;
addOccasion.mainCover = imageName; addOccasion.mainCover = imageName;
@@ -132,26 +131,15 @@ module.exports.updateOccasion = [
} }
const imageName = `occasion_${targetOccasion._id}_${Date.now()}.jpg`; const imageName = `occasion_${targetOccasion._id}_${Date.now()}.jpg`;
const target = sharp(image.data) await deleteOccasionImage(targetOccasion, 'mainCover');
await target
.resize(occasionWidth, occasionHeight, {
fit: 'cover'
})
.toFormat('jpg')
.jpeg({
quality: occasionQuality
})
.toFile(`./static/uploads/images/occasion/${imageName}`);
if (targetOccasion.mainCover) { await uploadProcessedImage(
var oldPic = `./static${targetOccasion.mainCover}`; image.data,
imageName,
if (fs.existsSync(oldPic)) { occasionWidth,
fs.unlink(oldPic, (err) => { occasionHeight,
if (err) return res500(res, err?.message); occasionQuality
}); );
}
}
targetOccasion.status = true; targetOccasion.status = true;
targetOccasion.mainCover = imageName; targetOccasion.mainCover = imageName;
@@ -184,15 +172,7 @@ module.exports.deleteOccasion = [
return res404(res, `مناسبت مورد نظر پیدا نشد`); return res404(res, `مناسبت مورد نظر پیدا نشد`);
} }
if (targetOccasion.mainCover) { await deleteOccasionImage(targetOccasion, 'mainCover');
var oldPic = `./static${targetOccasion.mainCover}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
await targetOccasion.deleteOne(); await targetOccasion.deleteOne();
+130 -91
View File
@@ -1,109 +1,148 @@
const fs = require("fs/promises");
const os = require("os");
const path = require("path");
const axios = require("axios");
const { body, validationResult } = require("express-validator"); const { body, validationResult } = require("express-validator");
const { _sr } = require("../plugins/serverResponses"); const { _sr } = require("../plugins/serverResponses");
const { checkValidations } = require("../plugins/controllersHelperFunctions"); const { checkValidations } = require("../plugins/controllersHelperFunctions");
const Book = require("../models/Book"); const Book = require("../models/Book");
var convertapi = require('convertapi')('6zZB0nquI5V3P3Vg'); const {
uploadPdf,
uploadBookSlide,
deletePdf,
deleteBookSlide,
} = require("../plugins/bookImageStorage");
const convertapi = require("convertapi")("6zZB0nquI5V3P3Vg");
module.exports.AddPDF = [ module.exports.AddPDF = [
[ [body("title").notEmpty().withMessage(_sr["fa"].required.title)],
body('title') checkValidations(validationResult),
.notEmpty().withMessage(_sr['fa'].required.title) async (req, res) => {
], let tmpDir;
checkValidations(validationResult),
async (req, res) => { try {
try { const firstbook = [];
const firstbook = [];
if (!req.files?.file) {
if (!req.files?.file) { return res
return res.status(422).json({ validation: { file: { msg: _sr['fa'].required.file } } }); .status(422)
} .json({ validation: { file: { msg: _sr["fa"].required.file } } });
}
if (req.files?.file.mimetype.split('/')[1] !== 'pdf') {
return res.status(422).json({ validation: { file: { msg: 'فقط فرمت PDF قابل قبول است' } } }); if (req.files?.file.mimetype.split("/")[1] !== "pdf") {
} return res
.status(422)
const book = await Book.findById(req.body.bookId); .json({ validation: { file: { msg: "فقط فرمت PDF قابل قبول است" } } });
const bookId = book ? book._id : null; }
const data = { title: req.body.title }; const book = await Book.findById(req.body.bookId);
const file = req.files.file; const bookId = book ? book._id : null;
const fileName = req.body.title.replace(Date.now(), '-') + '_' + Date.now() + '.pdf';
const imageName = req.body.title.replace(Date.now(), '-') + '_' + Date.now(); const file = req.files.file;
const fileName =
const filePath = `./static/uploads/pdf/${fileName}`; req.body.title.replace(Date.now(), "-") + "_" + Date.now() + ".pdf";
const imageName =
await file.mv(filePath); req.body.title.replace(Date.now(), "-") + "_" + Date.now();
data.file = fileName;
const { url: pdfUrl } = await uploadPdf(file.data, fileName);
const convertPromise = convertapi.convert('jpg', {
File: filePath tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "book-"));
}, 'pdf'); const tmpPdfPath = path.join(tmpDir, fileName);
await fs.writeFile(tmpPdfPath, file.data);
const result = await convertPromise;
const savedFiles = await result.saveFiles(`./static/uploads/books/${imageName}.jpeg`); const result = await convertapi.convert(
"jpg",
const imagePath = `https://ostan-mr.ir/uploads/books/${imageName}.jpeg`; { File: tmpPdfPath },
firstbook.push(imagePath); "pdf"
);
if (bookId) {
const update = await Book.findByIdAndUpdate( const convertedResponse = await axios.get(result.files[0].url, {
{_id:bookId}, responseType: "arraybuffer",
{ $push: { slides: imagePath } }, });
{ upsert: true } const imagePath = await uploadBookSlide(
); Buffer.from(convertedResponse.data),
return res.status(201).json({ msg: "اسلاید کتاب اضافه شد", Data: update }); imageName
} else { );
const newBook = new Book({ firstbook.push(imagePath);
title: req.body.title,
uri: `https://ostan-mr.ir/uploads/pdf/${fileName}`, if (bookId) {
slides: firstbook const update = await Book.findByIdAndUpdate(
}); { _id: bookId },
await newBook.save(); { $push: { slides: imagePath } },
return res.status(201).json({ msg: "کتاب ایجاد شد", Data: newBook }); { upsert: true }
} );
return res
} catch (error) { .status(201)
console.error(error); .json({ msg: "اسلاید کتاب اضافه شد", Data: update });
return res.status(500).json({ msg: "خطایی در پردازش فایل رخ داد", error: error.message }); }
}
const newBook = new Book({
title: req.body.title,
uri: pdfUrl,
slides: firstbook,
});
await newBook.save();
return res.status(201).json({ msg: "کتاب ایجاد شد", Data: newBook });
} catch (error) {
console.error(error);
return res.status(500).json({
msg: "خطایی در پردازش فایل رخ داد",
error: error.message,
});
} finally {
if (tmpDir) {
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});
}
} }
},
]; ];
module.exports.GetAll = [ module.exports.GetAll = [
async (req, res,next) => { async (req, res, next) => {
try { try {
const Books = await Book.find({}); const Books = await Book.find({});
return res.status(200).json({ Books }); return res.status(200).json({ Books });
} catch (error) { } catch (error) {
next(error) next(error);
}
} }
},
]; ];
module.exports.GetOne = [ module.exports.GetOne = [
async (req, res,next) => { async (req, res, next) => {
try { try {
const id = req.params.id const id = req.params.id;
const book = await Book.findById(id); const book = await Book.findById(id);
return res.status(200).json({ msg: book }); return res.status(200).json({ msg: book });
} catch (error) { } catch (error) {
next(error) next(error);
}
} }
},
]; ];
module.exports.DeleteOne = [ module.exports.DeleteOne = [
async(req,res,next)=>{ async (req, res, next) => {
try { try {
const book = await Book.deleteOne({_id:req.params.id}) const book = await Book.findById(req.params.id);
if(!book){ if (!book) {
return res.status(200).json({ msg: 'کتاب وجود ندارد ' }); return res.status(200).json({ msg: "کتاب وجود ندارد " });
} }
return res.status(200).json({ msg: 'کتاب حذف شد' });
} catch (error) { const uri = book.get("uri", null, { getters: false });
next(error) if (uri) {
} await deletePdf(uri.split("/").pop());
}
const slides = book.get("slides", [], { getters: false }) || [];
for (const slide of slides) {
const imageName = slide.split("/").pop().replace(/\.jpeg$/i, "");
await deleteBookSlide(imageName);
}
await book.deleteOne();
return res.status(200).json({ msg: "کتاب حذف شد" });
} catch (error) {
next(error);
} }
] },
];
+20 -41
View File
@@ -3,7 +3,6 @@ const {
body, body,
validationResult validationResult
} = require('express-validator'); } = require('express-validator');
const sharp = require('sharp');
const { const {
_sr _sr
} = require('../plugins/serverResponses'); } = require('../plugins/serverResponses');
@@ -14,7 +13,10 @@ const {
isLatinCharactersWithSymbol, isLatinCharactersWithSymbol,
generateRandomDigits generateRandomDigits
} = require('../plugins/controllersHelperFunctions'); } = require('../plugins/controllersHelperFunctions');
const fs = require('fs'); const {
deleteSliderImage,
uploadProcessedImage,
} = require('../plugins/sliderImageStorage');
////// variables ////// variables
const profileWidth = 600; const profileWidth = 600;
@@ -113,15 +115,13 @@ module.exports.addSlider = [
} }
const imageName = `slider_${Date.now()}_${createSlider._id}.${image.mimetype.split('/')[1]}`; const imageName = `slider_${Date.now()}_${createSlider._id}.${image.mimetype.split('/')[1]}`;
try { try {
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(profileWidth, profileHeight, { imageName,
fit: 'cover' profileWidth,
}) profileHeight,
.jpeg({ profileQuality
quality: profileQuality );
})
.toFile(`./static/uploads/images/slider/${imageName}`);
createSlider.cover = imageName; createSlider.cover = imageName;
@@ -253,28 +253,15 @@ module.exports.updateSlider = [
} }
const imageName = `slider_${Date.now()}_${targetSlider._id}.${image.mimetype.split('/')[1]}`; const imageName = `slider_${Date.now()}_${targetSlider._id}.${image.mimetype.split('/')[1]}`;
try { try {
const target = sharp(image.data) await deleteSliderImage(targetSlider, "cover");
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/slider/${imageName}`);
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (targetSlider.cover) { profileWidth,
var oldPic = `./static${targetSlider.cover}`; profileHeight,
profileQuality
if (fs.existsSync(oldPic)) { );
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
targetSlider.cover = imageName; targetSlider.cover = imageName;
} catch (e) { } catch (e) {
@@ -322,15 +309,7 @@ module.exports.deletOneSlider = [
return res500(res, `شما اجازه حذف این اسلایدر را ندارید`); return res500(res, `شما اجازه حذف این اسلایدر را ندارید`);
} }
if (targetSlider.cover) { await deleteSliderImage(targetSlider, "cover");
var oldPic = `./static${targetSlider.cover}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (error) => {
if (error) return res500(res, error?.message);
});
}
}
/** delete slider */ /** delete slider */
await targetSlider.deleteOne(); await targetSlider.deleteOne();
+20 -41
View File
@@ -3,7 +3,6 @@ const {
body, body,
validationResult validationResult
} = require('express-validator'); } = require('express-validator');
const sharp = require('sharp');
const { const {
_sr _sr
} = require('../plugins/serverResponses'); } = require('../plugins/serverResponses');
@@ -14,7 +13,10 @@ const {
isLatinCharactersWithSymbol, isLatinCharactersWithSymbol,
generateRandomDigits generateRandomDigits
} = require('../plugins/controllersHelperFunctions'); } = require('../plugins/controllersHelperFunctions');
const fs = require('fs'); const {
deleteSliderImage,
uploadProcessedImage,
} = require('../plugins/sliderImageStorage');
////// variables ////// variables
const profileWidth = 880; const profileWidth = 880;
@@ -113,15 +115,13 @@ module.exports.addSlider = [
} }
const imageName = `slider_${Date.now()}_${createSlider._id}.${image.mimetype.split('/')[1]}`; const imageName = `slider_${Date.now()}_${createSlider._id}.${image.mimetype.split('/')[1]}`;
try { try {
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(profileWidth, profileHeight, { imageName,
fit: 'cover' profileWidth,
}) profileHeight,
.jpeg({ profileQuality
quality: profileQuality );
})
.toFile(`./static/uploads/images/slider/${imageName}`);
createSlider.cover = imageName; createSlider.cover = imageName;
@@ -253,28 +253,15 @@ module.exports.updateSlider = [
} }
const imageName = `slider_${Date.now()}_${targetSlider._id}.${image.mimetype.split('/')[1]}`; const imageName = `slider_${Date.now()}_${targetSlider._id}.${image.mimetype.split('/')[1]}`;
try { try {
const target = sharp(image.data) await deleteSliderImage(targetSlider, "cover");
await target
.resize(profileWidth, profileHeight, {
fit: 'cover'
})
.jpeg({
quality: profileQuality
})
.toFile(`./static/uploads/images/slider/${imageName}`);
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (targetSlider.cover) { profileWidth,
var oldPic = `./static${targetSlider.cover}`; profileHeight,
profileQuality
if (fs.existsSync(oldPic)) { );
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
targetSlider.cover = imageName; targetSlider.cover = imageName;
} catch (e) { } catch (e) {
@@ -322,15 +309,7 @@ module.exports.deletOneSlider = [
return res500(res, `شما اجازه حذف این اسلایدر را ندارید`); return res500(res, `شما اجازه حذف این اسلایدر را ندارید`);
} }
if (targetSlider.cover) { await deleteSliderImage(targetSlider, "cover");
var oldPic = `./static${targetSlider.cover}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (error) => {
if (error) return res500(res, error?.message);
});
}
}
/** delete slider */ /** delete slider */
await targetSlider.deleteOne(); await targetSlider.deleteOne();
+28 -65
View File
@@ -4,7 +4,6 @@ const { rateLimit } = require("express-rate-limit");
const bcrypt = require("bcryptjs"); const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken"); const jwt = require("jsonwebtoken");
const crypto = require("crypto"); const crypto = require("crypto");
const sharp = require("sharp");
const { secretKey } = require("./../authentication"); const { secretKey } = require("./../authentication");
const { _sr } = require("../plugins/serverResponses"); const { _sr } = require("../plugins/serverResponses");
const { const {
@@ -14,7 +13,10 @@ const {
isLatinCharactersWithSymbol, isLatinCharactersWithSymbol,
generateRandomDigits, generateRandomDigits,
} = require("../plugins/controllersHelperFunctions"); } = require("../plugins/controllersHelperFunctions");
const fs = require("fs"); const {
deleteUserImage,
uploadProcessedImage,
} = require("../plugins/userImageStorage");
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
const Category = require("../models/Category"); const Category = require("../models/Category");
const Logger = require("../models/Logger"); const Logger = require("../models/Logger");
@@ -566,15 +568,13 @@ module.exports.registerAdmin = [
image.mimetype.split("/")[1]; image.mimetype.split("/")[1];
data.profilePic = imageName; data.profilePic = imageName;
try { try {
const target = sharp(image.data); await uploadProcessedImage(
await target image.data,
.resize(profileWidth, profileHeight, { imageName,
fit: "cover", profileWidth,
}) profileHeight,
.jpeg({ profileQuality
quality: profileQuality, );
})
.toFile(`./static/uploads/images/users/${imageName}`);
} catch (e) { } catch (e) {
return res500(res, e?.message); return res500(res, e?.message);
} }
@@ -713,18 +713,7 @@ module.exports.deleteOneUser = [
.json({ message: `شما نمیتوانید این کاربر را حذف کنید` }); .json({ message: `شما نمیتوانید این کاربر را حذف کنید` });
} }
/** await deleteUserImage(user, "profilePic");
* if exist old pic delete it from file
*/
if (user.profilePic) {
var oldPic = `./static${user.profilePic}`;
if (fs.existsSync(oldPic)) {
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
/** delete user */ /** delete user */
await user.deleteOne(); await user.deleteOne();
@@ -922,28 +911,15 @@ module.exports.updateUser = [
image.mimetype.split("/")[1]; image.mimetype.split("/")[1];
try { try {
const target = sharp(image.data); await deleteUserImage(user, "profilePic");
await target
.resize(profileWidth, profileHeight, {
fit: "cover",
})
.jpeg({
quality: profileQuality,
})
.toFile(`./static/uploads/images/users/${imageName}`);
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (user.profilePic) { profileWidth,
var oldPic = `./static${user.profilePic}`; profileHeight,
profileQuality
if (fs.existsSync(oldPic)) { );
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
} catch (e) { } catch (e) {
return res500(res, e?.message); return res500(res, e?.message);
} }
@@ -1129,28 +1105,15 @@ module.exports.updateProfile = [
image.mimetype.split("/")[1]; image.mimetype.split("/")[1];
try { try {
const target = sharp(image.data); await deleteUserImage(user, "profilePic");
await target
.resize(profileWidth, profileHeight, {
fit: "cover",
})
.jpeg({
quality: profileQuality,
})
.toFile(`./static/uploads/images/users/${imageName}`);
/** await uploadProcessedImage(
* if exist old pic delete it from file image.data,
*/ imageName,
if (user.profilePic) { profileWidth,
var oldPic = `./static${user.profilePic}`; profileHeight,
profileQuality
if (fs.existsSync(oldPic)) { );
fs.unlink(oldPic, (err) => {
if (err) return res500(res, err?.message);
});
}
}
} catch (e) { } catch (e) {
return res500(res, e?.message); return res500(res, e?.message);
} }
+8 -8
View File
@@ -2,8 +2,7 @@ const YearBanner = require('../models/YearBanner');
const {body, validationResult, checkSchema} = require('express-validator'); const {body, validationResult, checkSchema} = require('express-validator');
const {_sr} = require('../plugins/serverResponses'); const {_sr} = require('../plugins/serverResponses');
const {res404, res500} = require('../plugins/controllersHelperFunctions'); const {res404, res500} = require('../plugins/controllersHelperFunctions');
const fs = require('fs'); const {uploadProcessedImage} = require('../plugins/yearBannerImageStorage');
const sharp = require('sharp');
////// variables ////// variables
const yearBannerWidth = 1920 const yearBannerWidth = 1920
@@ -51,12 +50,13 @@ module.exports.updateYearBanner = [
imageName = `mainPage_cover.jpg`; imageName = `mainPage_cover.jpg`;
const target = sharp(image.data) await uploadProcessedImage(
await target image.data,
.resize(yearBannerWidth, yearBannerHeight, {fit: 'cover'}) imageName,
.toFormat('jpg') yearBannerWidth,
.jpeg({quality: yearBannerQuality}) yearBannerHeight,
.toFile(`./static/uploads/images/mainCover/${imageName}`); yearBannerQuality
);
} }
if (yearBanner) { if (yearBanner) {
+22 -7
View File
@@ -1,16 +1,31 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2'); const mongoosePaginate = require('mongoose-paginate-v2');
const s3Storage = require('../plugins/s3Storage');
function pdfUri(uri) {
function PDF(pdf) { if (!uri) return null;
if (pdf) return '/uploads/files/ReadOnly-PDF' + pdf if (uri.startsWith('http://') || uri.startsWith('https://')) return uri;
const fileName = uri.startsWith('/') ? uri.split('/').pop() : uri;
return s3Storage.getPublicUrl(`uploads/pdf/${fileName}`);
} }
function slideUrl(slide) {
if (!slide) return null;
if (slide.startsWith('http://') || slide.startsWith('https://')) return slide;
const imageName = slide.startsWith('/') ? slide.split('/').pop() : slide;
const key = imageName.endsWith('.jpeg')
? `uploads/books/${imageName}`
: `uploads/books/${imageName}.jpeg`;
return s3Storage.getPublicUrl(key);
}
const BookSchema = mongoose.Schema({ const BookSchema = mongoose.Schema({
title: String, title: String,
uri: String, uri: { type: String, get: pdfUri, default: null },
slides:{ slides: {
default:[], default: [],
type:Array type: [String],
get: (slides) => (slides || []).map(slideUrl),
} }
}); });
+14 -4
View File
@@ -1,4 +1,5 @@
const mongoose = require("mongoose"); const mongoose = require("mongoose");
const s3Storage = require("../plugins/s3Storage");
function autoPopulateSubs(next) { function autoPopulateSubs(next) {
this.populate({ this.populate({
@@ -14,12 +15,21 @@ function autoPopulateSubs(next) {
} }
function file(file) { function file(file) {
return "/uploads/files/terms/" + file; if (!file) return null;
if (file.startsWith("http://") || file.startsWith("https://")) return file;
return s3Storage.getPublicUrl(`uploads/files/terms/${file}`);
} }
function image(img) { function image(img) {
if (img) return "/uploads/images/category/" + img; if (!img) return "/img/no-cover.jpg";
else return "/img/no-cover.jpg"; if (img.startsWith("http://") || img.startsWith("https://")) return img;
return s3Storage.getPublicUrl(`uploads/images/category/${img}`);
}
function shafafiatIcon(icon) {
if (!icon) return null;
if (icon.startsWith("http://") || icon.startsWith("https://")) return icon;
return s3Storage.getPublicUrl(`uploads/images/category/shafafiat/${icon}`);
} }
const CategoryTermsFile = mongoose.Schema({ const CategoryTermsFile = mongoose.Schema({
@@ -71,7 +81,7 @@ const CategorySchema = mongoose.Schema({
managerName: String, managerName: String,
managerDescription: String, managerDescription: String,
/** if category was shafafiat this icon is for that */ /** if category was shafafiat this icon is for that */
icon: String, icon: { type: String, get: shafafiatIcon, default: null },
}); });
CategorySchema.index({ parent: 1, childs: 1 }); CategorySchema.index({ parent: 1, childs: 1 });
+4 -1
View File
@@ -1,7 +1,10 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/content/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/content/${img}`);
} }
+4 -1
View File
@@ -1,8 +1,11 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2'); const mongoosePaginate = require('mongoose-paginate-v2');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/election/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/election/${img}`);
} }
const CandidatesSchema = mongoose.Schema({ const CandidatesSchema = mongoose.Schema({
+4 -1
View File
@@ -1,7 +1,10 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/links/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/links/${img}`);
} }
const LinksSchema = mongoose.Schema({ const LinksSchema = mongoose.Schema({
+4 -1
View File
@@ -1,8 +1,11 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2'); const mongoosePaginate = require('mongoose-paginate-v2');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/occasion/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/occasion/${img}`);
} }
const OccasionSchema = mongoose.Schema({ const OccasionSchema = mongoose.Schema({
+4 -1
View File
@@ -1,8 +1,11 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2'); const mongoosePaginate = require('mongoose-paginate-v2');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/slider/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/slider/${img}`);
} }
const SliderSchema = mongoose.Schema({ const SliderSchema = mongoose.Schema({
+4 -1
View File
@@ -1,8 +1,11 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2'); const mongoosePaginate = require('mongoose-paginate-v2');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/users/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/users/${img}`);
} }
const AdminSchema = mongoose.Schema({ const AdminSchema = mongoose.Schema({
+4 -1
View File
@@ -1,7 +1,10 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const s3Storage = require('../plugins/s3Storage');
function image(img) { function image(img) {
if (img) return '/uploads/images/mainCover/' + img if (!img) return null;
if (img.startsWith('http://') || img.startsWith('https://')) return img;
return s3Storage.getPublicUrl(`uploads/images/mainCover/${img}`);
} }
const YearBannerSchema = mongoose.Schema({ const YearBannerSchema = mongoose.Schema({
+33
View File
@@ -0,0 +1,33 @@
const s3Storage = require("./s3Storage");
const BACKUP_PREFIX = "backup";
const UPLOADS_PREFIX = "uploads";
const appendS3UploadsToArchive = async (archive) => {
const keys = await s3Storage.listObjects(UPLOADS_PREFIX);
for (const key of keys) {
const buffer = await s3Storage.getObjectBuffer(key);
archive.append(buffer, { name: key });
}
};
const uploadBackupArchive = async (buffer, fileName) => {
await s3Storage.uploadBuffer(
`${BACKUP_PREFIX}/${fileName}`,
buffer,
"application/zip"
);
};
const deleteOldBackups = async () => {
await s3Storage.deleteObjectsByPrefix(BACKUP_PREFIX);
};
module.exports = {
BACKUP_PREFIX,
UPLOADS_PREFIX,
appendS3UploadsToArchive,
uploadBackupArchive,
deleteOldBackups,
};
+48
View File
@@ -0,0 +1,48 @@
const s3Storage = require("./s3Storage");
const PDF_PREFIX = "uploads/pdf";
const BOOK_SLIDE_PREFIX = "uploads/books";
const uploadPdf = async (fileData, fileName) => {
const key = `${PDF_PREFIX}/${fileName}`;
await s3Storage.uploadBuffer(key, fileData, "application/pdf");
return {
fileName,
url: s3Storage.getPublicUrl(key),
};
};
const uploadBookSlide = async (buffer, imageName) => {
const key = `${BOOK_SLIDE_PREFIX}/${imageName}.jpeg`;
await s3Storage.uploadBuffer(key, buffer, "image/jpeg");
return s3Storage.getPublicUrl(key);
};
const deletePdf = async (fileName) => {
if (!fileName) return;
try {
await s3Storage.deleteObject(`${PDF_PREFIX}/${fileName}`);
} catch (error) {
console.log("Failed to delete PDF from S3:", error?.message);
}
};
const deleteBookSlide = async (imageName) => {
if (!imageName) return;
try {
await s3Storage.deleteObject(`${BOOK_SLIDE_PREFIX}/${imageName}.jpeg`);
} catch (error) {
console.log("Failed to delete book slide from S3:", error?.message);
}
};
module.exports = {
PDF_PREFIX,
BOOK_SLIDE_PREFIX,
uploadPdf,
uploadBookSlide,
deletePdf,
deleteBookSlide,
};
+94
View File
@@ -0,0 +1,94 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const CATEGORY_IMAGE_PREFIX = "uploads/images/category";
const CATEGORY_SHAFAFIAT_PREFIX = "uploads/images/category/shafafiat";
const TERMS_FILE_PREFIX = "uploads/files/terms";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteCategoryImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${CATEGORY_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const deleteShafafiatIcon = async (fileName) => {
if (!fileName) return;
try {
await s3Storage.deleteObject(`${CATEGORY_SHAFAFIAT_PREFIX}/${fileName}`);
} catch (error) {
console.log("Failed to delete shafafiat icon from S3:", error?.message);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${CATEGORY_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
const uploadShafafiatIcon = async (fileData, fileName, contentType) => {
await s3Storage.uploadBuffer(
`${CATEGORY_SHAFAFIAT_PREFIX}/${fileName}`,
fileData,
contentType
);
return fileName;
};
const uploadTermsFile = async (fileData, fileName) => {
await s3Storage.uploadBuffer(
`${TERMS_FILE_PREFIX}/${fileName}`,
fileData,
"application/pdf"
);
return fileName;
};
const deleteTermsFile = async (fileName) => {
if (!fileName) return;
try {
await s3Storage.deleteObject(`${TERMS_FILE_PREFIX}/${fileName}`);
} catch (error) {
console.log("Failed to delete terms file from S3:", error?.message);
}
};
module.exports = {
CATEGORY_IMAGE_PREFIX,
CATEGORY_SHAFAFIAT_PREFIX,
TERMS_FILE_PREFIX,
getStoredImageName,
deleteCategoryImage,
deleteShafafiatIcon,
uploadProcessedImage,
uploadShafafiatIcon,
uploadTermsFile,
deleteTermsFile,
};
+52
View File
@@ -0,0 +1,52 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const CONTENT_IMAGE_PREFIX = "uploads/images/content";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteContentImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${CONTENT_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const deleteContentImages = async (doc) => {
await deleteContentImage(doc, "cover");
await deleteContentImage(doc, "thumb");
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${CONTENT_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
CONTENT_IMAGE_PREFIX,
getStoredImageName,
deleteContentImage,
deleteContentImages,
uploadProcessedImage,
};
+58
View File
@@ -0,0 +1,58 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const ELECTION_IMAGE_PREFIX = "uploads/images/election";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteElectionImage = async (fileName) => {
if (!fileName) return;
try {
await s3Storage.deleteObject(`${ELECTION_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete election image from S3:`, error?.message);
}
};
const deleteCandidateImage = async (candidate) => {
const fileName = getStoredImageName(candidate, "profilePic");
await deleteElectionImage(fileName);
};
const deleteElectionCandidateImages = async (election) => {
for (const candidate of election.candidates) {
await deleteCandidateImage(candidate);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${ELECTION_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
ELECTION_IMAGE_PREFIX,
getStoredImageName,
deleteElectionImage,
deleteCandidateImage,
deleteElectionCandidateImages,
uploadProcessedImage,
};
+46
View File
@@ -0,0 +1,46 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const LINKS_IMAGE_PREFIX = "uploads/images/links";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteLinksImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${LINKS_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${LINKS_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
LINKS_IMAGE_PREFIX,
getStoredImageName,
deleteLinksImage,
uploadProcessedImage,
};
+46
View File
@@ -0,0 +1,46 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const OCCASION_IMAGE_PREFIX = "uploads/images/occasion";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteOccasionImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${OCCASION_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${OCCASION_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
OCCASION_IMAGE_PREFIX,
getStoredImageName,
deleteOccasionImage,
uploadProcessedImage,
};
+47
View File
@@ -2,6 +2,8 @@ const {
S3Client, S3Client,
PutObjectCommand, PutObjectCommand,
DeleteObjectCommand, DeleteObjectCommand,
ListObjectsV2Command,
GetObjectCommand,
} = require("@aws-sdk/client-s3"); } = require("@aws-sdk/client-s3");
const config = { const config = {
@@ -85,9 +87,54 @@ const deleteObject = async (key) => {
); );
}; };
const listObjects = async (prefix = "") => {
const keys = [];
let continuationToken;
do {
const response = await getClient().send(
new ListObjectsV2Command({
Bucket: config.bucket,
Prefix: normalizeKey(prefix),
ContinuationToken: continuationToken,
})
);
for (const item of response.Contents || []) {
if (item.Key) keys.push(item.Key);
}
continuationToken = response.IsTruncated
? response.NextContinuationToken
: undefined;
} while (continuationToken);
return keys;
};
const getObjectBuffer = async (key) => {
const response = await getClient().send(
new GetObjectCommand({
Bucket: config.bucket,
Key: normalizeKey(key),
})
);
return Buffer.from(await response.Body.transformToByteArray());
};
const deleteObjectsByPrefix = async (prefix) => {
const keys = await listObjects(prefix);
await Promise.all(keys.map((key) => deleteObject(key)));
};
module.exports = { module.exports = {
isConfigured, isConfigured,
getPublicUrl, getPublicUrl,
uploadBuffer, uploadBuffer,
deleteObject, deleteObject,
listObjects,
getObjectBuffer,
deleteObjectsByPrefix,
}; };
+46
View File
@@ -0,0 +1,46 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const SLIDER_IMAGE_PREFIX = "uploads/images/slider";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteSliderImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${SLIDER_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${SLIDER_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
SLIDER_IMAGE_PREFIX,
getStoredImageName,
deleteSliderImage,
uploadProcessedImage,
};
+46
View File
@@ -0,0 +1,46 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const USER_IMAGE_PREFIX = "uploads/images/users";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteUserImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${USER_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${USER_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
USER_IMAGE_PREFIX,
getStoredImageName,
deleteUserImage,
uploadProcessedImage,
};
+46
View File
@@ -0,0 +1,46 @@
const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const YEAR_BANNER_IMAGE_PREFIX = "uploads/images/mainCover";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
const deleteYearBannerImage = async (doc, field) => {
const fileName = getStoredImageName(doc, field);
if (!fileName) return;
try {
await s3Storage.deleteObject(`${YEAR_BANNER_IMAGE_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete ${field} from S3:`, error?.message);
}
};
const uploadProcessedImage = async (
imageData,
imageName,
width,
height,
quality
) => {
const buffer = await sharp(imageData)
.resize(width, height, { fit: "cover" })
.jpeg({ quality })
.toBuffer();
await s3Storage.uploadBuffer(
`${YEAR_BANNER_IMAGE_PREFIX}/${imageName}`,
buffer,
"image/jpeg"
);
return imageName;
};
module.exports = {
YEAR_BANNER_IMAGE_PREFIX,
getStoredImageName,
deleteYearBannerImage,
uploadProcessedImage,
};