spicato

WEB and GRAPHIC
CREATIVE STUDIO

T.072-424-9827 F.072-424-5923
hello@spicato.com
Ogaito 3-3-2
Kumatori-cho, Osaka, Japan
date
2021.07.06(tue)
views
1525
category
all view

GASを使ってSlack botを作ってみた

こんにちは、エンジニアの有村です。満を辞して?ブログ初登場です。
今回はGAS(GoogleAppsScript)を使って、Googleスプレッドシートで作成した当番表をSlack botにする方法を解説していこうと思います。

スピッカートでは、週明けのミーティングでその週の発表担当者が気になったwebサイトをシェアするという場があります。また、掃除や電話対応などのタスクも毎週持ち回りで担当しており、その当番表をスプレッドシートで管理しています。
ただ、確認のたびにスプレッドシートを見にいく必要があったり、週の担当が誰かわからずスキップするなんてことも起こり得ます。さらに、週が変わったら手動で次回担当者を変更する作業が発生したりと、若干不便。
そこで今回、Slack上で当番表を確認できるSlack botを作ってみたので作成手順を紹介します。

やりたいこと
・Googleスプレッドシートで作成した当番表をSlackで通知する

作成するbotの仕様
・Web発表担当者を毎週特定の曜日に、リマインダー通知
・祝日の場合、リマインダー通知をスキップ
・当番一覧をSlackのスラッシュコマンドで表示
・週末にスプレッドシートのセルを自動ローテーション

※ゴールデンウィークなどのイレギュラーな休み時のみ手動でシートを調整する想定

スラッシュコマンドとはSlackのメッセージの入力ボックスに / から始まる文字列を入力することでアプリを動かすためのものです。
今回の場合で言うと、/toubanのように入力すると当番担当者が通知されるイメージです。
(参照:Slack のスラッシュコマンド)

手順
①Google スプレッドシートを作成
②Webアプリケーションとして公開
③Slackのワークスペースにappを追加
④Slackのスラッシュコマンドを登録
⑤Google Apps Scriptにコードを書く

Google スプレッドシートを作成

まずGoogle スプレッドシートを作っていきます。

今回は直接メンションを飛ばしたいので、B列にSlackのメンバーIDを入れています。
これをWeb発表用、電話担当用など、タスクごとにシートを作成します。

次に、SlackでGoogleスプレッドシートを操作するため、GASコードをWebアプリケーションとして公開します。
スプレッドシートの「ツール」→「スクリプトエディタ」を選択してGASのスクリプトエディターを開きます。

実際のコードを書く前にまず以下のコードでテストします。

function myFunction() {
    Logger.log('hello, world')
  }

ログはツールバーの「実行」を押して「実行ログ」から確認することができます。
Logger.log()でログを出力します。
ログを確認できたらテストは成功です。

Webアプリケーションとして公開
Slackのワークスペースにappを追加する
Slackのスラッシュコマンドを登録する

次に「Webアプリケーションとして公開」→「Slackのワークスペースにappを追加する」→「Slackのスラッシュコマンドを登録する」と工程を進めていきます。ここの手順は他のサイトでたくさん説明されているので割愛します。
(参照:GASで作るSlack Slash Commands入門)
(参照:コピペでできる!GASで作るSlack bot)

※個人的に少し詰まったところが、
Basic InformationのInstall your app」を選択→「Install to Workspace」をクリックしてワークスペースへインストールする際に、
「●● doesn’t have a bot user to install」と表示される場合がありました。

これはインストールするためのbot userがないということなので以下の手順で解決できます。

・メニューの「App Home」から「Your App’s Presence in Slack」セクションの「Edit」をクリック。
・好きな「Display Name」を設定。(こちらの内容は後からでも変更可能です。)

GAS(Google Apps Script)でコードを書く

再度スプレッドシートの「ツール」→「スクリプトエディタ」を選択してGASのスクリプトエディターを開きます。
実際に動かしていくためのコードを書いていきます。

