feat(15-03): fire-and-forget phishing detection on ticket.created webhook
- triggerPhishingDetection() mirrors triggerWorkflowEngine's payload.entity-first shape - reads createdByContactID (Autotask field) into created_by_contact_id, per entity-mapper.ts:211 - called alongside the existing workflow-engine trigger, not awaited in the request path
This commit is contained in:
parent
dbd2ebe63c
commit
194b58b196
1 changed files with 43 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ import { workflowEngine } from './workflow-engine';
|
|||
import { ticketWorkflowEngine } from './ticket-workflow-engine';
|
||||
import '../services/workflow-steps'; // Register all workflow step executors
|
||||
import { WorkflowEvent, TicketData } from '../types/workflow';
|
||||
import { detectPhishingTicket, DetectableTicket } from './phishing-detector';
|
||||
|
||||
export class WebhookService {
|
||||
private _autotaskClient: AutotaskClient | null = null;
|
||||
|
|
@ -114,6 +115,9 @@ export class WebhookService {
|
|||
this.triggerWorkflowEngine(payload).catch(err =>
|
||||
console.error('[WEBHOOK] Workflow engine error:', err)
|
||||
);
|
||||
this.triggerPhishingDetection(payload).catch(err =>
|
||||
console.error('[WEBHOOK] Phishing detection error:', err)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -436,6 +440,45 @@ export class WebhookService {
|
|||
// DEPRECATED: old workflow engine (will be removed after testing period)
|
||||
// await workflowEngine.process(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger phishing detection for a new ticket.
|
||||
* Runs asynchronously — does not block webhook response. Mirrors
|
||||
* triggerWorkflowEngine's "prefer inline payload.entity, else payload.entityId" shape.
|
||||
*/
|
||||
private async triggerPhishingDetection(payload: AutotaskWebhookPayload): Promise<void> {
|
||||
let ticket: DetectableTicket;
|
||||
|
||||
if (payload.entity) {
|
||||
// NOTE: Autotask's requester field is `createdByContactID` (mapped to
|
||||
// created_by_contact_id at lib/utils/entity-mapper.ts:211). There is no
|
||||
// similarly-named alternative field — since payload.entity is typed
|
||||
// Record<string, any>, a wrong field name would compile cleanly but
|
||||
// silently produce undefined at runtime.
|
||||
ticket = {
|
||||
id: payload.entityId,
|
||||
ticket_number: payload.entity.ticketNumber || null,
|
||||
title: payload.entity.title || null,
|
||||
description: payload.entity.description || null,
|
||||
company_id: payload.entity.companyID || null,
|
||||
contact_id: payload.entity.contactID || null,
|
||||
created_by_contact_id: payload.entity.createdByContactID || null,
|
||||
};
|
||||
} else {
|
||||
ticket = {
|
||||
id: payload.entityId,
|
||||
ticket_number: null,
|
||||
title: null,
|
||||
description: null,
|
||||
company_id: null,
|
||||
contact_id: null,
|
||||
created_by_contact_id: null,
|
||||
};
|
||||
}
|
||||
|
||||
console.log(`[WEBHOOK] Triggering phishing detection for ticket ${payload.entityId}`);
|
||||
await detectPhishingTicket(ticket);
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue