「コラボフロー Advent Calendar 2023」3日目の記事だよ~
コラボフローの詳細は こちら。
去年はJavaScriptカスタマイズしたので、今年はWebhookカスタマイズで遊んでみました。
コラボフローでジャンケン!
対戦よろしくお願いします。
申請して挑みます。今回は「ぱー」でいきましょう!
じゃんけん~
どきどき・・・
うわぁぁーー! 負けちゃいました。
戦績が見れるように リストビュー と ビューフォルダ設定 を組み合わせて一覧表示してみました。
ちょき率が高そう。ふむふむ・・・。もう一回!
といきたいですが、そろそろ本題(実装)の紹介です。
用意するもの
コラボフロー
30日間無料お試し からクラウドの環境を申し込めます。
Webhook 受信サーバー
Webhook は指定したURLに対して何かしらのイベント通知を行う仕組みで、コラボフローではPOST送信が使われています。イベント通知の受け手となる受信サーバー&プログラムの用意が必要です。
今回は、お手軽に使えるみんな大好き Google Action Script (GAS) を使います。
大まかな流れ
ざっくりとこんな流れでイベント・処理がすすみます。
- コラボフロー で申請書が出されて判定段階に到達する
- コラボフロー Webhook 通知が発火する
- GAS
doPost(e)
メソッドが呼び出される-
e.postData.contents
に通知内容が入っている
-
- GAS の自前処理
- 判定段階チェック
- ジャンケン処理、勝ち負け判定
- コラボフローの判定REST APIを実行
実装
GAS で新しくプロジェクトを作成して「コード.gs」に Webhook を受信するための doPost()
メソッドの実装と、フィードバックするためにコラボフローのREST API設定・認証情報を組み込みます。
ソースコード
/** APIエンドポイント (システム管理>環境変数>REST API) */
const API_ENDPOINT = "https://cloud.collaboflow.com/example/api/index.cfm";
/** 実行ユーザーID */
const API_USER = "tonakai";
/** APIキー */
const API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
/**
* POST で受け取る処理
*/
function doPost(e) {
const out = ContentService.createTextOutput();
out.setMimeType(ContentService.MimeType.JSON);
const result = handlePost(e);
out.setContent(JSON.stringify({
...result
}));
return out;
}
function handlePost(e) {
// GASで受信時はJSON形式の文字列。オブジェクトに変換します
const payload = e?.postData?.contents;
if (!payload || typeof payload !== "string") {
return {
error: "エラー: 不正な payload",
};
}
const webhook = JSON.parse(payload);
// It's ゲームタイム!
if (isGameTime(webhook, "ジャンケン相手")) {
return gameJudge(webhook);
}
}
/**
* 指定した判定段階への到達チェック
* @param phaseTitle {string} 判定アイテムで設定した判定名
*/
function isGameTime(webhook, phaseTitle) {
// 判定中で受信時
if (webhook.flow_status === "flow" && webhook.action_type === "receive") {
if (!Array.isArray(webhook.determs)) {
return false;
}
// 段階名チェック
for (const d of webhook.determs) {
if (d.phase_title === phaseTitle) {
return true;
}
}
}
return false;
}
/**
* ジャンケン!
*/
function gameJudge(webhook) {
const appId = webhook.app_cd;
const docId = webhook.document_id; // 文書ID
const userName = webhook.request_user.name; // 申請者名
const doc = webhook.contents; // 申請内容
// トナカイの手札を決定する
const hands = ["ぐー", "ちょき", "ぱー"];
const cpuHandId = Math.round(Math.random() * 2);
const cpuHand = hands[cpuHandId];
// 挑戦者の手札を把握する
const fighterHand = doc.fidFighterHand.value;
// ジャッジメントですの!
let judge = `「${fighterHand}」と「${cpuHand}」で、`;
if (fighterHand === cpuHand) {
judge += "あいこでした";
} else {
// あいこ以外
// 「挑戦者の手札vsトナカイの手札」形式で組み合わせキーにする
const matching = {
"ぐーvsちょき": "勝ち!",
"ぐーvsぱー": "負け",
"ちょきvsぐー": "負け",
"ちょきvsぱー": "勝ち!",
"ぱーvsぐー": "勝ち!",
"ぱーvsちょき": "負け",
};
const key = `${fighterHand}vs${cpuHand}`;
judge += `${userName}さんの` + matching[key];
}
// コラボフローに判定フィードバック
return api_acceptDocument(appId, docId, {
fidCpuHand: cpuHand,
fidJudge: judge,
});
}
/**
* 認証ヘッダーを生成
*/
function makeAuthHeader() {
const credential = `${API_USER}/apikey:${API_KEY}`;
return {
"X-Collaboflow-Authorization": "basic " + Utilities.base64Encode(credential),
}
}
/**
* 申請書を承認判定する
* @param appId {number} アプリケーションコード
* @param docId {number} 対象の文書ID
* @param document {object} 更新内容
*/
function api_acceptDocument(appId, docId, document) {
// @see http://docs.collaboflow.com/api-docs/#/Document/putDocumentStatus
const apiUrl = `${API_ENDPOINT}/v1/documents/${Number(docId)}`;
const body = {
app_cd: appId,
action: "accept",
document,
};
const response = UrlFetchApp.fetch(apiUrl, {
method: "PUT",
headers: makeAuthHeader(),
contentType: "application/json",
payload: JSON.stringify(body),
muteHttpExceptions: true,
followRedirects: false,
});
const responsePayload = response.getContentText("UTF-8");
return {
success: response.getResponseCode() === 200,
result: responsePayload,
};
}
GAS 設定
コードを書いたらデプロイして、Webbhook で受け付けれるURLを入手します。
「デプロイ>新しいデプロイ」を選択します。
続いて、歯車アイコン>ウェブアプリを選択します。
名称を適宜入れ、アクセスできるユーザーを「全員」にしてデプロイします。
初回のみ、各種アクセス権限を付与していいか確認があります。許可して続行します。
デプロイが終わると、ウェブアプリの URL が表示されます。これをコピーしてメモしておきます。
※後でも「デプロイ>デプロイを管理」から見れます。
アクセスできるユーザーが全員の、ウェブアプリURLは知られると誰でも送信できてしまいます。漏れないよう取扱いに注意します。
コラボフロー設定
フォーム
パーツの例。「パーツID」の自動OFFにして fidFighterHand
と指定して作ります。
相手側は fidCpuHand
と指定して作ります。これで Webhook 受信時もこれらの名称が使えます。
判定メッセージも受け取れるようにしましょう。
経路・判定設定
申請書類の設定で、フォームと紐付け、ジャンケン挑戦者(申請者)がズルできないように相手の手をブロックします。
判定アイテムの設定でポイントになるのは2つ。
- 判定アイテムの段階名を Webhook 内でチェックする段階名(
phase_title
)と一致させる。 - GAS の応答で書き込むパーツを編集可にする。
一通り経路設定ができたら保存します。
経路・Webhook 設定
いよいよ最後です。GAS へのつなぎ込みをします。
Webhook のタブから新規登録します。
- 通知先のWebhook URLに、メモしたウェブアプリのURLを入れます。
- 通知条件で、判定者・回覧者操作の「受信時」のみチェックを付けます。
(action_type
で受け取る "receive" に相当します。)
完成!
これで GAS を利用してコラボフローの Webhook 通知を処理できるようになりました。
あとは、トナカイさんに挑みましょう。ねらい目はぐー✊ですね。
リファレンス
コラボフロー関連
Google Action Script 関連
謝辞
-
今から10分ではじめる Google Apps Script(GAS) で Web API公開
- doPost 一連の処理について大変参考になりました