📚

【GAS】メッセヌゞ受取/転送投皿/リアクションするSlack Appの䜜り方

に公開

https://zenn.dev/mokomoka/articles/6d281d27aa344e
前回の蚘事の続きのようなものになりたす。

前回の蚘事では、「1.4 Botの開発」「2.2 Event API䜿甚のための準備」「2.4 Appの開発」の箇所で、具䜓的な実装に぀いおは蚘茉しおいなかったため、こちらの蚘事ではGoogle Apps ScriptGASによる実装にフォヌカスしお曞いおいきたいず思いたす。
ちなみに、私が実装するずきには前の蚘事の順番ではなく、2.2→1.4ず2.4䞊行ずいった感じで実装したので、この蚘事でも実装を考えた順に説明したす。

どんなAppBotを䜜るの

「特定のワヌドが入ったメッセヌゞが投皿されたら、そのメッセヌゞにリアクションを付けた埌、そのメッセヌゞのリンクを特定のチャンネルに投皿する以降「転送」ず呌ぶ」Botを䜜りたす。おたけ機胜ずしお、転送したメッセヌゞの内容などをスプレッドシヌトに蚘録したす。

このBotの甚途ずしお、「iOSに関する質問です」ずいうワヌドを含むメッセヌゞが投皿されたら#question-iosチャンネルに、「Androidに関する質問です」ずいうワヌドを含むメッセヌゞが投皿されたら#question-androidチャンネルに、「hoge他の条件に圓おはたらない文字列に関する質問です」ずいうワヌドを含むメッセヌゞが投皿されたら#question-othersチャンネルにそれぞれのメッセヌゞぞのリンクを投皿するずいった運甚をしたした。リアクションは転送枈みの蚌、スプレッドシヌトの蚘録は埌ほど䜿うかもしれないので念の為Slackから消えおも残るようにしたかった ような扱いです。

単玔に蚀えば、「ナヌザからのメッセヌゞ投皿を受け取り、そのメッセヌゞにリアクションを付けるそのメッセヌゞ内容に応じおBotもメッセヌゞ投皿をするスプレッドシヌトにメッセヌゞの情報を蚘録する」ずいうものですので、必芁な郚分だけ抜き出せば他の䜿甚䟋にも応甚しやすいかず思いたす。

コヌド党䜓は以䞋のGitHub Repositoryで公開しおいたす。
基本的にはそちらのコヌドを参照し、この蚘事ではそのコヌドに至った考え方や補足などを確認しおいただければず思いたす。この蚘事の文章䞭には、あたりコヌドが茉っおいたせん 
https://github.com/mokomoka/SlackBots/blob/master/sources/ForwardBot.gs

ずいうこずで、以䞋の流れで䜜っおいきたす。

  1. Events APIやBotの情報を蚭定する前の蚘事の2.2の内容を含む
  2. 転送郚分を䜜る
  3. リアクション郚分を䜜る
  4. 履歎蚘録郚分を䜜る
  5. メッセヌゞ投皿を受け取る郚分などを䜜る
    ※今回は、スプレッドシヌトを䜜成しお「スクリプト ゚ディタ」からGASのコヌドを曞く前提で進めたす

1. Events APIやBotの情報を蚭定する

1.1 スクリプトのプロパティ蚭定

Bot User OAuth Access TokenやAppのVerification Tokenは、コヌド内に茉せるずオンラむンで公開/管理する際によろしくないです。
GASの堎合は、そういった倀を「スクリプトのプロパティ」に蚭定したす。
以前はUI䞊から蚭定可胜だったのですが、私がこのBotを開発しおいる時期くらいにGASのWeb UIが倉わり、どうやらUI䞊で蚭定できなくなったようです。そのため、PropertiesService.getScriptProperties().setPropertyやPropertiesService.getScriptProperties().setPropertiesなどでコヌド䞊で蚭定する方法しか珟状芋぀かっおいたせん。
プロパティ蚭定甚の関数を䜜り、公開するずきにはその郚分を陀倖するのが良いでしょうか このあたりの知芋はあたりないので、良い方法を知っおいる方がいれば教えお䞋さい

ずりあえず今回は以䞋のような感じで、Bot User OAuth Access Token, Verification Token, そしおワヌクスペヌスのURLの䞀郚xxx.slack.comのxxx郚分を蚭定したした。

