Slack bot で指定した曜日・時刻に任意のテキストを投稿する方法

# はじめに

でびるです。

今日は Slack bot を作成して、指定した時刻に任意のテキストを投稿する方法を紹介します。

# この方法のポイント

- あらかじめ用意した好きなテキストを、ランダム or 順番に投稿できる
    - 今回は順番に投稿してみます
    - 1週目は「今週はAさん」、2週目は「今週はBさん」、3週目は「今週はCさん」、4周目は「今週はAさん」、のように順繰りに指定したテキストを投稿できます
- 「毎週金曜日の 10:00」に投稿できる
    - GAS はデフォルトだと「10時〜11時の間に投稿する」のように1時間単位でしか時刻指定できず、分指定ができません
    - これをハックして分指定までできるようにします（秒指定はできません。指定した時刻より20〜30秒ほど実行時刻は遅れるようです）

# 第1ステップ：Slack bot を Webhook で作成する

テキストを投稿するという単純な機能であっても Slack だけでは完結しません。Slack 側で Webhook を公開して、外部からその API を呼び出すという構成で bot を作成します。

1. サイドバー「その他」から「自動化」を選びます
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/a7ce4f76-ab22-bbe3-04e5-8bc99e68438e.png)
1. そして「ワークフロー」画面から「ワークフローを作成する」ボタンを押します
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/ed99a465-8c77-d7a2-322f-7155240ac5bd.png)
1. 右側サイドバーの「Webhook から」を選びます
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/a774d9b7-101f-483a-a51d-e855cc6cd1a0.png)
1. 「変数を設定する」ボタンを押します
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/c1966a60-94c7-dfb1-27b0-37f0fc0d0532.png)
1. キーに「text」と入力して「終了」ボタンを押します
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/3268fe9a-5be4-13a0-e696-a991ac1c7696.png)
1. 「続行する」ボタンを押します
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/1447c7d9-d89c-a702-587a-77a4826bd3ad.png)
1. サイドバーから「メッセージ」を選んで「チャンネルへメッセージを送信する」を選びます
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/ca9f877b-c4a7-2ee8-e571-122051f75f81.png)
1. 「変数を挿入する」から「text」を選びます。そして投稿したいチャンネルを選びます。また必要があればメッセージ欄を編集します。「text」の部分に外部から入力した任意のテキストが挿入されます
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/2fa63a3c-84bc-cf62-79f1-db341985b0ff.png)
1. ワークフロー名とアイコンを設定します。画面左上の「無題のワークフロー」の部分をクリックすると編集できます
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/6f2a1411-4c8a-94fc-9749-5f4fd56a20bd.png)
1. 「Webhook を使って開始する」を押して「ウェブリクエストの URL」の「リンクをコピーする」ボタンを押します
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/28eb6114-4d05-25ba-835b-b334795aa73a.png)

この「ウェブリクエストの URL」を控えておきます。

`https://hooks.slack.com/triggers/ABCDEFGHI/1234567890123/1234567890abcdef1234567890abcdef` のような形式の URL なはずです。

# 第2ステップ：スプレッドシートを用意する

Google アカウントにログインした状態で、https://drive.google.com/drive/my-drive にアクセスします。

好きな場所にスプレッドシートファイルを作成します。

スプレッドシートのタイトルを入力して、画面下部のシートを2つ用意しておきます。`シート1` をリネームして `content` に、新たなシートを作成して `log` という名前にしておきます。

`content` シートには A 列に、順に表示したいテキストを入力しておきます。`log` シートは空のままで大丈夫です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/24660d04-4064-e603-0326-618760e33b8f.png)

メニューバーの「拡張機能」から「Apps Script」を選びます。

プロジェクト名（上部ヘッダ）と「コード.gs」の部分を変更しておきます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/7ed765ba-291c-8400-0459-5bff0616c21e.png)

そして、コード本文に以下のソースコードの内容を貼り付けます。

