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 { const { confirmation_code } = await req.json(); if (!confirmation_code) { throw new Error('Confirmation code is required'); } const supabaseClient = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_ANON_KEY') ?? '', { global: { headers: { Authorization: req.headers.get('Authorization')! }, }, } ); // Get authenticated user const { data: { user }, error: userError, } = await supabaseClient.auth.getUser(); if (userError || !user) { throw new Error('Unauthorized'); } console.log(`Confirming deletion for user: ${user.id}`); // Find deletion request const { data: deletionRequest, error: requestError } = await supabaseClient .from('account_deletion_requests') .select('*') .eq('user_id', user.id) .eq('status', 'pending') .maybeSingle(); if (requestError || !deletionRequest) { throw new Error('No pending deletion request found'); } // Verify confirmation code if (deletionRequest.confirmation_code !== confirmation_code) { throw new Error('Invalid confirmation code'); } // Check if 14 days have passed const scheduledDate = new Date(deletionRequest.scheduled_deletion_at); const now = new Date(); if (now < scheduledDate) { const daysRemaining = Math.ceil((scheduledDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); throw new Error(`You must wait ${daysRemaining} more day(s) before confirming deletion`); } // Use service role client for admin operations const supabaseAdmin = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' ); console.log('Starting deletion process...'); // Delete reviews (CASCADE will handle review_photos) const { error: reviewsError } = await supabaseAdmin .from('reviews') .delete() .eq('user_id', user.id); if (reviewsError) { console.error('Error deleting reviews:', reviewsError); } // Anonymize submissions and photos const { error: anonymizeError } = await supabaseAdmin .rpc('anonymize_user_submissions', { target_user_id: user.id }); if (anonymizeError) { console.error('Error anonymizing submissions:', anonymizeError); } // Delete user roles const { error: rolesError } = await supabaseAdmin .from('user_roles') .delete() .eq('user_id', user.id); if (rolesError) { console.error('Error deleting user roles:', rolesError); } // Delete profile const { error: profileError } = await supabaseAdmin .from('profiles') .delete() .eq('user_id', user.id); if (profileError) { console.error('Error deleting profile:', profileError); throw profileError; } // Update deletion request status const { error: updateError } = await supabaseAdmin .from('account_deletion_requests') .update({ status: 'completed', completed_at: new Date().toISOString(), }) .eq('id', deletionRequest.id); if (updateError) { console.error('Error updating deletion request:', updateError); } // Delete auth user (this should cascade delete the deletion request) const { error: authError } = await supabaseAdmin.auth.admin.deleteUser(user.id); if (authError) { console.error('Error deleting auth user:', authError); throw authError; } // Send confirmation email 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: user.email, subject: 'Account Deletion Confirmed', html: `
Your account has been permanently deleted 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.
`, }), }); console.log('Deletion confirmation email sent'); } catch (emailError) { console.error('Failed to send email:', emailError); } } console.log('Account deletion completed successfully'); return new Response( JSON.stringify({ success: true, message: 'Account deleted successfully', }), { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, } ); } catch (error) { console.error('Error confirming deletion:', error); return new Response( JSON.stringify({ error: error.message }), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, } ); } });