Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Notion + GASでタスク一覧をSlackに通知してタスク管理をしやすくする

こんにちは!Sansan 技術本部 Mobile Applicationグループのふるしんです
furusin (@furusin_oriver) / Twitter

私はNotionのTask Listを使って日々のTODOを管理していますが、毎日うまくタスク管理ができている気があまりしません
どうすればいいかな?とChatGPTに色々と相談した結果「まずはタスク一覧を毎日見ざるを得ない仕組みを作ろう!」というところから仕組みを考えました

そこで「毎朝Notionで管理しているタスクをSlackに通知するGAS」を作ることにしました
その通知はSlackに通知する時に鼓舞してもらうように工夫しました

この記事では具体的にどうやって実装したのかを解説します

構成

  • Notion:Task ListとしてBoard ViewのDatabaseを用意。To DoやDoing, Doneといった列を用意
  • GAS:Notion APIを叩いてTask ListからTo DoとDoingになっているタスクの一覧を取得し、SlackにPost


Notion側での準備

やることは3点あります

  1. Integration を作成する
  2. Task List を作成する
  3. Task List とIntegrationをコネクトする

Integrationを作成する

IntegrationはNotion内のプロジェクトのようなものだと思ってください
Notion APIを利用するには、このIntegrationに紐づく形で払い出されるTokenを利用します

こちらからMy Integrationsへアクセスし、「New Integration」で作成します
そうするとその先に「Internal Integration Token」が用意されています

Task List を作成する

通常、Notionで新しくワークスペースを作成したら生成されているかと思います
別途作りたい場合はBoard Viewで新規作成しましょう

Board ViewはNotion内ではDatabaseという扱いです。なのでNotion APIからアクセスする際はdatabasesというエンドポイントになります
公式ドキュメントはこの辺りです
developers.notion.com

Task List とIntegrationをコネクトする

ここ重要です!
Task ListとIntegrationをコネクトしないと、Notion APIからDatabaseにアクセスしても404になるので必ず必要です

私の場合は「for task list」というIntegrationを作っていたのでこれを選択しました


Slack側での準備

GASから通知したいチャンネルのWebhook URLを作成&取得します
公式ドキュメントの通りにやれば大丈夫だと思います

GAS側での準備

やることは5点あります

  1. IntegrationからNotion APIのTokenを持ってくる
  2. Task List(Database)のIDを持ってくる
  3. Slack チャンネルのWebhook URLを持ってくる
  4. Notion APIで取得してきたタスクの一覧を整形する
  5. Slack Webhook URLからPostする

GASのコードのほとんどはChatGPT(GPT-4)に生成してもらいました
あとは持ってきた各情報を当て込むのと、取得したいタスクのQueryを作るだけです

ただ、ChatGPTに生成してもらったものだとAPI Keyなどがコード上にベタ書きになっておりセキュアではないので、GASのスクリプトプロパティを使ったほうが良いかと思います。
Class PropertiesService  |  Apps Script  |  Google Developers

const NOTION_API_KEY = "your_notion_api_key";
const DATABASE_ID = "your_database_id";
const SLACK_WEBHOOK_URL = "your_slack_webhook_url";

function getTasksFromNotion() {
  const url = `https://api.notion.com/v1/databases/${DATABASE_ID}/query`;
  const options = {
    method: "post",
    headers: {
      "Notion-Version": "2021-08-16",
      "Authorization": `Bearer ${NOTION_API_KEY}`,
      "Content-Type": "application/json",
    },
    payload: JSON.stringify({})
  };

  const response = UrlFetchApp.fetch(url, options);
  const data = JSON.parse(response.getContentText());
  const tasks = data.results.map(result => result.properties.Name.title[0].plain_text);

  return tasks;
}

function sendTasksToSlack(tasks) {
  const message = tasks.map((task, index) => `${index + 1}. ${task}`).join("\n");
  const payload = {
    text: `今日のタスク:\n${message}`
  };

  const options = {
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
}

function main() {
  const tasks = getTasksFromNotion();
  sendTasksToSlack(tasks);
}

DatabaseからTo DoとDoingに入っているタスクの一覧を取得するためのQueryは以下のようにしました

  query = {
	"filter": {
		"or": [
			{
				"property": "Status",
				"select": {
					"equals": "To Do"
				}
			},
			{
				"property": "Status",
				"select": {
					"equals": "Doing"
				}
			}
		]
	},
   "sorts": [
    {
      "property": "Status",
      "direction": "descending"
    }
  ]
};

※注意※
2023年4月現在では、どうやら「各カラムに入っているそのままの順番で出力する」ことはできないようです
デフォルトの仕様としては「created_timeの新しい順」のようです
私は優先度順で上から並べていたので「ギャースカピーーーーー」となりました
対策として、順番を示すプロパティを作ってNotionUI側でもそれをソート条件にすれば可能ではあります。ただ、優先度を並び替えるだけなのにこのプロパティを毎回イジるのは大変なので今回は実施しませんでした(直感的なドラッグドロップでの並び替えにAPIが対応してほしいぞ)

なので私は「通知され視認できること」に重きを置き、まずは通知することを優先しました
ソート条件でStatusを指定すると、Statusごとにまとめられるのでそれだけでいいかなってところです
(Descendingにすると、Doingに含まれるものが先に出力され、次にTo Doに含まれるものが出力されます)

どんなソート条件が使えるかは公式ドキュメントを参照してください
developers.notion.com

Slackに出力する文言の工夫

なんとか自分を鼓舞するべく、やる気が出るようにしました

  • 🎉でテンション上げる
  • 「今日も1日頑張っていきましょう!キミならできる!!」と言ってもらう

1ミリでもやる気や元気が出たら勝ちです!

やってみて

  • 「さて今日はなにやろっかな」が無くなった
  • 「手が空いた時にちょっとこっちもやっておこう」と意識を複数タスクに向けやすくなった
  • なんとなく朝イチの頭のスッキリ具合が良くなった

よかったら皆さんのタスク管理方法も教えてください!

© Sansan, Inc.