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
+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,
PutObjectCommand,
DeleteObjectCommand,
ListObjectsV2Command,
GetObjectCommand,
} = require("@aws-sdk/client-s3");
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 = {
isConfigured,
getPublicUrl,
uploadBuffer,
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,
};