【GAS, JavaScript, Slack API】古いポストから一定期間が過ぎたら自動削除するbotはGASが超簡単!

13 / 06 / 2018
Category: FRONTEND, GAS, JavaScript
Tags: | |

どうもー、ドイツでフリーランスのフロントエンドエンジニアをしています Arisa です。

ワーホリビザはとっくに切れ、仮ビザでフリーランスビザ申請待ちを見事に喰らいましたが、普通に仕事していいよとのことなので、変わらずドイツで過ごしています。

詳細はもう少し申請が進んでからまた書こうと思っています。(御察しの通り長くなるので 笑)

 

今日はSlackに一定期間が過ぎたら古いポストから順に自動で消すボットを作成して導入したときの備忘録です。

Slackの無料枠って、意外と100人以上の規模の活発な組織で使用すると8ヶ月ほどで上限を超えそうになるようで、無料枠に抑え続けるための秘策といえば、自動投稿削除ボット。

私が普段関わっているオンラインサロン、wasabiの海外フリーランス養成スクールの運営者であるwasabiさん( @wasabi_nomadik)が、サロンで使用しているSlackが無料枠上限に達しそうということで、担当させていただいたのが実はきっかけなんです。

 

GAS(Google App Script)やSlack API、JavaScript、ボット搭載に興味がある人向けの記事です。

吐き出されたエラーやハマったポイントも含んでます。

 

GASをJavaScriptで書くことができるのは今まで知らなかったので、なんでこんな便利な技術を知らなかったんだろうと思ったぐらい、目からウロコ情報でした!

JavaScriptで書くといってもそこまで難しいものではなく、for文、for each、do while、if文、ちょっとした比較演算子やANDが書ければ、あとはスプレッドシートにアクセスする関数と組み合わせればOKという感じです。

 

Contents

前書き

 

実装したい内容

 

まず実装したい内容は以下。

 

- 設定した期間で定期的に古いポストから順に自動削除

- 削除対象のチャンネルを指定できるようにする

 

制限

 

実装後に気が付いたんですが、やっぱりそれなりに制限はあるようです。

 


- #general チャンネルは無効だった - 多分DMも無効 - スクリプトはES5仕様で書く

 

予備知識

 

Container Bound Script(スプレッドシートに紐付けたスクリプト)と独立したスクリプトの違い

 

これはGASでSlackボットを作成する内容のチュートリアル記事でよく省略されている内容で、知っていると超初歩内容なのですが、知らないとハマることも。(私だけかもですが)

 

まずContainer Bound Scriptは、Google スプレッドシートを先に作成してから、スクリプトを紐付けしてあります。

割とマニュアルですが、スプレッドシートをGoogle Docsで新規作成して、 Tools → Script Editor でGASのスクリプトを立ち上げます。

 

 

A列に書いてあるのは、紐付けさせるSlackの自動ポスト削除ボットを導入したいチャンネル名です。

スクリプトが立ち上がると、そこにコードを書き始めることができます。

この時点ですでにスクリプトファイルとスプレッドシートは、紐付けによりアクセスできる状態です。

 

反対に、独立したスクリプトというのは、以下のスクショのようにGASスクリプトファイルをスプレッドシートとはまずは紐付けせずに単独で作成するスクリプトです。

 

 

上記で Google App Script を選択して、GASスクリプトを立ち上げます。

この時点ではスプレッドシートとは何も紐付けはない状態なので、アクセスはできません。

 

どういうときに使い分けをするのが便利かということですが、

 

「スプレッドシートには他人に書き込み権限を与えたい。でもスクリプトに書き込めるのは自分だけにしたい」

 

という場合には、独立したファイルを作る必要があります。

そこまでこだわらない、もしくは他の人にむしろスプレッドシートでチャンネル名を管理させたいというときには紐付けされたスクリプトを作るのが良いですね。

 

ハマったポイント:Container Bound Scriptと独立したスクリプトはアクセスする書き方が違う

 

ハマったというと大げさですが、地味に上記のContainer Bound Scriptのことを知らず、「どうやってスプレッドシートにアクセスするのか?もしや関数が用意されている?」と、ちょっと時間を無駄にしてしまったので、これは知っておくと便利。

 

まずスプレッドシートにアクセスできなければGASスクリプトを書いてもお互い独立しているのであれば何も意味がないので、アクセスしている方法の違いに着目します。

 

Container Bound Scriptは、すでにスプレッドシートからGASスクリプトを新規作成しているので、アクセスはすでにできる状態。

なのでアクセスは以下の書き方になります。

 

var sheet = SpreadsheetApp.getActiveSpreadsheet();

 

一方まだ紐付けされていない独立スクリプトは、以下の書き方でアクセス。

 

var sheet = SpreadsheetApp.openById('<キー>'); // スプレッドシートのURLがキー

 

このアクセス方法の書き方が違うと、エラーログが吐き出されるので、Container Bound Scriptなのか、独立スクリプトなのかを把握する必要は大事。

 

手順1:Google スプレッドシート作成

 

Container Bound Scriptで作成する

 

さて、前置きが長くなりましたが早速ボットを作成していきましょう。

Container Bound Scriptが個人的には簡単だったので、まずは紐付けしたスクリプトをスプレッドシートから上記手順で作成。

 

SlackAppをライブラリに追加する

 

Slack APIをGASから呼び出すので、そういったときにはSlackAppを使用するのが簡単で便利です。

まずは、こちらのSlackAPPのGithubにある Library Key をコピー。

 

GASスクリプトファイルの上部より、Resources → Libraries... を選択し、以下のスクショ画面で先ほどコピーしたライブラリ キーをペーストし、 Add を選択。

以下のように記入 & バージョンを選択して保存。

 

 

ググると上記のスクショ箇所のバージョンを何も選択していない非表示で追加するように書いてある記事をいくつか見ましたが、2018年6月現在では ver. 22 がエラーログが吐き出されることなく、無事にSlackAppをライブラリに追加することができます。

 

これでライブラリにSlackAppが追加され、使用できるようになりました。

 

SlackのトークンをGASのスクリプトのプロパティへ追加

 

まだスクリプトを書く準備は最後に1つだけ残っています。

Slackでトークンを発行する必要があるので、まずはこちらのLegacy TokensページでSlackにログインした状態でトークンを発行します。

 

トークンが発行できたらGASスクリプトページに戻って、 File → Project Property... を選択し、以下のスクショのようにトークンを貼り付け、プロパティ名をつけて保存。

 

 

これでスクリプト内でトークンを呼び出せます。

 

GASでスクリプトを実装

 

ここからが実際のスクリプトを書いての実装です。

コメントアウトで機能の説明補助をしていますので参考にしてください。

 


function cleanChannels() {
    var sheet = SpreadsheetApp.getActiveSheet(); // Container Bound Scriptでスプレッドシートにアクセス
    var values = sheet.getDataRange().getValues(); // 値が入っているシートの全セルをRangeオブジェクトとして取得

    var channelNames = [];
    for (var i = 1; i < values.length; ++i) {
        channelNames.push(values[i][0]);
    }

    var token = PropertiesService.getScriptProperties().getProperty('SLACK_API_TOKEN'); // トークン
    var slackApp = SlackApp.create(token);

    for each(var channelName in channelNames) {
        cleanChannel(slackApp, channelName);
    }
}

function cleanChannel(slackApp, channelName) {
    var channelId = getChannelId(slackApp, channelName);
    if (channelId.length == 0) {
        return;
    }

    var date = new Date();
    date.setDate(date.getDate() - 5); // 5日前の投稿取得
    var timestamp = Math.round(date.getTime() / 1000) + '.000000';

    do {
        var optParams = {
            latest: timestamp,
            count: 1
        };
        var result = slackApp.channelsHistory(channelId, optParams);
        if (result.ok) {
            for each(var message in result.messages) {
                slackApp.chatDelete(channelId, message.ts); //5日前の投稿取得 → 削除のループ
            }
        }
    } while (result.ok && result.has_more)
}

function getChannelId(slackApp, channelName) { // チャンネル名からチャンネルIDの取得
    var channelId = '';
    var result = slackApp.channelsList();
    if (result.ok) {
        for each(var channel in result.channels) {
            if (channel.name == channelName) {
                channelId = channel.id;
                break;
            }
        }
    }
    return channelId;
}

 

 

スクリプトを承認

 

スクリプトを書いただけでは、関数 cleanChannels を実行のつもりで Run とGASスクリプトファイルから押しても実行されず、エラーログが出ます。

そもそもトリガーがまだないので、いつ実行していいかはGASには伝わっていないです。

 

ここでトリガーを設定したいのですが、その前に、スクリプトを実行しようとRunしてもエラーログが返ってくると書きましたが、このエラーログはどちらかというとトリガーの設定がないのもそうですが、先にトリガーを設定しても、サーバーエラーのログが出てトリガーも設定できません。(2018年6月現在)

 

まずすべきこととしては、スクリプトの実行Runを押下したときに出てくる以下のスクショ画面で、Googleの認証をする必要があります。

 

 

Review Permission をクリックしますが、ここでもエラー画面が出ます。

ただし、エラー画面といっても内容は承認をするための工程画面なので、 Advanced をクリック。

 

 

そうすると、表記は小さいのですが、スクリプトやスプレッドシートにつけたファイル名のアプリケーションにアクセス承認をするような誘導があるので、クリック。

 

