Closed7
Slack投稿の絵文字リアクションをトリガーにNotionページを自動作成する

概要
Slackの投稿に特定の絵文字リアクションが付与されたら、その投稿とスレッド内容をNotionのページとして自動保存する仕組みを構築する。
セットアップ
Slack
- Slack APIでアプリ作成
- Bot Token ScopesとUser Token Scopesに必要な権限を追加
channels:history
groups:history
mpim:history
im:history
reactions:read
- User OAuth Tokenを取得
Notion
- Notion Developersでインテグレーション作成
- Internal Integration Token取得
- データベースIDを取得
GAS
スクリプトプロパティに以下を設定
SLACK_TOKEN
NOTION_TOKEN
NOTION_DATABASE_ID

GASでのスクリプト実装
GASに以下コードを実装
const targetEmoji = "notion"; // 追跡する絵文字に置き換える
// eslint-disable-next-line
function doPost(e) {
// Slackからのリクエストを解析
const params = JSON.parse(e.postData.contents);
// SlackからのURL検証リクエストを処理
if (params.type === "url_verification") {
return ContentService.createTextOutput(params.challenge);
}
// 絵文字リアクションが追加された場合
if (params.event && params.event.type === "reaction_added") {
const reaction = params.event.reaction;
if (reaction === targetEmoji) {
// prettier-ignore
// eslint-disable-next-line
const slackToken = PropertiesService.getScriptProperties().getProperty("SLACK_TOKEN");
// Slack APIを使って該当のメッセージとスレッドを取得
const channelId = params.event.item.channel;
const messageTs = params.event.item.ts;
const messageResponse = UrlFetchApp.fetch(
`https://slack.com/api/conversations.history?channel=${channelId}&latest=${messageTs}&limit=1&inclusive=true`,
{
method: "get",
headers: {
Authorization: `Bearer ${slackToken}`,
},
}
);
const messageData = JSON.parse(messageResponse.getContentText())
.messages[0];
// スレッドのメッセージを取得
const threadTs = messageData.thread_ts || messageTs;
const threadResponse = UrlFetchApp.fetch(
`https://slack.com/api/conversations.replies?channel=${channelId}&ts=${threadTs}`,
{
method: "get",
headers: {
Authorization: `Bearer ${slackToken}`,
},
}
);
const threadMessages = JSON.parse(
threadResponse.getContentText()
).messages;
// Notionに書き込むデータを準備
const data = threadMessages.map((msg) => ({
object: "block",
type: "paragraph",
paragraph: {
rich_text: [
{
type: "text",
text: {
content: msg.text,
},
},
],
},
}));
// 絵文字リアクションが追加されたテキストの投稿日付をUTCからJSTに変換
const postDate = new Date(messageData.ts * 1000 + 9 * 60 * 60 * 1000)
.toISOString()
.split("T")[0]; // 日付をYYYY-MM-DD形式に変換
// データベースIDを取得
// prettier-ignore
// eslint-disable-next-line
const databaseId = PropertiesService.getScriptProperties().getProperty("NOTION_DATABASE_ID");
// Notionに送信するリクエストボディを構築
const notionRequestBody = {
parent: { database_id: databaseId },
properties: {
name: {
title: [
{
text: {
content: "Slackのメモ", // ページのタイトル
},
},
],
},
date: {
date: {
start: postDate, // 日付
end: null, // 今回は終了日付は不要
},
},
Status: {
status: {
name: "未着手", // ステータス
},
},
},
children: data, // テキスト
};
// Notion APIトークンを取得
// prettier-ignore
// eslint-disable-next-line
const notionToken = PropertiesService.getScriptProperties().getProperty("NOTION_TOKEN");
// Notion APIにリクエストを送信
UrlFetchApp.fetch("https://api.notion.com/v1/pages", {
method: "post",
headers: {
Authorization: `Bearer ${notionToken}`,
"Content-Type": "application/json",
"Notion-Version": "2022-06-28",
},
payload: JSON.stringify(notionRequestBody),
});
}
}
return ContentService.createTextOutput("OK");
}

Slack側の設定
- デプロイ後に生成されたURLをSlack API Event Subscriptions に設定
- eventsに必要な権限を追加する。
reactions:read

この仕様だと、スレッドの最初のメッセージに絵文字リアクションをつけることで、そのメッセージに紐づくスレッド内のメッセージが全てNotionに書き込まれる。
スレッドの最初のメッセージと投稿日付が異なるスレッド途中のメッセージに絵文字リアクションをつけた場合、テキスト内容が正しくNotionに書き込まれない(書き込めるように暇あったら修正したい)

Notion APIを使う時のメモ
指定したデータベースのプロパティを確認する
※事前に作成したインテグレーションをDBにアクセス許可する必要あり
例
curl -X GET 'https://api.notion.com/v1/databases/DATABASE_ID' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Notion-Version: 2022-06-28'
指定したデータベースにページを追加する
例
curl -X POST 'https://api.notion.com/v1/pages' \
-H 'Authorization: Bearer {YOUR_INTEGRATION_TOKEN}' \
-H 'Content-Type: application/json' \
-H 'Notion-Version: 2022-06-28' \
-d '{
"parent": { "database_id": "YOUR_DATABASE_ID" },
"properties": {
"名前": {
"title": [
{
"text": {
"content": "プロジェクトA計画"
}
}
]
},
"日付": {
"date": {
"start": "2024-04-01",
"end": null
}
},
"Status": {
"status": {
"name": "計画中"
}
}
},
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "プロジェクト概要の説明"
}
}
]
}
},
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "主要なマイルストーン"
}
}
]
}
},
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "予算と人員配置の検討"
}
}
]
}
}
]
}'

成果物

slackのuser idを取得する方法
このスクラップは3ヶ月前にクローズされました
ログインするとコメントできます