【GAS】Slack App(Bot)へのDMを他のチャンネルに自動転送する
はじめに
Slack Botを利用して、DMで受け取ったメッセージや画像を特定のチャンネルに自動転送する機能を実装しました。この記事では、実装方法と必要なSlack Botの権限設定について解説します。
前提条件
- SlackワークスペースへのBotアプリ作成済み
- DMを転送したいチャンネルにBotを追加済み
- BotにDMを送れるようにSlack App ページ内で設定済み
- AppHome > Show Tabs > Messages Tab > Allow users to send Slash commands and messages from the messages tab にチェック
必要な権限
Slack APIを利用するために、Botに以下のOAuth権限を付与します。
-
channels:read
: チャンネル情報の取得 -
channels:join
: チャンネルへの参加 -
chat:write
: チャンネルへのメッセージ投稿 -
files:write
: ファイルの投稿 -
files:read
: ファイルの取得 -
im:read
: DMメッセージの取得
これらの権限を追加することで、BotはDMで受信したメッセージや画像を指定したチャンネルに転送できるようになります。
コードの説明
以下は、Slack BotがDMで受信したメッセージや画像を特定のチャンネルに転送するコードです。
1. 初期設定
まず、Slack BotのOAuthトークンを取得し、Slack APIのライブラリを設定します。
// Slack Bot User OAuth Token
const SLACK_API_TOKEN = 'xoxb-XXXXXXXXX-XXXXXXXXX-XXXXXXXXX';
2. チャンネルのID設定
DMからのメッセージを転送するチャンネルのIDを設定します。
const ChannelId_Bot = 'D0XXXXXXXXX'; // SlackAppチャンネル
const ChannelId_Trf = 'C0XXXXXXXXX'; // DM転送先チャンネル
3. メインのイベントハンドリング関数
doPost
関数は、Slackからのイベント(メッセージ受信など)を処理します。DMからメッセージを受け取った場合、そのメッセージやファイルを指定したチャンネルに転送します。
function doPost(e) {
const json = JSON.parse(e.postData.contents);
const event = json.event;
const text = event.text;
const eventType = event.type;
const eventChannel = event.channel;
const channelType = event.channel_type;
// キャッシュ処理: 同一メッセージの重複処理防止
const cache = CacheService.getScriptCache();
if (cache.get(json.event.client_msg_id) === 'done') {
return ContentService.createTextOutput();
} else {
cache.put(json.event.client_msg_id, 'done', 600); // キャッシュを600秒保持
}
// メッセージイベントかつ特定のチャンネルでのDMイベントの場合に処理
if (eventType === 'message' && eventChannel === ChannelId_Bot && channelType === 'im') {
postToSlack(text, event.files);
}
return ContentService.createTextOutput();
}
4. メッセージとファイルの転送関数
postToSlack
関数は、メッセージやファイルを転送先チャンネルに投稿するための関数です。ファイルの場合は、ファイルのダウンロードとアップロードURLの取得、再アップロード処理を行います。
function postToSlack(text, files) {
if (files && files.length > 0) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
const fileUrl = file.url_private;
// step1:ファイルをSlackからダウンロード
const response = UrlFetchApp.fetch(fileUrl, {
headers: {
'Authorization': 'Bearer ' + SLACK_API_TOKEN
}
});
const blob = response.getBlob();
const fileSize = blob.getBytes().length;
// step2:アップロードURLを取得
const uploadUrlResponse = UrlFetchApp.fetch(`https://slack.com/api/files.getUploadURLExternal?filename=${encodeURIComponent(file.name)}&length=${fileSize}`, {
method: 'get',
headers: {
'Authorization': 'Bearer ' + SLACK_API_TOKEN,
'Content-Type': 'application/json; charset=utf-8'
},
muteHttpExceptions: true
});
const uploadUrlResult = JSON.parse(uploadUrlResponse.getContentText());
if (!uploadUrlResult.ok) {
continue;
}
const uploadUrl = uploadUrlResult.upload_url;
const fileId = uploadUrlResult.file_id;
// step3:ファイルをアップロード
const uploadFileResponse = UrlFetchApp.fetch(uploadUrl, {
method: 'post',
payload: blob,
muteHttpExceptions: true
});
if (uploadFileResponse.getResponseCode() !== 200) {
continue;
}
// step4:アップロード完了通知
const completeUploadResponse = UrlFetchApp.fetch('https://slack.com/api/files.completeUploadExternal', {
method: 'post',
headers: {
'Authorization': 'Bearer ' + SLACK_API_TOKEN,
'Content-Type': 'application/json; charset=utf-8'
},
payload: JSON.stringify({
files: [{ id: fileId, title: file.name }],
channel_id: ChannelId_Trf,
}),
muteHttpExceptions: true
});
const completeUploadResult = JSON.parse(completeUploadResponse.getContentText());
if (!completeUploadResult.ok) {
Logger.log('ファイルのアップロード完了通知に失敗しました: ', completeUploadResult.error);
}
}
} else { // ファイルがない場合はテキストを転送
const messageResponse = UrlFetchApp.fetch('https://slack.com/api/chat.postMessage', {
method: 'post',
contentType: 'application/json',
headers: {
'Authorization': 'Bearer ' + SLACK_API_TOKEN
},
payload: JSON.stringify({
channel: ChannelId_Trf,
text: text
})
});
const messageResult = JSON.parse(messageResponse.getContentText());
if (!messageResult.ok) {
Logger.log('メッセージの投稿に失敗しました: ', messageResult.error);
}
}
}
まとめ
このコードを利用することで、Slack BotはDMで受け取ったメッセージや画像を特定のチャンネルに転送できるようになります。私はこれで匿名で話せるチャンネルを作りました。やはり、言いにくいことを言える場を作るのも大事だと思います。
生成AIでこのコードをほとんど書いたのですが、使えないfiles.upload API
を紹介してきたり、step3:ファイルのアップロードのmethod
をなぜかput
にしてきたりしました。生成AIによるコーディングでエラー吐いたら、ちゃんと公式ドキュメントを読むようにしましょう...
参考
Discussion