こんにちは。
GMOインサイトのkanetechです。
弊社ではコロナ禍のソーシャルディスタンス対策として、フリーアドレスを導入いたしました。
フリーアドレス勤務の場合、着席位置をSlackで一報入れるルールにしていますが、万が一感染者が発生したときに誰と近い席に座っていたか辿るため、Googleスプレッドシートにも着席位置を記載しています。
同じような情報を2か所に記載していますね。。。
怠惰なエンジニアには苦痛です。
そこで、着席情報の入力をSlack Workflow化し、Googleスプレッドシートに自動転記する仕組みを構築しました。
弊社ではG Suiteを導入しており、セキュリティ制限によって外部からdoPost()、doGet()をコールすることができません。ですので、5分毎にSlackの履歴APIをGASからフェッチする設計で作っていきます。
Slackの作業
着席位置についてフリーテキストを受け付ける仕様だと辛いので、定型文に落とし込むため登録フォームを作ります。
Tools -> Workflow Builder を開きます。
Createをクリックし、ワークフロー名「着席」を作ります。
今回はユーザの任意タイミングで動かしたいので、ショートカットを選択します。
連携するチャンネル名とショートカット名を入力します。ここで入力したshort nameが実際に表示される名前になります。
次に、Add a StepからCreate a formをAddします。
フォームは座席コードをリストから選択させたいので、Choose a question typeは「Select from a list」を選択してください。
Publishをクリックして有効化します。
ここまで進めると、ボタンに作ったフォームへのリンクが登場します。
なお、フォームの選択肢に設定できる項目数が現在は最大20のようです。今回は座席が入りきらないのでフォームを島ごとに作成しています。
このフォームを用いると、以下のような定型のポストを行うことができます。
Google Apps Scriptの作業
冒頭に書いたように、doPost()でSlack Events APIから直接データを受け取ることができないため、時間トリガーでフェッチする関数を書いていきます。
関数名は何でもよいですが、今回はfetchSlackHistory()関数としました。
おおまかなロジックは以下の通りです。
- Slack勤怠ポストチャンネルの履歴を取得
- メッセージからユーザーIDと座席コード、時刻を取得
- スプレッドシートからユーザーIDが合致する行を捜索
- 日付から列を算出し、座席コードを更新
出来上がったコードはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
const X_LIMIT = 50; const DAY_OFFSET = 2; const SLACK_CHANNEL = "Cxxxxxxxx"; function fetchSlackHistory() { var response = UrlFetchApp.fetch("https://slack.com/api/conversations.history?token=xoxp-00000000000-00000000000-000000000000-deadbeefdeadbeefdeadbeef&channel="+SLACK_CHANNEL+"&limit=10&pretty=1"); var json = JSON.parse(response.getContentText()); var messages = Array(); json.messages.reverse().forEach(function(val,index,ar) { if(val.subtype != "bot_message") return; var code = val.text.match(/[A-Z]-[0-9]+/); if(code == null || code.length != 1) return; var uid = val.text.match(/[A-Z0-9]{9}/); if(uid == null || uid.length != 1) return; var time = Moment.moment(val.ts * 1000); var sheetName = time.format("YYYY年M月"); currentSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName); if(currentSheet == null) return; updateSheet(currentSheet, time, uid[0], code[0]); }); } function findUserCol(sheet, uid) { var x,y; for(x=3; x<X_LIMIT; x++) { var _uid = sheet.getRange(1, x).getValue(); if(uid == _uid) return x; } return -1; } function updateSheet(sheet, time, uid, code) { var x = findUserCol(sheet, uid); if(x <= 0) return; y = time.date() + DAY_OFFSET; sheet.getRange(y, x).setValue(code); } |
補足
このコードでは時刻処理のためにMomentライブラリを用いています。
リソース -> ライブラリ
Add a libraryにMomentのライブラリID MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48 を入力して追加します。
これで面倒な日付処理にMomentが利用できるようになります。
今回のプログラムではSlack APIから取得できるタイムスタンプの処理に利用しています。
Google スプレッドシートの作業
特殊なことはあまりありませんが、下方向に日時、横方向に社員が並びます。
1行目には小さくSlackのユーザーIDが埋めてあります。
GASトリガーの作業
現在のプロジェクトのトリガーを開きます。
時間主導型のタイマーを作成します。今回は5分おきにフェッチするようにしました。
以上で完成です。
労力に対して得られるものがちょっと小さいですが、GMOグループでは日々千分の一の改善を積み重ねて大きな成果を作ることを良しとしているため、この規模の改善も積極的に行っております。