import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', }; serve(async (req) => { if (req.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }); } try { // Use service role for admin operations const supabaseAdmin = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' ); console.log('Processing scheduled account deletions...'); // Find pending deletion requests that are past their scheduled date const { data: pendingDeletions, error: fetchError } = await supabaseAdmin .from('account_deletion_requests') .select('*') .eq('status', 'pending') .lt('scheduled_deletion_at', new Date().toISOString()); if (fetchError) { throw fetchError; } if (!pendingDeletions || pendingDeletions.length === 0) { console.log('No deletions to process'); return new Response( JSON.stringify({ success: true, message: 'No deletions to process', processed: 0, }), { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, } ); } console.log(`Found ${pendingDeletions.length} deletion(s) to process`); let successCount = 0; let errorCount = 0; for (const deletion of pendingDeletions) { try { console.log(`Processing deletion for user: ${deletion.user_id}`); // Get user email for confirmation email const { data: userData } = await supabaseAdmin.auth.admin.getUserById(deletion.user_id); const userEmail = userData?.user?.email; // Delete reviews (CASCADE will handle review_photos) await supabaseAdmin .from('reviews') .delete() .eq('user_id', deletion.user_id); // Anonymize submissions and photos await supabaseAdmin .rpc('anonymize_user_submissions', { target_user_id: deletion.user_id }); // Delete user roles await supabaseAdmin .from('user_roles') .delete() .eq('user_id', deletion.user_id); // Delete profile await supabaseAdmin .from('profiles') .delete() .eq('user_id', deletion.user_id); // Update deletion request status await supabaseAdmin .from('account_deletion_requests') .update({ status: 'completed', completed_at: new Date().toISOString(), }) .eq('id', deletion.id); // Delete auth user await supabaseAdmin.auth.admin.deleteUser(deletion.user_id); // Send final confirmation email if we have the email if (userEmail) { const forwardEmailKey = Deno.env.get('FORWARDEMAIL_API_KEY'); const fromEmail = Deno.env.get('FROM_EMAIL_ADDRESS') || 'noreply@thrillwiki.com'; if (forwardEmailKey) { try { await fetch('https://api.forwardemail.net/v1/emails', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Basic ${btoa(forwardEmailKey + ':')}`, }, body: JSON.stringify({ from: fromEmail, to: userEmail, subject: 'Account Deletion Completed', html: `

Account Deletion Completed

Your account has been automatically deleted as scheduled on ${new Date().toLocaleDateString()}.

Your profile and reviews have been removed, but your contributions to the database remain preserved.

Thank you for being part of our community.

`, }), }); } catch (emailError) { console.error('Failed to send confirmation email:', emailError); } } } successCount++; console.log(`Successfully deleted account for user: ${deletion.user_id}`); } catch (error) { errorCount++; console.error(`Failed to delete account for user ${deletion.user_id}:`, error); } } console.log(`Processed ${successCount} deletion(s) successfully, ${errorCount} error(s)`); return new Response( JSON.stringify({ success: true, message: `Processed ${successCount} deletion(s)`, processed: successCount, errors: errorCount, }), { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, } ); } catch (error) { console.error('Error processing scheduled deletions:', error); return new Response( JSON.stringify({ error: error.message }), { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, } ); } });