function setProperties() {
  PropertiesService.getScriptProperties().setProperty("bot_token", "xoxb-xxx...");
  PropertiesService.getScriptProperties().setProperty("verification_token", "xxx...");
  PropertiesService.getScriptProperties().setProperty("workspace", "xxx...");
}

もちろん、Propertiesのほうを䜿っおたずめお蚭定しおも良いですね。その堎合は公匏ドキュメントを参照すればできるず思いたす。

そしおメむンずなる関数であるdoPost(e)の序盀でsetProperties()を呌び出せば蚭定できたす。

ちなみに、旧UIに戻しお蚭定する堎合は、ボタンからの入力で蚭定できたす。

プロゞェクトのプロパティ遞択画面
スクリプトのプロパティ入力画面

1.2 Events API甚の蚘述

「特定のワヌドが入ったメッセヌゞが投皿されたら」の郚分の䞋地ずしお、doPost(e)内でEvents APIを䜿うための蚘述をしたす。

  // Events APIからのPOSTを取埗
  // 参考→https://api.slack.com/events-api
  const json = JSON.parse(e.postData.getDataAsString());
  
  // Events APIからのPOSTであるこずを確認
  if (prop.getProperty("verification_token") != json.token) {
    throw new Error("invalid token.");
  }
  
  // Events APIを䜿甚する初回、サヌバの存圚確認みたいなのがあるので、そのための蚘述
  if (json.type == "url_verification") {
    return ContentService.createTextOutput(json.challenge);
  } 

ほが前回蚘事の2.2ず同じですが 
このような感じで、POSTを取埗しパヌスしたあず、それがEvents APIからのPOSTであるこずを確認し、その埌初回のurl_verificationに察凊するための蚘述をしおいたす。

2. 転送郚分を䜜る

コヌド䞭の forwardMessage 関数にあたる郚分です。

2.1 基本的なメッセヌゞ投皿郚分の蚘述に぀いお

コヌド䞭にコメントで蚘茉しおいる通り、メッセヌゞを送るずきはhttps://api.slack.com/methods/chat.postMessage を参照しお必芁な情報を甚意したしょう。

䞊蚘サむトで必須Requiredず蚘茉されおいるのはtokenずchannelの2぀のみですが、珟実的にはtextも必芁でしょう。
今回のコヌドでは、payload倉数にtoken channel textを蚭定しおいたす。
今回は、Events APIで取埗したメッセヌゞのリンクをlinkずいう定数に代入枈みずしお、

let payload = {
  "token" : token,
  "text" : link
};

こんな感じでpayloadの初期化時に枡しおいたす。
channelはその埌のfor文内if文の条件によっおどのチャンネルに送るか決めた時にpayloadに枡しおいたす。
これを曞いおから、「channelの倀は適圓な定数に代入しおおいお、for文終わった埌にpayloadの初期化自䜓をすれば、payloadも定数で良かったな ずいうかparamsに盎接代入も可胜だったな 」ず気づきたした。

そしお䞊蚘の情報をAPI゚ンドポむントにPOSTしたす。
GASのUrlFetchAppクラスのfetchメ゜ッドを䜿いたす。公匏リファレンス

const params = {
  "method" : "post",
  "payload" : payload
};
const r = UrlFetchApp.fetch(forward_url, params);

こんな感じでpostず先皋のpayloadをparamsに代入し、UrlFetchApp.fetchの匕数に枡せばOKです。
レスポンスは埌ほど、このPOSTが成功したかの刀定に䜿うこずを芋越しお、rに代入しおありたす。

2.2 この甚途独自の郚分に぀いお

基本的にメッセヌゞ投皿は2.1の内容でできたすが、今回の甚途のために蚘述した郚分も念の為いく぀か説明したす。

今回のBotでは「特定のワヌド」に応じお「特定のチャンネル」にメッセヌゞを投皿するため、そのワヌドずチャンネルの察応をkey/valueずしおchannelsに代入しおいたす。他に良い方法が思い぀かなかった 
そしお、for文内で、受け取ったメッセヌゞにchannelsのkeyのいずれかが含たれおいるかを刀定し、含たれおいれば転送するチャンネルのIDをpayloadに代入するようにしおいたす。

channelsのvalueに䜿うチャンネルのIDは、以䞋のように、チャンネル名を右クリックから「リンクをコピヌ」で取埗できたす。
チャンネルIDの取埗

