🤖
召喚されたら召喚者が参加していないTimesチャンネルを教えてくれるSlack botを作りました
こんにちは、TRUSTDOCKのよもぎたです。
前回、前々回とつづいたSlack botシリーズの、たぶん最終形態です。
botの名前も「シン・人工無能」にしました。庵野監督の「シン・」○○は「シン・ゴジラ」が好きです。
アプローチ
概要
前回、前々回で
- Timesチャンネルの一覧を取得する
- Slackのメッセージに返信する
ことが出来るようになっています。
今回は、上記に加えて次の2つが出来るようにしました。
- botが参加しているチャンネル(=私のTimesチャンネル)で特定のメッセージが投稿され時にそれに返信する
- 各Timesチャンネルにメッセージを投稿したユーザーが参加しているかどうかを判定する
実行結果
こんな感じになります。
参加していないTimesチャンネルがある場合
すべてのTimesチャンネルに参加している場合
実装
Slackアプリの準備
今回も過去私が投稿したこちらの記事を参考にしました。
アプリに付与した権限は、
になります。
いざGASで実装
doPost()
function doPost(e) {
let params = JSON.parse(e.postData.getDataAsString());
const app_user_id = 'U...';
if (params.type == 'url_verification') {
return ContentService.createTextOutput(params.challenge);
}
if (params.event && params.event.type == 'message' && params.event.user != app_user_id && !params.event.subtype) {
handleEvent(params.event);
}
return ContentService.createTextOutput(JSON.stringify({ "challenge": params.challenge }));
}
メッセージの投稿者(params.event.user
)がbot自身でないことの判定は試験的に実装していた時の名残です。最終的には不要になりました。(不要のはずです)
bot自身のユーザーIDは、botにメッセージを投稿させて取得しました。もっとスマートなやり方があったら教えてください。
handleEvent()
function handleEvent(event){
if(event.text.includes('人工無能召喚')){
send_reply(event);
}
}
send_reply()
function send_reply(event){
const slack_oauth_token = 'xoxb-deadbeef...';
const slack_dest_channel_id = 'C...';
const all_times_channels = get_all_times_channels(slack_oauth_token);
const not_joined_times_channels = get_not_joined_times_channels(slack_oauth_token, event.user, all_times_channels);
let response_message = '<@' + event.user + '>\n\n人工無能見参!!\n\n';
if(not_joined_times_channels.length > 0){
response_message = response_message + get_user_display_name(slack_oauth_token, event.user) + 'さんが参加していないSlackチャンネルをお知らせします\n\n';
not_joined_times_channels.forEach((channel) =>
{
response_message = response_message + get_user_display_name(slack_oauth_token, channel[1]) + 'さんの<#' + channel[0] + '>\n';
}
)
response_message = response_message + '\nぜひ新しいTimesチャンネルに参加してコミュニケーションの輪を拡げましょう!';
}else{
response_message = response_message + 'すばらしい!!\n' + get_user_display_name(slack_oauth_token, event.user) + 'さんはいまある全てのTimesチャンネルに参加しています';
}
let slack_chat_post_message_api = 'https://slack.com/api/chat.postMessage';
let headers = {'Authorization': 'Bearer ' + slack_oauth_token, 'Content-types': 'application/json; charset=UTF-8'};
let payload = {'channel': slack_dest_channel_id, 'thread_ts': event.ts, 'text': response_message};
let options = {'method': 'POST', 'headers': headers, 'payload': payload};
UrlFetchApp.fetch(slack_chat_post_message_api, options);
}
get_all_times_channels()
function get_all_times_channels(slack_oauth_token){
const slack_conversations_api_url = 'https://slack.com/api/conversations.list?exclude_archived=true&limit=1000';
const headers = {'Authorization': 'Bearer ' + slack_oauth_token};
const options = {'headers': headers};
const channels = JSON.parse(UrlFetchApp.fetch(slack_conversations_api_url, options).toString()).channels;
let times_channels = [];
channels.forEach((channel) =>
{
if(channel.name.match(/^z-times-/)){
times_channels.push([channel.id, channel.creator]);
}
}
)
return times_channels;
}
get_not_joined_times_channels()
function get_not_joined_times_channels(slack_oauth_token, slack_target_user_id, all_times_channels){
const slack_conversations_memers_api = 'https://slack.com/api/conversations.members'
const headers = {'Authorization': 'Bearer ' + slack_oauth_token};
const options = {'headers': headers};
let not_joined_times_channels = [];
all_times_channels.forEach((channel) =>
{
let channel_id = channel[0];
let channel_creator = channel[1];
let req_api = slack_conversations_memers_api + '?channel=' + channel_id + '&limit=200';
let response = JSON.parse(UrlFetchApp.fetch(req_api, options).getContentText())
let members = response.members;
if(!members.includes(slack_target_user_id)){
not_joined_times_channels.push([channel_id, channel_creator]);
}
}
)
return not_joined_times_channels;
}
get_user_display_name()
この関数はまた以前の記事から流用しています。
コードは以上です。
最後に
最初は何気ない一言から始まったこのシリーズも、当初は考えてもいなかったところまで発展しました。探求心とか好奇心って大切ですね。
最後までお読みいただきありがとうございました。
Discussion