短期間で投稿が削除されるライブチャンネルを導入してSlackを節約する

毎年12月しかブログを書かずカレンダーに穴を開けている人です。
総コンAdvent Calendar 2018 2日目。 adventar.org

私の所属する大学のサークルではSlackを使って連絡を取っています。
資金的な余裕がないので無料プランで利用しているのですが、その場合困るのが10000件のメッセージ制限。
そこで昔のメッセージが自動で消える「ライブチャンネル」というものを実装しました。 (名前は独自に名付けた)
これによりゆるーい会話もできて重要なメッセージも残りやすい環境をというのが今回のテーマです。

仕組み

今回はこちらの記事をかなり参考にしています。
こちらと同じくGoogle Apps ScriptとSlackのAPIを使用します。

qiita.com

ただできるだけ保守の手間がかからないようにしたかったので、このような仕組みになっています。
設定は全てスプレッドシート上で変更可能です。

  • ライブ化するチャンネルを正規表現を使って抽出する
  • 残すメッセージの投稿期間を指定する
  • 1日1回指定の期間を過ぎたメッセージを自動で削除する

弊サークルでは名前に live が含まれるチャンネルをライブチャンネルに設定しています。
この仕組みだと新しく live_hoge という名前でチャンネルを作れば自動的にライブ化させることができます。
また後から名前を変更しても適用されます。

スクリプトはこちら

docs.google.com

使い方

SlackのAPIトークンを取得する

  • この辺を参考にレガシーでないトークンを取得してください (レガシーなやつは色々危険)
  • 必要なスコープ
    • chat:write
    • channels:read
    • channels:history

スクリプトを設定する

  1. 上メニュー ファイルコピーを作成
  2. ツールスクリプトエディタスクリプトを開く
  3. ファイルプロジェクトのプロパティスクリプトのプロパティSLACK_API_TOKENトークンを設定する
  4. 編集現在のプロジェクトのトリガー → 右下 トリガーを追加 から以下の2つを設定する
  5. 時刻はアクティブが低そうな時間帯にしています

f:id:tkww:20181201033359p:plain

メッセージを削除する

  • 最初はスプレッドシートの上メニュー FunctionsClean Channels から手動で削除してください
  • GASは処理に6分以上かかると強制的に処理が終了するので、大量のメッセージを削除する初回はオーバーする可能性があります
    • その場合はもう1度ボタンを押してください (すぐ処理が終わるようであれば削除されているはずです)
    • ワークスペースの管理者であれば https://[workspace-name].slack.com/admin/stats からメッセージ数が見られるので減っているか確認できます
  • Channelsに指定したチャンネルが追加されます
  • デフォルトでは live live_** **_live **_live_** のチャンネルが対象です

スクリプトについて

トークンは普通に変数で指定してもいいですが、GASの機能であるスクリプトのプロパティを使いました。
保存するメッセージの期間や正規表現スプレッドシート側で設定し、実行時に毎回読み込んでいます。
通常は行と列の番号で指定しますが、GASにはExcelと同じく名前付き範囲というものがありセルの範囲に名前を付けられます。
名前付き範囲は行や列の挿入や削除でセルの位置が変わっても自動的に位置を移動してくれるので、セルの位置やシートの名前に依存しないスクリプトが組めて大変便利です。
今回はそれを使ってシート側の設定を取得しています。

トリガーで呼ばれる関数が cleanChannels です。

function cleanChannels() {
  var channels = updateTargetChannels();
  
  var periodDay = getNamedRange('period').getValue();
  var date = new Date();
  date.setDate(date.getDate() - periodDay);
  var timestamp = Math.round(date.getTime() / 1000) + '.000000';
  
  channels.forEach(function(channel) {
    var count = cleanChannel(channel.id, timestamp);
    console.log('clean ' + count + ' messages in ' + channel.name);
  });
}

最初に対象のチャンネルを取得して、それぞれのチャンネルで指定の期間を過ぎているメッセージを削除します。

チャンネルを掃除すると、Stackdriverのログにどのチャンネルで何件消したかログを残します。
GASには最後の実行時の出力しか見られない簡易的なログと、Stackdriverというデバッグ用のツールに出力するログの2種類あります。
毎回の実行結果を溜めておきたい場合は後者を使います。
なおログをとんでもなく溜めすぎると有料になります。 個人で使う場合はだいたい大丈夫です。
ログはスクリプトを開いて 表示Stackdriver logging から見られます。

正規表現にヒットするチャンネルを取得するのがこれです。

function updateTargetChannels() {
  var regex = new RegExp( getNamedRange('regex').getValue() );
  var targetChannelsRange = getNamedRange('channels');
  
  var channels = slackApp.channelsList().channels;
  var targetChannels = [];
  var targetChannelNames = [];
  channels.forEach(function(channel) {
    if (regex.test(channel.name)) {
      targetChannels.push(channel);
      targetChannelNames.push([channel.name]);
    }
  });
  
  var sheet = targetChannelsRange.getSheet();
  sheet.getRange(targetChannelsRange.getRow(), targetChannelsRange.getColumn(), targetChannelNames.length, 1).setValues(targetChannelNames);
  return targetChannels;
}

Slack APIchannels.list でチャンネルの一覧を取得して、一つ一つチャンネル名が条件にヒットするか探索します。

対象チャンネル内のメッセージを削除する関数がこちらです。

function cleanChannel(channelId, timestamp) {
  var count = 0;
  do {
    var optParams = {
      latest: timestamp
    };
    var result = slackApp.channelsHistory(channelId, optParams);
    if (result.ok) {
      result.messages.forEach(function(message) {
        slackApp.chatDelete(channelId, message.ts);
        count++;
      });
    }
  } while(result.ok && result.has_more);
  return count;
}

channels.history でチャンネルのメッセージ履歴を取得します。
chat.delete はチャンネルIDとメッセージのタイムスタンプを指定して削除するメソッドです。
Slackにはここからここまでの期間のメッセージを消すというAPIがないので1つ1つAPIを叩いて消しています。

スクリプトの本質の部分は以上です。

ライブチャンネルの使い道

弊サークルではプレゼンするイベント中にSlackで実況する文化があるので、実況用のチャンネルに割り当てています。
イベントの期間だけ1日で百件以上の投稿があるので1週間経ったら消えるようにしています。
(ちなみにその影響で制度導入前は半年の間に全体で1万件のメッセージが投稿されていました)
あとはAPIテスト用のチャンネルや通知専用のチャンネルに割り当てると効果的です。
分報文化が盛んなワークスペースは分報チャンネルに割り当てるとだいぶ削減できると思います。

ライブチャンネルの副作用

良い意味でも悪い意味でも副作用があって、それは発言の敷居が下がることです。
すぐ消えるとあれば割と適当なことを呟きまくるチャンネルが発生します。
私はそれをいい副作用と捉えて導入することにしました。
大学のサークルとあって誰でも発言しやすいコミュニティの方が交流が盛んになるので十分メリットがあると思いました。
コミュニティによっては保存期間を1日とかさらに短くして、よりライブ感のあるチャンネルを作ってみてもいいかもしれません。

おわりに

Slackの活性化は私がSlackを導入した時に悩んだ課題です。
連絡ツールとして機能を果たすことも大事ですが、どうでもいい会話や情報共有がコミュニティの活発化に繋がると思います。
活性化すればするほど1万件制限が厳しくなるので、金銭的に余裕がある場合は課金した方が吉です。
Slackをサークルに導入したときの話は友人が書いてくれているので、こちらも参考までにご覧ください。

sector.hatenablog.com