feat: Implement file cleanup middleware for automatic old file deletion using local and Cloudinary storage providers.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { LocalStorageProvider } from '../file/storage-providers/local-storage.provider';
|
||||
import { CloudinaryStorageProvider } from '../file/storage-providers/cloudinary-storage.provider';
|
||||
|
||||
const getStorageProvider = () => {
|
||||
if (process.env.FILE_DRIVER === 'cloudinary') {
|
||||
return new CloudinaryStorageProvider();
|
||||
}
|
||||
return new LocalStorageProvider();
|
||||
};
|
||||
|
||||
export const applyFileCleanup = (prisma: PrismaClient) => {
|
||||
const models = [
|
||||
{ name: 'user', field: 'image' },
|
||||
{ name: 'restaurant', field: 'logo' },
|
||||
];
|
||||
|
||||
models.forEach(({ name, field }) => {
|
||||
// @ts-ignore
|
||||
const delegate = prisma[name];
|
||||
if (delegate && delegate.update) {
|
||||
const originalUpdate = delegate.update.bind(delegate);
|
||||
|
||||
// @ts-ignore
|
||||
delegate.update = async (args: any) => {
|
||||
// 1. Get old record
|
||||
// We need to be careful not to trigger infinite loops if findUnique uses update? No.
|
||||
let oldRecord = null;
|
||||
try {
|
||||
oldRecord = await delegate.findUnique({
|
||||
where: args.where,
|
||||
select: { [field]: true },
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`[FileCleanup] Failed to fetch old record for ${name}`, e);
|
||||
}
|
||||
|
||||
// 2. Perform update
|
||||
const result = await originalUpdate(args);
|
||||
|
||||
// 3. Check for change and cleanup
|
||||
try {
|
||||
const newPath = args.data[field];
|
||||
// Check if field is in data (it might be undefined if not updating that field)
|
||||
if (args.data && field in args.data) {
|
||||
const oldPath = oldRecord?.[field];
|
||||
|
||||
if (oldPath && oldPath !== newPath) {
|
||||
console.log(`[FileCleanup] Cleaning up old file: ${oldPath}`);
|
||||
const storageProvider = getStorageProvider();
|
||||
console.log(`[FileCleanup] Using provider: ${storageProvider.constructor.name}`);
|
||||
|
||||
// Delete from storage
|
||||
console.log(`[FileCleanup] Calling delete on provider...`);
|
||||
await storageProvider.delete(oldPath).catch(err =>
|
||||
console.error(`[FileCleanup] Storage delete failed: ${err.message}`)
|
||||
);
|
||||
console.log(`[FileCleanup] Delete called.`);
|
||||
|
||||
// Delete from File table
|
||||
// Use the prisma instance to delete from File table
|
||||
await prisma.file.deleteMany({
|
||||
where: { storagePath: oldPath }
|
||||
}).catch(err =>
|
||||
console.error(`[FileCleanup] DB File record delete failed: ${err.message}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[FileCleanup] Error during cleanup for ${name}`, e);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user