Googleフォームで投函した内容を Discord に横流しする
目的とか要件とか
身内の内輪ネタみたいなものの一つに、あまりにしょうもない話(戯言と呼ばれる)[1]を振ると Discord の保存用チャンネルにコピペされて保存されるというものがある。しかし、概ねの戯言は微笑ましいものながら、中にはラジカル[2]過ぎて誰が言ったかを隠したかったりしたいものもあった。
ここで発信源や話を振った人の属性を隠して内容だけ安全に投げよう、という不純な動機が生まれた。匿名性を確保しつつ簡便に投稿を行うに当たっては Google フォーム + Google Apps Script がよろしいと思われた。
そんな感じで雑に開発(と言えるには怪しい規模ながら)を行うことにした。まあ、ややこしいジグラット的システムを組まずとも砂場の城を組むぐらいなら御しやすい。
開発方針
こんなことにややこしいビルドを要求する言語など使いたくないし、こんなことをするほど技術に見識が広いわけではないので穏当に TypeScript[3] を使う。詳細は以下のとおり。
- 開発言語は TypeScript で行う。
-
claspと呼ばれる Google Apps Script 用のフロントエンドツールを用いる。
Zer da clasp? [4]
google/clasp とは Google 謹製の GAS フロントエンドツールである。詳細は説明は省くものの、これを導入すれば今までドライブでポチポチ頑張っていた手順の7割ぐらいが省略できる。更に言うと開発支援ツールの要素もあり、なんと TypeScript のビルドと実環境へのデプロイもこれだけで済む。
環境整備
コマンドで十分だろう。
ただし、プロジェクトフォルダ名については作られるフォーム名に影響するので、少しは考えたほうがいい。後でも変えられるものの。
/
$ mkdir project
$ cd project
$ mkdir src
/project
$ yarn init -y
$ yarn add @google/clasp @types/google-apps-script typescript
$ yarn tsc --init
/project/.tsconfig
次の設定が要求される。
"target": "esnext",
"experimentalDecorators": true,
clasp の連携処理をしておく
ここもコマンドで詰まる部分はない。
$ clasp login # ブラウザで認証を求められ、降ろせば終わる
$ clasp create # 形式の選択が求められるので form を選択する
clasp の生成ファイルの整理
多分 /project/appsscript.json ができているので、これを /src あたりに移動させる。ファイル内の timeZone は私の環境ではニューヨーク[5]になっていたので、気になるなら Asia/Tokyo とかにする。
/project/.clasp.json は clasp の設定ファイルである。色々シークレット的なやつがあるのでこれだけは外部に露出させないほうがよいと思う(.gitignore するとか)が、よくわからない。私は安全策に寄せた。さて、このファイルの rootDir が肝要で、これをいじるとビルド対象のフォルダを絞り込めるので ./src とかにしてしまう。
フォームを作る
clasp create した段階でどこかにフォームのファイルがドライブ上に作られているはずなので、それを開いてゴリゴリフォームを書いておく。今回は要件上、段落として設定した質問をひとつくればよかったのでそうしたし、話もそれ前提で進める。
色々書いておいたことにしたい
この世には FizzBuzz Enterprise Editionというパイラミッド、ジグラット、戦艦大和に次ぐ重厚長大なスカムが存在する。FizzBuzz ごときでもいくらでもややこしくできるという証左である。
さて、今回書くコードは17行で終わる。
はい。
詳説[6]
当然ではあるが、Discord の投稿先チャンネルに対応する webhook のアドレスを持ってこなければならない。そう難しくはなく、チャンネルの詳細設定を開いて Integration → Webhook でいくらでも生成できる。Webhook のアドレスは外部に晒すことのないようにする。
あまり説明することはないけれど、必要に応じて型を注入している。getItemResponses() あたりについては参考文献(2)に詳しいので、それを見てみてほしい。端折って述べると Responses の言うところはフォームの質問をまとめた配列であり、[0] すると最初の質問、その要素の getResponse() が回答者の書いた答えとなる。
後は GAS の API に搭載されている UrlFetchApp で webhook に POST して終わる。そう難しい話はなく、トリッキーなこともしていないのでわかりやすいかなと思う。
心惜しい点としては起点となる onSubmit() に渡される引数たる e の型がわからなかったので any としている。これなあに?しかしながら e.response はどうやら FormResponse、const body は URLFetchRequestOptions ということはわかったので、そのような注釈を入れることができた。
GAS のトリガーを設定する
GAS側のエディタ画面(フォーム右上の詳細ボタン→スクリプトエディタから呼び出せる)からトリガー画面に遷移して、それらしいボタンを押してそれらしい関数(今回は onSubmit())がそれらしいイベント(今回はフォームの投稿)に対して反応するように仕組めば良い。細かい部分は参考文献(3)に詳しい。
動かす
私が必要な説明を端折っていなければ、この時点でフォーム経由で何かを投稿すれば Discord の Webhook に結びついたチャンネルに話が飛ぶはずである。飛ばなかったら……頑張ってね![7]
参考文献
- claspを使ってGoogle Apps Scriptの開発環境を構築してみた
- 【保存版!】Googleフォームの質問と回答をGASで自在に取り出す方法まとめ
- Google FormsとDiscordでApex中毒の弟の勉強を監視する
Discussion