diff --git a/messages/de.json b/messages/de.json
index 7cc841c..9869d41 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -299,7 +299,8 @@
"runNotSent": "Bei diesem Lauf ging keine Nachricht raus.",
"runNoChannel": "Es ist kein Kanal hinterlegt.",
"runNotFound": "Im Kanal war keine passende Nachricht zu finden. Braucht der Bot noch das Recht channels:history?",
- "channelRequired": "Zum Bot-Token gehört ein Kanal, sonst weiß Logbuch nicht, wohin."
+ "channelRequired": "Zum Bot-Token gehört ein Kanal, sonst weiß Logbuch nicht, wohin.",
+ "slackSaid": "Slack sagt: {detail}"
},
"errors": {
"nameRequired": "Trag einen Namen ein.",
diff --git a/messages/en.json b/messages/en.json
index 563b1df..70e5592 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -299,7 +299,8 @@
"runNotSent": "That run sent no message.",
"runNoChannel": "No channel is stored.",
"runNotFound": "No matching message found in the channel. Does the bot still need channels:history?",
- "channelRequired": "A bot token needs a channel, otherwise Logbuch has no target."
+ "channelRequired": "A bot token needs a channel, otherwise Logbuch has no target.",
+ "slackSaid": "Slack says: {detail}"
},
"errors": {
"nameRequired": "Enter a name.",
diff --git a/src/components/admin/MessageDeleteButton.tsx b/src/components/admin/MessageDeleteButton.tsx
index 2489792..be2e222 100644
--- a/src/components/admin/MessageDeleteButton.tsx
+++ b/src/components/admin/MessageDeleteButton.tsx
@@ -30,7 +30,11 @@ export function MessageDeleteButton({ runId, hint }: MessageDeleteButtonProps) {
{hint ? {hint} : null}
{state.status === 'error' && state.message ? (
- {messages(state.message)}
+
+ {state.message === 'slackSaid'
+ ? messages('slackSaid', { detail: state.values?.detail ?? '' })
+ : messages(state.message)}
+
) : null}
)
diff --git a/src/lib/admin-settings.ts b/src/lib/admin-settings.ts
index 9a6acfa..e8c58b5 100644
--- a/src/lib/admin-settings.ts
+++ b/src/lib/admin-settings.ts
@@ -132,21 +132,27 @@ export async function performDeleteMessage(viewer: Viewer, formData: FormData):
return invalid('runNoChannel')
}
- const messageTs = run.messageTs ?? await findMessageTs({
- token,
- channel,
- text: reportText({ from: run.fromAt, to: run.toAt, total: run.total }),
- around: run.createdAt,
- })
+ let messageTs = run.messageTs
if (!messageTs) {
- return invalid('runNotFound')
+ const lookup = await findMessageTs({
+ token,
+ channel,
+ 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, channel, messageTs)
if (!result.ok) {
- return invalid('runDeleteFailed')
+ return invalid('slackSaid', { detail: result.detail })
}
await markReportRunDeleted(run.id)
diff --git a/src/lib/slack.ts b/src/lib/slack.ts
index 6669545..6cb810c 100644
--- a/src/lib/slack.ts
+++ b/src/lib/slack.ts
@@ -79,14 +79,18 @@ export async function deleteFromSlack(token: string, channel: string, messageTs:
return { ok: true, sent: { channel, messageTs } }
}
+export type LookupResult =
+ | { ok: true, messageTs: string }
+ | { ok: false, detail: string }
+
export async function findMessageTs(args: {
token: string
channel: string
text: string
around: Date
window?: number
-}): Promise {
- const window = args.window ?? 30 * 60 * 1000
+}): Promise {
+ const window = args.window ?? 6 * 60 * 60 * 1000
const oldest = (args.around.getTime() - window) / 1000
const latest = (args.around.getTime() + window) / 1000
@@ -95,15 +99,25 @@ export async function findMessageTs(args: {
oldest: String(oldest),
latest: String(latest),
inclusive: true,
- limit: 100,
+ limit: 200,
})
- if (!ok || !Array.isArray(data.messages)) {
- return undefined
+ if (!ok) {
+ return { ok: false, detail: String(data.error ?? 'unknown_error') }
}
- const found = (data.messages as { text?: string, ts?: string }[])
- .find(message => typeof message.ts === 'string' && message.text === args.text)
+ const messages = Array.isArray(data.messages) ? data.messages as { text?: string, ts?: string }[] : []
+ const exact = messages.find(message => typeof message.ts === 'string' && message.text === args.text)
- return found?.ts
+ if (exact?.ts) {
+ return { ok: true, messageTs: exact.ts }
+ }
+
+ const loose = messages.find(message => typeof message.ts === 'string' && (message.text ?? '').startsWith('Logbuch,'))
+
+ if (loose?.ts) {
+ return { ok: true, messageTs: loose.ts }
+ }
+
+ return { ok: false, detail: `no_match_in_${messages.length}_messages` }
}