【GAS】Slackのリアクション追加をトリガーに、Notionデータベースにアイテムを追加する

これは[Acompany😎 Advent Calendar 2024](https://adventar.org/calendars/10761)の8日目の記事です。

# 背景
私の記憶力はゴミです。
タスクを覚えておく、ということがまったくできません。
なので全てのタスクをNotionにメモしているのですが、会社のSlackコミュニケーションが活発なので、半分くらいのタスクはSlackでのやりとりから発生します。
手でタスク表に追加したり、Slackのブックマーク機能を使ったりしていたのですが、どうにも非効率だなと感じたので、Slackのリアクションをトリガーに、Notionデータベースにアイテムを追加したいなと考えました。

# 作るもの
メッセージにリアクションを追加する
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/7f1d88a8-8c50-e104-f440-9c872dce6236.png" width="50%">

データベースにアイテムが追加される
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/98e61b8c-301f-416e-0ff1-94db14f3b865.png">
 

# 手順
## GASでアプリをデプロイ
以下URLからプロジェクトを新規作成します。

https://script.google.com/home

以下のスクリプトを貼って、デプロイしてください。
``` script.js
function doPost(e){
  var params = JSON.parse(e.postData.getDataAsString());
  if (params.type === "url_verification") {
      return ContentService.createTextOutput(params.challenge);
  }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/512abacc-a0cc-db70-b33a-3113e4bcb54c.png)
アクセスできるユーザーは、全員にしてください。


## Slackアプリを作る
以下のURLからアプリを新規作成

https://api.slack.com/apps

### アプリ設定
- Basic Information
    - Display Information
        - アプリの表示名を入力
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/3571442c-20b9-c1ad-97b4-dac6bc5d7a4a.png)
- OAuth & Permissions
    - Scopes
        - Bot Token Scopes
            - 以下の権限を追加
                - `channels:history`
                - `reactions:read`
            - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/0fe7c8f5-2040-42fb-63fc-81a8ca94ab49.png)

- Event Subscriptions
    - Subscribe to bot events
        - `reaction_added`を追加
    - Enabel Events
        - Request URL
            - 先ほどデプロイしたGASアプリのウェブアプリURLを貼る
            - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/ecbdc522-a3a2-c18f-cf6a-6a2db8fa9195.png)
            - Verifiedと表示されたら成功

### Slackワークスペースにアプリを追加
- Install APP
    - ワークスペースにアプリをインストールする

## Notionインテグレーションを追加

https://www.notion.so/ja/help/add-and-manage-connections-with-the-api

上記手順に沿ってインテグレーションを追加してください。


## スクリプト
先程のスクリプトを消して、以下のスクリプトを貼り付けてください。
` DATABASE_ID`, `NOTION_TOKEN`, `SLACK_APP_TOKEN`はそれぞれ記入してください。

``` script.js
const post_url = 'https://api.notion.com/v1/pages';
const url_replies = "https://slack.com/api/conversations.replies";
const url_getPermalink = "https://slack.com/api/chat.getPermalink";
const DATABASE_ID = "XXXX"; // NotionのデータベースID
const NOTION_TOKEN = "XXXX"; // Notionアプリのトークン
const SLACK_APP_TOKEN ="XXXX"; // SlackアプリのBotトークン
const query_url = 'https://api.notion.com/v1/databases/' + DATABASE_ID + '/query';
const properties = PropertiesService.getScriptProperties();

function doPost(e){

  let json = JSON.parse(e.postData.getDataAsString());
  let event = json.event;
  let reaction = event.reaction;
  let ts = event.item.ts;
  let channel = event.item.channel;
  let type = event.type;
  let event_ts = event.event_ts;
  
  if(properties.getProperty("event_ts") != event_ts){
    if(type == "reaction_added"){
      if(reaction == "takedayaru"){
        properties.setProperty("event_ts", event_ts);
        getMessage(ts, channel);
      } 
    }
  };
};

function getMessage(ts, channel){
  
  let options_replies = {
    "method" : "get",
    "contentType": "application/x-www-form-urlencoded",
    "payload" : { 
      "token": SLACK_APP_TOKEN,
      "channel": channel,
      "ts":ts
    }
  };
  
  
  let options_getPermalink = {
    "method" : "get",
    "contentType": "application/x-www-form-urlencoded",
    "payload" : { 
      "token": SLACK_APP_TOKEN,
      "channel": channel,
      "message_ts":ts
    }
  };

  // メッセージテキストを取得
  let responseReplies = UrlFetchApp.fetch(url_replies, options_replies);
  let jsonResponseReplies = JSON.parse(responseReplies);
  let text = jsonResponseReplies.messages[0].text;
  
  // メッセージリンクを取得
  let responsePermalink = UrlFetchApp.fetch(url_getPermalink, options_getPermalink)
  let jsonResponsePermalink = JSON.parse(responsePermalink);
  let link = jsonResponsePermalink.permalink;
  
  addTask(text, link);

};

function addTask(text, link){
  let today = new Date();
  
  // 日付をフォーマット
  let formattedDate = today.getFullYear() + '-' +
                        String(today.getMonth() + 1).padStart(2, '0') + '-' +
                          String(today.getDate()).padStart(2, '0');
  let dueDate = new Date(formattedDate);
  
  let json = {
    parent: {
      database_id: DATABASE_ID,
    },
    properties: {
      "名前": {
        "title": [{
          "text": {
            "content": text
          }
        }]
      },
      "期日": {
        "date": {
          "start": formattedDate
        }
      },
      "URL": {
        "url": link
      }
    }
  }

  let options_post = {
    "method": "POST",
    "headers": {
      "Content-type": "application/json",
      "Authorization": "Bearer " + NOTION_TOKEN,
      "Notion-Version": '2022-06-28',
    },
    "payload": JSON.stringify(json),
  };

  UrlFetchApp.fetch(post_url, options_post);

};
```

`プロジェクトの設定`→`スクリプトプロパティ`から、プロパティを作成し`event_ts`と入力してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/a62945fe-531d-270e-ad48-c7767a4bbbe4.png)

:::note warn
なぜかリアクションを1回押しただけなのに、イベントが2回発生して、タスクが2レコード生成されることがありました。
その防止策として、最初にリアクション追加タイムスタンプを条件分岐に使用しています。
:::

再度デプロイします。


# 完成
これで完成です。
[Be Hacker](https://speakerdeck.com/acompany/zhu-shi-hui-she-acompany-karutiyadetuku?slide=21)なタスク管理で、クリスマスを待ちましょう！