function doPost(e) {
      //スプレッドシートのデータを取得
      const obj = SpreadsheetApp.openById('シートのID'); 
    
      //担当者の名前を取得する関数
      function getName(sheetName) {
        const sheet = obj.getSheetByName(sheetName);
        const lastrow = sheet.getLastRow();
        const areaRange = sheet.getRange(1, 1, lastrow);
        const data = areaRange.getValues();
        const names = data.map(row => row[0]);
        return names[0];
      }
    
     //getName()のカッコ内はシート名
      const web = getName('web');
      const tel = getName('電話当番');
      const cleaning = getName('掃除当番');
      const copy = getName('印刷当番');
      const visitor = getName('来客当番');
      
      //スラッシュコマンドで表示させるテキスト
      const text = `■Web発表
      次回担当は${web}です。
      
      ■電話
      今週の担当は${tel}です。
      
      ■そうじ(トイレ)
      今週の担当は${cleaning}です。
      
      ■印刷
      今週の担当は${copy}です。
      
      ■来客当番
      今週の担当は${visitor}です。
      
      よろしくお願いします。`;
      
      const response = {
        text: text,
        response_type: 'in_channel'
      };
      return ContentService
        .createTextOutput(JSON.stringify(response))
        .setMimeType(ContentService.MimeType.JSON);
    }
    
    //スプレッドシートをローテーションさせる関数
    function execRotation(sheetName){
      const obj = SpreadsheetApp.openById('シートのID');
      const sheet = obj.getSheetByName(sheetName);
      const lastrow = sheet.getLastRow();
      const areaRange = sheet.getRange(1, 1, lastrow);
      const data = areaRange.getValues();
    
      //シートのセルをローテーション
      data.push(data.shift());
      areaRange.setValues(data); 
    }
    
    function rotation() {
          execRotation('web');
       execRotation('電話当番');
       execRotation('掃除当番');
       execRotation('印刷当番');
       execRotation('来客当番');
    }
    
    //リマインダー通知
    function remaind() {
      //現在日時を取得
      const today = new Date();
    
       //祝日の場合実行しない
      if (isHoliday(today)) {
        return
      }
      const obj = SpreadsheetApp.openById('シートのID');
      const sheet = obj.getSheetByName('web');
      const lastrow = sheet.getLastRow();
      const areaRange = sheet.getRange(1, 1, lastrow, 2);
      const data = areaRange.getValues();
      const names = data.map(row => row[0]);
    
      //SlackのメンバーIDを取得
      const id = sheet.getRange("B1").getValues()[0][0];
    
      //メンション付きリマインダー用のテキスト
      const reply = id ? `<@${id}>\n` : '';
      const text = `${reply}次回のWeb発表担当は${names[0]}です。\nよろしくお願いします。`
    
      //SlackのWebhook URLにHTTPリクエスト送信
      //fetch()の第一引数にSlackのIncoming WebhooksのURLを入力
      UrlFetchApp.fetch('Incoming WebhooksのURL', {
      'method' : 'post',
      'contentType': 'application/json',
      'payload' : JSON.stringify({ text: text })
      });
    }
    
    //祝日かどうか判定する関数
    function isHoliday(date) {
      const id = 'ja.japanese#holiday@group.v.calendar.google.com';
      const cal = CalendarApp.getCalendarById(id);
      const events = cal.getEventsForDay(date);
      if (events.length) {
        return true;
      }
      return false;
    }

コードを変更したので、もう一度アプリケーションの公開を行なってください。
その際、「Project version」を「New」に設定します。
※公開後にコードに変更を加えた場合はその都度この工程が必要なので注意です。

トリガーの設定

Web発表の当番をリマインダー通知させたいので、スクリプトを定期実行するトリガーを設定します。

左側にあるメニューの時計のアイコンを押して、「トリガーを追加」をクリック。

「実行する関数を選択」で先程定義した「remaind」選択。あとは定期実行したい時間を設定してください。
同様にローテション用のトリガーも設定。
これでスクリプトが定期実行されます。

アイコンを変更

最後に、このままだと味気ないので、アイコンも変更します。
スラッシュコマンドを登録したときにアクセスした、Slackの「Basic Information」の画面下部にある「Display Information」から変更できます。

アイコン画像はスピッカートの裏ボス、はちにします!
これではちが毎回当番を教えてくれるようになりました。

はちもしばしば事務所に出社します。癒し。

そしてこれが実際の実行イメージです。

以上で完成です。

ちなみにこのWeb発表ですが、下の動画内で代表の細尾さんも言っていますが、ここでデザイナー、エンジニア、ディレクターそれぞれのデザインの趣向を知ることで、無意識のうちに「スピッカートらしさ」のすり合わせを行う場になっています。
尚、この動画はNOT4Hさんが事務所に撮影に来て下さった時のものです。
NOT4Hさんはweb業界に関するコンテンツを配信されているYouTubeチャンネルですが、毎回内容がとても有益で個人的に勉強させてもらってます。ぜひチェックしてみてください。

ちなみに我々スピッカートもYouTubeやっております。
チラッとリンクを載せておきます。こちらも覗いていただけると嬉しいです。

スピッカートチャンネル

まとめ

今回初めてGASを触りましたが、すごく面白いですね。
Slackと組み合わせることで他にも業務効率につながるものを作れそうだなと感じました。それは今後の宿題とします。
JavaScriptの多少の知識があればできるので、皆さんもよかったらトライしてみてください!
それでは最後まで読んで頂きありがとうございました。