Send through a bot token so messages can be deleted again
Incoming webhooks return no message id, so nothing can be removed later. Settings now take a bot token plus channel, chat.postMessage records channel and timestamp on the run, and the history carries a delete button per message. The webhook stays as a fallback and is marked as not deletable.
This commit is contained in:
@@ -1,22 +1,40 @@
|
||||
import { recordAudit } from '~/data/repositories/audit'
|
||||
import { clearSetting, writeSetting } from '~/data/repositories/settings'
|
||||
import { invalid, readField, readFlag, type AdminFormState } from './admin-forms'
|
||||
import {
|
||||
clearSetting,
|
||||
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 } from './slack'
|
||||
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<AdminFormState> {
|
||||
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' })
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
if (webhook === '') {
|
||||
await clearSetting('slack.webhook')
|
||||
@@ -25,6 +43,20 @@ export async function performSaveSlack(viewer: Viewer, formData: FormData): Prom
|
||||
}
|
||||
}
|
||||
|
||||
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({
|
||||
@@ -33,7 +65,12 @@ export async function performSaveSlack(viewer: Viewer, formData: FormData): Prom
|
||||
action: 'settings.slack',
|
||||
entity: 'setting',
|
||||
entityId: 'slack',
|
||||
data: { webhookSet: keep ? 'unchanged' : webhook !== '', includeInternal },
|
||||
data: {
|
||||
webhookSet: keep ? 'unchanged' : webhook !== '',
|
||||
botTokenSet: keepToken ? 'unchanged' : token !== '',
|
||||
channel,
|
||||
includeInternal,
|
||||
},
|
||||
})
|
||||
|
||||
return { status: 'ok', message: 'slackSaved' }
|
||||
@@ -57,3 +94,47 @@ export async function performSendReport(viewer: Viewer, origin: string): Promise
|
||||
|
||||
return invalid(outcome.reason === 'nothing_published' ? 'reportEmpty' : outcome.reason === 'not_configured' ? 'reportNoWebhook' : 'reportRejected')
|
||||
}
|
||||
|
||||
export async function performDeleteMessage(viewer: Viewer, formData: FormData): Promise<AdminFormState> {
|
||||
const id = readField(formData, 'runId')
|
||||
|
||||
if (!isUuid(id)) {
|
||||
return invalid('runUnknown')
|
||||
}
|
||||
|
||||
const run = await findReportRun(id)
|
||||
|
||||
if (!run) {
|
||||
return invalid('runUnknown')
|
||||
}
|
||||
|
||||
if (!run.channel || !run.messageTs) {
|
||||
return invalid('runNotDeletable')
|
||||
}
|
||||
|
||||
const values = await readSettings(['slack.botToken'])
|
||||
const token = values.get('slack.botToken')?.trim()
|
||||
|
||||
if (!token) {
|
||||
return invalid('runNoToken')
|
||||
}
|
||||
|
||||
const result = await deleteFromSlack(token, run.channel, run.messageTs)
|
||||
|
||||
if (!result.ok) {
|
||||
return invalid('runDeleteFailed')
|
||||
}
|
||||
|
||||
await markReportRunDeleted(run.id)
|
||||
|
||||
await recordAudit({
|
||||
actorId: viewer.id,
|
||||
actorLabel: viewer.email,
|
||||
action: 'settings.reportDelete',
|
||||
entity: 'setting',
|
||||
entityId: run.id,
|
||||
data: { channel: run.channel, messageTs: run.messageTs },
|
||||
})
|
||||
|
||||
return { status: 'ok', message: 'messageDeleted' }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user