Slack AppとGASで簡単な鍵管理ができるBotを作成する

## はじめに

私の研究室では、研究室の鍵を借りに行く人たちが入れ違いになることがあります。
そこで、鍵を誰が借りたかを他のメンバーに共有するためにSlack Appを作成します。

## Slack Appの作成

[slack api](https://api.slack.com/apps)からSlack Appを作成します。

- 「Create New App」＞「From scratch」をクリックして作成します。
- 左の一覧から「OAuth & Permissions」をクリックしてパーミッションの設定をします。
- 「Bot Token Scopes」＞「Add an OAuth Scope」をクリックして「chat:write」を追加します。
- 「Install to Workspace」をクリックしてインストールします。

他にもOAuth Scopeがたくさんありますが、今回のBotはこれだけで十分です。

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156166/1bbf6e16-5b5b-d0f7-fd82-5eb75f57cf3d.png)
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156166/2febf4f7-c042-e4d7-b042-53b3f22820d2.png)


そうすると、`xoxb-*****`から始まるBot User OAuth Tokenが発行されます。こちらのTokenは他の人に知られないように管理してください。

次にSlackを起動してメッセージを送信したいチャンネルにAppの追加とそのチャンネルのIDを取得してください。

## Google Apps Scriptの作成

Google Apps Scriptでプログラムを書きます。

下記のソースコードをコピーして取得したチャンネルIDとTokenに書き換えて実行すればslackにメッセージを送信できると思います。

初めてプログラムの実行をすると承認が必要とポップアップされるので許可をしてください。

メッセージの送信は`chat.postMessage`を使用します。

```js
function postMessage() {
  const url = "https://slack.com/api/chat.postMessage";
  const channelId = "チャンネルのID";
  const token = "Slack Appのtoken";
  const blocks = [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "ボタンを押してね！",
        "emoji": true
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "emoji": true,
            "text": "借りた　:key:"
          },
          "style": "primary",
          "value": "借りました"
        },
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "emoji": true,
            "text": "返した　:lock:"
          },
          "style": "danger",
          "value": "返しました"
        }
      ]
    }
  ];

  const headers = {
    "Content-Type": "application/json; charset=utf-8",
    "Authorization": "Bearer " + token
  };
  const payload = {
    "channel": channelId,
    "blocks": blocks
  };
  const params = {
    "method": "POST",
    "headers": headers,
    "payload": JSON.stringify(payload)
  };
  
  UrlFetchApp.fetch(url, params);
}
```

![c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156166/3a5494f1-32df-2d2c-c23c-8bab90c9ed78.png)

実行に成功すると上記の画像のようなものが送信できたと思います。

`payload`には他にも `text` `attachments`があるのでお好みで変更してください。

