235 lines
6.5 KiB
JavaScript
235 lines
6.5 KiB
JavaScript
const File = require('./fileModel')
|
|
const AppError = require('../../globalErrorHandler/AppError')
|
|
const util = require('util')
|
|
const fs = require('fs')
|
|
const {
|
|
uploadObject,
|
|
deleteObject,
|
|
listOfObjects,
|
|
signedUrl,
|
|
copyObject,
|
|
removeObject,
|
|
} = require('../../utils/upload/bucket')
|
|
|
|
const deleteTempFile = util.promisify(fs.unlink)
|
|
|
|
const bucketSingleUpload = async (file, bucketName) => {
|
|
const fileData = {
|
|
originalName: file.originalname,
|
|
filename: file.filename,
|
|
path: file.path,
|
|
}
|
|
|
|
const result = await uploadObject(fileData, bucketName)
|
|
|
|
const data = {
|
|
fileURL: result.fileURL,
|
|
fileName: result.fileName,
|
|
fileEndpoint: result.fileEndpoint,
|
|
bucketName,
|
|
}
|
|
|
|
// Delete file from uploads folder
|
|
await deleteTempFile(file.path)
|
|
|
|
const fileRecord = await createFile(data)
|
|
|
|
return {
|
|
status: 'success',
|
|
fileRecord,
|
|
}
|
|
}
|
|
|
|
const bucketMultiUpload = async (files, bucketName) => {
|
|
const results = []
|
|
|
|
for (let file of files) {
|
|
const result = await bucketSingleUpload(file, bucketName)
|
|
results.push(result)
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
const bucketDeleteFile = async (fileName, bucketName) => {
|
|
let raw = typeof fileName === 'object' && fileName !== null
|
|
? (fileName.fileName || fileName.url || fileName.name || '')
|
|
: fileName
|
|
let exportedFileName = getLastUrlSegment(String(raw || ''))
|
|
if (exportedFileName) {
|
|
await deleteObject(exportedFileName, bucketName).catch((err) => {
|
|
console.error('Error deleting object from MinIO bucket:', err)
|
|
})
|
|
await deleteFile(exportedFileName).catch((err) => {
|
|
console.error('Error deleting file record from DB:', err)
|
|
})
|
|
}
|
|
|
|
return { fileName: exportedFileName }
|
|
}
|
|
|
|
const getLastUrlSegment = (url) => {
|
|
if (!url || typeof url !== 'string') {
|
|
return ''
|
|
}
|
|
if (!url.includes('/')) {
|
|
return url
|
|
}
|
|
const cleanUrl = url.endsWith('/') ? url.slice(0, -1) : url
|
|
const segments = cleanUrl.split('/')
|
|
return segments[segments.length - 1]
|
|
}
|
|
|
|
const getAllFiles = async () => {
|
|
return File.find({}, null, null)
|
|
}
|
|
|
|
const getFile = async (fileId) => {
|
|
const file = await File.findById(fileId, null, null)
|
|
|
|
if (!file) {
|
|
throw new AppError('NoFileFound', 404, {})
|
|
}
|
|
|
|
return file
|
|
}
|
|
|
|
const createFile = async (data) => {
|
|
return File.create(data, null)
|
|
}
|
|
|
|
const updateFile = async (fileId, data) => {
|
|
const file = await File.findOneAndUpdate({ _id: fileId }, data, null)
|
|
|
|
if (!file) {
|
|
throw AppError('NoFileFound', 404, {})
|
|
}
|
|
|
|
return file
|
|
}
|
|
|
|
const deleteFile = async (fileName) => {
|
|
await File.findOneAndDelete({ fileName }, null)
|
|
|
|
return null
|
|
}
|
|
|
|
const bucketGetFiles = async (bucketName) => {
|
|
return listOfObjects(bucketName)
|
|
}
|
|
|
|
const getSignedUrl = async (fileName, bucketName) => {
|
|
if (!fileName) {
|
|
return
|
|
}
|
|
return signedUrl(bucketName, fileName)
|
|
}
|
|
|
|
const getMultipleSignedUrls = async (fileNameArray, bucketName) => {
|
|
const urls = []
|
|
for (let fileName of fileNameArray) {
|
|
urls.push({ url: await getSignedUrl(fileName, bucketName), fileName: fileName})
|
|
}
|
|
return urls
|
|
}
|
|
|
|
const moveFromTempToMain = async (files, targetBucket) => {
|
|
const tempBucket = 'temp'
|
|
if (!files || !Array.isArray(files) || files.length === 0) {
|
|
return []
|
|
}
|
|
|
|
const { ensureBucketsExist, minioClient } = require('../../utils/upload/bucket')
|
|
await ensureBucketsExist([tempBucket, targetBucket]).catch(() => {})
|
|
|
|
const updatedUrls = []
|
|
|
|
for (const item of files) {
|
|
const rawStr = typeof item === 'object' && item !== null ? (item.url || item.fileName || item.name || '') : String(item || '')
|
|
const fileName = getLastUrlSegment(rawStr)
|
|
|
|
if (!fileName) {
|
|
continue
|
|
}
|
|
|
|
try {
|
|
// Check if object exists in temp bucket
|
|
const existsInTemp = await minioClient.statObject(tempBucket, fileName).then(() => true).catch(() => false)
|
|
if (existsInTemp) {
|
|
// Copy object from temp to targetBucket
|
|
await copyObject(targetBucket, fileName, `/${tempBucket}/${fileName}`)
|
|
// Remove from temp bucket
|
|
await removeObject(tempBucket, fileName)
|
|
// Update File record in database if exists
|
|
await File.findOneAndUpdate({ fileName }, { bucketName: targetBucket }, null).catch(() => {})
|
|
}
|
|
|
|
// Construct new URL for targetBucket
|
|
const protocol = process.env.AWS_USE_SSL === 'true' ? 'https://' : 'http://'
|
|
const endpoint = process.env.AWS_ENDPOINT || 'localhost'
|
|
const hostPort = (endpoint.includes(':') || !process.env.AWS_PORT) ? endpoint : `${endpoint}:${process.env.AWS_PORT}`
|
|
const fullHost = hostPort.startsWith('http://') || hostPort.startsWith('https://') ? hostPort : `${protocol}${hostPort}`
|
|
const newUrl = `${fullHost.replace(/\/$/, '')}/${targetBucket}/${fileName}`
|
|
|
|
updatedUrls.push(newUrl)
|
|
} catch (err) {
|
|
console.error(`Failed to move file "${fileName}" from ${tempBucket} to ${targetBucket}:`, err)
|
|
if (rawStr.includes(`/${tempBucket}/`)) {
|
|
updatedUrls.push(rawStr.replace(`/${tempBucket}/`, `/${targetBucket}/`))
|
|
} else {
|
|
updatedUrls.push(rawStr)
|
|
}
|
|
}
|
|
}
|
|
|
|
return updatedUrls
|
|
}
|
|
|
|
const getImage = async (bucketName, fileName) => {
|
|
if (!fileName) {
|
|
throw new AppError('NoFileFound', 404, {})
|
|
}
|
|
|
|
|
|
// Get signed URL from the file service
|
|
const signedUrl = await getSignedUrl(fileName, bucketName);
|
|
|
|
if (!signedUrl) {
|
|
return null;
|
|
}
|
|
|
|
// Fetch the image from the signed URL
|
|
const response = await fetch(signedUrl);
|
|
|
|
if (!response.ok) {
|
|
throw new AppError('NoFileFound', 404, {})
|
|
}
|
|
|
|
// Get the content type from the response headers
|
|
const contentType = response.headers.get('content-type');
|
|
|
|
// Convert the response to a buffer
|
|
const buffer = await response.arrayBuffer();
|
|
|
|
// Return both the buffer and content type
|
|
return {
|
|
buffer: Buffer.from(buffer),
|
|
contentType
|
|
};
|
|
};
|
|
module.exports = {
|
|
moveFromTempToMain,
|
|
getMultipleSignedUrls,
|
|
getSignedUrl,
|
|
createFile,
|
|
updateFile,
|
|
deleteFile,
|
|
getAllFiles,
|
|
getFile,
|
|
bucketSingleUpload,
|
|
bucketMultiUpload,
|
|
bucketDeleteFile,
|
|
bucketGetFiles,
|
|
getImage,
|
|
}
|