遅延タスクに毎朝自動的にマークを追加 : Notion 解説(27)

はじめに

今朝、Twitter をみたら、こんなツイートがありました。

このアイディア面白いなと思いました。これまで、CRUD の C(reate) しか作っていなかったので、R(ead)とU(pdate)を試してみたくて実装してみました。

事前準備

ここで、Rails でいう index と update に相当する API 呼び出しが発生します。前回までのスクリプトでは、スクリプトの中に MY_NOTION_ID や DATABASE_ID を直書きしていましたが、何度も出てくるのでメソッド化するとともに、前回使ったスクリプトプロパティに書き出すことにしました。これで、スクリプトを気兼ねせずに人に見せることができます。

この対応のために、以下のスクリプトを追加しました。以前のエディタでは、GUI でプロパティを設定できたのですが、新しいエディタはなくなってしまったので、コードで登録します(これが面倒だと思うなら、以前のエディタに一時的に戻すのもありです)。スクリプトを記述したら storeTokenAndId を実行します。キーと値が表示されたらこのメソッドは消してしまって良いです。

// MY_NOTION_TOKEN と DATABASE_ID をプロパティに登録する(1回だけ使い、終わったらIDを消す)
function storeTokenAndId() {
  const scriptProperties = PropertiesService.getScriptProperties()
 scriptProperties.setProperties({
    "MY_NOTION_TOKEN": "ここに「Notion Token」を記述",
    "DATABASE_ID": "ここに「データベースID」を記述"
  })
  // 登録できたことを確認
  const data = scriptProperties.getProperties()
  for (var key in data) {
    Logger.log("キー: %s, 値: %s", key, data[key])
  }
}

これらを読み出すメソッド myNotionToken() および databaseId() メソッドを作っておきます。

// MY_NOTION_TOKEN を取得
function myNotionToken() {
  return PropertiesService.getScriptProperties().getProperty("MY_NOTION_TOKEN")
}

// DATABASE_ID を取得
function databaseId() {
  return PropertiesService.getScriptProperties().getProperty("DATABASE_ID")
}

汎用的な読み出しメソッド

他の作業でも使いそうなので、getNotion という汎用メソッドを作っておきます。先ほどの myNotionToken() メソッドや databaseId() メソッドを使っています。filter やorder は引数の payload で指定します。

// Notion のデータベースを query するメソッド (payload にフィルタや並び順を設定しておく)
function getNotion(payload) {
  let url = "https://api.notion.com/v1/databases/" + databaseId() + "/query" // API URL
  let options = {
    "method" : "POST",
    "headers": {
      "Content-type": "application/json",
      "Authorization": "Bearer " + myNotionToken(),
      "Notion-Version": "2021-05-13",
    },
    "payload" : JSON.stringify(payload)
  }
  // デバッグ用
  // Logger.log(url)
  // Logger.log(options)
  return JSON.parse(UrlFetchApp.fetch(url, options))
}

未終了のタスクを取得

先程の getNotion を使って、未終了のタスクを取得します。Done プロパティが false で日付が今日より前のものを取得します。並び順は今回は関係ないですが、説明用につけています。

// 未終了のタスクを一括で取得する
function getUnfinished() {
  let payload = {
    "filter": {
      "and": [
        {
          "property": "Done",
          "checkbox": {
            "equals": false
          }
        },
        {
          "property": "日付",
          "date": {
            "before": new Date()
          }
        }
      ]
    },
    "sorts": [
      {
        "property": "日付",
        "direction": "ascending"
      }
    ]
  }
  return getNotion(payload)
}

データを更新する汎用メソッド

getNotion と同じように汎用のパッチメソッドを作ります。対象となるページの id を pageId として渡し、payload に更新情報を渡します。

// Notion のデータベースを query するメソッド (payload に更新するデータを設定しておく)
function patchNotion(pageId, payload) {
  let url = "https://api.notion.com/v1/pages/" + pageId // API URL
  let options = {
    "method" : "PATCH",
    "headers": {
      "Content-type": "application/json",
      "Authorization": "Bearer " + myNotionToken(),
      "Notion-Version": "2021-05-13",
    },
    "payload": JSON.stringify(payload)
  };
  // デバッグ用
  // Logger.log(url)
  // Logger.log(options)
  UrlFetchApp.fetch(url, options)
}

遅延プロパティの更新

これまでに作ったものを組み合わせて、今回の目的である遅延プロパティを更新します。rich_text プロパティが配列であることに気づかず、なぜ更新できないのだろうとハマって時間がかかりました。

rich_text プロパティがあるときには、plain_text 属性を取得し、その後ろに「●」をつけています。🟠は見た目がズレるので、今回はとりあえず「●」にしています。後で別の絵文字などに変えるかもしれません。Notion の制限を回避するために、1秒に1更新にしています。

function updateDelayedTask() {
  // unfinished 
  let unfinished = getUnfinished()["results"];
  unfinished.forEach(t => {
    let pageId = t["id"]
    Logger.log(t)
    let delayedText = t["properties"]["遅延"]["rich_text"][0]
    let plainText = delayedText ? delayedText.plain_text : ""
    let payload = {
      "properties": {
        "遅延": {
          "rich_text": [
            {
              "text": {
                "content": plainText + "●"
              }
            }
          ]
        }
      }
    }
    patchNotion(pageId, payload)
    // Notion は 3アクセス/1秒なので、余裕を持って1秒待つ
    Utilities.sleep(1000);
  })
}

テスト実行

updateDelayedTask を選択し、実行してみました。テストのために、Done がついていないものを作ってテストしてみました。また、一つ「aaa」という余計な文字列が入っている時のテストも実施してみました。

f:id:hkob:20210630102340p:plain
実行例

もう一回実行してみました。●がちゃんと増えていますね。サボっといるだけどんどん●が増えていき、ヤバさが伝わってきます。

f:id:hkob:20210630102520p:plain
2回目の実行

毎日実行するように設定

毎日実行される関数があるので、そこに今回の関数を追加しました。GAS で朝4時から5時の間に doEverydayPost が実行されるので、その際に未完了タスクにも●が追加されるようになります。

// これまで通り、毎朝呼ばれる関数
function doEverydayPost() {
  selectEvents(new Date())
  updateDelayedTask()
}

おわりに

Twitter の「#まいにちNotion」タグから、またヒントをいただきました。いろんな人がいろんなアイディアを持っているので、参考になりますね。


はてなブログに書いた Notion 記事一覧