import type { DatabaseClient } from "./database"; import { recordCardAck } from "./task-one-click-push-service"; export type WecomCallbackFields = Record; export type WecomCallbackEventResult = { recognized: boolean; action: string; taskId: string; btnKey: string; operator: string; }; export function parseWecomCallbackXml(xml: string): WecomCallbackFields { const fields: WecomCallbackFields = {}; const source = String(xml ?? ""); const pattern = /<([A-Za-z][A-Za-z0-9_]*)>(?:|([^<]*))<\/\1>/g; let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { const tag = match[1]; const value = match[2] ?? match[3] ?? ""; if (!(tag in fields)) fields[tag] = value.trim(); } return fields; } export function extractWecomEncryptField(body: string): string { const fields = parseWecomCallbackXml(body); return fields.Encrypt ?? ""; } export async function handleWecomCallbackEvent( db: DatabaseClient, fields: WecomCallbackFields, ): Promise { const event = fields.Event ?? ""; const taskId = fields.TaskId ?? ""; const btnKey = fields.BtnKey ?? ""; const operator = fields.FromUserName ?? ""; if (fields.MsgType === "event" && event === "template_card_event") { if (btnKey === "mark_handled") { await recordCardAck(db, { cardTaskId: taskId, btnKey, operator }); console.info("[KOC LOOP] wecom card ack recorded", { taskId, operator }); return { recognized: true, action: "card_ack", taskId, btnKey, operator }; } return { recognized: true, action: "ignored", taskId, btnKey, operator }; } console.info("[KOC LOOP] wecom callback event ignored", { msgType: fields.MsgType ?? "", event, }); return { recognized: false, action: "ignored", taskId, btnKey, operator }; }