mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 06:31:13 -05:00
Add robust error handling for image uploads, improve navigation logic in AutocompleteSearch with toast notifications for missing identifiers, refine useIsMobile hook return type, and update Supabase function error reporting to handle non-Error types. Replit-Commit-Author: Agent Replit-Commit-Session-Id: a759d451-40bf-440d-96f5-a19ad6af18a8 Replit-Commit-Checkpoint-Type: intermediate_checkpoint
119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
|
|
|
const corsHeaders = {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
|
};
|
|
|
|
// Helper function to decode JWT and extract user ID
|
|
function decodeJWT(token: string): { sub: string } | null {
|
|
try {
|
|
const parts = token.split('.');
|
|
if (parts.length !== 3) return null;
|
|
|
|
const payload = JSON.parse(atob(parts[1]));
|
|
return payload;
|
|
} catch (error) {
|
|
console.error('JWT decode error:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Deno.serve(async (req) => {
|
|
// Handle CORS preflight requests
|
|
if (req.method === 'OPTIONS') {
|
|
return new Response(null, { headers: corsHeaders });
|
|
}
|
|
|
|
try {
|
|
// Create admin client with service role key
|
|
const supabaseAdmin = createClient(
|
|
Deno.env.get('SUPABASE_URL') ?? '',
|
|
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '',
|
|
{
|
|
auth: {
|
|
autoRefreshToken: false,
|
|
persistSession: false
|
|
}
|
|
}
|
|
);
|
|
|
|
// Get the user from the authorization header
|
|
const authHeader = req.headers.get('Authorization');
|
|
if (!authHeader) {
|
|
console.error('Missing authorization header');
|
|
throw new Error('No authorization header provided. Please ensure you are logged in.');
|
|
}
|
|
|
|
const token = authHeader.replace('Bearer ', '');
|
|
console.log('Extracting user ID from JWT token...');
|
|
|
|
// Parse JWT token to get user ID directly
|
|
const payload = decodeJWT(token);
|
|
if (!payload || !payload.sub) {
|
|
console.error('Invalid JWT token structure');
|
|
throw new Error('Invalid session token. Please refresh the page and try again.');
|
|
}
|
|
|
|
const userId = payload.sub;
|
|
console.log(`Cancelling email change for user ${userId}`);
|
|
|
|
// Call the database function to clear email change fields
|
|
// This function has SECURITY DEFINER privileges to access auth.users
|
|
const { data: cancelled, error: cancelError } = await supabaseAdmin
|
|
.rpc('cancel_user_email_change', { _user_id: userId });
|
|
|
|
if (cancelError || !cancelled) {
|
|
console.error('Error cancelling email change:', cancelError);
|
|
throw new Error('Unable to cancel email change: ' + (cancelError?.message || 'Unknown error'));
|
|
}
|
|
|
|
console.log(`Successfully cancelled email change for user ${userId}`);
|
|
|
|
// Log the cancellation in admin_audit_log
|
|
const { error: auditError } = await supabaseAdmin
|
|
.from('admin_audit_log')
|
|
.insert({
|
|
admin_user_id: userId,
|
|
target_user_id: userId,
|
|
action: 'email_change_cancelled',
|
|
details: {
|
|
cancelled_at: new Date().toISOString(),
|
|
},
|
|
});
|
|
|
|
if (auditError) {
|
|
console.error('Error logging audit:', auditError);
|
|
// Don't fail the request if audit logging fails
|
|
}
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
success: true,
|
|
message: 'Email change cancelled successfully',
|
|
user: {
|
|
id: userId,
|
|
email: null,
|
|
new_email: null,
|
|
},
|
|
}),
|
|
{
|
|
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
status: 200,
|
|
}
|
|
);
|
|
} catch (error) {
|
|
console.error('Error in cancel-email-change function:', error);
|
|
return new Response(
|
|
JSON.stringify({
|
|
success: false,
|
|
error: error instanceof Error ? error.message : 'An unknown error occurred',
|
|
}),
|
|
{
|
|
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
status: 400,
|
|
}
|
|
);
|
|
}
|
|
});
|