Slackのchannels.history とIncoming Webhook を使い、特定のメッセージを他のチャンネルに投稿する

はじめに

非エンジニアの友人から下記のような依頼を受けました。
Salesforce上でデータが更新されるとSlackの特定チャンネルにメッセージが投稿される。
このチャンネルには全社のデータがとうこうされるため、無関係のものが多い。
通知が来ても鬱陶しいのでミュートにしているけど、それだと自部署のものを見落としてしまう。
自分に関係するものだけSlackの別チャンネルに送れないか。

SlackにAPIがあるので、メッセージ履歴は取得できるでしょうし、メッセージを投稿するのはIncomingWebhookを使えば容易だろうと思い作ったものがこちらです。

構成

  • 「Slackのchannels.history APIを呼び出し、レスポンスの中に別チャンネルに送信したいものがあればIncoming Webhook経由で指定のチャンネルへ送信」する処理をGASで作成し、1分毎に実行するようにしました。
  • 前回の実行移行のデータを取るには、実行時刻をどこかに起動して置かなければなりません。そのあたりはハイブリッドでいこうさんのこちらを参考にしました。

GASのソース

// 環境構築メモ
//   現在時刻を取るためにMoment.jsを追加した(https://m-kawaguchi.hatenablog.jp/entry/2017/11/12/TogglのログをGoogleカレンダーに自動記録するスクリプ)

var TOKEN   = 'xxxxxxxxxx';
var CHANNEL = 'XXXDDDD';

function main() {
  
  var baseUrl = 'https://slack.com/api/channels.history';
  var baseParameters = [
    'token=' + TOKEN,
    'channel=' + CHANNEL,
    'oldest=' + getLastModifyDatetime(),
    // ↓ テスト用(10/1以降のデータを取得)
    //'oldest=1569921952',
    'count=1000',
  ];

  var messages = [];
  var latestMessage = '';
  
  var parameters = baseParameters.concat([latestMessage]).join('&');
  var res = fetchSlackMessage(baseUrl + '?' + parameters);
  
  // Slackから通知を取得した時間を記録(次回はこの時間以降のデータを取得する)
  putLastModifyDatetime();
  
  res.messages.forEach(function(message) {
    if(message.subtype === 'bot_message' && 0 <= message.attachments.division.indexOf('自部署名') ){
      const text = generateMessage(message);
      postMessage(text);       
    }
  }); 
}

// 渡されたURLを取得
function fetchSlackMessage(url) {
    var res = UrlFetchApp.fetch(url, {
        method: 'GET',
        headers: { "Content-Type": 'application/json' }
    });
  return JSON.parse(res);
}

// 前回実行日時を返す
function getLastModifyDatetime() {
  
  var file = DriveApp.getFilesByName('slack_exporter_cache');
  
  if(!file.hasNext()) {
    var now = Moment.moment().format('X');
    const currentDateTime = parseInt(now , 10).toFixed();
    putLastModifyDatetime();
    return currentDateTime;
  }
  
  file = file.next();
  var data = file.getAs("application/octet-stream").getDataAsString();
  return parseInt(data, 10).toFixed();
}

// 実行時刻をファイルに保存
function putLastModifyDatetime() {
  
  var file = DriveApp.getFilesByName('slack_exporter_cache');
  
  var now = Moment.moment().format('X');
  var currentDateTime = parseInt(now , 10).toFixed();

  if(!file.hasNext()) {
    DriveApp.createFile('slack_exporter_cache',currentDateTime);
    return;
  }
                        
  file = file.next();
  file.setContent(currentDateTime);
}

// 別チャンネルに送信する用のメッセージを作成
function generateMessage(messageJson){
  var text = '';
  text = text + '【下記の手続きを進めてください】 \n' ;
  text = text + '担当者 : ' + messageJson.name + '\n';  
  text = text + '企業名 : ' + messageJson.customer + '\n';  
  text = text + '期間 : ' + messageJson.span + '\n';  
  return text;
}

// Slackに通知する
function postMessage(message){

   var username = 'お知らせ'; // 通知時に表示されるユーザー名
   var icon = ':smile:'; // 通知時に表示されるアイコン
   var postUrl = 'https://hooks.slack.com/services/Incoming WebHooks への投稿URL

   var jsonData = {
      "username": username,
      "icon_emoji": icon,
      "text": message,
   };

   var payload = JSON.stringify(jsonData);
   var options = {
      "method": "post",
      "contentType": "application/json",
      "payload": payload
   };

   UrlFetchApp.fetch(postUrl, options);

}
上記スクリプトを作成し、1分毎に実行するようにトリガーを設定しました。

感想

  • Outgoing Webhooksを使えばよかった
    • 作って「できたよ」って言った後にOutgoing Webhooksの存在を知りました。。
    • 最初ちらっと見たときは「先頭文字列でしか判断できないらしいしなあ、、」って思って使いませんでした。が、今思うととりあえず取る → GASを呼び出す ってしたら毎分確認しに行くってことしなくてよかったんですよね。
  • ググって得た知識の継ぎ接ぎですが、動くものを作って、利用者に喜んでもらえるとやっぱり嬉しいですね。

0 件のコメント :

コメントを投稿