mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 17:51:12 -05:00
Implement 5-day plan
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -6,16 +7,28 @@ const corsHeaders = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Deno.serve(async (req) => {
|
Deno.serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
// Handle CORS preflight requests
|
// Handle CORS preflight requests
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get the user from the authorization header
|
// Get the user from the authorization header
|
||||||
const authHeader = req.headers.get('Authorization');
|
const authHeader = req.headers.get('Authorization');
|
||||||
if (!authHeader) {
|
if (!authHeader) {
|
||||||
console.error('Missing authorization header');
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Missing authorization header', {
|
||||||
|
action: 'cancel_email_change',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
throw new Error('No authorization header provided. Please ensure you are logged in.');
|
throw new Error('No authorization header provided. Please ensure you are logged in.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,12 +62,22 @@ Deno.serve(async (req) => {
|
|||||||
const { data: { user }, error: authError } = await supabaseAdmin.auth.getUser(token);
|
const { data: { user }, error: authError } = await supabaseAdmin.auth.getUser(token);
|
||||||
|
|
||||||
if (authError || !user) {
|
if (authError || !user) {
|
||||||
console.error('Auth verification failed:', authError);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Auth verification failed', {
|
||||||
|
action: 'cancel_email_change',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: authError
|
||||||
|
});
|
||||||
throw new Error('Invalid session token. Please refresh the page and try again.');
|
throw new Error('Invalid session token. Please refresh the page and try again.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
console.log(`Cancelling email change for user ${userId}`);
|
edgeLogger.info('Cancelling email change for user', {
|
||||||
|
action: 'cancel_email_change',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId
|
||||||
|
});
|
||||||
|
|
||||||
// Call the database function to clear email change fields
|
// Call the database function to clear email change fields
|
||||||
// This function has SECURITY DEFINER privileges to access auth.users
|
// This function has SECURITY DEFINER privileges to access auth.users
|
||||||
@@ -85,6 +108,14 @@ Deno.serve(async (req) => {
|
|||||||
// Don't fail the request if audit logging fails
|
// Don't fail the request if audit logging fails
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('Successfully cancelled email change', {
|
||||||
|
action: 'cancel_email_change',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -94,21 +125,37 @@ Deno.serve(async (req) => {
|
|||||||
email: null,
|
email: null,
|
||||||
new_email: null,
|
new_email: null,
|
||||||
},
|
},
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
status: 200,
|
status: 200,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in cancel-email-change function:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error in cancel-email-change function', {
|
||||||
|
action: 'cancel_email_change',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: error instanceof Error ? error.message : 'An unknown error occurred',
|
error: error instanceof Error ? error.message : 'An unknown error occurred',
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
status: 400,
|
status: 400,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -7,8 +8,15 @@ const corsHeaders = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -35,10 +43,20 @@ serve(async (req) => {
|
|||||||
} = await supabaseClient.auth.getUser();
|
} = await supabaseClient.auth.getUser();
|
||||||
|
|
||||||
if (userError || !user) {
|
if (userError || !user) {
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Authentication failed', {
|
||||||
|
action: 'confirm_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
throw new Error('Unauthorized');
|
throw new Error('Unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Confirming deletion for user: ${user.id}`);
|
edgeLogger.info('Confirming deletion for user', {
|
||||||
|
action: 'confirm_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
|
|
||||||
// Find deletion request
|
// Find deletion request
|
||||||
const { data: deletionRequest, error: requestError } = await supabaseClient
|
const { data: deletionRequest, error: requestError } = await supabaseClient
|
||||||
@@ -133,26 +151,50 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Account deactivated and deletion confirmed');
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('Account deactivated and deletion confirmed', {
|
||||||
|
action: 'confirm_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Deletion confirmed. Account deactivated and scheduled for permanent deletion.',
|
message: 'Deletion confirmed. Account deactivated and scheduled for permanent deletion.',
|
||||||
scheduled_deletion_at: deletionRequest.scheduled_deletion_at,
|
scheduled_deletion_at: deletionRequest.scheduled_deletion_at,
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error confirming deletion:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error confirming deletion', {
|
||||||
|
action: 'confirm_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: error.message }),
|
JSON.stringify({
|
||||||
|
error: error.message,
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { sanitizeError } from '../_shared/errorSanitizer.ts';
|
import { sanitizeError } from '../_shared/errorSanitizer.ts';
|
||||||
import { edgeLogger } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -17,9 +17,16 @@ interface ExportOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
// Handle CORS preflight requests
|
// Handle CORS preflight requests
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -40,14 +47,34 @@ serve(async (req) => {
|
|||||||
} = await supabaseClient.auth.getUser();
|
} = await supabaseClient.auth.getUser();
|
||||||
|
|
||||||
if (authError || !user) {
|
if (authError || !user) {
|
||||||
edgeLogger.error('Authentication failed', { action: 'export_auth' });
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Authentication failed', {
|
||||||
|
action: 'export_auth',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: 'Unauthorized', success: false }),
|
JSON.stringify({
|
||||||
{ status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
error: 'Unauthorized',
|
||||||
|
success: false,
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 401,
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
edgeLogger.info('Processing export request', { action: 'export_start', userId: user.id });
|
edgeLogger.info('Processing export request', {
|
||||||
|
action: 'export_start',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
|
|
||||||
// Check rate limiting - max 1 export per hour
|
// Check rate limiting - max 1 export per hour
|
||||||
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
|
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
|
||||||
@@ -64,16 +91,31 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (recentExports && recentExports.length > 0) {
|
if (recentExports && recentExports.length > 0) {
|
||||||
|
const duration = endRequest(tracking);
|
||||||
const nextAvailableAt = new Date(new Date(recentExports[0].created_at).getTime() + 60 * 60 * 1000).toISOString();
|
const nextAvailableAt = new Date(new Date(recentExports[0].created_at).getTime() + 60 * 60 * 1000).toISOString();
|
||||||
console.log(`[Export] Rate limited for user ${user.id}, next available: ${nextAvailableAt}`);
|
edgeLogger.warn('Rate limit exceeded for export', {
|
||||||
|
action: 'export_rate_limit',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
duration,
|
||||||
|
nextAvailableAt
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Rate limited. You can export your data once per hour.',
|
error: 'Rate limited. You can export your data once per hour.',
|
||||||
rate_limited: true,
|
rate_limited: true,
|
||||||
next_available_at: nextAvailableAt
|
next_available_at: nextAvailableAt,
|
||||||
|
requestId: tracking.requestId
|
||||||
}),
|
}),
|
||||||
{ status: 429, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
{
|
||||||
|
status: 429,
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +129,11 @@ serve(async (req) => {
|
|||||||
format: 'json'
|
format: 'json'
|
||||||
};
|
};
|
||||||
|
|
||||||
edgeLogger.info('Export options', { action: 'export_options', userId: user.id });
|
edgeLogger.info('Export options', {
|
||||||
|
action: 'export_options',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
|
|
||||||
// Fetch profile data
|
// Fetch profile data
|
||||||
const { data: profile, error: profileError } = await supabaseClient
|
const { data: profile, error: profileError } = await supabaseClient
|
||||||
@@ -97,7 +143,11 @@ serve(async (req) => {
|
|||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (profileError) {
|
if (profileError) {
|
||||||
edgeLogger.error('Profile fetch failed', { action: 'export_profile' });
|
edgeLogger.error('Profile fetch failed', {
|
||||||
|
action: 'export_profile',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
throw new Error('Failed to fetch profile data');
|
throw new Error('Failed to fetch profile data');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,33 +310,61 @@ serve(async (req) => {
|
|||||||
changes: {
|
changes: {
|
||||||
export_options: options,
|
export_options: options,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
data_size: JSON.stringify(exportData).length
|
data_size: JSON.stringify(exportData).length,
|
||||||
|
requestId: tracking.requestId
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
edgeLogger.info('Export completed successfully', { action: 'export_complete', userId: user.id });
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('Export completed successfully', {
|
||||||
|
action: 'export_complete',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
traceId: tracking.traceId,
|
||||||
|
userId: user.id,
|
||||||
|
duration,
|
||||||
|
dataSize: JSON.stringify(exportData).length
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ success: true, data: exportData }),
|
JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
data: exportData,
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: {
|
headers: {
|
||||||
...corsHeaders,
|
...corsHeaders,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Content-Disposition': `attachment; filename="thrillwiki-data-export-${new Date().toISOString().split('T')[0]}.json"`
|
'Content-Disposition': `attachment; filename="thrillwiki-data-export-${new Date().toISOString().split('T')[0]}.json"`,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
edgeLogger.error('Export error', { action: 'export_error', error: error instanceof Error ? error.message : String(error) });
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Export error', {
|
||||||
|
action: 'export_error',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
});
|
||||||
const sanitized = sanitizeError(error, 'export-user-data');
|
const sanitized = sanitizeError(error, 'export-user-data');
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
...sanitized,
|
...sanitized,
|
||||||
success: false
|
success: false,
|
||||||
|
requestId: tracking.requestId
|
||||||
}),
|
}),
|
||||||
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
{
|
||||||
|
status: 500,
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { edgeLogger } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -7,9 +7,16 @@ const corsHeaders = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Deno.serve(async (req) => {
|
Deno.serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
// Handle CORS preflight requests
|
// Handle CORS preflight requests
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -23,14 +30,33 @@ Deno.serve(async (req) => {
|
|||||||
// Get authenticated user
|
// Get authenticated user
|
||||||
const { data: { user }, error: userError } = await supabaseClient.auth.getUser();
|
const { data: { user }, error: userError } = await supabaseClient.auth.getUser();
|
||||||
if (userError || !user) {
|
if (userError || !user) {
|
||||||
edgeLogger.error('Authentication failed', { action: 'mfa_unenroll_auth' });
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Authentication failed', {
|
||||||
|
action: 'mfa_unenroll_auth',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: 'Unauthorized' }),
|
JSON.stringify({
|
||||||
{ status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
error: 'Unauthorized',
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 401,
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
edgeLogger.info('Processing MFA unenroll', { action: 'mfa_unenroll', userId: user.id });
|
edgeLogger.info('Processing MFA unenroll', {
|
||||||
|
action: 'mfa_unenroll',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
|
|
||||||
// Phase 1: Check AAL level
|
// Phase 1: Check AAL level
|
||||||
const { data: { session } } = await supabaseClient.auth.getSession();
|
const { data: { session } } = await supabaseClient.auth.getSession();
|
||||||
@@ -130,18 +156,50 @@ Deno.serve(async (req) => {
|
|||||||
edgeLogger.error('Notification failed', { action: 'mfa_unenroll_notification', userId: user.id });
|
edgeLogger.error('Notification failed', { action: 'mfa_unenroll_notification', userId: user.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
edgeLogger.info('MFA successfully disabled', { action: 'mfa_unenroll_success', userId: user.id });
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('MFA successfully disabled', {
|
||||||
|
action: 'mfa_unenroll_success',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ success: true }),
|
JSON.stringify({
|
||||||
{ status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
success: true,
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
edgeLogger.error('Unexpected error', { action: 'mfa_unenroll_error', error: error instanceof Error ? error.message : String(error) });
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Unexpected error', {
|
||||||
|
action: 'mfa_unenroll_error',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: 'Internal server error' }),
|
JSON.stringify({
|
||||||
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
error: 'Internal server error',
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 500,
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
||||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
||||||
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -19,8 +20,15 @@ interface NotificationPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -42,7 +50,9 @@ serve(async (req) => {
|
|||||||
is_escalated
|
is_escalated
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
console.log('Notifying moderators about submission via topic:', {
|
edgeLogger.info('Notifying moderators about submission via topic', {
|
||||||
|
action: 'notify_moderators',
|
||||||
|
requestId: tracking.requestId,
|
||||||
submission_id,
|
submission_id,
|
||||||
submission_type,
|
submission_type,
|
||||||
content_preview
|
content_preview
|
||||||
@@ -78,14 +88,25 @@ serve(async (req) => {
|
|||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (workflowError || !workflow) {
|
if (workflowError || !workflow) {
|
||||||
console.error('Error fetching workflow:', workflowError);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error fetching workflow', {
|
||||||
|
action: 'notify_moderators',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: workflowError
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Workflow not found or not active'
|
error: 'Workflow not found or not active',
|
||||||
|
requestId: tracking.requestId
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
status: 500,
|
status: 500,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -112,6 +133,10 @@ serve(async (req) => {
|
|||||||
hasPhotos: has_photos,
|
hasPhotos: has_photos,
|
||||||
itemCount: item_count,
|
itemCount: item_count,
|
||||||
isEscalated: is_escalated,
|
isEscalated: is_escalated,
|
||||||
|
|
||||||
|
// Request tracking
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
traceId: tracking.traceId,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send ONE notification to the moderation-submissions topic
|
// Send ONE notification to the moderation-submissions topic
|
||||||
@@ -125,21 +150,39 @@ serve(async (req) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Failed to notify moderators via topic:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Failed to notify moderators via topic', {
|
||||||
|
action: 'notify_moderators',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Failed to send notification to topic',
|
error: 'Failed to send notification to topic',
|
||||||
details: error.message
|
details: error.message,
|
||||||
|
requestId: tracking.requestId
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
status: 500,
|
status: 500,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Successfully notified all moderators via topic:', data);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('Successfully notified all moderators via topic', {
|
||||||
|
action: 'notify_moderators',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
traceId: tracking.traceId,
|
||||||
|
duration,
|
||||||
|
transactionId: data?.transactionId
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -147,22 +190,38 @@ serve(async (req) => {
|
|||||||
message: 'Moderator notifications sent via topic',
|
message: 'Moderator notifications sent via topic',
|
||||||
topicKey: 'moderation-submissions',
|
topicKey: 'moderation-submissions',
|
||||||
transactionId: data?.transactionId,
|
transactionId: data?.transactionId,
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
status: 200,
|
status: 200,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error in notify-moderators-submission:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error in notify-moderators-submission', {
|
||||||
|
action: 'notify_moderators',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message,
|
error: error.message,
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
status: 500,
|
status: 500,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -7,8 +8,15 @@ const corsHeaders = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -29,10 +37,20 @@ serve(async (req) => {
|
|||||||
} = await supabaseClient.auth.getUser();
|
} = await supabaseClient.auth.getUser();
|
||||||
|
|
||||||
if (userError || !user) {
|
if (userError || !user) {
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Authentication failed', {
|
||||||
|
action: 'request_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
throw new Error('Unauthorized');
|
throw new Error('Unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Processing deletion request for user: ${user.id}`);
|
edgeLogger.info('Processing deletion request', {
|
||||||
|
action: 'request_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
|
|
||||||
// Check for existing pending deletion request
|
// Check for existing pending deletion request
|
||||||
const { data: existingRequest } = await supabaseClient
|
const { data: existingRequest } = await supabaseClient
|
||||||
@@ -142,25 +160,52 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('Deletion request created successfully', {
|
||||||
|
action: 'request_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
duration,
|
||||||
|
requestId: deletionRequest.id
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Account deletion request created successfully',
|
message: 'Account deletion request created successfully',
|
||||||
scheduled_deletion_at: scheduledDeletionAt.toISOString(),
|
scheduled_deletion_at: scheduledDeletionAt.toISOString(),
|
||||||
request_id: deletionRequest.id,
|
request_id: deletionRequest.id,
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error processing deletion request:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error processing deletion request', {
|
||||||
|
action: 'request_deletion',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: error.message }),
|
JSON.stringify({
|
||||||
|
error: error.message,
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -7,8 +8,15 @@ const corsHeaders = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -29,10 +37,20 @@ serve(async (req) => {
|
|||||||
} = await supabaseClient.auth.getUser();
|
} = await supabaseClient.auth.getUser();
|
||||||
|
|
||||||
if (userError || !user) {
|
if (userError || !user) {
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Authentication failed', {
|
||||||
|
action: 'resend_deletion_code',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
throw new Error('Unauthorized');
|
throw new Error('Unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Resending deletion code for user: ${user.id}`);
|
edgeLogger.info('Resending deletion code for user', {
|
||||||
|
action: 'resend_deletion_code',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id
|
||||||
|
});
|
||||||
|
|
||||||
// Find pending deletion request
|
// Find pending deletion request
|
||||||
const { data: deletionRequest, error: requestError } = await supabaseClient
|
const { data: deletionRequest, error: requestError } = await supabaseClient
|
||||||
@@ -114,23 +132,49 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('New confirmation code sent successfully', {
|
||||||
|
action: 'resend_deletion_code',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'New confirmation code sent successfully',
|
message: 'New confirmation code sent successfully',
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error resending code:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error resending code', {
|
||||||
|
action: 'resend_deletion_code',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: error.message }),
|
JSON.stringify({
|
||||||
|
error: error.message,
|
||||||
|
requestId: tracking.requestId
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -13,8 +14,15 @@ interface EmailRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -31,6 +39,12 @@ serve(async (req) => {
|
|||||||
const { data: { user }, error: userError } = await supabaseClient.auth.getUser();
|
const { data: { user }, error: userError } = await supabaseClient.auth.getUser();
|
||||||
|
|
||||||
if (userError || !user) {
|
if (userError || !user) {
|
||||||
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Authentication failed', {
|
||||||
|
action: 'send_password_email',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration
|
||||||
|
});
|
||||||
throw new Error('Unauthorized');
|
throw new Error('Unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +54,13 @@ serve(async (req) => {
|
|||||||
throw new Error('Email is required');
|
throw new Error('Email is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edgeLogger.info('Sending password added email', {
|
||||||
|
action: 'send_password_email',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
email
|
||||||
|
});
|
||||||
|
|
||||||
const recipientName = displayName || username || 'there';
|
const recipientName = displayName || username || 'there';
|
||||||
const siteUrl = Deno.env.get('SITE_URL') || 'https://thrillwiki.com';
|
const siteUrl = Deno.env.get('SITE_URL') || 'https://thrillwiki.com';
|
||||||
|
|
||||||
@@ -141,30 +162,53 @@ serve(async (req) => {
|
|||||||
throw new Error(`Failed to send email: ${emailResponse.statusText}`);
|
throw new Error(`Failed to send email: ${emailResponse.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Password addition email sent successfully to: ${email}`);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.info('Password addition email sent successfully', {
|
||||||
|
action: 'send_password_email',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
userId: user.id,
|
||||||
|
email,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Password addition email sent successfully',
|
message: 'Password addition email sent successfully',
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in send-password-added-email function:', error);
|
const duration = endRequest(tracking);
|
||||||
|
edgeLogger.error('Error in send-password-added-email function', {
|
||||||
|
action: 'send_password_email',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
duration,
|
||||||
|
error: error instanceof Error ? error.message : 'Unknown error'
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: error instanceof Error ? error.message : 'Unknown error',
|
error: error instanceof Error ? error.message : 'Unknown error',
|
||||||
|
requestId: tracking.requestId,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 500,
|
status: 500,
|
||||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
...corsHeaders,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Request-ID': tracking.requestId
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user