この記事は夏のブログリレー 24日目です。
TL;DR
GASでリマインダーを作成しました。リマインダーのメッセージ例:
↓は先行研究と成果物のリポジトリです。
こだわりポイントは以下の通りです。
- clasp
- TypeScript + eslint + Prettier
- traP内wikiから情報を読み取る
- traQのWebhook機能でtraQに投稿
- 夏のブログリレー以外でも使えるように
上から順番に解説していきます。
clasp
ローカルで書いたGASのスクリプトをリモートに同期できるCLIツールです。
git, VSCodeなど好みの環境で開発できるようになるのがいいところです。使い方は↑のREADMEなどが参考になります。
また、次のTypeScript + eslint + PrettierもclaspがなければGASと両立出来ませんでした。GAS自体はTypeScriptをサポートしていませんが、ローカルのスクリプトをリモートに反映させる時にclaspがTypeScriptをGAS上で動くようにトランスパイルしてくれます。便利ですね。
TypeScript + eslint + Prettier
Web開発ではよくある構成だと思います。僕はNode.jsの経験があまりないので、セットアップに手間取ってしまいました。ついでにGitHub ActionsでTypeScriptのビルド、eslint、そしてPrettierをチェックするようにしました。
traP内wikiから情報を読み取る
ここが本題です、多分。そもそもtraPには部内wikiというものが存在します。
SysAd班 | 東京工業大学デジタル創作同好会traP より
Wiki (Crowi)
情報共有サービスです。今まで行なってきたイベントのログや、サークルメンバーが溜めた知見などが公開されています。
一応リポジトリも載せておきます。
そしてtraPのブログリレーでは、担当表をこのCrowiで管理しています。そしてありがたいことに、Crowiには(ドキュメント化されてないけど)APIが生えています。
作成したリマインダーでは、このAPIでcrowiの担当表があるページを読んで必要な情報を抜き出すようにしました。Markdownの表パースが地味に面倒でした。
ちなみにMarkdownの担当表は以下のような形式です。(実際のものから頭だけコピペ)
| 日付 | 日目 | 担当者 | タイトル(内容) |
| --- | --- | --- | --- |
| 8/21 | 1 | :@H1rono_K: | 夏のブログリレー始まります |
| 同上 | 1 | :@d_etteiu8383: | :natori_sana: |
ちなみにちなみに:~~~:
のような記述はslackやdiscordでもあるスタンプ記法です。ちなみにx3 実装はtraPtitech/traq-markdown-itです(多分)。
CrowiのAPIを叩く際にアクセストークンが必要になりますが、このトークンはもちろん公開してはいけない情報です。そのため、GASのProperties Service (環境変数的なやつ)にこういった情報を保存しました。後述の、traQのWebhookで使用するシークレットも同様です。
traQのWebhook機能でtraQに投稿
traQのWebhook機能を使うと、traQにメッセージを投稿することができます。DiscordのWebhook機能みたいな感じですね。Webhook機能に関するドキュメントはtraQ BOT consoleにあります。traQのWebhookにはInsecure方式とSecure方式があるのですが、このリマインダーではSecure方式のWebhookを前提としています。以下はBOT consoleから引用したSecure方式の説明です。
traQ-bot-console/src/docs/webhook/send.md at dev · traPtitech/traQ-bot-console #Secure方式 より
Secure方式
Webhook作成・編集時に登録した
Webhookシークレット
が必要になります。Secure方式では
Webhookシークレット
を鍵としてメッセージ本文をHMAC-SHA1
でハッシュ化した結果を同時に送信し、
traQサーバーがWebhookの送信元の正当性を検証します。
つまり、Secure方式でwebhookを送信するならこんな感じにリクエストを送る必要があります。(上記引用と同じページよりコピーしたスニペットを一部改変)
WEBHOOK_ID="Webhook ID"
WEBHOOK_SECRET="Webhookシークレット"
MESSAGE="投稿するメッセージ本文"
SIGNATURE=$(echo -n "$MESSAGE" | openssl sha1 -hmac "$WEBHOOK_SECRET")
curl -X POST -H "Content-Type: text/plain; charset=utf-8" -H "X-TRAQ-Signature: $SIGNATURE" -d "$MESSAGE" "https://q.trap.jp/api/v3/webhooks/$WEBHOOK_ID"
GAS内では、HTTP POSTリクエストはUrlFetchApp
、HMAC-SHA1はUtilities.computeHmacSignature
で実現できます。HMAC-SHA1の計算でcharset指定を忘れていてハマりました。
夏のブログリレー以外でも使えるように
Properties Serviceをプライベートな情報を保持する目的で紹介しましたが、このGASプロジェクトではそれ以外にも使用しています。例えば:
- traQのサーバーホスト名
- リマインドメッセージを投稿するチャンネル情報
- 担当表があるCrowiのページ情報
まあ色々Propertiesに持たせたので、任意のブログリレー、任意のtraQサーバー、Crowiサーバーに対応しています。つまり、traQサーバーとCrowiサーバーさえ用意すればこのリマインダーでブログリレーができちゃいます。多分。 どこに需要があるんだ 嬉しいですね。
やってないこと
この記事書いてて「あーやっときゃよかった」と思ったことです。
- claspをpackage.jsonの依存関係に含める
- ソースコードを
src
ディレクトリ以下に置く - ソースファイルを分ける
- テスト(カバレッジもできたら)
- dependabot
- CIでGASプロジェクトにpush
リポジトリにPR出してくれたら泣いて喜びます。
参考記事
おしまい
ここまで書きましたが、そんなに大したことしてない気がしてきました。
明日の担当は@yashuさんです。お楽しみに!