EY-Office ブログ

Slack無料プラン変更で90日以前の投稿が見えなくなるので、ダイレクトメッセージのバックアップツールを作った

EY-OfficeではSlackを使っていますが無料プランで済ましています。しかし最近Slack 初の料金改定とフリープランの内容変更のお知らせで90日以前の投稿が見えなくなるそうなのでダイレクトメッセージをバックアップするツールを作りました。

Slack

なぜ有料プランにしないのか

EY-OfficeもSlackは使っていますが、有料プランの必要性をかんじなかったので無料プランで使っています。

理由は、

  • 社内でSlackは使っていない、EY-Officeは2人でやっていますが、職種が違うのでSlackを使って密にコミュニケーションする必要は感じません
  • お客様とのコミュニケーションはSlackが多いですが、お客様のチャンネルに招待してもらうので有料プランは不要です
  • オンライン教育でSlackを使いますが、教育の期間のみの利用で教育が終わればアーカイブして消してしまうので、今のところ有料プランの必要性を感じていません

ダイレクトメッセージをバックアップするツール

Slackのチャンネルは設定画面からエクスポートできますが、ダイレクトメッセージは無料プランではエクスポート出来ないので自分で作ることにしました。
このQiitaの記事を参考に作りました。

  • 以下のPermissionを持つアプリを作成しワークスペースに追加しました
    • channels:history
    • files:read
    • groups:history
    • im:history
    • mpim:history
  • .envファイルに以下を設定
    • CHANNEL_ID= ダイレクトメッセージのチャネルID(右クリック → コピー → リンクをコピー で取得)
    • USER_OAUTH_TOKEN= 作成したアプリのUser OAuth Token
  • バックアップファイルはAPIで取得されたJSONデータです
  • 使い捨てツールなのでany型を使ってます😅
import fetch from 'node-fetch'
import 'dotenv/config'
import { writeFileSync } from 'fs'

const getSlackMessage = async () => {
  const apiURL =
    `https://slack.com/api/conversations.history?channel=${process.env.CHANNEL_ID}`
  let cursor: string | undefined = undefined
  let messages: Array<any> = []

  try {
    do {
      const url = cursor ? apiURL + `&cursor=${cursor}` : apiURL
      const request = await fetch(url,
        {headers: {Authorization: `Bearer ${process.env.USER_OAUTH_TOKEN}`}})
      const response:any = await request.json()
      if (response.ok) {
        messages = messages.concat(response.messages)
        cursor = response?.response_metadata?.next_cursor
      } else {
        console.log("### Not ok", url)
        return messages
      }
    } while (cursor)
    console.log("--- end", messages.length)
    return messages
  } catch (err) {
    console.log("### Error", err)
    return messages
  }
}

const getAndSave = async () => {
  const messages = await getSlackMessage()
  writeFileSync("/tmp/slack/SLACK.json", JSON.stringify(messages.reverse()))
}


getAndSave()

添付ファイル

ダイレクトメッセージに添付したファイルも取っておいた方が良いかなと思い。添付ファイルも取得するコードも作りました。

  • 上のコードを少し変更して作ったものなので一緒にすることも出来ると思いますが、使いすてツールなのでコピペで作りました😅
  • 画像等のバイナリーファイルの取得は少し面倒ですね
import fetch from 'node-fetch'
import 'dotenv/config'
import { writeFile } from 'fs/promises'

type DownloadFile = {url: string, name: string}

const getSlackMessage = async () => {
  const apiURL = 
    `https://slack.com/api/conversations.history?channel=${process.env.CHANNEL_ID}`
  let cursor: string | undefined = undefined

  let downloads: Array<DownloadFile> = []
  try {
    do {
      const url = cursor ? apiURL + `&cursor=${cursor}` : apiURL
      const request = await fetch(url,
        {headers: {Authorization: `Bearer ${process.env.USER_OAUTH_TOKEN}`}})
      const response:any = await request.json()
      if (response.ok) {
        console.log(response.messages.length)
        response.messages.forEach((message:any) => {
          if (message.files) {
            message.files.forEach((file:any) => {
              console.log(`${file.url_private_download}`)
              downloads.push({url: file.url_private_download, name: file.name})
            })
          }
        })
        cursor = response?.response_metadata?.next_cursor
      } else {
        console.log("### Not ok", url)
        return downloads
      }
    } while (cursor)
    console.log("--- end")
    return downloads
  } catch (err) {
    console.log("### Error", err)
    return downloads
  }
}

const getSlackFile = async (url: string): Promise<any> => {
  const request = await fetch(url,
    {headers: {Authorization: `Bearer ${process.env.USER_OAUTH_TOKEN}`}})
  const data = await request.blob()
  return data
}

const getAndSave = async () => {
  const downloads: Array<DownloadFile> = await getSlackMessage()
  downloads.forEach(async(download:DownloadFile) => {
    const data:Blob = await getSlackFile(download.url)
    await writeFile(`/tmp/slack/${download.name}`,
      Buffer.from(await data.arrayBuffer()))
  })
}


getAndSave()

まとめ

ということで、無事に保存しておいた方が良さそうなダイレクトメッセージをアーカイブできました。
はたして、このアーカイブを使う事はあるのでしょうか? 😁

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