5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Slackの新着絵文字をお知らせするBotをGASで作る

Last updated at Posted at 2023-03-28

はじめに

特定の個人を攻撃したり風紀を乱すような絵文字を追加する従業員の良からぬ行動によって、社内のSlackのモラルが下がる、場合や内容によってはハラスメントにつながる、というお話を小耳に挟みまして、こまめに絵文字を監視するより「絵文字追加したら皆に知れ渡るよ」ということで防止する、というアイディアを目の当たりにしたので、モラル崩壊云々はさておきネタとしても面白く、これは良いと思い早速作ってみました。

今回の流れ

  1. Google Cloud Platform(以下GCP) でプロジェクトを作る
    1. OAuth同意画面を作る
  2. Google Apps Script(以下 GAS )で外部から呼び出し可能なプロジェクトを作る
    1. GASのプロジェクトを新規作成する
    2. GCPのプロジェクトを関連付ける
    3. GASでHTTPのPOSTリクエストを受け付けるコードを用意する
    4. GASをウェブアプリとしてデプロイして外部から呼ばれるようにする
  3. GASでSlack Eventを受信してIncoming Webhookで通知する
    1. SlackSlack Appを作る
    2. Incoming Webhookを有効化する
    3. Event Subscriptionsを有効化してSlack EventsをGASで受信できるようにしておく
    4. 受信したSlack EventをGASで処理する

1.1~3.2までは色々と検索したり記事を参照して各自で頑張ってみてください。🙋‍♀️
また、先にGitHubのソースを公開しておきます。

以下、本記事は下記(及びそれらを準備する知識)が揃っている前提となります。

前提として揃っているもの

  • ウェブアプリとしてデプロイできるGAS
  • BotとしてIncoming Webhookが出来るSlack App

実際にGASでBotを作ってみる

GAS側でSlack Eventに対応する準備をする

手始めに、GASの doPost 関数を以下のようにしてください。

doPost
function  doPost(e) {
  const rowData = e.postData.getDataAsString();
  const jsonData = JSON.parse(rowData);

  //  return a response as HTML to confirm the challenge
  if (jsonData['challenge']) {
    const output = ContentService.createTextOutput(jsonData['challenge']);
    output.setMimeType(ContentService.MimeType.TEXT);
    return output;
  }
  const output = ContentService.createTextOutput("ok");
  output.setMimeType(ContentService.MimeType.TEXT);
  return output;
}

コード解説

doPost は引数で受け取ったオブジェクトにPOSTで受信したデータが含まれているので、これをテキストとして読み込み、JSONとしてパースしてオブジェクトとして扱います。

  const rowData = e.postData.getDataAsString();
  const jsonData = JSON.parse(rowData);

Slack Bot[Events API](Slack Events API) はイベント通知先として指定したURLが正しいものかどうかの確認で下記のようなJSONを渡してくるので

{
    "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
    "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
    "type": "url_verification"
}

この challenge の部分をそっくりそのまま返す処理が必要になります。

  if (jsonData['challenge']) {
    const output = ContentService.createTextOutput(jsonData['challenge']);
    output.setMimeType(ContentService.MimeType.TEXT);
    return output;
  }

💡GASを書き換えたら必ずデプロイして新しいコードで書かれたウェブアプリを更新しましょう。

Slack App で Event Subscriptions を有効化する

Slack Events を GAS で受信できるようにする

  1. Slack Appの一覧で、対応させるSlack Appを選びます。
  2. 左側メニュー Event Subscriptions をクリックしイベント設定画面へ入ります。
  3. Enable EventsONにし、Request URL に、GASでデプロイしたウェブアプリのURLを入力します。
    ここでGASがJSONに含まれるチャレンジを正しく返していれば、入力したURLに Verified と表示されます。
    image.png

受信するイベントを指定する

Subscribe to bot eventsをクリックして開き、Add Bot User Eventのボタンをクリックしてイベントを追加します。
追加するイベントはemoji_changedです。
image.png

イベントが追加されると、OAuthのスコープに emoji:read が自動的に追加されます。

以上で、Slackワークスペースに絵文字が追加されたら、Slackイベントemoji_changedが発生し、GASで作られたウェブアプリへPOSTされるところまで出来ました。
あとは、このPOSTを元に新しい絵文字が来たことをIncoming Webhookを使って通知するだけですね。😉

