fix: admin empty thùng rác
This commit is contained in:
+213
-68
@@ -4319,100 +4319,245 @@ class AdminTrashController {
|
||||
throw new BadRequestException('Tham số không hợp lệ.');
|
||||
}
|
||||
|
||||
const deleteResults = { success: 0, failed: 0, errors: [] as string[] };
|
||||
|
||||
if (type === 'tour') {
|
||||
for (const tourId of ids) {
|
||||
console.log('[deletePermanent] Deleting tour:', tourId);
|
||||
const photos = await this.prisma.photo.findMany({ where: { tourId } });
|
||||
console.log('[deletePermanent] Found', photos.length, 'photos for tour');
|
||||
|
||||
for (const p of photos) {
|
||||
if (p.imageUrl) {
|
||||
const displayFilePath = path.join(process.cwd(), p.imageUrl.replace(/^\//, ''));
|
||||
try {
|
||||
console.log('[deletePermanent] Deleting tour:', tourId);
|
||||
|
||||
// First, delete all files from disk
|
||||
const photos = await this.prisma.photo.findMany({ where: { tourId } });
|
||||
console.log('[deletePermanent] Found', photos.length, 'photos for tour');
|
||||
|
||||
for (const p of photos) {
|
||||
if (p.imageUrl) {
|
||||
const displayFilePath = path.join(process.cwd(), p.imageUrl.replace(/^\//, ''));
|
||||
console.log('[deletePermanent] Checking display file:', displayFilePath);
|
||||
if (fs.existsSync(displayFilePath)) {
|
||||
try {
|
||||
fs.unlinkSync(displayFilePath);
|
||||
console.log('[deletePermanent] Deleted display file:', displayFilePath);
|
||||
} catch (e) {
|
||||
console.error('[deletePermanent] Error deleting display file:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p.originalUrl) {
|
||||
const originalFilePath = path.join(process.cwd(), p.originalUrl.replace(/^\//, ''));
|
||||
console.log('[deletePermanent] Checking original file:', originalFilePath);
|
||||
if (fs.existsSync(originalFilePath)) {
|
||||
try {
|
||||
fs.unlinkSync(originalFilePath);
|
||||
console.log('[deletePermanent] Deleted original file:', originalFilePath);
|
||||
} catch (e) {
|
||||
console.error('[deletePermanent] Error deleting original file:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the tour - cascade will handle related records
|
||||
await this.prisma.tour.delete({ where: { id: tourId } });
|
||||
console.log('[deletePermanent] Deleted tour from database:', tourId);
|
||||
deleteResults.success++;
|
||||
} catch (e: any) {
|
||||
console.error('[deletePermanent] Error deleting tour:', tourId, e);
|
||||
deleteResults.failed++;
|
||||
deleteResults.errors.push(`Tour ${tourId}: ${e?.message || 'Unknown error'}`);
|
||||
}
|
||||
}
|
||||
} else if (type === 'photo') {
|
||||
console.log('[deletePermanent] Deleting', ids.length, 'photos');
|
||||
console.log('[deletePermanent] Photo IDs:', JSON.stringify(ids));
|
||||
|
||||
if (!ids || ids.length === 0) {
|
||||
console.warn('[deletePermanent] No photo IDs provided');
|
||||
return { success: true, deleted: 0, failed: 0 };
|
||||
}
|
||||
|
||||
for (const photoId of ids) {
|
||||
try {
|
||||
console.log('[deletePermanent] ========== START Processing photo:', photoId);
|
||||
const photo = await this.prisma.photo.findUnique({ where: { id: photoId } });
|
||||
|
||||
if (!photo) {
|
||||
console.warn('[deletePermanent] Photo not found in DB:', photoId);
|
||||
deleteResults.failed++;
|
||||
deleteResults.errors.push(`Photo ${photoId}: not found in database`);
|
||||
console.log('[deletePermanent] ========== SKIP (not found):', photoId);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log('[deletePermanent] Found photo:', { id: photo.id, imageUrl: photo.imageUrl, isDeleted: photo.isDeleted, tourId: photo.tourId });
|
||||
|
||||
// First, delete all comments for this photo (because of foreign key)
|
||||
console.log('[deletePermanent] Deleting comments for photo:', photoId);
|
||||
try {
|
||||
const commentResult = await this.prisma.comment.deleteMany({
|
||||
where: { photoId }
|
||||
});
|
||||
console.log('[deletePermanent] Deleted', commentResult.count, 'comments for photo');
|
||||
} catch (e: any) {
|
||||
console.warn('[deletePermanent] Error deleting comments (continuing):', e?.message);
|
||||
}
|
||||
|
||||
// Delete files from disk
|
||||
if (photo.imageUrl) {
|
||||
const displayFilePath = path.join(process.cwd(), photo.imageUrl.replace(/^\//, ''));
|
||||
console.log('[deletePermanent] Checking display file:', displayFilePath);
|
||||
if (fs.existsSync(displayFilePath)) {
|
||||
try {
|
||||
fs.unlinkSync(displayFilePath);
|
||||
console.log('[deletePermanent] Deleted display file:', displayFilePath);
|
||||
console.log('[deletePermanent] ✓ Deleted display file');
|
||||
} catch (e) {
|
||||
console.error('[deletePermanent] Error deleting display file:', e);
|
||||
}
|
||||
} else {
|
||||
console.log('[deletePermanent] Display file not found (OK):', displayFilePath);
|
||||
}
|
||||
}
|
||||
if (p.originalUrl) {
|
||||
const originalFilePath = path.join(process.cwd(), p.originalUrl.replace(/^\//, ''));
|
||||
|
||||
if (photo.originalUrl) {
|
||||
const originalFilePath = path.join(process.cwd(), photo.originalUrl.replace(/^\//, ''));
|
||||
console.log('[deletePermanent] Checking original file:', originalFilePath);
|
||||
if (fs.existsSync(originalFilePath)) {
|
||||
try {
|
||||
fs.unlinkSync(originalFilePath);
|
||||
console.log('[deletePermanent] Deleted original file:', originalFilePath);
|
||||
console.log('[deletePermanent] ✓ Deleted original file');
|
||||
} catch (e) {
|
||||
console.error('[deletePermanent] Error deleting original file:', e);
|
||||
}
|
||||
} else {
|
||||
console.log('[deletePermanent] Original file not found (OK):', originalFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete from database
|
||||
console.log('[deletePermanent] Attempting database delete for photo:', photoId);
|
||||
const result = await this.prisma.photo.delete({ where: { id: photoId } });
|
||||
console.log('[deletePermanent] ✓ Successfully deleted photo from database:', photoId);
|
||||
deleteResults.success++;
|
||||
console.log('[deletePermanent] ========== SUCCESS:', photoId);
|
||||
} catch (e: any) {
|
||||
console.error('[deletePermanent] ✗ Error deleting photo:', photoId);
|
||||
console.error('[deletePermanent] Error details:', e?.message || String(e));
|
||||
deleteResults.failed++;
|
||||
deleteResults.errors.push(`Photo ${photoId}: ${e?.message || 'Unknown error'}`);
|
||||
console.log('[deletePermanent] ========== FAILED:', photoId);
|
||||
}
|
||||
await this.prisma.tour.delete({ where: { id: tourId } });
|
||||
console.log('[deletePermanent] Deleted tour from database:', tourId);
|
||||
}
|
||||
} else if (type === 'photo') {
|
||||
console.log('[deletePermanent] Deleting', ids.length, 'photos');
|
||||
for (const photoId of ids) {
|
||||
console.log('[deletePermanent] Processing photo:', photoId);
|
||||
const photo = await this.prisma.photo.findUnique({ where: { id: photoId } });
|
||||
if (!photo) {
|
||||
console.warn('[deletePermanent] Photo not found:', photoId);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log('[deletePermanent] Photo found, imageUrl:', photo.imageUrl);
|
||||
|
||||
if (photo.imageUrl) {
|
||||
const displayFilePath = path.join(process.cwd(), photo.imageUrl.replace(/^\//, ''));
|
||||
console.log('[deletePermanent] Checking display file:', displayFilePath);
|
||||
if (fs.existsSync(displayFilePath)) {
|
||||
try {
|
||||
fs.unlinkSync(displayFilePath);
|
||||
console.log('[deletePermanent] Deleted display file');
|
||||
} catch (e) {
|
||||
console.error('[deletePermanent] Error deleting display file:', e);
|
||||
}
|
||||
} else {
|
||||
console.log('[deletePermanent] Display file not found (OK)');
|
||||
}
|
||||
}
|
||||
|
||||
if (photo.originalUrl) {
|
||||
const originalFilePath = path.join(process.cwd(), photo.originalUrl.replace(/^\//, ''));
|
||||
console.log('[deletePermanent] Checking original file:', originalFilePath);
|
||||
if (fs.existsSync(originalFilePath)) {
|
||||
try {
|
||||
fs.unlinkSync(originalFilePath);
|
||||
console.log('[deletePermanent] Deleted original file');
|
||||
} catch (e) {
|
||||
console.error('[deletePermanent] Error deleting original file:', e);
|
||||
}
|
||||
} else {
|
||||
console.log('[deletePermanent] Original file not found (OK)');
|
||||
}
|
||||
}
|
||||
|
||||
const result = await this.prisma.photo.delete({ where: { id: photoId } });
|
||||
console.log('[deletePermanent] Deleted photo from database:', photoId);
|
||||
}
|
||||
|
||||
console.log('[deletePermanent] Photos deletion complete - success:', deleteResults.success, 'failed:', deleteResults.failed);
|
||||
} else if (type === 'note') {
|
||||
console.log('[deletePermanent] Deleting', ids.length, 'notes');
|
||||
const result = await this.prisma.tourNote.deleteMany({
|
||||
where: { id: { in: ids } }
|
||||
});
|
||||
console.log('[deletePermanent] Deleted notes from database, count:', result.count);
|
||||
try {
|
||||
const result = await this.prisma.tourNote.deleteMany({
|
||||
where: { id: { in: ids } }
|
||||
});
|
||||
console.log('[deletePermanent] Deleted notes from database, count:', result.count);
|
||||
deleteResults.success = result.count;
|
||||
} catch (e: any) {
|
||||
console.error('[deletePermanent] Error deleting notes:', e);
|
||||
deleteResults.failed = ids.length;
|
||||
deleteResults.errors.push(`Notes deletion: ${e?.message || 'Unknown error'}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[deletePermanent] Deletion complete, type:', type);
|
||||
return { success: true };
|
||||
console.log('[deletePermanent] Deletion complete - success:', deleteResults.success, 'failed:', deleteResults.failed);
|
||||
|
||||
if (deleteResults.failed > 0) {
|
||||
console.warn('[deletePermanent] Errors:', deleteResults.errors);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
deleted: deleteResults.success,
|
||||
failed: deleteResults.failed,
|
||||
errors: deleteResults.errors.length > 0 ? deleteResults.errors : undefined
|
||||
};
|
||||
}
|
||||
|
||||
@Post('empty-all')
|
||||
async emptyAllTrash() {
|
||||
console.log('[emptyAllTrash] Starting to empty all trash');
|
||||
const deleteResults = { success: 0, failed: 0, errors: [] as string[] };
|
||||
|
||||
try {
|
||||
// Get all deleted photos
|
||||
console.log('[emptyAllTrash] Finding all deleted photos');
|
||||
const deletedPhotos = await this.prisma.photo.findMany({
|
||||
where: { isDeleted: true }
|
||||
});
|
||||
console.log('[emptyAllTrash] Found', deletedPhotos.length, 'deleted photos');
|
||||
|
||||
// Delete all comments from deleted photos
|
||||
console.log('[emptyAllTrash] Deleting all comments from deleted photos');
|
||||
const commentCount = await this.prisma.comment.deleteMany({
|
||||
where: {
|
||||
photoId: { in: deletedPhotos.map(p => p.id) }
|
||||
}
|
||||
});
|
||||
console.log('[emptyAllTrash] Deleted', commentCount.count, 'comments');
|
||||
|
||||
// Delete files from disk
|
||||
for (const photo of deletedPhotos) {
|
||||
if (photo.imageUrl) {
|
||||
const filePath = path.join(process.cwd(), photo.imageUrl.replace(/^\//, ''));
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
fs.unlinkSync(filePath);
|
||||
console.log('[emptyAllTrash] Deleted display file:', filePath);
|
||||
} catch (e) {
|
||||
console.error('[emptyAllTrash] Error deleting display file:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (photo.originalUrl) {
|
||||
const filePath = path.join(process.cwd(), photo.originalUrl.replace(/^\//, ''));
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
fs.unlinkSync(filePath);
|
||||
console.log('[emptyAllTrash] Deleted original file:', filePath);
|
||||
} catch (e) {
|
||||
console.error('[emptyAllTrash] Error deleting original file:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all photos
|
||||
console.log('[emptyAllTrash] Deleting all', deletedPhotos.length, 'photos from database');
|
||||
const photoResult = await this.prisma.photo.deleteMany({
|
||||
where: { isDeleted: true }
|
||||
});
|
||||
console.log('[emptyAllTrash] Deleted', photoResult.count, 'photos');
|
||||
deleteResults.success += photoResult.count;
|
||||
|
||||
// Delete all deleted tours (cascade will handle related)
|
||||
console.log('[emptyAllTrash] Deleting all deleted tours');
|
||||
const tourResult = await this.prisma.tour.deleteMany({
|
||||
where: { isDeleted: true }
|
||||
});
|
||||
console.log('[emptyAllTrash] Deleted', tourResult.count, 'tours');
|
||||
deleteResults.success += tourResult.count;
|
||||
|
||||
// Delete all deleted notes
|
||||
console.log('[emptyAllTrash] Deleting all deleted notes');
|
||||
const noteResult = await this.prisma.tourNote.deleteMany({
|
||||
where: { isDeleted: true }
|
||||
});
|
||||
console.log('[emptyAllTrash] Deleted', noteResult.count, 'notes');
|
||||
deleteResults.success += noteResult.count;
|
||||
|
||||
console.log('[emptyAllTrash] Successfully emptied all trash - total deleted:', deleteResults.success);
|
||||
} catch (e: any) {
|
||||
console.error('[emptyAllTrash] Error emptying trash:', e?.message || e);
|
||||
deleteResults.failed++;
|
||||
deleteResults.errors.push(`Emptying trash: ${e?.message || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalDeleted: deleteResults.success,
|
||||
errors: deleteResults.errors.length > 0 ? deleteResults.errors : undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user