私は[Block Kit](https://app.slack.com/block-kit-builder/T01AP65HZQV#%7B%22blocks%22:%5B%7B%22type%22:%22header%22,%22text%22:%7B%22type%22:%22plain_text%22,%22text%22:%22New%20request%22,%22emoji%22:true%7D%7D,%7B%22type%22:%22actions%22,%22elements%22:%5B%7B%22type%22:%22button%22,%22text%22:%7B%22type%22:%22plain_text%22,%22emoji%22:true,%22text%22:%22Approve%22%7D,%22style%22:%22primary%22,%22value%22:%22click_me_123%22%7D,%7B%22type%22:%22button%22,%22text%22:%7B%22type%22:%22plain_text%22,%22emoji%22:true,%22text%22:%22Reject%22%7D,%22style%22:%22danger%22,%22value%22:%22click_me_123%22%7D%5D%7D%5D%7D)で簡単にメッセージを作成することができました。
他にもメッセージ送信のテストは[Tester](https://api.slack.com/methods/chat.postMessage/test)で簡単にできるので使用してみてください。

## インタラクティブなメッセージ送信をできるようにする

GASからSlackにメッセージを送信することができましたが、このままだと本来の目的であった誰が鍵を借りたのかが分かりません。

それができるようにするために、まずはSlack Appの設定をします。

- 左の一覧から「Interactivity & Shortcuts」をクリックして「On」に変更します。
- 「Request URL」にはGASのURLを記入します。
- 右下の「Save Changes」をクリックします。

GASのURLの取得は、GASを開いて「デプロイ」＞「新しいデプロイ」＞「ウェブアプリ」＞「アクセスできるユーザー」を全員に変更してデプロイします。
`https://script.google.com/macros/s/*******/exec`のようなURLが発行されるのでこちらを記入します。

![d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156166/f5510b6c-054a-78ee-776a-3234998566c6.png)

![e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156166/e2994917-5773-f51d-e3d1-f8c5581e4cd7.png)


ボタンがクリックされた時に実行するソースコードが下記になります。

```js
function doPost(e) {
  const json = JSON.parse(e.parameter.payload);
  const user = json.user.name;
  const value = json.actions[0].value;
  const responseUrl = json.response_url;
  const blocks = [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "<@" + user + ">が鍵を" + value,
        "emoji": true
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "emoji": true,
            "text": "借りた　:key:"
          },
          "style": "primary",
          "value": "借りました"
        },
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "emoji": true,
            "text": "返した　:lock:"
          },
          "style": "danger",
          "value": "返しました"
        }
      ]
    }
  ];

  const payload = { "blocks": blocks };
  const params = {
    "method": "POST",
    "payload": JSON.stringify(payload)
  };

  UrlFetchApp.fetch(responseUrl, params);
}
```

誰が何をしたのかを知りたいので `name`と`value` を取得して、メンションをして送信したいと思います。

一つ注意してほしいのが、ソースコードを変更したら「デプロイ」＞「デプロイの管理」＞右上の編集マークをクリック＞バージョンを**新バージョンに変更**してデプロイする必要があります。

![f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2156166/fd678d61-ab2a-90c6-b7d4-94354ec12b5c.png)


これでインタラクティブにすることができると思います。

## 完成したソースコード

最後に完成したソースコードがこちらです。

blocksの部分が2つの関数で重複している部分があるので、少し変更しています。

```js
function postFirstMessage() {
  const url = "https://slack.com/api/chat.postMessage";
  const channelId = "チャンネルのID";
  const token = "Slack Appのtoken";
  const blocks = createBlocks();

  const headers = {
    "Content-Type": "application/json; charset=utf-8",
    "Authorization": "Bearer " + token
  };
  const payload = {
    "channel": channelId,
    "blocks": blocks
  };
  const params = {
    "method": "POST",
    "headers": headers,
    "payload": JSON.stringify(payload)
  };
  
  UrlFetchApp.fetch(url, params);
}

function doPost(e) {
  const json = JSON.parse(e.parameter.payload);
  const user = json.user.name;
  const value = json.actions[0].value;
  const responseUrl = json.response_url;
  const blocks = createBlocks(user, value);

  const payload = { "blocks": blocks };
  const params = {
    "method": "POST",
    "payload": JSON.stringify(payload)
  };

  UrlFetchApp.fetch(responseUrl, params);
}

function createBlocks(user, value) {
  let blocks = [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "<@" + user + ">が鍵を" + value,
        "emoji": true
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "emoji": true,
            "text": "借りた　:key:"
          },
          "style": "primary",
          "value": "借りました"
        },
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "emoji": true,
            "text": "返した　:lock:"
          },
          "style": "danger",
          "value": "返しました"
        }
      ]
    }
  ];
  if (user == null) {
    // headerメッセージの文章の変更
    blocks[0].text.text = "ボタンを押してね！";
  }
  return blocks;
}
```

## おわりに

Slackにメッセージを送信するという記事は検索したら多く出てきましたが、様々のやり方があり少し苦戦しました。

是非参考にしてみてください。