Fix submission deletion and image cleanup

This commit is contained in:
gpt-engineer-app[bot]
2025-09-29 00:51:50 +00:00
parent f9778dd9d9
commit f3c4d97992

View File

@@ -299,32 +299,77 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
setActionLoading(item.id); setActionLoading(item.id);
try { try {
console.log('Starting deletion process for submission:', item.id);
// Step 1: Extract photo IDs from the submission content // Step 1: Extract photo IDs from the submission content
const photoIds: string[] = []; const photoIds: string[] = [];
const validImageIds: string[] = [];
const skippedPhotos: string[] = [];
if (item.content?.photos && Array.isArray(item.content.photos)) { if (item.content?.photos && Array.isArray(item.content.photos)) {
for (const photo of item.content.photos) { for (const photo of item.content.photos) {
if (photo.url) { if (photo.url) {
// Extract UUID from blob URL: blob:https://domain/[uuid] // Check if this looks like a Cloudflare image ID (not a blob URL)
const urlParts = photo.url.split('/'); if (photo.url.startsWith('blob:')) {
const imageId = urlParts[urlParts.length - 1]; // This is a blob URL - we can't extract a valid Cloudflare image ID
// Basic UUID validation (should be at least 32 characters) console.warn('Skipping blob URL (cannot extract Cloudflare image ID):', photo.url);
if (imageId && imageId.length >= 32) { skippedPhotos.push(photo.url);
photoIds.push(imageId); } 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) console.log(`Found ${validImageIds.length} valid image IDs to delete, ${skippedPhotos.length} photos will be orphaned`);
if (photoIds.length > 0) {
const deletePromises = photoIds.map(async (imageId) => { // Step 2: Delete photos from Cloudflare Images (if any valid IDs)
if (validImageIds.length > 0) {
const deletePromises = validImageIds.map(async (imageId) => {
try { 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', 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) { } 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 // 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 // Step 3: Delete the submission from the database
console.log('Deleting submission from database:', item.id);
const { error } = await supabase const { error } = await supabase
.from('content_submissions') .from('content_submissions')
.delete() .delete()
.eq('id', item.id); .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({ toast({
title: "Submission deleted", 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 // Remove item from the current view