What?
Notionを編集したら必要な情報だけをSlack通知させるためのメモ。
主にタスク管理用のBoardで使用している。
Why?
Notionの通知、粒度が細かくて辛い、、、
1文字編集が入っただけでも通知が飛んできてしまう。
How?
そもそも、もっといい方法がありそうな気がしているので、そっと教えて欲しい気持ち。
今使っている方法は、
- NotionのSlack連携機能で、とりあえずどこかのチャンネルで全ての通知を受ける
- Slackに届いた通知内容をSlackAPPの仕組みを使ってサーバ(と書きつつ今はGASを使用中)にPOSTする
- サーバサイド(GAS)で、SlackMessageのTextやOptの中身を正規表現で検索して、投稿内容をいい感じにフィルタリングする
- フィルタを通過した内容をサーバ(GAS)からSlackにIncomingWebhookで送り返す
という回りくどい方法で実装してみている。
GASなのは通知の頻度とプロジェクトの量的に無料枠で支障がなかったため。です。今のところ。
繰り返しになりますが、もっといい方法がありそうな気がしているので、知っている方はそっと教えて頂きたいです。
手順メモ
SlackBotのPost先のverifyまで
- GASのプロジェクト用意する
- GASプロジェクトに、SlackBotのverifyするためのコードを書く
- GASのプロジェクトをWebAPPとしてデプロイしてエンドポイントURL作る
- SlackにNotionの全ての通知を受けるチャンネル(プライベート可)を作る
- フィルタリングした後の通知を流す用のチャンネルも作る
- SlackAPPを作る
- Event Subscriptions をOnにしてGASのエンドポイントをRequest URLにいれる
※ verifiedが通らなかったらGASのコードとかGASの公開設定とかデプロイしてるかとか確認
SlackBotの導入まで
- Subscribe to bot events に
message.channels
とmessage.groups
を設定 して Save - SlackAPPをSlackのWorkSpaceに再導入する(権限の関係で。多分ページ上部にアナウンスでる)
- Incoming WebhooksをOnにしてチャンネルに追加してURLをメモる
- Slack AppのTokenをメモる
- GASにNotionの通知メッセージをフィルタリングするコードを書く
- GASのプロジェクトのコード上で通知を飛ばせるようにWebhooksとTokenを設定する
- GASのコードをWebAPPとして再デプロイする
※ GAS側を何か更新するたびに、WebAPPとして再デプロイしないと更新が反映されないので注意 - SlackのNotionの全ての通知を受けるチャンネル(プライベート可)で、
/invite @{Botの名前}
をして、そのチャンネルにBotを追加する - Notionを更新して通知が飛ぶかを試す。 うまくいったらDone.
以上。お疲れ様でした。
Code
SlackBot Verify
function doPost(e){
// PostHandring
// console.log("receive POST");
if(!e){
return;
}
const params = JSON.parse(e.postData.getDataAsString());
const jsonString = JSON.stringify(params, undefined, 4);
if(params.challenge){
return ContentService.createTextOutput(params.challenge);
}
// console.log("return.");
// メッセージをフィルタリングする部分を書く
// filterMessage(params);
return;
}
MessageFilter
function filterMessage(params){
const token = params["token"];
const eventType = params["event"]["type"];
const messageText = params["event"]["text"];
const messageAttachments = params["event"]["attachments"];
// Tokenの確認。 スクリプトプロパティから引いているのは好みの問題。
const slackbotToken = PropertiesService.getScriptProperties().getProperty('SLACKBOT_TOKEN');
if(token !== slackbotToken){
// console.log("Token ERROR.");
return;
}
// Messageを正規表現でフィルタリング
const searchRegex = / commented in | created | deleted /g;
const ignoreRegix = / deleted .*\|Untitled>/g;
const searchInAttachmentRegex = /\*Status\*: |@/g;
if(messageText.search(searchRegex) >= 0){
if(messageText.search(ignoreRegix) >= 0){
// console.log("ignore from searchRegex");
}else{
// IncomingWebhockを使ってSlackに通知を送り返す処理をここに。 (このままコピペしても動作しないです)
// slackNotification(messageText, messageAttachments);
// console.log("send notification to slack.");
}
}else if(messageAttachments){
//messageAttachments が undefinedとかではない場合、その中のテキストも検索する。
for(let i = 0; i<messageAttachments.length; i++){
let attachmentText = messageAttachments[i]["text"];
if(!attachmentText){
attachmentText = "";
}
if(attachmentText.search(searchInAttachmentRegex) >= 0){
// IncomingWebhockを使ってSlackに通知を送り返す処理をここに。 (このままコピペしても動作しないです)
// slackNotification(messageText, messageAttachments);
// console.log("Check Attachments: send notification to slack.");
break;
}
}
}
}
SlackNotification
function slackNotification(text, attachments) {
// WebhookURL の指定。 スクリプトプロパティから引いているのは好みの問題。
const webhookUrl = PropertiesService.getScriptProperties().getProperty('WEBHOOK_URL');
const dataObj = {
username: 'NotionBot',
text: text,
//icon_emoji: ':notebook:',
link_names: true,
attachments: attachments,
mrkdwn: true
};
const options =
{
"method" : "post",
"contentType" : "application/json",
"payload" : JSON.stringify(dataObj)
};
UrlFetchApp.fetch(webhookUrl, options);
}