Skip to content

Instantly share code, notes, and snippets.

@Toanzzz
Forked from firatkucuk/delete-slack-messages.js
Last active January 21, 2020 18:53
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Toanzzz/0bc9f903207a6cd4d51ada76edd45513 to your computer and use it in GitHub Desktop.
Save Toanzzz/0bc9f903207a6cd4d51ada76edd45513 to your computer and use it in GitHub Desktop.
Deletes slack public/private channel and chat messages.
#!/usr/bin/env node
// Channel ID is on the the browser URL.: https://mycompany.slack.com/messages/MYCHANNELID/
// Token can get from: https://api.slack.com/custom-integrations/legacy-tokens
// Pass it as a parameter: node ./delete-slack-messages.js TOKEN CHANNEL_ID
// Or use it without download the script: curl -Ls RAW_GIST_URL | node - TOKEN CHANNEL_ID
// GLOBALS #############################################################################################################
const [, , token, channel, _delay = 300] = process.argv
let delay = _delay // Allow inscrease delay later - thanks `colinricardo` for pointing it out
if (!token || !channel) {
console.log('Usage: node ./delete-slack-messages.js TOKEN CHANNEL_ID')
console.log('Usage: curl -Ls RAW_GIST_URL | node - TOKEN CHANNEL_ID')
process.exit(1)
}
const https = require('https')
const baseApiUrl = 'https://slack.com/api'
const historyApiUrl = `${baseApiUrl}/conversations.history?token=${token}&count=1000&channel=${channel}&cursor=`
const deleteApiUrl = `${baseApiUrl}/chat.delete?token=${token}&channel=${channel}&ts=`
// ---------------------------------------------------------------------------------------------------------------------
const sleep = ms => new Promise(r => setTimeout(r, +ms))
const getJsonAsync = url =>
new Promise((resolve, reject) =>
https
.get(url, res => {
let body = ''
res.on('data', chunk => (body += chunk))
res.on('end', () => resolve(JSON.parse(body)))
})
.on('error', reject)
)
async function deleteMessage(messages) {
console.log(`Deleting ${messages.length} messages`)
while (messages.length > 0) {
const ts = messages.shift()
const response = await getJsonAsync(deleteApiUrl + ts)
if (response.ok === true) {
console.log(ts + ' deleted!')
} else if (response.ok === false) {
console.log(ts + ' could not be deleted! (' + response.error + ')')
if (response.error === 'ratelimited') {
await sleep(1000)
delay += 100 // If rate limited error caught then we need to increase delay.
messages.unshift(ts)
}
}
await sleep(delay)
}
}
// ---------------------------------------------------------------------------------------------------------------------
async function processHistory() {
let nextCursor = ''
while (true) {
const { ok, error, messages, has_more, response_metadata } = await getJsonAsync(historyApiUrl + nextCursor)
if (!ok) throw new Error(error)
if (Array.isArray(messages)) await deleteMessage(messages.map(z => z.ts))
else console.log('No message found')
if (!has_more) break
nextCursor = response_metadata.next_cursor
}
}
// ---------------------------------------------------------------------------------------------------------------------
processHistory().catch(console.log)
@Toanzzz
Copy link
Author

Toanzzz commented Sep 6, 2019

Update:
You can now use the gist without downloading it (using cURL and make node execute script from stdin)

curl -Ls RAW_GIST_URL | node - TOKEN CHANNEL_ID

@colinricardo
Copy link

One thing here: if you get rate limited, then the script tries to reassign the delay variable, which is a const, so the script fails.

Something like the following will fix it:

Change:

const [, , token, channel, delay = 300] = process.argv

to:

const [, , token, channel] = process.argv
let delay = 300;

@Toanzzz
Copy link
Author

Toanzzz commented Dec 16, 2019

Yeah you're right, thanks for pointing it out @colinricardo 👍

Gist updated 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment