Slackでスタンプがしたい

Slackの絵文字ってちっさくて見えないよね？だから大きくしてみようぜ！っていう話

# 先行事例

調べたらやってる方がいらっしゃった。

- [Slackの絵文字をLINEのスタンプみたいに大きく使えるようにしてみた](https://blog.icchi.me/slack-stamp-post/)

ただ、今回自分が作りたいものはすぐに誰でもできるようにしたかったので、ユーザートークンをとってきたりすることは不必要とした。また、ドライブのフォルダに絵文字のエイリアス(例: :thinking:=thinking)と同じ名前の画像をアップロードするだけで使えるようにした。

# Outgoing Webhook(発信 Webフック)

先行事例に則ってOutgoing Webhook(発信 Webフック)を設定する。Integration(カスタムインテグレーション)から作成する。

<img width="375" alt="Outgoing Webhookの説明画像" src="https://qiita-image-store.s3.amazonaws.com/0/191209/09fdd5ca-ed00-3526-31a8-f5c98ca2491f.png">

こんな感じで、「引き金となる言葉」のところに「：」を登録する。それだけ。説明とかはお好みで。URLだけはあとで作成するGASスクリプトのURLを設定する。

# 投稿用のbotを作成する

同じく、Integration(カスタムインテグレーション)から作成する。このとき、

<img width="375" alt="ueckoken.slack.com_services_B26DEHP5Y(iPhone 6_7_8).png" src="https://qiita-image-store.s3.amazonaws.com/0/191209/c9f80696-f0e2-e022-f05f-d7ebea7b1ae2.png">

tokenをコピーしておく。

# GASスクリプトの作成

Googleドライブから作成する。左上の新規→その他→Google Apps Scriptを選択。名前を適当につけて編集画面へ

GASでSlackAPIを叩くためのライブラリとして、soundTrickerさんの「[Slack BotをGASでいい感じで書くためのライブラリを作った](https://qiita.com/soundTricker/items/43267609a870fc9c7453)」を使わせてもらう。導入方法はこの素晴らしい記事を参考に。

その後以下のコードをコピーする。

```js:bigstamp.js
///Googleドライブ上の画像フォルダのID
var folderID = ""

function doGet(e) {
}

function doPost(e) {
    if (!e) {
        // 異常終了
        return null;
    }
    if (e.parameter.user_name == "slackbot") {
        // slackbotの投稿は無視する
        return null;
    }
    // パラメータにテキストがなかったら終了
    if (!e.parameter.text) {
        throw new Error("exit");
    }
    //スタンプだけのテキストじゃなかったら終了
    if (!isStamp(e.parameter.text.trim())) {
        throw new Error("exit");
    }
    //最長一致
    var m = e.parameter.text.match(/\:(.+)\:/);
    var textMessage = "";
    if (m && m[1]) {
        textMessage = m[1];
        var files = DriveApp.getFolderById(folderID).getFiles();
        var file = undefined;
        for (var i = 0; files.hasNext(); i++) {
            file = files.next();
            var filename = file.getName().replace(/(.+)\..+$/, "$1");
            if (filename == m[1]) {
                textMessage = filename;
                break;
            }
        }
        if (file) {
            var fileId = file.getId();
            var date = new Date();
            var stamp_url = "https://drive.google.com/uc?id=" + fileId + "&" + date.getTime();
            var channel_id = e.parameter.channel_id;
            var user_name = e.parameter.user_name;
            ///SlackのBotsのトークン
            var token = "";
            var att = [{ "fallback": "スタンプを送信しました", "image_url": stamp_url }];
            param = {
                attachments: JSON.stringify(att),
                as_user: true,
            };
            var app = SlackApp.create(token);
            if (e.parameter.thread_ts !== undefined) {
                param["thread_ts"] = e.parameter.thread_ts;
            }
            var post_info = app.postMessage(channel_id, "", param);
        }
    }

    return true;
}

///
/// スタンプかどうかのチェック関数
/// 最初と最後が：ならスタンプとみなす(だから絵文字で挟むともしかしたら余計な判定をするかも)
///
function isStamp(text) {
    if (text.slice(0, 1) == ":" && text.slice(-1) == ":") return true;
    else return false;
}
```

このうち最初の
`var folderID = ""`
にGoogleドライブ上の画像フォルダのIDを入れる。IDはそのフォルダにアクセスしたときの`https://drive.google.com/drive/u/0/folders/hogehogefugafuga`だったらhogehogefugafugaのところ。

これだけでOK

# コードの説明

まず最初の

```js:bigstamp.js
function doPost(e) {
    if (!e) {
        // 異常終了
        return null;
    }
    if (e.parameter.user_name == "slackbot") {
        // slackbotの投稿は無視する
        return null;
    }
    // パラメータにテキストがなかったら終了
    if (!e.parameter.text) {
        throw new Error("exit");
    }
    //スタンプだけのテキストじゃなかったら終了
    if (!isStamp(e.parameter.text.trim())) {
        throw new Error("exit");
    }
    ...
```

は、SlackからのPOSTであることと、次の部分に移る前のバリデーションチェックである。

```js:bigstamp.js
    //最長一致
    var m = e.parameter.text.match(/\:(.+)\:/);
    var textMessage = "";
    if (m && m[1]) {
        textMessage = m[1]
        var files = DriveApp.getFolderById(folderID).getFiles();
        var file = undefined
        for (var i = 0; files.hasNext(); i++) {
            file = files.next();
            var filename = file.getName().replace(/(.+)\..+$/, "$1");
            if (filename == m[1]) {
                textMessage = filename;
                break;
            }
        }
        ...
```

この部分は、受信したテキストメッセージのうち絵文字のエイリアスのところを持ってくる部分と、それと一致する名前をもつ画像をドライブから検索する部分である。このあたりはTakumaKawashiroさんの「[GAS入門 - DriveAppクラスリファレンス](https://qiita.com/TakumaKawashiro/items/b32be642d05269e4b28f)」を参考につくってみた。<font color="lightgray">for文のなかでbreakするのは許して</font>

```js:bigstamp.js
        if (file) {
            var fileId = file.getId();
            var date = new Date();
            var stamp_url = "https://drive.google.com/uc?id=" + fileId + "&" + date.getTime();
            var channel_id = e.parameter.channel_id;
            var user_name = e.parameter.user_name;
            ///SlackのBotsのトークン
            var token = "";
            var att = [{ "fallback": "スタンプを送信しました", "image_url": stamp_url }];
            param = {
                attachments: JSON.stringify(att),
                as_user: true,
            };
            var app = SlackApp.create(token);
            if (e.parameter.thread_ts !== undefined) {
                param["thread_ts"] = e.parameter.thread_ts;
            }
            var post_info = app.postMessage(channel_id, "", param);
        }
```

最後の部分は、ファイルが見つかったらIDを取得して、外部ファイルとして表示できるURLにパラメータとしてくっつけたものをSlackAPIのchatMessageで投げているところ。[元記事](https://blog.icchi.me/slack-stamp-post/)がすばらしいのでスレッドにも対応してる。

# おわりに

スタンプっていいよね