Slack→GAS→NotionでTODOリスト化を少し便利にする

これは 🎅GMOペパボエンジニア Advent Calendar 2022 の9日目の記事です。

🎄GMOペパボエンジニア Advent Calendar 2022もありますのでぜひご覧ください!!

昨日は yana-gi さんによる 中学生以来の電子工作をして meishi2 を組み立てたでした。自分でキーボードを組み立てて、しかも好きなマクロを登録できるって楽しそうですね!私も記事内で紹介されていた「自作キーボードを作る会」に参加していて、これからキーボード作りに取り組むのが楽しみです😋

追記

  • 2022/12/09 00:38追記 リプライを取得できないことを確認したので修正中です。
  • 2022/12/09 01:14追記 コードの修正が完了しました。

タスク管理の悩みごと

みなさんは仕事などにおけるタスク管理をどのように行われているでしょうか?私はNotionのデータベースを使用して管理しています!優先度や関連するURL、進行具合などをすぐに確認できるようにしています。

ここで一点悩みが……

タスク管理をする際に、自分用のTODOリストとチーム用のカンバンと2箇所で管理をしています。両方のデータベースに登録する際に、片方だけ登録してもう片方に登録し忘れるということが頻発してしまうのです。

「一方だけに登録すればいいのでは?」とも思うのですが…チームにも自分にも関することは両方に登録したいですし、どちらか一方だけ登録できればOKという場合もあって悩んでいました。あと、普段のやり取りをSlackでするのにタスク管理のためにNotionに移動するのが面倒ですからね… …つい本音が漏れてしまいました

ということで今回は

  1. タスク管理したいSlackのメッセージに特定のemojiをリアクション
  2. Notionの指定したデータベースにページを作成し、メッセージの内容を名前として登録する

の流れを自動化してみました。

Notionの準備

データベースの準備

まずはタスクを登録するデータベースが必要です。今回は仮想のデータベースを二つ作成しました。

Notionのスクリーンショット。同一ページ内に仮想のタスクを登録するデータベースが2つ存在している。
今回は見本として同じページ内にデータベースを作成しました。

インテグレーションの準備

Notionのページ作成をAPIから実行できるようにするためインテグレーションを作成します。

Notionの自分のインテグレーションのページ。

今回はページの作成ができれば十分なので「コンテンツを挿入」だけ設定します。

Notionインテグレーションに「コンテンツを挿入」の権限を付与。

Google Apps Script の準備

Slack AppとNotionの仲介役にサーバーが必要です。今回は、GASを使ってリクエストを処理するようにします。

docs.google.com

見本のシートを作成したので、自分のGoogleドライブに保存して使用してください。 これから保存していただいたシートに情報を書き込むのですが、トークンなどがバレないようにリンクの漏洩などには十分にご注意ください。

この先、Slack AppがGASを認証できるように設定を行います。「拡張機能」から「Apps Script」を開いて

以下のコードをコピペします。ペーストしたら、2行目の GoogleスプレッドシートのIDを置き換えるスプレッドシートのIDに置き換えてください。IDは https://docs.google.com/spreadsheets/d/xxxxxxxxxxxx/edit......xxxxxxxxxxxx の部分です。

function doPost(e) {
  const sheet = SpreadsheetApp.openById("GoogleスプレッドシートのIDを置き換える");
  const notionToken = sheet.getRange("F2").getValue();
  const slackToken = sheet.getRange("H2").getValue();
  const lastRow = sheet.getLastRow();
  const params = JSON.parse(e.postData.getDataAsString());

  if (params.type == 'url_verification') {
    return ContentService.createTextOutput(params.challenge);
  } else {
    const slackEvent = params.event;
    const targetEmoji = slackEvent.reaction;
    const ts = slackEvent.item.ts;
    const channel = slackEvent.item.channel;
    const title = getSlackMessage(slackToken, channel, ts)
    let settingCells;
    let databaseId, emoji;
    let destinations = {};
    
    for(let i = 2; i <= lastRow; i++){
      settingCells = sheet.getRange(`A${i}:C${i}`).getValues();
      [, databaseId, emoji] = settingCells[0];

      if (!Object.keys(destinations).includes(emoji)) {
        destinations[emoji] = [];
      }

      destinations[emoji].push(databaseId);
    }

    Object.keys(destinations).forEach(key => {
      if(targetEmoji == key) {
        destinations[key].forEach(destination => {
          postToNotion(notionToken, destination, title);
        })
      }
    })
  }
}

function getSlackMessage(slackToken, channel, ts) {
  const options = {
    "headers": {
      "Authorization": `Bearer ${slackToken}`,
    },
    "payload": {
      "channel": channel,
      "latest" : ts,
      "inclusive": "true",
      "limit": "1",
      "ts": ts
     }
  }

  let res = UrlFetchApp.fetch("https://slack.com/api/conversations.replies", options)
  return JSON.parse(res.getContentText()).messages[0].text;
}