- `webhookUrl` は、先程控えた「ウェブリクエストの URL」に書き換えてください
- `enablePost` の値を `true` に変更すると、実際に Slack bot への投稿処理を実施するようになります
- あとは、初回のトリガーをセットするだけです。Apps Script の画面から、`setNextTrigger` 関数を一度実行してください
- 投稿処理を試したければ、Apps Script の画面から `doSlackBot` 関数を実行してください
    - 投稿が順繰りに行われるはずです。投稿のローテーションをリセットしたければ `log` シートの A1 セルの値を削除してください

```javascript
const Util = {
  Weekdays: Object.freeze({ SUNDAY: 0, MONDAY: 1, TUESDAY: 2, WEDNESDAY: 3, THURSDAY: 4, FRIDAY: 5, SATURDAY: 6, length: 7 }),
  getDefault(arg, def) { return arg == null || arg === '' ? def : arg; },
  modInt(baseValue, modValue) { return ((baseValue % modValue) + modValue) % modValue; },
  getDateStr(date) { if (date == null) date = new Date(); return Utilities.formatDate(date, 'JST', 'yyyy-MM-dd HH:mm:ss') },
  output(range, value) { return range.setNumberFormat('@').setValue(value); },
};

function doSlackBot() {
  setNextTrigger();

  const webhookUrl = 'https://hooks.slack.com/triggers/***';
  const enablePost = false;

  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const contentSheet = spreadsheet.getSheetByName('content');
  const contentLength = Math.max(contentSheet.getLastRow(), 1);

  const logSheet = spreadsheet.getSheetByName('log');
  const lastIndex = Util.getDefault(logSheet.getRange('A1').getValue() | 0, 0) - 1;
  const nextIndex = Util.modInt(lastIndex + 1, contentLength);
  const nextRow = nextIndex + 1;
  Util.output(logSheet.getRange('A1'), nextRow);

  const text = contentSheet.getRange(`A${nextRow}`).getValue();
  const dateStr = Util.getDateStr();
  const logNewRow = logSheet.getLastRow() + 1;
  const getLogCell = (col) => logSheet.getRange(`${col}${logNewRow}`);
  Util.output(getLogCell('A'), dateStr);
  Util.output(getLogCell('B'), text);

  const options = {
    method : 'post',
    contentType : 'application/json',
    payload : JSON.stringify({ text }),
  };
  if (enablePost) UrlFetchApp.fetch(webhookUrl, options);
}

function setNextTrigger() {
  const weekday = Util.Weekdays.FRIDAY;
  const hour = 10;
  const minute = 0;

  const today = new Date();
  const nextDay = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0);
  const weekdayDiff = (weekday + Util.Weekdays.length - nextDay.getDay()) % Util.Weekdays.length;
  const nextTheWeekday = new Date(nextDay.getFullYear(), nextDay.getMonth(), nextDay.getDate() + weekdayDiff, hour, minute, 0);

  removePrevTrigger();
  const trigger = ScriptApp.newTrigger('doSlackBot').timeBased().at(nextTheWeekday).create();
}

function removePrevTrigger() {
  const allTriggers = ScriptApp.getProjectTriggers();
  allTriggers.forEach(trigger => {
    if (trigger.getHandlerFunction() === 'doSlackBot') ScriptApp.deleteTrigger(trigger);
  });
}
```

# おわりに

GAS が指定した曜日の指定した時刻にトリガーが実行できれば `setNextTrigger` や `removePrevTrigger` のような実装は不要になるのですが、なぜか現状では分指定ができず1時間単位でしか時刻を指定できないのですよね。

この実装では、繰り返し予定によるトリガーではなく、次の一回の実行を日時指定するトリガーを、トリガー実行の度に付けたり外したりしています。

上記のコードは、毎週金曜日の10:00に投稿するサンプルですが、これを変更したければ `setNextTrigger` の冒頭の部分を書き換えてください。

もし毎週1回ではなく毎日1回にしたい場合や、テキストを順繰りでなくランダム投稿にしたいような場合は、それぞれの関数を中身をそれなりに修正する必要があります。

修正方法が分からなければコメントしてください。

以上です。Slack bot で投稿を自動化する方法でした。