import { recordAudit } from '~/data/repositories/audit' import { clearSetting, findLatestSentRun, findReportRun, markReportRunDeleted, readSettings, writeSetting, } from '~/data/repositories/settings' import { invalid, isUuid, readField, readFlag, type AdminFormState } from './admin-forms' import { runWeeklyReport } from './report-settings' import { deleteFromSlack, findMessageTs, resolveChannelId } from './slack' import { reportText } from './weekly-report' import type { Viewer } from './auth-access' function looksLikeWebhook(value: string): boolean { return value === '' || /^https:\/\/hooks\.slack\.com\/services\/[\w/+-]+$/u.test(value) } function looksLikeToken(value: string): boolean { return value === '' || /^xox[bp]-[\w-]+$/u.test(value) } export async function performSaveSlack(viewer: Viewer, formData: FormData): Promise { const webhook = readField(formData, 'webhook') const token = readField(formData, 'botToken') const channel = readField(formData, 'channel') const keep = readFlag(formData, 'keep') const keepToken = readFlag(formData, 'keepToken') const includeInternal = readFlag(formData, 'includeInternal') if (!keep && !looksLikeWebhook(webhook)) { return invalid('webhookInvalid', undefined, { webhook: 'webhookInvalid' }) } if (!keepToken && !looksLikeToken(token)) { return invalid('tokenInvalid', undefined, { botToken: 'tokenInvalid' }) } const stored = await readSettings(['slack.botToken']) const withToken = keepToken ? Boolean(stored.get('slack.botToken')) : token !== '' if (withToken && channel === '') { return invalid('channelRequired', undefined, { channel: 'channelRequired' }) } if (!keep) { if (webhook === '') { await clearSetting('slack.webhook') } else { await writeSetting('slack.webhook', webhook) } } if (!keepToken) { if (token === '') { await clearSetting('slack.botToken') } else { await writeSetting('slack.botToken', token) } } if (channel === '') { await clearSetting('slack.channel') } else { await writeSetting('slack.channel', channel) } await writeSetting('slack.includeInternal', includeInternal ? 'true' : 'false') await recordAudit({ actorId: viewer.id, actorLabel: viewer.email, action: 'settings.slack', entity: 'setting', entityId: 'slack', data: { webhookSet: keep ? 'unchanged' : webhook !== '', botTokenSet: keepToken ? 'unchanged' : token !== '', channel, includeInternal, }, }) return { status: 'ok', message: 'slackSaved' } } export async function performSendReport(viewer: Viewer, origin: string): Promise { const outcome = await runWeeklyReport({ origin, trigger: `admin:${viewer.email}` }) await recordAudit({ actorId: viewer.id, actorLabel: viewer.email, action: 'settings.report', entity: 'setting', entityId: 'slack', data: { reason: outcome.reason, total: outcome.run.total }, }) if (outcome.reason === 'sent') { return { status: 'ok', message: 'reportSent' } } return invalid(outcome.reason === 'nothing_published' ? 'reportEmpty' : outcome.reason === 'not_configured' ? 'reportNoWebhook' : 'reportRejected') } export async function performDeleteMessage(viewer: Viewer, formData: FormData): Promise { const id = readField(formData, 'runId') if (!isUuid(id)) { return invalid('runUnknown') } const run = await findReportRun(id) if (!run) { return invalid('runUnknown') } if (!run.sent) { return invalid('runNotSent') } if (!run.messageTs) { return invalid('runNotDeletable') } const values = await readSettings(['slack.botToken', 'slack.channel']) const token = values.get('slack.botToken')?.trim() const channel = run.channel ?? values.get('slack.channel')?.trim() if (!token) { return invalid('runNoToken') } if (!channel) { return invalid('runNoChannel') } const resolved = await resolveChannelId(token, channel) if (!resolved.ok) { return invalid('slackSaid', { detail: resolved.detail }) } let messageTs = run.messageTs if (!messageTs) { const lookup = await findMessageTs({ token, channel: resolved.id, text: reportText({ from: run.fromAt, to: run.toAt, total: run.total }), around: run.createdAt, }) if (!lookup.ok) { return invalid('slackSaid', { detail: lookup.detail }) } messageTs = lookup.messageTs } const result = await deleteFromSlack(token, resolved.id, messageTs) if (!result.ok) { return invalid('slackSaid', { detail: result.detail }) } await markReportRunDeleted(run.id) const previous = await findLatestSentRun() if (previous) { await writeSetting('slack.lastSentAt', previous.toAt.toISOString()) } else { await clearSetting('slack.lastSentAt') } await recordAudit({ actorId: viewer.id, actorLabel: viewer.email, action: 'settings.reportDelete', entity: 'setting', entityId: run.id, data: { channel: resolved.id, messageTs }, }) return { status: 'ok', message: 'messageDeleted' } } export async function performResetWindow(viewer: Viewer): Promise { await clearSetting('slack.lastSentAt') await recordAudit({ actorId: viewer.id, actorLabel: viewer.email, action: 'settings.reportReset', entity: 'setting', entityId: 'slack', data: {}, }) return { status: 'ok', message: 'windowReset' } }