S3 : news controller

This commit is contained in:
2026-06-19 12:26:40 +03:30
parent 99a9f9ace5
commit 85c8107799
3 changed files with 114 additions and 152 deletions
+81 -149
View File
@@ -9,14 +9,15 @@ const {
const Category = require("../models/Category");
const Comment = require("../models/Comment");
const User = require("../models/User");
const fs = require("fs");
const NewsFile = require("../models/NewsFile");
const Polls = require("../models/Polls");
const moment = require("moment-jalaali");
const {
getStoredImageName,
deleteNewsImage,
deleteNewsAttachment,
uploadProcessedImage,
uploadNewsAttachment,
} = require("../plugins/newsImageStorage");
////// variables
@@ -463,112 +464,16 @@ module.exports.addNews = [
* if we have pic upload to server
*/
if (req.files) {
let hasCover = false;
let hasThumb = false;
const timestamp = Date.now();
if (req.files.cover) {
const image = req.files.cover;
if (!validateNewsImage(image)) {
return res.status(422).json({
validation: {
cover: {
msg: _sr["fa"].format.image,
},
},
});
}
const imageName = `news_cover_${timestamp}_${createNews._id}.${
image.mimetype.split("/")[1]
}`;
try {
await processAndUploadNewsImage(
image.data,
imageName,
coverNewsWidth,
coverNewsHeight,
coverQuality
);
createNews.cover = imageName;
hasCover = true;
} catch (e) {
return res500(res, e?.message);
}
if (!req.files.thumbCover) {
const thumbImageName = `news_thumb_${timestamp}_${createNews._id}.${
image.mimetype.split("/")[1]
}`;
try {
await processAndUploadNewsImage(
image.data,
thumbImageName,
thumbCoverNewsWidth,
thumbCoverNewsHeight,
thumbCoverQuality
);
createNews.thumbCover = thumbImageName;
hasThumb = true;
} catch (e) {
return res500(res, e?.message);
}
}
try {
await handleFileUploads(req, res, createNews);
await createNews.save();
} catch (error) {
return res.status(422).json({
validation: {
cover: { msg: error.message },
},
});
}
if (req.files.thumbCover) {
const image = req.files.thumbCover;
if (!validateNewsImage(image)) {
return res.status(422).json({
validation: {
thumbCover: {
msg: _sr["fa"].format.image,
},
},
});
}
const thumbImageName = `news_thumb_${timestamp}_${createNews._id}.${
image.mimetype.split("/")[1]
}`;
try {
await processAndUploadNewsImage(
image.data,
thumbImageName,
thumbCoverNewsWidth,
thumbCoverNewsHeight,
thumbCoverQuality
);
createNews.thumbCover = thumbImageName;
hasThumb = true;
} catch (e) {
return res500(res, e?.message);
}
if (!req.files.cover) {
const coverImageName = `news_cover_${timestamp}_${createNews._id}.${
image.mimetype.split("/")[1]
}`;
try {
await processAndUploadNewsImage(
image.data,
coverImageName,
coverNewsWidth,
coverNewsHeight,
coverQuality
);
createNews.cover = coverImageName;
hasCover = true;
} catch (e) {
return res500(res, e?.message);
}
}
}
createNews.newsStatus = hasCover || hasThumb;
await createNews.save();
}
/**
@@ -956,6 +861,11 @@ module.exports.deletOneNews = [
await deleteNewsImage(targetNews, "cover");
await deleteNewsImage(targetNews, "thumbCover");
for (const attachment of targetNews.attachments) {
const fileName = attachment.get("file", null, { getters: false });
await deleteNewsAttachment(fileName);
}
await targetNews.deleteOne();
await Comment.deleteMany({ modelRef: targetNews._id });
@@ -970,13 +880,22 @@ module.exports.deletOneNews = [
module.exports.deleteAllNews = [
async (req, res) => {
try {
const importedNews = await News.find({ imported: true });
for (const news of importedNews) {
await deleteNewsImage(news, "cover");
await deleteNewsImage(news, "thumbCover");
for (const attachment of news.attachments) {
const fileName = attachment.get("file", null, { getters: false });
await deleteNewsAttachment(fileName);
}
}
await News.deleteMany({ imported: true });
return res.json("ok");
} catch (error) {
/**
* if we got unkown error show to client
*/
return res500(res, error.message);
}
},
@@ -1271,52 +1190,65 @@ module.exports.searchForSlider = [
module.exports.addAttachmentToNews = [
[body("attTitle").notEmpty().withMessage(_sr["fa"].required.title)],
checkValidations(validationResult),
(req, res) => {
if (!req.files?.file)
return res
.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 قابل قبول است" } } });
async (req, res) => {
try {
if (!req.files?.file) {
return res
.status(422)
.json({ validation: { file: { msg: _sr["fa"].required.file } } });
}
const data = { title: req.body.attTitle };
const file = req.files.file;
const fileName =
req.body.attTitle.replace(titleFilterRegex, "-") +
"_" +
Date.now() +
".pdf";
file.mv(`./static/uploads/files/newsAttachments/${fileName}`);
data.file = fileName;
if (req.files.file.mimetype.split("/")[1] !== "pdf") {
return res
.status(422)
.json({ validation: { file: { msg: "فقط فرمت PDF قابل قبول است" } } });
}
News.findById(req.params.newsId, (err, news) => {
if (err || !news) return res404(res, err);
news.attachments.push(data);
news.save((err) => {
if (err) return res500(res, err);
else return res.json({ message: _sr["fa"].response.success_save });
});
});
const news = await News.findById(req.params.newsId);
if (!news) {
return res404(res, "خبر مورد نظر پیدا نشد");
}
const fileName =
req.body.attTitle.replace(titleFilterRegex, "-") +
"_" +
Date.now() +
".pdf";
await uploadNewsAttachment(req.files.file.data, fileName);
news.attachments.push({ title: req.body.attTitle, file: fileName });
await news.save();
return res.json({ message: _sr["fa"].response.success_save });
} catch (error) {
return res500(res, error.message);
}
},
];
module.exports.removeAttachmentFromNews = [
(req, res) => {
News.findOne({ "attachments._id": req.params.fileId }, (err, news) => {
if (err || !news) return res404(res, err);
const file = news.attachments.id(req.params.fileId);
if (!file) return res404(res, "not found");
file.remove();
fs.unlink(`./static/${file.file}`, (err) => {
if (err) console.log(err);
});
news.save((err) => {
if (err) return res500(res, err);
else return res.json({ message: _sr["fa"].response.success_remove });
});
});
async (req, res) => {
try {
const news = await News.findOne({ "attachments._id": req.params.fileId });
if (!news) {
return res404(res, "not found");
}
const attachment = news.attachments.id(req.params.fileId);
if (!attachment) {
return res404(res, "not found");
}
const fileName = attachment.get("file", null, { getters: false });
attachment.remove();
await deleteNewsAttachment(fileName);
await news.save();
return res.json({ message: _sr["fa"].response.success_remove });
} catch (error) {
return res500(res, error.message);
}
},
];
+5 -3
View File
@@ -8,12 +8,14 @@ function image(img) {
return s3Storage.getPublicUrl(`uploads/images/news/${img}`);
}
function file(file) {
return '/uploads/files/newsAttachments/' + file
function attachmentFile(file) {
if (!file) return null;
if (file.startsWith('http://') || file.startsWith('https://')) return file;
return s3Storage.getPublicUrl(`uploads/files/newsAttachments/${file}`);
}
const NewsAttachmentSchema = mongoose.Schema({
file: {type: String, get: file},
file: {type: String, get: attachmentFile},
title: String
})
+28
View File
@@ -2,6 +2,7 @@ const sharp = require("sharp");
const s3Storage = require("./s3Storage");
const NEWS_IMAGE_PREFIX = "uploads/images/news";
const NEWS_ATTACHMENT_PREFIX = "uploads/files/newsAttachments";
const getStoredImageName = (doc, field) =>
doc.get(field, null, { getters: false });
@@ -38,9 +39,36 @@ const uploadProcessedImage = async (
return imageName;
};
const uploadNewsAttachment = async (
fileData,
fileName,
contentType = "application/pdf"
) => {
await s3Storage.uploadBuffer(
`${NEWS_ATTACHMENT_PREFIX}/${fileName}`,
fileData,
contentType
);
return fileName;
};
const deleteNewsAttachment = async (fileName) => {
if (!fileName) return;
try {
await s3Storage.deleteObject(`${NEWS_ATTACHMENT_PREFIX}/${fileName}`);
} catch (error) {
console.log(`Failed to delete attachment from S3:`, error?.message);
}
};
module.exports = {
NEWS_IMAGE_PREFIX,
NEWS_ATTACHMENT_PREFIX,
getStoredImageName,
deleteNewsImage,
uploadProcessedImage,
uploadNewsAttachment,
deleteNewsAttachment,
};