import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
import { withEdgeRetry } from '../_shared/retryHelper.ts';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
interface EscalationRequest {
submissionId: string;
escalationReason: string;
escalatedBy: string;
}
serve(async (req) => {
const tracking = startRequest();
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
try {
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
);
const { submissionId, escalationReason, escalatedBy }: EscalationRequest = await req.json();
edgeLogger.info('Processing escalation notification', {
requestId: tracking.requestId,
submissionId,
escalatedBy,
action: 'send_escalation'
});
// Fetch submission details
const { data: submission, error: submissionError } = await supabase
.from('content_submissions')
.select('*, profiles:user_id(username, display_name, id)')
.eq('id', submissionId)
.single();
if (submissionError || !submission) {
throw new Error(`Failed to fetch submission: ${submissionError?.message || 'Not found'}`);
}
// Fetch escalator details
const { data: escalator, error: escalatorError } = await supabase
.from('profiles')
.select('username, display_name')
.eq('user_id', escalatedBy)
.single();
if (escalatorError) {
edgeLogger.error('Failed to fetch escalator profile', {
requestId: tracking.requestId,
error: escalatorError.message,
escalatedBy
});
}
// Fetch submission items count
const { count: itemsCount, error: countError } = await supabase
.from('submission_items')
.select('*', { count: 'exact', head: true })
.eq('submission_id', submissionId);
if (countError) {
edgeLogger.error('Failed to fetch items count', {
requestId: tracking.requestId,
error: countError.message,
submissionId
});
}
// Prepare email content
const escalatorName = escalator?.display_name || escalator?.username || 'Unknown User';
const submitterName = submission.profiles?.display_name || submission.profiles?.username || 'Unknown User';
const submissionType = submission.submission_type || 'Unknown';
const itemCount = itemsCount || 0;
const emailSubject = `🚨 Submission Escalated: ${submissionType} - ID: ${submissionId.substring(0, 8)}`;
const emailHtml = `
Submission ID:
${submissionId}
Submission Type:
${submissionType}
Items Count:
${itemCount}
Submitted By:
${submitterName}
Escalated By:
${escalatorName}
📝 Escalation Reason:
${escalationReason}
`;
const emailText = `
SUBMISSION ESCALATED - Admin Review Required
Submission ID: ${submissionId}
Submission Type: ${submissionType}
Items Count: ${itemCount}
Submitted By: ${submitterName}
Escalated By: ${escalatorName}
Escalation Reason:
${escalationReason}
Please review this submission in the admin panel.
`;
// Send email via ForwardEmail API with retry
const forwardEmailApiKey = Deno.env.get('FORWARDEMAIL_API_KEY');
const adminEmail = Deno.env.get('ADMIN_EMAIL_ADDRESS');
const fromEmail = Deno.env.get('FROM_EMAIL_ADDRESS');
if (!forwardEmailApiKey || !adminEmail || !fromEmail) {
throw new Error('Email configuration is incomplete. Please check environment variables.');
}
const emailResult = await withEdgeRetry(
async () => {
const emailResponse = await fetch('https://api.forwardemail.net/v1/emails', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa(forwardEmailApiKey + ':'),
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: fromEmail,
to: adminEmail,
subject: emailSubject,
html: emailHtml,
text: emailText,
}),
});
if (!emailResponse.ok) {
let errorText;
try {
errorText = await emailResponse.text();
} catch (parseError) {
errorText = 'Unable to parse error response';
}
const error = new Error(`Failed to send email: ${emailResponse.status} - ${errorText}`);
(error as any).status = emailResponse.status;
throw error;
}
const result = await emailResponse.json();
return result;
},
{ maxAttempts: 3, baseDelay: 1500, maxDelay: 10000 },
tracking.requestId,
'send-escalation-email'
);
edgeLogger.info('Email sent successfully', {
requestId: tracking.requestId,
emailId: emailResult.id
});
// Update submission with notification status
const { error: updateError } = await supabase
.from('content_submissions')
.update({
escalated: true,
escalated_at: new Date().toISOString(),
escalated_by: escalatedBy,
escalation_reason: escalationReason
})
.eq('id', submissionId);
if (updateError) {
edgeLogger.error('Failed to update submission escalation status', {
requestId: tracking.requestId,
error: updateError.message,
submissionId
});
}
const duration = endRequest(tracking);
edgeLogger.info('Escalation notification sent', {
requestId: tracking.requestId,
duration,
emailId: emailResult.id,
submissionId
});
return new Response(
JSON.stringify({
success: true,
message: 'Escalation notification sent successfully',
emailId: emailResult.id,
requestId: tracking.requestId
}),
{ headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
} }
);
} catch (error) {
const duration = endRequest(tracking);
edgeLogger.error('Error in send-escalation-notification', {
requestId: tracking.requestId,
duration,
error: error instanceof Error ? error.message : 'Unknown error'
});
return new Response(
JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error occurred',
details: 'Failed to send escalation notification',
requestId: tracking.requestId
}),
{ status: 500, headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
} }
);
}
});