たた、今回Botで投皿するメッセヌゞの内容は、ナヌザが投皿したメッセヌゞぞのリンクです。
メッセヌゞのリンクは
ワヌクスペヌスのURL + /archives/ + 投皿されたメッセヌゞのチャンネルID + /p + メッセヌゞのタむムスタンプ
ずいった文字列で構成されおいたす。
ワヌクスペヌスずチャンネルずタむムスタンプでメッセヌゞを䞀意に特定できるずいうこずですね
ここで必芁ずなるチャンネルIDずメッセヌゞのタむムスタンプは、Events API経由で取埗したナヌザが投皿したメッセヌゞの情報に含たれおいたす。
タむムスタンプは.が含たれる圢匏で取埗されるものの、URL䞊では.が䜿甚されないため、今回のコヌドではreplace(".","")を甚いお.を取り陀いおいたす。

3. リアクション郚分を䜜る

コヌド䞭の addReaction 関数にあたる郚分です。
コヌド䞭にコメントで蚘茉しおいる通り、メッセヌゞに絵文字リアクションを぀ける堎合はhttps://api.slack.com/methods/reactions.add を参照しお必芁な情報を甚意したす。

必須項目はtoken channel name timestampです。
nameは絵文字の名前です。日本語が䜿えるかは未確認ですが、ナヌザが登録した絵文字が日本語名しか付いおいない堎合もあるず思うので、察応しおいるかな 
channelずtimestampは、リアクションを付ける察象ずなるメッセヌゞが投皿されたチャンネルずタむムスタンプを衚しおいたす。ちょうど2.2で説明したメッセヌゞのリンクを構成するために必芁な文字列ず同じで、リアクション察象ずなるメッセヌゞを䞀意に特定するための情報です。

それらの必須項目が甚意できたら、あずはほがメッセヌゞ投皿転送ず同じようにUrlFetchApp.fetchでPOSTすればOKです。

4. 履歎蚘録郚分を䜜る

コヌド䞭の recordHistory 関数にあたる郚分です。
この郚分は3たでず異なり、スプレッドシヌトの扱いに぀いおの説明になりたす。

たず、蚘録先のスプレッドシヌトを取埗したす。
let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
次に、䞋に向かっお远蚘しおいきたいため、スプレッドシヌトの最終行を取埗したす。
let lastrow = sheet.getLastRow();
コヌド内では䞊蚘の2行をdoPost(e)内で実行しおいたしたが、recordHistory内でやっおも良かったかなず思いたす。
最埌に、最終行の次の行、曞き蟌みたい列を指定しおその箇所に曞き蟌みたい文字列をセットしたす。䞋蚘の䟋では最終行の次の行の3列目にtextを曞き蟌む
sheet.getRange(lastrow+1,3).setValue(text);

以䞊です。簡単ですね

5. メッセヌゞ投皿を受け取る郚分などを䜜る

最埌の仕䞊げずしお、メむンであるdoPost(e)に戻り、メッセヌゞ投皿受け取り→各皮関数呌び出しを実装したす。

メッセヌゞ投皿の受け取りは、1.2で甚意したEvents APIを䜿甚したす。
コヌド䞭にコメントで蚘茉しおいる通り、https://api.slack.com/events/message.channelsを参照するず、どのような圢匏で情報が埗られるかわかりたす。
今回は、認蚌のためにtokenが必芁なのは圓然ずしお、event内のtype channel text tsが他の関数のために必芁ずなりたす。
const json = JSON.parse(e.postData.getDataAsString()); でJSONをパヌスしたのち、json.event.typeなどの指定で必芁な情報を取り出せたす。

そしおメッセヌゞの転送をするために、2で䜜成したforwardMessageを呌び、その結果responseが正垞だった堎合はaddReaction recordHistoryを呌びたす。

以䞊です。
今回の内容ができれば、他にも簡単な応答をしおくれるBotなら䜜れるず思いたす
実際に私は、「耒めおずメッセヌゞ投皿したら、リアクションをしおからランダムに耒めるメッセヌゞを投皿しおくれるBot」も同様の圢匏で実装しお、研究宀のワヌクスペヌスで皌働させおいたす。耒めbot ver.2

前回の蚘事ず同様、質問や困ったこずがあればお気軜にどうぞ

Discussion