イベントの内容をSlackへ通知する

Slack AppからSlackへ通知を行うにはIncoming Webhookを使うだけでOKです。
では早速、GASのコードを以下にまるっと置き換えてみましょう。
7032/gas_emojichecker/main.gs

GASのスクリプトプロパティを設定する

スクリプトプロパティ Webhook-EMOJI に、Slack Appで設定した Incoming WebhookのURLを設定してください。

SlackへのIncoming Webhookによる通知

関数 _SendMessageToSlack(propName,message) は引数を2つとり、以下の処理を行います。

  • propNameで指定されたスクリプトプロパティから値を読み出す
  • 読み出したスクリプトプロパティで指定されたURLへSlackメッセージとしてmessageで指定された内容を通知する
    • HTTPヘッダー Content-Typeapplication/json を指定する
    • JSONの下記の形式をボディとしてPOSTで送信する
POSTのボディとして送信する内容(JSON)
{ "text" : "送信したいメッセージの内容" }

実際の処理は以下の部分となります。

function  _SendMessageToSlack(propName,message) {
  const propService = PropertiesService.getScriptProperties();
  const url  = propService.getProperty(propName);
  try {
    var response  = UrlFetchApp.fetch(
                      //  URL stored in the property
                      url,
                      //  Options set to header and payload
                      {
                        "method" :            "POST",
                        "headers":            { "Content-Type" : "application/json", },
                        "payload":            JSON.stringify({ "text" : message }),
                        "muteHttpExceptions": true
                      }
                    );
  }
  catch (e) {
    console.log("[Slack:WebHook error]"+JSON.stringify(e)+"\nURL:"+url);
  }
}

受信したSlack Eventを処理してSlackへ通知する処理

Slackイベント emoji_changed は、以下のようなJSONをPOSTしてきます。

{ "event" : {
    "type": "emoji_changed",
    "name": "絵文字の名前。コロンで挟まれた部分",
    "value": "新しい絵文字が投稿された場合のURL、またはエイリアス元の絵文字名"
  }
}
JSONキー 内容
event.type 絵文字、絵文字のエイリアスが追加された場合、emoji_changed が入ります。
event.name 絵文字の名前 = コロンで挟まれた :hogehoge:hoge 部分が入ります。
event.value 新規で絵文字が追加された場合は、その画像の保存先のURLが入ります。エイリアスの場合は alias:hoge という形式の文字列が入ります。 alias: というプレフィックスがついてエイリアス元の絵文字名が入ってくるので、ここで「新規で投稿された絵文字」か「エイリアスが追加されたのみ」かを判断します。

以上を元に通知メッセージを構築して、先述の _SendMessageToSlack 関数へ渡して通知を行います。
この処理のメインとなる部分が以下です。

if (jsonData["event"]) {
  if (jsonData["event"]["type"]) {
    switch(jsonData.event.type) {
    //  EMOJI
    case  "emoji_changed": {
      //  Add EMOJI
      const emojiName = jsonData.event.name;
      const emojiVal  = jsonData.event.value;
      const emojiAli  = "alias:";
      var   strMessage= "*[New EMOJI]* :"+emojiName+": is added as *`:"+emojiName+":`* !!!\n";
      if (emojiVal.slice(0,emojiAli.length) == emojiAli) {
        const emojiOrginal  = emojiVal.slice(emojiAli.length);
        strMessage  +=  "This is just an *alias* of *`:"+emojiOrginal+":`* :"+emojiOrginal+":";
      } else {
        strMessage  +=  "Original picture is "+emojiVal;
      }
      _SendMessageToSlack("Webhook-EMOJI",strMessage);
      }
      break;
    }
  }
}

以上で、

  • 絵文字が追加されると Slack Event emoji_changed が発生する
  • Slack Appが上記のSlack Eventを受け取る
  • 受け取った内容を元にIncoming Webhookで通知する
    という流れで、ワークスペースへ絵文字が追加されたら特定のチャンネルで通知するということが出来る様になりました。🙌🙌🙌

さいごに

ITのお知らせのチャンネルなどに流しても良いですし、絵文字の追加が活発なワークスペースであればネタチャンネルとして新着絵文字専用チャンネルなどを作っても良いかもしれませんね。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?