function postToNotion(notionToken, databaseId, title) {
  const payload = {
    "parent": {
      "database_id": databaseId
    },
    "properties" : {
      "title": {
        "title": [
          {
            "text": {
              "content": title
            }
          }
        ]        
      }
    }
  }

  const options = {
    "headers": {
      "Authorization": `Bearer ${notionToken}`,
      "Notion-Version": "2022-06-28"
    },
    "contentType": "application/json",
    "method": "post",
    "muteHttpExceptions": true,
    "payload": JSON.stringify(payload)
  }

  UrlFetchApp.fetch("https://api.notion.com/v1/pages", options)
};

コピペしたら右上の「デプロイ」からWebアプリとしてデプロイします。Slack Appからのリクエストを受け付けるように「アクセスできるユーザー」は「全員」に設定します。

「アクセスを承認」のボタンが出てきたら、自分のアカウントを選択→「Advanced」→Go to (GASのプロジェクト名)…と作成したGASを承認してください。

無事デプロイが完了したら、作成したGASのWebアプリのURLが表示されるのでコピーします。

Slackの準備

ワークスペースやチャンネルの作成の説明については省略します。

Slack Appの作成

以下のリンクにアクセスし「Create an app」→「from scratch」で新しくSlack Appを作成しましょう。

api.slack.com

Slack Appの名前と対象のワークスペースを決定したら、「Basic Information」が開くので「Event Subscriptions」に移動します。

Slack AppのBasic Informationのスクリーンショット。どのようなAppにするか決定できる。

ここで先ほどコピーしたGASのWebアプリのURLを「Request URL」に登録してサーバーの認証を行います。認証ができると「Request URL Verified ✅」が表示されます。

そのままページ下部に移動すると「Subscribe to bot events」という項目があるので、emojiを押したことをAppが検知できるように「Add Bot User Event」から「reaction_added」を追加します。

右下の「Save Changes」を押して忘れずに変更を保存しましょう。

Slack Appの権限設定

このあと作成するAPIのために「OAuth & Permissions」から権限を設定します。「Scopes」の「User Token Scopes」に以下の4つを追加しましょう。「Bot Token Scopes」のreactions:read は先ほど「Subscribe to bot events」を設定したときに適用されています。

  • channels:history
  • groups:history
  • im:history
  • mpim:history

Slack Appの名前を設定する

「App Home」からSlack Appの名前を設定します。これを設定しないと、「インストールするボットユーザーがありません」というエラーが出てAppをインストールできません。

登録に成功すると「Bot user added!」と表示されます。

Slack Appのインストール

「Basic Information」に移動すると「Install your app」という項目があるので、「Install to Workspace」からAppをインストールしましょう。

右下の「許可する」でインストールしましょう。

チャンネルへの追加

Appを使用したいチャンネルへ追加します。

チャンネル詳細を開き、「インテグレーション」の「App」から「アプリを追加する」を選択します。追加できるアプリの一覧が表示されるので、先ほど作成したアプリを追加しましょう。

Notionデータベースとスプレッドシートの準備

AとB、二つのデータベースを作成したので、「Aのデータベースに登録するときはAのemoji」「Bのデータベースに登録するときはBのemoji」「両方に登録するときにはOKのemoji」を使うことにしました。

Slackのメッセージ。AのデータベースにはA、BにはB、両方にはOKを押せば登録することを決定した。

Notionのデータベースの右上、メニューを開いて「ビューのリンクをコピー」を押します。

すると https://www.notion.so/aaaaaaaaaaaaa?v=......... のようなリンクを取得できるので aaaaaaaaaaaaaスプレッドシートに貼りましょう。もう片方のデータベースについても同様に取得と貼り付けをします。また、どのemojiを押したときにページ作成を行うか設定もしておきましょう。

コネクトの追加

Notionのインテグレーションを導入するためにページ右上のコネクトから、自分が作成したインテグレーションを選択します。

tokenをスプレッドシートに貼り付け

長かった工程もこれが最後です!

www.notion.so

冒頭で準備したNotionのインテグレーションのシークレットトークンをスプレッドシートのF2セルにコピペします。

また、上記画像のようにSlack Appの「User OAuth Token」も「Installed App Settings」から取得してH2セルにペーストします。

動作確認

Slackでメッセージを送ってemojiでreactionしてみましょう。

するとNotionのデータベースにページが自動で作成されます。

これで少しだけ便利にできるSlack・GAS・Notion連携の完成です!

最後に

今回はemojiを判定して対応させたいデータベースへの登録を行いました。Slack AppやGAS、Notion APIを使うことで少しだけ便利にすることができたました!これからもっと発展させてURLを自動登録したり、他のプロパティも登録できるようなアプリケーションに進化させていきたいです。

参考にした情報

この記事・アプリを作成するにあたってたくさんの情報を参考にさせていただきました。情報を発信してくださった方々に感謝いたします。


明日の🎅GMOペパボエンジニア Advent Calendar 2022は、我らがCTOのあんちぽさんです!🙌