見出し画像

【Notion API × GAS】タスクを自動追加したい!#3 スプレッドシートにGASを実装する

こんにちは、おしょうです。

前回はサブ関数をいくつか作成しました。
今回はそれらを用いて、実際にタスクの自動追加をやってみたいと思います。

1. Notionでサブページ作成

前々回作成したテンプレートボタンを押してみましょう。
押したらすぐ「Todoリスト yyyy/mm/dd」というタイトルのサブページが作成されると思います。
そのタイトルを週の始まりの日付に変更します。私の場合は毎週月曜日を始まりにしたいので、そのようにします。続いて、同様の手順を踏んで前週分Todoリストも、テスト用に作成してしまいましょう。

2. Google スプレッドシート作成

Notionにまとめて追加したいタスクを入れておくシートです。
今回のプログラムで必要な情報は以下の3つです。
 ①今週分TodoリストのデータベースのURL
 ②前週分TodoリストのデータベースのURL
 ③毎日やるタスク(日課)のリスト
これらを入力できるよう、スプレッドシートを作成していきましょう!
もちろん、どこのセルを使ってもいいのですが、今回は①はA2、②はA5、③はA8〜一番下までにしてみました。

タスク名の右の列については、一旦何も入れないことにします。例えば、ゴミ捨てスケジュールのような、特定の曜日だけ適用させたいものもあるかもしれませんし、初めから予定時間を綿密に組んでおきたいタスクもあるかもしれません。そういった今後の拡張性を残しておくためです。

スクリーンショット 2021-06-09 15.07.08

3. GASを連携させる

このスプレッドシートの上部メニュー「ツール」→「スクリプトエディタ」の順番で押下し、スプレッドシートにGASを連携させます。

4. GAS作成 〜 グローバル定数作成

スコープの問題等から、グローバル領域での定義については賛否両論あるかと思いますが、グローバル定数があった方が何かと便利な部分があるので、私は限定的に使用しています。今回のスクリプトにはグローバル定数をいくつか宣言しておきたいと思います。以下の文言をスクリプトの一番上に記述します。

const ENDPOINT_PAGES = "https://api.notion.com/v1/pages/"
// ページに関するAPIのエンドポイント
const ENDPOINT_DATABASES = "https://api.notion.com/v1/databases/"
// データベースに関するAPIのエンドポイント
const SECRET_KEY = 自分のInternal Integration Token
// 自分のトークン
const HEADERS = {
  "Authorization" : `Bearer ${SECRET_KEY}`,
  "Notion-Version" : "2021-05-13",
}
// APIを叩くときのヘッダ情報
const WEEKDAYS = ["月","火","水","木","金","土","日"]
const RANGE_NEW_DATABASE_ID = "A2"
const RANGE_OLD_DATABASE_ID = "A5"
// 新旧データベースIDを入れておくセル
const ROW_START_TASK = 8
// 1つ目のタスク情報が記載されている行
const COLUMN_TITLE = 1
// タスク情報のタイトル列

5. GAS作成 - メイン関数作成

それでは、今回のプログラムのメイン関数を作ります。ちょっとずつ小出しで追加していくスタイルでお伝えします。
メイン関数名は何でもいいので、とりあえずrun()にしておきますね。

6. GAS作成 - メイン関数 - スプレッドシートから情報を取り出す

まず、スプレッドシートからデータを取得するセクションを作ります。

function run(){
  //まずスプレッドシートから情報を取り出す

  let sh = SpreadsheetApp.getActiveSheet()
  // 連携しているスプレッドシート情報
  
  let lastRow = sh.getRange(ROW_START_RASK, COLUMN_TASK).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()
  // タスクの最終行の行番号

  let values = sh.getRange(ROW_START_TASK,COLUMN_TASK,lastRow - ROW_START_TASK + 1).getValues()
  // タスクの内容(二次元配列)

  let tasks = values.map(item => item[0])
  // values配列のそれぞれ第1項目だけを取り出した一次元配列

  let newDatabaseId = getId(sh.getRange(RANGE_NEW_DATABASE_ID).getValue())
  let oldDatabaseId = getId(sh.getRange(RANGE_OLD_DATABASE_ID)).getValue())
  // 新旧データベースURLからIDだけ抜き出したもの
}

