mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:51:13 -05:00
@@ -72,7 +72,13 @@ export async function fetchSubmissionItems(submissionId: string): Promise<Submis
|
|||||||
.eq('submission_id', submissionId)
|
.eq('submission_id', submissionId)
|
||||||
.order('order_index', { ascending: true });
|
.order('order_index', { ascending: true });
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) {
|
||||||
|
handleError(error, {
|
||||||
|
action: 'Fetch Submission Items',
|
||||||
|
metadata: { submissionId }
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
// Transform data to include relational data as item_data
|
// Transform data to include relational data as item_data
|
||||||
return await Promise.all((data || []).map(async item => {
|
return await Promise.all((data || []).map(async item => {
|
||||||
@@ -84,14 +90,23 @@ export async function fetchSubmissionItems(submissionId: string): Promise<Submis
|
|||||||
// Fetch location from park_submission_locations if available
|
// Fetch location from park_submission_locations if available
|
||||||
let locationData: any = null;
|
let locationData: any = null;
|
||||||
if (parkSub?.id) {
|
if (parkSub?.id) {
|
||||||
const { data } = await supabase
|
const { data, error: locationError } = await supabase
|
||||||
.from('park_submission_locations')
|
.from('park_submission_locations')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('park_submission_id', parkSub.id)
|
.eq('park_submission_id', parkSub.id)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
locationData = data;
|
|
||||||
|
if (locationError) {
|
||||||
|
handleNonCriticalError(locationError, {
|
||||||
|
action: 'Fetch Park Submission Location',
|
||||||
|
metadata: { parkSubmissionId: parkSub.id, submissionId }
|
||||||
|
});
|
||||||
|
// Continue without location data - non-critical
|
||||||
|
} else {
|
||||||
|
locationData = data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item_data = {
|
item_data = {
|
||||||
...parkSub,
|
...parkSub,
|
||||||
// Transform park_submission_location → location for form compatibility
|
// Transform park_submission_location → location for form compatibility
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ serve(async (req) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Log notification in notification_logs with idempotency key
|
// Log notification in notification_logs with idempotency key
|
||||||
await supabase.from('notification_logs').insert({
|
const { error: logError } = await supabase.from('notification_logs').insert({
|
||||||
user_id: '00000000-0000-0000-0000-000000000000', // Topic-based
|
user_id: '00000000-0000-0000-0000-000000000000', // Topic-based
|
||||||
notification_type: 'moderation_submission',
|
notification_type: 'moderation_submission',
|
||||||
idempotency_key: idempotencyKey,
|
idempotency_key: idempotencyKey,
|
||||||
@@ -225,13 +225,23 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (logError) {
|
||||||
|
// Non-blocking - notification was sent successfully, log failure shouldn't fail the request
|
||||||
|
edgeLogger.warn('Failed to log notification in notification_logs', {
|
||||||
|
action: 'notify_moderators',
|
||||||
|
requestId: tracking.requestId,
|
||||||
|
error: logError.message,
|
||||||
|
submissionId: submission_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const duration = endRequest(tracking);
|
const duration = endRequest(tracking);
|
||||||
edgeLogger.info('Successfully notified all moderators via topic', {
|
edgeLogger.info('Successfully notified all moderators via topic', {
|
||||||
action: 'notify_moderators',
|
action: 'notify_moderators',
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
traceId: tracking.traceId,
|
traceId: tracking.traceId,
|
||||||
duration,
|
duration,
|
||||||
transactionId: data?.transactionId
|
transactionId: data?.transactionId
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
|
|||||||
@@ -213,14 +213,19 @@ const handler = async (req: Request) => {
|
|||||||
console.error(`[${requestId}] Approval transaction failed:`, rpcError);
|
console.error(`[${requestId}] Approval transaction failed:`, rpcError);
|
||||||
|
|
||||||
// Update idempotency key to failed
|
// Update idempotency key to failed
|
||||||
await supabase
|
try {
|
||||||
.from('submission_idempotency_keys')
|
await supabase
|
||||||
.update({
|
.from('submission_idempotency_keys')
|
||||||
status: 'failed',
|
.update({
|
||||||
error_message: rpcError.message,
|
status: 'failed',
|
||||||
completed_at: new Date().toISOString()
|
error_message: rpcError.message,
|
||||||
})
|
completed_at: new Date().toISOString()
|
||||||
.eq('idempotency_key', idempotencyKey);
|
})
|
||||||
|
.eq('idempotency_key', idempotencyKey);
|
||||||
|
} catch (updateError) {
|
||||||
|
console.error(`[${requestId}] Failed to update idempotency key to failed:`, updateError);
|
||||||
|
// Non-blocking - continue with error response even if idempotency update fails
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -229,12 +234,12 @@ const handler = async (req: Request) => {
|
|||||||
details: rpcError.details,
|
details: rpcError.details,
|
||||||
retries: retryCount
|
retries: retryCount
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 500,
|
status: 500,
|
||||||
headers: {
|
headers: {
|
||||||
...corsHeaders,
|
...corsHeaders,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -242,14 +247,19 @@ const handler = async (req: Request) => {
|
|||||||
console.log(`[${requestId}] Transaction completed successfully:`, result);
|
console.log(`[${requestId}] Transaction completed successfully:`, result);
|
||||||
|
|
||||||
// STEP 8: Success - update idempotency key
|
// STEP 8: Success - update idempotency key
|
||||||
await supabase
|
try {
|
||||||
.from('submission_idempotency_keys')
|
await supabase
|
||||||
.update({
|
.from('submission_idempotency_keys')
|
||||||
status: 'completed',
|
.update({
|
||||||
result_data: result,
|
status: 'completed',
|
||||||
completed_at: new Date().toISOString()
|
result_data: result,
|
||||||
})
|
completed_at: new Date().toISOString()
|
||||||
.eq('idempotency_key', idempotencyKey);
|
})
|
||||||
|
.eq('idempotency_key', idempotencyKey);
|
||||||
|
} catch (updateError) {
|
||||||
|
console.error(`[${requestId}] Failed to update idempotency key to completed:`, updateError);
|
||||||
|
// Non-blocking - transaction succeeded, so continue with success response
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify(result),
|
JSON.stringify(result),
|
||||||
|
|||||||
@@ -107,24 +107,25 @@ serve(withRateLimit(async (req) => {
|
|||||||
const tracking = startRequest();
|
const tracking = startRequest();
|
||||||
const requestOrigin = req.headers.get('origin');
|
const requestOrigin = req.headers.get('origin');
|
||||||
const allowedOrigin = getAllowedOrigin(requestOrigin);
|
const allowedOrigin = getAllowedOrigin(requestOrigin);
|
||||||
|
|
||||||
// Check if this is a CORS request with a disallowed origin
|
// Check if this is a CORS request with a disallowed origin
|
||||||
if (requestOrigin && !allowedOrigin) {
|
if (requestOrigin && !allowedOrigin) {
|
||||||
edgeLogger.warn('CORS request rejected', { action: 'cors_validation', origin: requestOrigin, requestId: tracking.requestId });
|
edgeLogger.warn('CORS request rejected', { action: 'cors_validation', origin: requestOrigin, requestId: tracking.requestId });
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
error: 'Origin not allowed',
|
error: 'Origin not allowed',
|
||||||
message: 'The origin of this request is not allowed to access this resource'
|
message: 'The origin of this request is not allowed to access this resource'
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 403,
|
status: 403,
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define CORS headers at function scope so they're available in catch block
|
||||||
const corsHeaders = getCorsHeaders(allowedOrigin);
|
const corsHeaders = getCorsHeaders(allowedOrigin);
|
||||||
|
|
||||||
// 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 })
|
||||||
|
|||||||
Reference in New Issue
Block a user