1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GASで、NotionのデータベースからGoogleカレンダーへ連携

Posted at

はじめに

Notionで、日付付きのデータベース(データのページ)を作って、それをNotion上でカレンダービューにすることはできるけど、普段はGoogleカレンダーを使っているから、その上にレイヤーを重ねるように反映させたい。Notionカレンダーを、Googleカレンダーの「他のカレンダー>「+」で追加 したい。

つまり、Notion→Googleカレンダーの方向の連携をGASで作ってみたお話です。

連携ツールは有料のものがあるけど、ここで示す方法なら無料です。

準備

Notionで、インテグレーションを追加して、ページに接続。Notionのデータを読めるようにします。解説ページがたくさんあるので、その方法は割愛。

作ったインテグレーションの設定の中から、"内部インテグレーションシークレット"を取得します。すごい名前ですが、APIトークンと言い換えていいでしょう。

GASでの実装

役割は大きく2つです。

作る順で説明すると

  • ①Notionからカレンダー情報を取得
  • ②Googleカレンダーから呼び出しがかかるので、それに答えるときに、Notionからカレンダー情報を取得(①)し、ICS形式に変換し、返答する

実質は、②の中で①を呼び出すので1つといえば1つです。

①Notionからカレンダー情報を取得

APIに投げるだけ。

const url = `https://api.notion.com/v1/databases/${NOTION_DATABASE_ID}/query`;
const options = {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${NOTION_API_TOKEN}`,
        "Content-Type": "application/json",
        "Notion-Version": "2022-06-28",
    },
};

const response = UrlFetchApp.fetch(url, options);
const data = JSON.parse(response.getContentText());

APIの仕様書はこちら。

data.resultsに、Notionのデータベース(=1つの予定)の配列が入ります。

"データベース"という言葉からは、レコード群を含むテーブルを含むハコみたいな大きなものを想定してしまいますが、Notionにおけるデータベースオブジェクトとは、1つのレコードです。以下では、一般的な意味と区別するために、Notionのデータベースオブジェクトを、Database とアルファベットで書きます。

data.resultsから得られる配列の1要素であるDatabaseの公式のAPI仕様書はこちら
下記のように、1要素ずつ、properties['場所']のように取り出します。

const events = data.results.map(item => {
    const props = item.properties;
    //console.log(props);

    const place0 = props['場所'].rich_text[0]?.plain_text || '';
    const place = place0.length > 0 ? `場所: ${place0}\n` : '';
    const category0 = props['カテゴリ'].multi_select?.map(c => c.name).join(',') || '';
    const category = category0.length > 0 ? `カテゴリ: ${category0}\n` : '';

    const url = item.url || '';
    const description = `${place}${category}${url}`;

    return {
        title: props['イベント名'].title[0]?.plain_text || 'No Title',
        start: props['日付'].date?.start || null,
        end: props['日付'].date?.end || props['日付'].date?.start || null,
        description: description,
        id: item.id,
    };
});

②Googleカレンダーから呼び出されたとき、Notionからカレンダー情報を取得し、ICS形式に変換し、返答する

後で説明しますが、Googleカレンダーでは、他のカレンダー>+>URLで追加でカレンダーを追加します。そうすると、Googleカレンダー側から指定したURLへGETリクエストが投げられて、受けた側が正しくICS形式で返すと、Googleカレンダーに表示されるという仕組みです。

まずGETリクエストの関数は、GASではdoGet(e)を定義することでその役割を果たします。なので以下はその関数内の実装。

(1)Notionからデータを取得し、(2)ICS形式へ変換、それを (3)returnするという処理を実装します。

②-(1) Notionからデータを取得

これは①のことです。

②-(2) ICS形式へ変換

ICS形式と言っても結局文字列です。それを作成する処理。

VACENDARという要素の中に、VEVENTという要素を繰り返すという形式を作ります。

外枠(固定文字列)
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Notion to iCal//EN
CALSCALE:GREGORIAN
<<中身を繰り返す>>
END:VCALENDAR
中身
BEGIN:VEVENT
UID:(一意のID)
SUMMARY:(タイトルになる文字列)
DTSTAMP:(作成日、必須)
DTSTART:(予定の開始日時)
DTEND:(予定の終了日時)
DESCRIPTION:(予定の詳細)
END:VEVENT

Notionで得た情報をもとに、ループで作っていくだけです。

VEVENTの属性は、他にも設定できるようですが、Googleカレンダーが採用していないと最終的には意味がないので、必要に応じて調べてください。

UIDは、Notion側で更新したり削除したときに、このUIDを頼りに反映されると思うので、1つのDatabaseから一意になる値を設定してください。幸い、NotionのDatabaseにもidという項目があるので、それをそのまま設定すればよいです。

②-(3) ICS形式をreturn

MimeTypeでICALを指定してdoGet()returnします。ここが特殊。

return ContentService
    .createTextOutput(icsText)
    .setMimeType(ContentService.MimeType.ICAL);

応用

URLのパラメータを使って、doGet()で分岐ができます。例えば、特定の部署だけを抽出するとか。

それができると、1つのURLだけどパラメータを変えることで、Databaseのプロパティに"部署"があるなら、"部署A用のカレンダー"、"部署B用のカレンダー"を簡単に作れます。部署Aの人向けに、"部署Aだけ"と"部署A以外"みたいなカレンダーもできます。必要に応じて簡単に実装できる。

まとめ

Notionからどの情報を抽出するかはケースバイケースなので、あまり詳しく書きませんでしたが、キモはこれがすべてです。

気になる点としては、長期運用するに従って単純に予定が増え、渡すデータが増えていくと思います。Notionから抽出するとき、"過去2か月以降の予定のみを抽出"などとフィルターすればよいといえばよいですが、過去の分はどう表示されるのか、前回の問い合わせにあったVEVENTが今回ないとき、どうなるのか。Googleカレンダー側の仕様なので、今の仕様が今後もずっとそうであるかはわからないし、どうしよっかなーと気になっています。
まぁ、2か月以降の予定にフィルターして、それより過去はGoogleカレンダーでは見えなかったとしても問題なさそうではあります。Notionにはちゃんと残っていますので。
いい方法をご存じの方がいらしたら、コメントで教えてください。

このICSという仕様は、ベタベタの文字列の仕様で簡単に作れるので、もし他で利用できる場面があるなら簡単に対応できます。また、GASのdoGet()との相性もいい。横展開はできるけど、その場面がどれだけあるのか。

ではよき計画的な生活を。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?