はじめに
Notion が Mermaid.js の描画に対応しました。グラフが Codeblock で書けるようになりました。要望があったので、Google Form をリアルタイムで集計する Notion ページを作ってみることにしました。いつものように作りながら記事を仕上げていきます。
Google Form の作成
とりあえず適当にフォームを作ってみました。内容は適当です。
何はなくともスプレッドシートを作成します。
新しいスプレッドシートを作成します。
シートが作成されました。まだ何も入れていないので空です。テスト用なので名前などの個人情報は集めていません。データがないとテストできないので、フォームに幾つかのデータを入れておきましょう。
こんな感じでダミーデータを入れてみました。
Google Apps Script の作成 (集計部分のみ)
Google Apps Script を作成します。以前と異なり、拡張機能のところに移動していました。
ひとまずテストのために値が取得できるかだけ確認してみます。こんなコードを書きました。B2 からB列の一番下までのデータを値で取得してきます。
// 現在のアクティブシートを得る function getSheet() { return SpreadsheetApp.getActiveSheet() } function calcStats() { const sheet = getSheet() const values = sheet.getRange("B2:B" + sheet.getLastRow()).getValues() console.log(values) }
保存するとコードの上の部分がこんな感じに変わります。デバッグの右側を「calcStats」に変更して「実行」をクリックします。
個人情報をアクセスするので権限の確認が入ります。
アプリの素性がわからないので、警告が出てきます。自分で作ったものなので「詳細」をクリックします。名前をつけているはずなのに「無題のプロジェクト」になってしまっていますが、気にしないことにします。
進んだ先のページで「許可」をクリックします。
実行結果が表示されます。先ほどのダミーデータが取得できました。結果は配列の配列として入っていることがわかります。後はコードを書くだけです。
集計するところまで書いてみました。updateCodeBlock で stats を取得して、表示してみました。
// 選択肢 const selection = [ "自分でプログラムコードを書いている", "Automate.io や Zapier を使っている", "Notion しか使っていない", "Notion もまだ使っていない" ] function outsideSelection(value) { return selection.indexOf(value) == -1 } function calcStats() { const sheet = getSheet() const values = sheet.getRange("B2:B" + sheet.getLastRow()).getValues() const stats = values.reduce((result, line) => { str = line[0] if (str in result) { result[str] += 1 } else { result[str] = 1 } return result }, {}) let other = Object.keys(stats).filter(outsideSelection).map(k => stats[k]).reduce((s, v) => s + v, 0) stats["その他"] = other return stats } function updateCodeBlock() { const stats = calcStats() console.log(stats) }
その他の意見は「その他」として集計されています。
Notion API 部分は Notion のサンプルページを作ってから取り組みます。
Notion ページの作成
Codeblock を一つだけ作ってみました。言語を Mermaid にし、プレビュー状態にしておきました。
共有で API test のインテグレーションを招待しています。今回は書き換えをしたいので「編集権限」にしておきます。
次に作成したコードブロックのリンクをコピーします。ブロックの id が必要なためです。適当なテキストエディタにコピーしておきます。
これで Notion の作業は終了です。
Google Apps Script の作成 (Notion API 部分)
Notion 側の準備ができたので、Notion に送る部分を作成します。まず、インテグレーションのキーと先ほどのブロック ID を Script のプロパティに登録してしまいます。登録専用の関数をいつものように使います。まずこの状態でそのまま貼り付けて storeTokenAndId() を実行してみます。
// MY_NOTION_TOKEN と DATABASE_ID をプロパティに登録する(1回だけ使い、終わったらIDを消す) function storeTokenAndId() { const scriptProperties = PropertiesService.getScriptProperties() scriptProperties.setProperties({ "MY_NOTION_TOKEN": "ここに「Notion Token」を記述", "PAGE_ID": "ここに「ページID」を記述", "BLOCK_ID": "ここに「ブロックID」を記述" }) // 登録できたことを確認 console.log("myNotionToken = " + myNotionToken()) console.log("blockId = " + blockId()) } // MY_NOTION_TOKEN を取得 function myNotionToken() { return PropertiesService.getScriptProperties().getProperty("MY_NOTION_TOKEN") } // PAGE_ID を取得 function pageId() { return PropertiesService.getScriptProperties().getProperty("PAGE_ID") } // BLOCK_ID を取得 function blockId() { return PropertiesService.getScriptProperties().getProperty("BLOCK_ID") }
実行するとこんな感じになります。
動いていることが確認できたら、インテグレーションのトークンとブロックIDを書き換えて再度実行します。インテグレーショントークンは Notion の設定のインテグレーションで「トークンをコピーする」から得られます。トークンを作っていない人は、「独自のインテグレーションを開発する」の部分から作ってください(ここは省略します)。 また、ページID は先ほどテキストエディタにコピーしたリンクの「#」より前の16進数部分です(/や-より後ろの部分)です。さらに、ブロックIDは「#」から後ろの部分です。これに3つの値をコピーしたら、再度 storeTokenAndId を実行します。
成功したら、storeTokenAndId 関数は消してしまってください。コードに危険な文字列などを残さないためにプロパティに格納しているので、この関数はもう必要ありません。
次に mermaid のデータ文字列を作成します。今回は pai チャートを表示します。updateCodeBlock から mermaidCode を呼び出すように変更して表示してみます。
function mermaidCode(stats) { ans = selection.reduce((result, k) => { return result + ' "' + k + '" : ' + stats[k] + "\n" }, "pie title Notion API アンケート\n") ans = ans + ' "その他" : ' + stats["その他"] return ans } function updateCodeBlock() { const stats = calcStats() const code = mermaidCode(stats) console.log(code) }
同様に API 用の payload を作ります。
function updatePayload(code) { return { "code": { "text": [ { "text": { "content": code } } ], "language": "mermaid" } } } function updateCodeBlock() { const stats = calcStats() const code = mermaidCode(stats) const payload = updatePayload(code) console.log(payload) }
ここの出力画面を撮り忘れましたが、ちゃんと動いていました。payload できてしまえば、いつものルーチンのものを持ってきます。updateCodeBlock も完成させてしまいましょう。
function sendNotion(url, payload, method){ let options = { "method" : method, "headers": { "Content-type": "application/json", "Authorization": "Bearer " + myNotionToken(), "Notion-Version": "2021-08-16", }, "payload" : JSON.stringify(payload) }; // デバッグ時にはコメントを外す //Logger.log(options) return JSON.parse(UrlFetchApp.fetch(url, options)) } function updateBlock(blockId, payload) { let url = "https://api.notion.com/v1/blocks/" + blockId // API URL sendNotion(url, payload, "PATCH") } function updateCodeBlock() { const stats = calcStats() const code = mermaidCode(stats) const payload = updatePayload(code) updateBlock(blockId(), payload) Utilities.sleep(1000); // もし、その他の意見をページに追加するようなら以下に記載 // 最終行がその他の意見だったら pageID で箇条書きを追加するなどをすればよいかと。 }
とりあえずチャートを更新する部分まで完成したので、実行してみます。ここで、外部サービスのアクセスがあったので、再度確認が出てきます。こちらも許可とします。
実行したらこうなりました。
完成したので「デプロイ」しておきます。右上のデプロイを実行します。
とりあえず update pie chart くらいにしておきます。
Google Form との連携
次にトリガーを設定します。開いたら右下の「トリガーを追加」をクリックします。
設定画面は以下の通りです。関数は updateCodeBlock、バージョンは先ほどデプロイした最新版にします。ソースはスプレッドシートで、イベントはフォーム送信時になります。これで、フォーム送信時にトリガーをかけることができます。
設定すると再度認証が入りますので、許可します。設定するとこんな感じになります。
せっかくなので Notion にフォームを埋め込んでみました。実際に送信してみるとちゃんとパイチャートが変化するのがわかります。うまくいきましたね。
おわりに
作成したページはここです。せっかくなのでアンケートに答えてみてください。もし Form 連携の参考になれば幸いです。