0
Help us understand the problem. What are the problem?

posted at

updated at

Lambda+API Gateway+SlackでNotionにタスクを追加

今回やったこと

・SlackのスラッシュコマンドでDMからNotionにタスクを追加できる機能を作成した
・ワークスペースにいるほかの人が勝手にタスクを登録できないようにユーザーIDで制限を付けた

Notionとは

Notionとはメモやプロジェクト管理,タスク管理のためのオールインワンワークスペースのこと。
個人利用であれば無料で利用することができる。

今回は下の画像のような形式のタスクを追加するものを作成する (プリパラはいいぞ)
task.png

Notion側の設定

[Notion] いま人気の Notion の API を試してみる
↑このページの流れで設定を行って、シークレットとデータベースIDをメモしておいてください。
データベースIDはhttps://www.notion.so/XXXXX?v=YYYYYYYY の中のXXXXXの部分です。

構成

超簡単構成
notion-api.drawio (2).png

Lambda関数の作成

まずはSlackbotから投げられるリクエストを処理する関数を作っていきます。

環境変数の設定

API_KEY → Notion APIのシークレット
DATABASE_ID → NotionのデータベースID
SLACK_TOKEN → Slack APIのOAuthトークン(後で追加)
CHANNEL → BotとのDMのチャンネルID
USER_ID → SlackのユーザーID (完成前に一度リクエストを送ってログでユーザーIDを取得しておく)

import

notion-slash.py
import json
import datetime
import sys
import urllib.parse
import os

import requests
import base64

ハンドラ

def get_request_url(end_point):
    return f'https://api.notion.com/v1/{end_point}'

def handler(event, context):
    data = event_interpretation(event) #イベント解釈へ
    
    #環境変数から情報を取得
    notion_api_key = os.environ.get("API_KEY") #Notion APIのシークレット
    database_id = os.environ.get("DATABASE_ID") #NotionのデータベースID
    
    headers = {"Authorization": f"Bearer {notion_api_key}",
               "Content-Type": "application/json",
               "Notion-Version": "2021-05-13"}
    
    #タイトル,ステータス,デッドライン,優先度を取得(ここは送る先の設定に準拠)
    property_name = {"title":[{"text":{"content":data["title"]}}]}
    
    status = {"select": {"name": data["status"]}}
    
    dead_line = {"date":{"start": datetime.date(data["dead_line"][0],data["dead_line"][1],data["dead_line"][2]).isoformat()}}
    
    task_priority = {"rich_text":[{"text":{"content":data["priority"]}}]}
    
    body = {
        "parent": {
            "database_id": database_id},
        "properties": {
            "Name": property_name,
            "ステータス": status,
            "デッドライン": dead_line,
            "優先度": task_priority
        }}
    
    response = requests.post(get_request_url('pages'), headers=headers, data=json.dumps(body))

    #成功メッセージ送信
    message = f"タスクの追加が完了しました\nタイトル:{data['title']}\nステータス:{data['status']}\nデッドライン:{data['dead_line']}\n優先度:{data['priority']}"
    response_slack(message)

    print(response.json())
    
    return

イベント解釈

イベントとして送られてくるjsonがそのままでは扱えないのでいろいろと変換&
不正なリクエストをここではじいている


def event_interpretation(event):
    #event["body"] = "タイトル,対応中,20221122,高"
    
    body_dict = {}
    
    split_body = base64.b64decode(event["body"]).decode().split("&")
    
    for status in split_body:
        status = status.split("=")
        body_dict[status[0]] = status[1]
        
    propaty_tmp = urllib.parse.unquote(body_dict["text"]).split("+")

    #不正なリクエストをチェック
    propaty_tmp = "fraud request" if body_dict["user_id"] != os.environ.get("USER_ID") else propaty_tmp
    
    #データの正当性チェック
    if propaty_tmp == "fraud request":
        message = "不正なリクエストです"
        response_slack(message)
        sys.exit()
    elif len(propaty_tmp) != 4:
        message = "送信形式が正しくありません ex:タイトル,対応中,20221122,高"
        response_slack(message)
        sys.exit()
    elif len(propaty_tmp[2]) != 8:
        message = "日付の形式が正しくありません ex:19991122"
        response_slack(message)
        sys.exit()
        
    date = [int(propaty_tmp[2][0:4]),int(propaty_tmp[2][4:6]),int(propaty_tmp[2][6:8])]
    propaty = {"title":propaty_tmp[0],"status":propaty_tmp[1],"dead_line":date,"priority":propaty_tmp[3]}
    
    return propaty

メッセージ返答

BotとのDMに対してメッセージを返す関数

def response_slack(message):
    TOKEN = os.environ.get("SLACK_TOKEN") #Slack APIのOAuthトークン
    CHANNEL = os.environ.get("CHANNEL") #BotとのDMのチャンネルID
    
    url = "https://slack.com/api/chat.postMessage"
    headers = {"Authorization": "Bearer "+TOKEN}
    
    data  = {
        'channel': CHANNEL,
        'text': message
    }
    r = requests.post(url, headers=headers, data=data)
    print("return ", r.json())
    

API Gatewayと紐づけ

解説は省略
発行されたエンドポイントURLをコピーしておく(形式: https://hogehoge.excute-api.apnortheast-1.amazonaws.com/default/[関数名])

SlackAPIの設定

  1. https://api.slack.com/ にアクセス
  2. 右上のYour Appsを選択しログインしていない場合はログインする.
  3. Create New AppでFrom scratchを選択
  4. App Nameとワークスペースを選択
  5. 左のメニューからSlash Commandsを選択&作成(Request URLはさっきのAPI Gatewayエンドポイント)
  6. 左のメニューのOAuth&Permissionsから必要なスコープを追加する(今回はim:write,chat:writeあたりを追加)
  7. ワークスペースにアプリをインストール

コマンド実行

(実行前にSlack APIのOAuthトークンをLambdaの環境変数に追加)

自分のDMで先ほど設定したスラッシュコマンドを実行すると,botがリアクションをくれてタスクが作成できた!!(はず・・・)
※処理に三秒以上かかるとdispatch_faildが出ますが処理は続いています

まとめ

今回は、ちょうどNotionのタスク追加手軽にしたいなと思っていたのでSlack Botの勉強ついでに作成してみました。
今回は影響範囲が自分のNotionだけだったので省略しましたが、SHA256を利用しての認証やdispatch_failedが帰ってきてしまう問題があるので時間があるときにもう少し拡張しようと考えています。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?