diff --git a/src/components/moderation/ModerationQueue.tsx b/src/components/moderation/ModerationQueue.tsx index b5a14579..58ca12c0 100644 --- a/src/components/moderation/ModerationQueue.tsx +++ b/src/components/moderation/ModerationQueue.tsx @@ -299,32 +299,77 @@ export const ModerationQueue = forwardRef((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((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