mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:11:13 -05:00
Fix submission deletion and image cleanup
This commit is contained in:
@@ -299,32 +299,77 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
||||
|
||||
setActionLoading(item.id);
|
||||
try {
|
||||
console.log('Starting deletion process for submission:', item.id);
|
||||
|
||||
// Step 1: Extract photo IDs from the submission content
|
||||
const photoIds: string[] = [];
|
||||
const validImageIds: string[] = [];
|
||||
const skippedPhotos: string[] = [];
|
||||
|
||||
if (item.content?.photos && Array.isArray(item.content.photos)) {
|
||||
for (const photo of item.content.photos) {
|
||||
if (photo.url) {
|
||||
// Extract UUID from blob URL: blob:https://domain/[uuid]
|
||||
const urlParts = photo.url.split('/');
|
||||
const imageId = urlParts[urlParts.length - 1];
|
||||
// Basic UUID validation (should be at least 32 characters)
|
||||
if (imageId && imageId.length >= 32) {
|
||||
photoIds.push(imageId);
|
||||
// Check if this looks like a Cloudflare image ID (not a blob URL)
|
||||
if (photo.url.startsWith('blob:')) {
|
||||
// This is a blob URL - we can't extract a valid Cloudflare image ID
|
||||
console.warn('Skipping blob URL (cannot extract Cloudflare image ID):', photo.url);
|
||||
skippedPhotos.push(photo.url);
|
||||
} else {
|
||||
// Try to extract image ID from various URL formats
|
||||
let imageId = '';
|
||||
|
||||
// If it's already just an ID
|
||||
if (photo.url.match(/^[a-f0-9-]{36}$/)) {
|
||||
imageId = photo.url;
|
||||
} else {
|
||||
// Extract from URL path
|
||||
const urlParts = photo.url.split('/');
|
||||
const lastPart = urlParts[urlParts.length - 1];
|
||||
if (lastPart && lastPart.match(/^[a-f0-9-]{36}$/)) {
|
||||
imageId = lastPart;
|
||||
}
|
||||
}
|
||||
|
||||
if (imageId) {
|
||||
photoIds.push(imageId);
|
||||
validImageIds.push(imageId);
|
||||
} else {
|
||||
console.warn('Could not extract valid image ID from URL:', photo.url);
|
||||
skippedPhotos.push(photo.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Delete photos from Cloudflare Images (if any)
|
||||
if (photoIds.length > 0) {
|
||||
const deletePromises = photoIds.map(async (imageId) => {
|
||||
console.log(`Found ${validImageIds.length} valid image IDs to delete, ${skippedPhotos.length} photos will be orphaned`);
|
||||
|
||||
// Step 2: Delete photos from Cloudflare Images (if any valid IDs)
|
||||
if (validImageIds.length > 0) {
|
||||
const deletePromises = validImageIds.map(async (imageId) => {
|
||||
try {
|
||||
await supabase.functions.invoke('upload-image', {
|
||||
console.log('Attempting to delete image from Cloudflare:', imageId);
|
||||
|
||||
// Direct fetch call to the edge function with proper DELETE method
|
||||
const response = await fetch('https://ydvtmnrszybqnbcqbdcy.supabase.co/functions/v1/upload-image', {
|
||||
method: 'DELETE',
|
||||
body: { imageId }
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlkdnRtbnJzenlicW5iY3FiZGN5Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTgzMjYzNTYsImV4cCI6MjA3MzkwMjM1Nn0.DM3oyapd_omP5ZzIlrT0H9qBsiQBxBRgw2tYuqgXKX4`
|
||||
},
|
||||
body: JSON.stringify({ imageId })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.text();
|
||||
throw new Error(`HTTP ${response.status}: ${errorData}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('Successfully deleted image:', imageId, result);
|
||||
|
||||
} catch (deleteError) {
|
||||
console.warn(`Failed to delete photo ${imageId} from Cloudflare:`, deleteError);
|
||||
console.error(`Failed to delete photo ${imageId} from Cloudflare:`, deleteError);
|
||||
// Continue with other deletions - don't fail the entire operation
|
||||
}
|
||||
});
|
||||
@@ -334,16 +379,34 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
||||
}
|
||||
|
||||
// Step 3: Delete the submission from the database
|
||||
console.log('Deleting submission from database:', item.id);
|
||||
const { error } = await supabase
|
||||
.from('content_submissions')
|
||||
.delete()
|
||||
.eq('id', item.id);
|
||||
|
||||
if (error) throw error;
|
||||
if (error) {
|
||||
console.error('Database deletion error:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('Submission successfully deleted from database');
|
||||
|
||||
const deletedCount = validImageIds.length;
|
||||
const orphanedCount = skippedPhotos.length;
|
||||
|
||||
let description = 'The submission has been permanently deleted';
|
||||
if (deletedCount > 0 && orphanedCount > 0) {
|
||||
description = `The submission and ${deletedCount} photo(s) have been deleted. ${orphanedCount} photo(s) could not be deleted from storage (orphaned blob URLs)`;
|
||||
} else if (deletedCount > 0) {
|
||||
description = `The submission and ${deletedCount} associated photo(s) have been permanently deleted`;
|
||||
} else if (orphanedCount > 0) {
|
||||
description = `The submission has been deleted. ${orphanedCount} photo(s) could not be deleted from storage (orphaned blob URLs)`;
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "Submission deleted",
|
||||
description: `The submission and ${photoIds.length > 0 ? `${photoIds.length} associated photo(s) have` : 'has'} been permanently deleted`,
|
||||
description,
|
||||
});
|
||||
|
||||
// Remove item from the current view
|
||||
|
||||
Reference in New Issue
Block a user