Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions worker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,7 @@ async function addZendeskInternalNote(
const auth = btoa(`${env.ZENDESK_EMAIL}/token:${env.ZENDESK_API_TOKEN}`);
const url = `https://${env.ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/tickets/${ticketId}`;

const payload: { ticket: { comment: { body: string; public: boolean }; status?: string } } = {
const payload: { ticket: { comment: { body: string; public: boolean }; status?: string; assignee_email?: string; custom_fields?: Array<{ id: number; value: string }> } } = {
ticket: {
comment: {
body: note,
Expand All @@ -1676,6 +1676,17 @@ async function addZendeskInternalNote(

if (solve) {
payload.ticket.status = 'solved';
// Zendesk requires an assignee to solve a ticket (system rule, not enforced via API error).
// Without this, the comment is added but the status change is silently ignored.
payload.ticket.assignee_email = env.ZENDESK_EMAIL;
// Category and Issue are required fields. These values are set unconditionally. Safe
// because auto-categorize triggers fire at ticket creation, and this solve call runs
// later only for report types where triggers didn't set specific values (e.g., "other"
// reports with the previously misconfigured trigger).
payload.ticket.custom_fields = [
{ id: 14559549220879, value: 'trust___safety' }, // Category
{ id: 14560383908879, value: 'other_content_report' }, // Issue
];
}

const response = await fetch(url, {
Expand Down Expand Up @@ -2238,9 +2249,10 @@ async function handleParseReport(
}

// Parse description with regex
const eventMatch = description.match(/Event ID:\s*([a-f0-9]{64})/i);
const pubkeyMatch = description.match(/Author Pubkey:\s*([a-f0-9]{64})/i);
const violationMatch = description.match(/Violation Type:\s*(\w+)/i);
// Tolerates markdown bold (**Event ID:**) and alternate field names (Reported Pubkey vs Author Pubkey)
const eventMatch = description.match(/\*{0,2}Event ID:?\*{0,2}\s*([a-f0-9]{64})/i);
const pubkeyMatch = description.match(/\*{0,2}(?:Author|Reported) Pubkey:?\*{0,2}\s*([a-f0-9]{64})/i);
const violationMatch = description.match(/\*{0,2}(?:Violation Type|Reason):?\*{0,2}\s*(\w[^\n]*\w|\w)/i);

const event_id = eventMatch?.[1] || null;
const author_pubkey = pubkeyMatch?.[1] || null;
Expand Down
Loading