Clasp 環境下で Slack API を使ってメッセージを送受信する

✏️ 編集

Clasp 環境から Slack API を使ってメッセージの送受信を行ってみたので、その時のメモを残す。

Clasp 環境は過去記事の環境を使用している。

Docker で clasp 環境を構築する | yamamoto-yuta.github.io

Slack App の作成

https://api.slack.com/apps から Slack App を作成する、

OAuth & Permissions から下記の Scope を設定してワークスペースへインストールする。

image

GAS でのメッセージ送受信部分の実装

Bot User Token と Slack App のメンバー ID を GAS のスクリプトプロパティに登録する。

メッセージ送受信部分の実装は次のとおり。 main.ts の実装は下記記事のコードをほぼほぼベースにしている。

Slack で動く ChatGPT のチャットボットを Google Apps Script(GAS)でサクッと作ってみる

index.ts :

1
2
3
4
5
6
import { doPost } from "./main";

declare const global: any;

// GAS において doPost() は特別な関数なので、global の名前は doPost にしておく必要がある
global.doPost = doPost;

main.ts :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import URLFetchRequestOptions = GoogleAppsScript.URL_Fetch.URLFetchRequestOptions;

// Slack へのメッセージ送信関数
const sendMessageToSlack = (channel: string, message: string) => {
  const SLACK_BOT_TOKEN =
    PropertiesService.getScriptProperties().getProperty("SLACK_BOT_TOKEN");
  if (!SLACK_BOT_TOKEN) throw new Error("SLACK_BOT_TOKEN is not set.");

  const url = "https://slack.com/api/chat.postMessage";
  const payload = {
    channel: channel,
    text: "echo: " + message,
  };

  const options: URLFetchRequestOptions = {
    method: "post",
    contentType: "application/json",
    headers: { Authorization: `Bearer ${SLACK_BOT_TOKEN}` },
    payload: JSON.stringify(payload),
  };

  UrlFetchApp.fetch(url, options);
};

export const doPost = (e: any) => {
  const reqObj = JSON.parse(e.postData.getDataAsString());

  // Slackから認証コードが送られてきた場合(初回接続時)
  // これをやっておかないと Event Subscriptions で URL が Verify されない
  if (reqObj.type == "url_verification") {
    // 認証コードをそのまま返すことで、アプリをSlackに登録する処理が完了する
    return ContentService.createTextOutput(reqObj.challenge);
  }

  // Slackからのコールバック以外の場合、OKを返して処理を終了する
  if (reqObj.type !== "event_callback" || reqObj.event.type !== "message") {
    return ContentService.createTextOutput("OK");
  }

  // メッセージが編集または削除された場合、OKを返して処理を終了する
  if (reqObj.event.subtype !== undefined) {
    return ContentService.createTextOutput("OK");
  }

  // Slackから送信されたトリガーメッセージ
  const triggerMsg = reqObj.event;
  // ユーザーID
  const userId = triggerMsg.user;
  // メッセージID
  const msgId = triggerMsg.client_msg_id;
  // チャンネルID
  const channelId = triggerMsg.channel;
  // タイムスタンプ
  const ts = triggerMsg.ts;

  // Bot自身によるメッセージである場合、OKを返して処理を終了する
  const SLACK_BOT_USER_ID =
    PropertiesService.getScriptProperties().getProperty("SLACK_BOT_USER_ID");
  if (!SLACK_BOT_USER_ID) throw new Error("SLACK_BOT_USER_ID is not set.");
  if (userId === SLACK_BOT_USER_ID) {
    return ContentService.createTextOutput("OK");
  }

  sendMessageToSlack(channelId, triggerMsg.text);
  return ContentService.createTextOutput("OK");
};

Slack App の Event Subscription の設定

GAS 側が実装できたら、 GAS からウェブアプリとしてデプロイする。

デプロイ後、ウェブアプリの URL を Slack App の Events Subscriptions の Request URL に貼り付ける。

次の bot events を subscribe するよう設定する。

image

実際に動かしてみる

作成した Slack App をチャンネルに招待してメッセージを送信すると、送信した文章を Slack App が echo するはず。

ローカルからデプロイする

clasp deploy でローカルからデプロイできる。が、いくつか注意点がある。

appsscript.json に下記設定を追加しないと、「ウェブアプリ」ではなく「ライブラリ」としてデプロイされてしまう=ウェブアプリの URL が発行されない

1
2
3
4
  "webapp": {
    "access": "ANYONE_ANONYMOUS",
    "executeAs": "USER_DEPLOYING"
  },

設定内容は下記画像と同じ。

image

clasp deploy 時にデプロイ ID を指定しないと新しいデプロイが作成されてしまい、ウェブアプリの URL が変わってしまう( → 公式ドキュメント

clasp deployment でアクティブなデプロイの一覧が取得できる。再デプロイする場合、デプロイ一覧の中から最新のデプロイ ID を取得し、それを clasp deploy で指定する。今回は次のような再デプロイ用スクリプトを作成して対処した。

redeploy.sh :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash

# Build
yarn webpack --mode production

# Push
yarn clasp push

# Get last deployment id
LAST_DEPLOYMENT_ID=$(yarn clasp deployments | tail -n 2 | head -n 1 | awk '{print $2}')

# Deploy
yarn clasp deploy --deploymentId $LAST_DEPLOYMENT_ID

クリプトは次の記事が参考になった。

Google Apps Script の Clasp で Web アプリの URL を変えないでデプロイする方法 - ある SE のつぶやき・改

参考記事

Hugo で構築されています。
テーマ StackJimmy によって設計されています。