持っているGoogleアカウントを選ぶように誘導があるので、使いたいアカウントを選択。

 

 

以下のスクショ画面になるので Allow で承認。

 

 

GASのスクリプト画面に戻ったら無事トリガーを追加できるようになりました。

これも実は結構省略されている内容の情報が多く、微妙にハマったポイントかもしれません。

 

トリガーを設定

 

あとはここでトリガーを設定するだけで、基本的にボットは使えるようになります。

トリガーの設定の仕方は非常に簡単。

 

Edit → Current Project Triggers をGASスクリプト画面から選択し、以下の様に Day Timer で設定します。

 

 

これで保存をし、スクリプトを実行すると完了です。

実際に反映をすぐ見たいという場合は、スクリプトを1日前の投稿を削除に変更し、トリガーを現在の時間に合わせると反映をすぐ確認できます。

 

ただし、事前に前日に何かしら #generalかDM以外のチャンネルに投稿している必要があります。

投稿が削除の対象なので、画像ファイルとチャット両方が消えていることが確認できます。

 

まとめ

 

Slackはチーム開発だけでなく、もはやプロジェクト単位、はたまたオンラインサロンや企業、コミュニティなど幅広く使われるようになっています。

一定期間を過ぎた投稿から削除するボットだけでなく、ファイルだけを削除するボットや、自動応答するボットなど、Slack APIやGASの組み合わせで、とても手軽にJavaScriptが書ける人であれば導入することができるようです。

 

Slack APIもとてもたくさんのドキュメントが用意されているので、もっと効率よくチームがSlackで関わっていけるようにするためのカスタマイズがたくさんあるようです。

今回はSlackの無料枠を超えそうな時のメジャーな解決策としてのお役立ちボットですが、そのほかにもいろんなことができそうですね。

 

この記事がお役に立てれば幸いです。

では

 

ちゅーす

SHARE

Comments

  1. Non より:

    参考にさせていただきました。

    実行時に以下のようなエラーが表示されて「channelId」が取得できないようです。

    TypeError: undefined のメソッド「channelsList」を呼び出せません。(行 44、ファイル「コード」)

    Library KeyもTokenも正確に思えるのですが、ご教示いただけると幸いです。
    よろしくお願いいたします。

    • ARISA ARISA より:

      Nonさん、

      初めまして、参考にしていただき光栄です:)
      実際のコードを見ていないので、状況は詳しく把握しかねますが、この方法もチャット数や画像数の多い大きなSlackコミュニティ規模になると5分の関数実行時間をオーバーしてしまい、実行はできず、エラーログが吐き出されます。

      44行目と言われているあたり、もしコードがほぼ似ているのであれば、チャンネル名からチャンネルID取得の関数箇所の可能性が高いので、チャンネル名が英語になっているかどうかを確認する必要はあります。日本語名だと反映されないことがあるので⚡️

      直接的な解決策になるかどうかはわかりませんが、参考にしていただければ幸いです:)

      • Non より:

        ARISA様

        ご返信ありがとうございます!
        スクリプトはそのまま使わせていただいているので、まさに”チャンネル名からチャンネルID取得の関数箇所”ですね…

        当方、非エンジニアで家族でのツールをLINEなどではなくSlackのフリープランを使いつつ、興味のあるニュースなどをRSSで取得して自動投稿してるので、放って置くと1万件に到達してしまうので、そのチャンネルのRSSから投稿されたものを一定期間過ぎたら自動的に削除したいな、と思い参考にさせていただきました。

        ちなみに、チャンネル名は英語ですが、パブリックではなくプライベートチャンネルです。このあたりも関係しそうでしょうか?

        質問ばかりで申し訳ありませんmm
        よろしければご教示いただけると幸いです。
        ※コマンドだとハードルが高く、GASでと考えておりました…

        • ARISA ARISA より:

          LINEではなく、Slackを選ばれた理由は何かあるのですか?💡

          特段理由がないのであればLINEだとそこまで制限を気にしなくても良いように思います:)

          チャンネルの種類は関係がある場合があります。

          例えばこの記事の方法ではDMは対象外です。

          パブリックチャンネルを試してうまく行けばチャンネルの種類による問題だと思います💡

          あと、すでにご使用中のSlackアカウントでチャット数や画像数があるのであれば、実行時間5分をこのコードでは回避するよう実装されていないので、エラーが返されます。

          • NON より:

            度々ご回答ありがとうございます。

            各ツールとのインテグレーションを活用しているので、LINEは対象外ですね…
            ご指摘の通り、プライベートチャンネルでやっていたので、パブリックで試してみたいと思います。

Leave a Comment

お名前、メールアドレスも必須項目です。メールアドレスが公開されることはありません。

Check before you submit.

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください