バイセル Tech Blog

バイセル Tech Blogは株式会社BuySellTechnologiesのエンジニア達が知見・発見を共有する技術ブログです。

フルリモートになったからSlack勤怠コマンドを作った

メリークリスマスイブ🎄🎄🎄テクノロジー戦略本部の杉田です。
私達の部署も、コロナによって完全リモートとなった組織のひとつです。それと同時に、出勤・退勤・離席等の連絡はSlackの勤怠チャンネルで行おう、というルールができました。
勤怠連絡は毎日のことですし、定型文を毎回打つのは正直めんどくさい...。そこで、ちょっとでも楽しちゃおう!というエンジニア魂からSlack勤怠コマンドを作りましたので、今日はそのお話をさせていただきます。

作ったもの

まずは完成品から見ていただきたいと思います。

f:id:nsugita:20201217182246g:plain
全部で6種類の勤怠連絡ができる
このように、コマンドに応じたメッセージを自動投稿するものを作りました。
使えるコマンドは start, lunch, away, back, dinner, end の6種類です。(上記のサンプルgifだと back を試し忘れてますが、「戻りました(絵文字)」と出ます😅)

使ったもの

Slash Command

Slackユーザーならお馴染みの、 /hoge で実行できるコマンドのことです。

f:id:nsugita:20201217171039p:plain
Slash Command設定画面
勤怠連絡なので、 work の頭文字を取って /w で発火させるようSlack側に設定を追加しました。
このコマンドが実行された際に後述のAPI Gatewayのエンドポイントを叩かせます。

API Gateway

弊社には、サーバーレスでちょっとしたツールを作りたいとき用の専用AWSアカウントがあるため、そちらに新しくAPI Gatewayを作成しました。
特別なことは何も行なっていません...。POSTメソッド作ってデプロイしただけです...。

Lambda

先に作ったAPI Gatewayと新しく作ったLambda関数を繋げて、Slackで /w が実行されたらLambdaが動くようにしました。
Slash Commandには「実行されてから3秒以内にSlack側にレスポンスを返さなければいけない」という仕様があるため、Lambdaのコールドスタート問題等を考慮し、実はこのコマンドは親関数(必要最低限の処理のみ行う)から子関数(メイン処理を行う)を呼び出す形で動いています。

f:id:nsugita:20201221121436p:plain

親Lambdaの処理

  1. Slackから送られてくるトークンを確認
  2. どのチャンネルで実行されたのか確認
  3. どのコマンドが打たれたのか確認
  4. 子Lambdaの呼び出し
1. Slackから送られてくるトークンを確認

Slash Commandの作成をした際に自動でトークンが生成され、 /w を実行した場合にはこのトークンがリクエストに自動で付与されてきます。Lambda側にはそのトークンを暗号化して持たせておき、送られてきたトークンと照らし合わせて、不正なリクエストでないかどうかをチェックしています。

2. どのチャンネルで実行されたのか確認

Slash Commandが実行された際に channel_id というパラメータが自動で渡ってくるため、それをチェックします。
私が所属しているテクノロジー戦略本部は、内部で更に複数の部に枝分かれしており、部ごとに勤怠チャンネルが分かれているため、それぞれの部の勤怠チャンネル内での入力のみを許可しています。それ以外のチャンネルで実行された場合はエラーにし、「勤怠チャンネルで打ってるつもりだったのに全然違うところで打っていてみんなに連絡が漏れていた...!」なんてことを起こりづらくしています。

f:id:nsugita:20201217185630p:plain
3. どのコマンドが打たれたのか確認

許可された6種類以外のコマンドが送られてきていないかチェックし、想定外のものは受け付けないでエラーにします。

f:id:nsugita:20201221122423p:plain

away だけは時間のオプションも許可しており、 任意の数字 + m または 任意の数字 + h が使用できます。例えば /w away 1h なら「1時間ほど離席します」と変換されます。

4. 子Lambdaの呼び出し
  • 有効なトークンであること
  • 有効なチャンネルおよびコマンドであること

上記が確認できたら初めて子Lambdaを呼び出し、処理が実行中である旨をSlackに返します。ここまでの処理が3秒以内に行われる想定です。

f:id:nsugita:20201221121813p:plain

子Lambdaの処理

  1. 送信するメッセージをセット
  2. Slackからユーザー情報を取得
  3. Incoming WebhookでSlackに投稿
1. 送信するメッセージをセット

打たれたコマンドの種類によって、送信するメッセージをセットします。 start なら 業務を開始します といった具合です。
遊び心で、定型文+ランダムで絵文字をひとつ末尾に追加したメッセージをセットするようにさせているため、「業務を開始します🚀」になったり「業務を開始します🌈」になったりします。
反響が大きかったのは「離席します💩」と「業務を終了します🏩」ですw

2. Slackからユーザー情報を取得

Slash Commandが実行された際に user_id というパラメータが自動で渡ってくるため、それを元にSlackのAPIを叩き、投稿者のSlack表示名とプロフィール画像を取得します。これは次項で使います。

3. Incoming WebhookでSlackに投稿

ここまできたらあとはIncoming Webhookでメッセージを送信するだけです。
この時に留意する点は以下で、

  • 送信先チャンネルを、コマンド実行元チャンネルと同じにすること
  • BOT名とBOTアイコンを、前項で取得したSlack表示名とプロフィール画像にすること

Slackの投稿を読む時、その投稿者が誰なのかは名前ではなくプロフィール画像で判別することも多いのではないでしょうか。こうして一手間加えることで、本当はBOTの投稿なのに、あたかも本人が投稿したかのように見せることができます。

終わりに

いかがでしたでしょうか?簡単にですが、自作Slack勤怠コマンドの仕組みを解説させていただきました。
4月にこのコマンドをリリースしてから、毎日たくさんの仲間が使ってくれています。エンジニアとして、作っている過程は勿論楽しいですが、やはり、自分が作ったものを実際に使ってもらえると嬉しいものですよね。
弊社では、効率化好きな意欲ある仲間を随時募集しています。気になったら是非一度応募してみてください。

さて、明日はアドベントカレンダー最終日!大トリは弊社の市田さんが担当予定です。どんな記事で〆てくれるのか、私も今から楽しみにしています。
それでは皆さん、良いクリスマスと年末を!!!