GASを利用して手軽にSlackの一定期間過ぎた投稿を自動削除するBot作成
Google Apps Scriptで定期的に一定期間過ぎた指定チャンネルの投稿を自動的に削除する方法
Slackの無料のフリープランだと、すぐに最大10,000件のメッセージを使ってしまい、過去のメッセージが見れなくなってしまうため、なるべく不要なメッセージは消したくなるかと思います。
当方のSlackチャンネルには、bot_newsというはてなブックマークのRSSの記事を流し込んでいるチャンネルがあるのですが、1日に20件〜30件投稿されるため、すぐに埋もれていってしまいます。新しい情報を得るためのチャンネルでもあり、あまり検索されるわけでもないため、できれば過去の投稿を消したいと思っていました。
ここでは、AWSなどのSaaSを使用することなく、Googleスプレッドシートと付随するスクリプトを利用して、手軽で簡単に過去の投稿を自動的に削除する仕組みをつくりたいと思います。
既存の情報の問題点
調べると、以下のような記事が見つかるのですが、いくつか問題があります。
Slackの特定チャンネルで一定期間を過ぎた昔の投稿を定期的に削除する
https://qiita.com/hideo-works/items/21c2a6784b7f6caa4c06
SlackAppをライブラリへ利用する前提になっていますが、SlackAppライブラリのメンテナンスが6年前で止まっており、以下の変更により、最新のSlackAPIに対応しなくなってしまいました。
例えば、channels.*と指定していたAPIが、conversations.*に変わります。
https://api.slack.com/changelog/2020-01-deprecating-antecedents-to-the-conversations-api
channels., groups., im., mpim.のSlackAPIが2021年2月24日をもって提供終了となります。これらのAPIで可能だった処理は conversations.*にて全て可能となっています。
Deprecating early methods in favor of the Conversations API
また、表記中のjavascriptのコードが非推奨のものであったり、エディタを旧式にしなければならなかったりと、そのままでは使えない状態です。
準備するもの
構成としては、上記の記事と同様です。
- Slackのトークン取得
- Googleスプレッドシート
- Google Apps Script
- トリガー設定
「どこのチャンネルの投稿をどのタイミングでどのくらい削除する」という命令を作りたいと思います。
ほとんどのことは、Google Apps Scriptの中のプログラミングで実行することになります。
「どこのチャンネル」に対する情報は、Googleスプレッドシートで指定します。
「どのタイミングで」に対する情報は、Google Apps Scriptのトリガー設定で指定します。
そして、それらに必要な鍵が、Slackのトークン取得というイメージです。
やりたいこと
Slackのチャンネルを指定して、一定期間経過したメッセージだけ自動で削除する
具体的には、以下のRSSから自動投稿しているSlackチャンネル(ニュースとセキュリティ情報)の2週間以上経過するメッセージを削除する
- bot_news
- bot_security
削除を実行するタイミングは毎日0時
手順
Slackのトークン取得
SlackAPIを使用するためには、トークン(OAuth Tokens)が必要になります。
以下が参考になるかと思います。
Appを作成して、「OAuth & Permissions」からスコープ(Scopes)を設定します。
App自身の投稿を消すのであれば、Bot Token Scopesで良いです。(※他のユーザーが所属するチャンネルの他のユーザーの投稿を消すためには、権限のあるUser Token Scopesにする必要があります)
必要なスコープは以下です。
- channels:read:チャンネルを取得するため
- channels:history:チャンネル内の削除対象となる投稿を取得するため
- chat:write:投稿を削除するため
そして作成された「OAuth Tokens for Your Team」のAccess Tokenをコピーします。
「xoxp-1111… 」というような文字列です。
割とマニュアルですが、スプレッドシートをGoogle Docsで新規作成して、 Tools → Script Editor でGASのスクリプトを立ち上げます。
Googleスプレッドシート
Googleドライブ上などで、新規スプレッドシートを作成します。
2行目から、削除対象のチャンネル名を記入します。(※先頭の#は不要です)
入力保存したら、「ツール」の「スクリプトエディタ」を選択します。
すると自動的に「Google Apps Script」が起動します。
Google Apps Script
冒頭にあったこちらのコードを参考にしたいと思います。
https://qiita.com/hideo-works/items/21c2a6784b7f6caa4c06
但しSlackAppをライブラリを使用している部分は置き換えます。
//mainコード
function cleanChannels()
{
var sheet = SpreadsheetApp.getActiveSheet();
var values = sheet.getDataRange().getValues();
var channelNames = [];
for (var i = 1; i < values.length; ++i) {
channelNames.push(values[i][0]);
}
var token = PropertiesService.getScriptProperties().getProperty('SLACK_API_TOKEN');
for (var index in channelNames) {
var channelName = channelNames[index];
Logger.log("[%s]",channelName)
cleanChannel(token, channelName);
}
}
SLACK_API_TOKENはスクリプトのプロパティとして別で定義できますが、そのままトークンを直書きでも良いです。
スクリプトのプロパティとして定義するには、
エディタ右に表示される「以前のエディタを使用」を押して旧式のエディタに変更します。
そして、「ファイル」>「プロジェクトのプロパティ」>「スクリプトのプロパティ」と開き、プロパティに「SLACK_API_TOKEN」、値に先程のトークン(xoxp-1111…)を設定します。
以下、その他の関数です。
//チャンネル内投稿削除
function cleanChannel(token, channelName)
{
var channelId = getChannelId(token, channelName);
if (channelId.length == 0) {
return;
}
var date = new Date();
date.setDate(date.getDate() - 14); // 2週間前
var timestamp = Math.round(date.getTime() / 1000) + '.000000';
do {
var result = getChannelHistory(token, channelId, timestamp);
if (result.ok) {
for (var index in result.messages) {
var message = result.messages[index];
var deleteResult = deleteChat(token, channelId, message.ts);
if (deleteResult.ok) {
Logger.log("delete success")
}
}
}
} while (result.ok && result.has_more && count < limit)
}
//チャンネル名->チャンネルID取得
function getChannelId(token, channelName)
{
var channelId = '';
var result = getChannelList(token);
if (result.ok) {
for (var index in result.channels) {
var channel = result.channels[index];
if (channel.name == channelName) {
channelId = channel.id;
break;
}
}
}
return channelId;
}
//チャンネル一覧取得
function getChannelList(token) {
var url = 'https://slack.com/api/conversations.list' +
'?token=' + token;
var response = UrlFetchApp.fetch(url)
return JSON.parse(response)
}
//チャンネル内投稿取得
function getChannelHistory(token, channelId, timestamp) {
var latest = timestamp;
var url = 'https://slack.com/api/conversations.history' +
'?token=' + token +
'&channel=' + channelId +
'&latest=' + latest +
'&inclusive=' + true;
var response = UrlFetchApp.fetch(url)
return JSON.parse(response)
}
// 投稿削除
function deleteChat(token, channelId, timestamp) {
var url = 'https://slack.com/api/chat.delete' +
'?token=' + token +
'&channel=' + channelId +
'&ts=' + timestamp;
var response = UrlFetchApp.fetch(url)
return JSON.parse(response)
}
トリガーを設定する
Google Apps Scriptの左メニューのトリガーを選択し「トリガー追加」ボタンを押します。
毎日0時に作動するよう以下のように設定します。
補足
SlackAPIの仕様変更があると、また変わる可能性がありますが、現時点では変わったばかりということで、しばらくは乗り切れそうです。
カスタマイズしたい場合は、スクリプト上でログ出力もできますし、ブレークポイントを貼ってデバッグもできます。API単体のテストは、SlackAPIの各種メソッドのドキュメント中の「Tester」タブでテストできます。
また、特にchat.deleteメソッドは連続的に複数回呼ばれると思いますので、削除する投稿数によっては、制限に引っかかる可能性があります。
その場合、レスポンスコード429の"ratelimited"エラーが返ります。
メソッドは、「Rate limiting: Tier 3」ということで、1分間に50回程度のアクセスは可能とのことですが、体感的には30回程度でエラーになっていました。
Web API Tier 3 50+ per minute Tier 3 methods allow a larger number of requests and are typically attached to methods with paginating collections of conversations or users. Sporadic bursts are welcome.
Web API Tier 3
一回の削除件数が多くなるようであれば、トリガーを増やして頻度を上げると良いかもしれません。