const sharp = require("sharp"); const s3Storage = require("./s3Storage"); const GALLERY_IMAGE_PREFIX = "uploads/images/gallery"; const GALLERY_GRAPHIC_PREFIX = "uploads/graphics/gallery"; const GALLERY_VIDEO_PREFIX = "uploads/videos/gallery"; const getPrefixForFileType = (fileType) => { switch (fileType) { case "graphic": return GALLERY_GRAPHIC_PREFIX; case "video": return GALLERY_VIDEO_PREFIX; default: return GALLERY_IMAGE_PREFIX; } }; const getGalleryObjectKey = (fileType, fileName) => `${getPrefixForFileType(fileType)}/${fileName}`; const getStoredFileName = (doc, field) => doc.get(field, null, { getters: false }); const getStoredArray = (doc, field) => { const value = doc.get(field, null, { getters: false }); return Array.isArray(value) ? value : []; }; const deleteGalleryFile = async (fileType, fileName) => { if (!fileName) return; const baseName = fileName.replace(/^thumb_/, ""); try { await s3Storage.deleteObject(getGalleryObjectKey(fileType, baseName)); } catch (error) { console.log(`Failed to delete ${baseName} from S3:`, error?.message); } if (fileType !== "video") { try { await s3Storage.deleteObject( getGalleryObjectKey(fileType, `thumb_${baseName}`) ); } catch (error) { console.log(`Failed to delete thumb_${baseName} from S3:`, error?.message); } } }; const uploadProcessedImage = async ( imageData, imageName, width, height, quality, prefix = GALLERY_IMAGE_PREFIX ) => { let pipeline = sharp(imageData); if (width && height) { pipeline = pipeline.resize(width, height, { fit: "cover" }); } const buffer = await pipeline.jpeg({ quality }).toBuffer(); await s3Storage.uploadBuffer( `${prefix}/${imageName}`, buffer, "image/jpeg" ); return imageName; }; const uploadGalleryVideo = async (fileData, fileName, contentType) => { await s3Storage.uploadBuffer( `${GALLERY_VIDEO_PREFIX}/${fileName}`, fileData, contentType ); return fileName; }; const uploadGalleryFile = async (fileType, file, galleryId, options = {}) => { const fileName = `gallery_${galleryId}_${Date.now()}.${ file.mimetype.split("/")[1] }`; const prefix = getPrefixForFileType(fileType); switch (fileType) { case "image": await uploadProcessedImage( file.data, fileName, options.mainWidth, options.mainHeight, options.mainQuality, prefix ); await uploadProcessedImage( file.data, `thumb_${fileName}`, options.thumbWidth, options.thumbHeight, options.thumbQuality, prefix ); break; case "graphic": await uploadProcessedImage( file.data, fileName, null, null, options.mainQuality, prefix ); await uploadProcessedImage( file.data, `thumb_${fileName}`, options.thumbWidth, options.thumbHeight, options.thumbQuality, prefix ); break; case "video": await uploadGalleryVideo(file.data, fileName, file.mimetype); break; } return fileName; }; const deleteAllGalleryFiles = async (gallery) => { const galleryType = getStoredFileName(gallery, "galleryType"); if (galleryType === "image") { const images = getStoredArray(gallery, "images"); for (const fileName of images) { await deleteGalleryFile("image", fileName); } return; } if (galleryType === "graphic") { await deleteGalleryFile("graphic", getStoredFileName(gallery, "graphic")); return; } if (galleryType === "video") { await deleteGalleryFile("video", getStoredFileName(gallery, "video")); } }; const deleteGalleryCover = async (gallery) => { const cover = getStoredFileName(gallery, "cover"); const thumbCover = getStoredFileName(gallery, "thumbCover"); if (cover) { try { await s3Storage.deleteObject(`${GALLERY_IMAGE_PREFIX}/${cover}`); } catch (error) { console.log(`Failed to delete cover from S3:`, error?.message); } } if (thumbCover) { try { await s3Storage.deleteObject(`${GALLERY_IMAGE_PREFIX}/${thumbCover}`); } catch (error) { console.log(`Failed to delete thumb cover from S3:`, error?.message); } } }; module.exports = { GALLERY_IMAGE_PREFIX, GALLERY_GRAPHIC_PREFIX, GALLERY_VIDEO_PREFIX, getStoredFileName, getStoredArray, deleteGalleryFile, uploadProcessedImage, uploadGalleryFile, deleteAllGalleryFiles, deleteGalleryCover, };