import { SecretsManagerClient, GetSecretValueCommand, } from "@aws-sdk/client-secrets-manager"; const secrets = new SecretsManagerClient(); const EXPENSE_BOT_TOKEN_SECRET_NAME = process.env.EXPENSE_BOT_TOKEN_SECRET_NAME; let cachedToken; async function getBotToken() { if (cachedToken) return cachedToken; const { SecretString } = await secrets.send( new GetSecretValueCommand({ SecretId: EXPENSE_BOT_TOKEN_SECRET_NAME }) ); cachedToken = SecretString; return cachedToken; } const SUBMITTED_CHANNEL = "C0AQ2AWLNEN"; const STAGES = { [SUBMITTED_CHANNEL]: { next: "C0APLSGABAB", label: "Processed" }, C0APLSGABAB: { next: "C0AQ09CDJH4", label: "Authorized" }, C0AQ09CDJH4: { next: "C0APYUM1JFP", label: "Matched" }, }; const REACT_HINT_RE = /_React_ :white_check_mark: _to advance to \w+_/; async function slackGet(method, token, params) { const qs = new URLSearchParams(params).toString(); const res = await fetch(`https://slack.com/api/${method}?${qs}`, { headers: { Authorization: `Bearer ${token}` }, }); const data = await res.json(); if (!data.ok) throw new Error(`${method} failed: ${data.error}`); return data; } async function slackPost(method, token, body) { const res = await fetch(`https://slack.com/api/${method}`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify(body), }); const data = await res.json(); if (!data.ok) throw new Error(`${method} failed: ${data.error}`); return data; } export const handler = async (event) => { if (event.type !== "reaction_added" || event.reaction !== "white_check_mark") { console.log(`Skipping event type=${event.type} reaction=${event.reaction}`); return; } const fromChannel = event.item.channel; const messageTs = event.item.ts; const route = STAGES[fromChannel]; if (!route) { console.log(`Channel ${fromChannel} not in STAGES, skipping`); return; } const toChannel = route.next; const label = route.label; const isOrigin = fromChannel === SUBMITTED_CHANNEL; const token = await getBotToken(); const history = await slackGet("conversations.history", token, { channel: fromChannel, latest: messageTs, limit: "1", inclusive: "true", }); const originalText = history.messages[0].text; const text = originalText.replace(REACT_HINT_RE, "").trim(); const nextStage = STAGES[toChannel]; const nextLabel = nextStage ? nextStage.label : null; const reactLine = nextLabel ? `\n\n_React_ :white_check_mark: _to advance to ${nextLabel}_` : ""; let permalinkLine = ""; if (isOrigin) { const permalinkResp = await slackGet("chat.getPermalink", token, { channel: fromChannel, message_ts: messageTs, }); permalinkLine = `\n\n:paperclip: *Original Submission:* <${permalinkResp.permalink}|View Original Message>`; } const fullText = `${text}${permalinkLine}${reactLine}`; await slackPost("chat.postMessage", token, { channel: toChannel, text: fullText, mrkdwn: true, unfurl_links: false, unfurl_media: false, }); if (isOrigin) { await slackPost("chat.postMessage", token, { channel: fromChannel, thread_ts: messageTs, text: `➡️ Advanced to ${label}`, }); console.log(`Advanced user submission to ${label} (origin preserved)`); } else { await slackPost("chat.delete", token, { channel: fromChannel, ts: messageTs, }); console.log(`Advanced to ${label} and deleted previous copy`); } };