7. GAS作成 - メイン関数 - 前週分未完了タスクを整形する

前回の前週分未完了タスク取得の関数だと、不要な値も多く返ってきます。
そこで、関数の戻り値から、必要な部分である「properties」だけ抽出し、前週分設定していた曜日の情報を除去します。

let incompleteTasks = getIncompleteTasks(oldDatabaseId)

let properties = incompleteTasks.results.map(item => item["properties"])
// 取得したJSONデータ中の「results」を、mapメソッドにより「properties」だけ抽出

properties.forEach(item => delete item["曜日"])
// propertiesはそれぞれのタスクのオブジェクトが配列として格納されている。それぞれの要素から「曜日」だけ削除する

8. GAS作成 - メイン関数 - タスクをデータベースに投入する

最後に、取得できた情報をもとに、データベースへ投入していきます。

for(let i in WEEKDAYS){
  for(let j = tasks.length - ; j >= 0; j—){
    let record = createRecord({id : newDatabaseId, task : tasks[j], day : WEEKDAYS[i], tags : ["日課"]})
    // タスクオブジェクト作成

    addRecord(record)
  }
}

for(let i in properties){
  let record = {
    "parent" : {
      "database_id" : newDatabaseId,
    },
    "properties" : properties[i]
  }
  addRecord(record)
}

9. GAS作成 - メイン関数 - 完成

最終的に、以下のような内容になれば、コーディング完了です。

function run(){
  //まずスプレッドシートから情報を取り出す

  let sh = SpreadsheetApp.getActiveSheet()
  // 連携しているスプレッドシート情報
  
  let lastRow = sh.getRange(ROW_START_RASK, COLUMS_TASK).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()
  // タスクの最終行の行番号

  let values = sh.getRange(ROW_START_TASK,COLUMN_TASK,lastRow - ROW_START_TASK + 1).getValues()
  // タスクの内容(二次元配列)

  let tasks = values.map(item => item[0])
  // values配列のそれぞれ第1項目だけを取り出した一次元配列

  let newDatabaseId = getId(sh.getRange(RANGE_NEW_DATABASE_ID).getValue())
  let oldDatabaseId = getId(sh.getRange(RANGE_OLD_DATABASE_ID).getValue())
  // 新旧データベースURLからIDだけ抜き出したもの

  let incompleteTasks = getIncompleteTasks(oldDatabaseId)
  let properties = incompleteTasks.results.map(item => item["properties"])
  // 取得したJSONデータ中の「results」を、mapメソッドにより「properties」だけ抽出

  properties.forEach(item => delete item["曜日"])
  // propertiesはそれぞれのタスクのオブジェクトが配列として格納されている。それぞれの要素から「曜日」だけ削除する


  for(let i in WEEKDAYS){
    for(let j = tasks.length - 1; j >= 0; j){      // リストの最後尾から追加していく → Notion上での表示がAPI投入の逆順になるため
      let record = createRecord({id : newDatabaseId, task : tasks[j], day : WEEKDAYS[i], tags : ["日課"]})
      // タスクオブジェクト作成

      addRecord(record)
    }
  }

  for(let i in properties){
    let record = {
      "parent" : {
        "database_id" : newDatabaseId,
      },
      "properties" : properties[i]
    }
    // タスクオブジェクト作成

    addRecord(record)
  }
}

10. まとめ

いかがでしたでしょうか?
ちなみに、私はこのメイン関数を、スプレッドシートのマクロに登録しておき、すぐにスクリプトを走らせることができるようにしています。
スプレッドシート上にタスクの詳細を入力できるようにする機能等、いくつかの拡張性は残していますが、一応これで完成といたします!
Notion APIがバージョンアップされたら、こちらのプログラムもアップデートしていきたいと考えていますので、よろしくお願いします!

この記事が気に入ったらサポートをしてみませんか?