🚪

Slack BOTを作った日記

2022/05/24に公開

目的

GW暇だったので、大学の研究室の入退室をbotで管理することにしました。
やったこと自慢&自分用メモの記事です。普通にslackbotの作り方が知りたい人はページ下の参考記事がオススメです。

どんなBOT?

基本は学生証をカードリーダーにピッてするけど、やり忘れた時にこのBOTを使う。
機能1:Slackの表示名が正しければスラッシュコマンドで表示名から学籍番号を抜き取ってAPI君に投げる。
機能2:表示名が正しくない場合にephemeralメッセージ(本人しか見えないメッセージ)でこっそり教えてあげる。

必要な設定

スラッシュコマンド編
サイドバーのSlach Commandsからスラッシュコマンドを作成する。
Create New Commandを選択。
「Command」に作りたいコマンドを書く(例:/carepi)
「Short Description」に簡単な説明を書く(例:入退室コマンドだよ)
「Usage Hint」に引数のヒントを書く(例:[時間])
終わり!こんな感じになる!

コード全体

import os
from dotenv import load_dotenv
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
import requests
import re

load_dotenv()
app = App(token=os.environ['SLACK_BOT_TOKEN'])

@app.command("/carepi")
def handle_carepi_command(ack, say, command):
    ack()
    user_id = command["user_id"]
    channel_id = command["channel_id"]
    display_name = app.client.users_info(user=user_id)['user']['profile']['display_name']
    ephemeral_text = '【ERROR】\n表示名を 学籍番号 + 名字 の形式にしてください。(例:2011140062秋本)'

    check_name = re.match(r'[0-9]{10}.*', display_name)
    if check_name != None:
      student_num = display_name[:10] 
      response = requests.post('http://localhost:3000/session', data = {'student_number': student_num})
      say(f'{response.json()["data"]} \n {command["text"]}')
    else:
      app.client.chat_postEphemeral(channel=channel_id, text=ephemeral_text, user=user_id)

if __name__ == '__main__':
  SocketModeHandler(app, os.environ['SLACK_APP_TOKEN']).start()

コードの解説

import os
from dotenv import load_dotenv
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
import requests
import re

必要なものをインポートしていく。

os、detenv ... 環境変数を読み込むためのライブラリ
slack bolt ... slack APIを使いやすくするためのフレームワーク
requests ... HTTP通信(getとかpostとか)を使うためのライブラリ
re ... 正規表現を使うためのモジュール

load_dotenv()
app = App(token=os.environ['SLACK_BOT_TOKEN'])

load_dotenv()で環境変数を読み込む。
今回だと.envファイルからAPPトークンとBOTトークンを読み込んでる。
ちなみに環境変数の読み込みをせずにトークンなどそのまま書いてGithubにあげちゃうとトークンが無効になって発行し直さないといけなくなります。(僕これ知りませんでした)

app = App(token=os.environ['SLACK_BOT_TOKEN'])で初期化(イニシャライズ)する。

@app.command("/carepi")
def handle_carepi_command(ack, say, command):
    ack()
    user_id = command["user_id"]
    channel_id = command["channel_id"]
    display_name = app.client.users_info(user=user_id)['user']['profile']['display_name']
    ephemeral_text = '【ERROR】\n表示名を 学籍番号 + 名字 の形式にしてください。(例:2011140062秋本)'

スラッシュコマンドとその機能はこんな感じで書く↓

@app.command("/スラッシュコマンドの名前")
def 関数名 (使いたい機能)
	関数(コマンド実行時)の機能

ack ... slack側にリクエストが正常に受信されたか確認する。コマンドを使用する際には必須。
say ... slack bot をチャンネル内で発現させるための関数。
command ... スラッシュコマンドが実行された時のリクエストを受け取るメソッド。
他はただの変数。

    check_name = re.match(r'[0-9]{10}.*', display_name)
    if check_name != None:
      student_num = display_name[:10] 
      response = requests.post('http://localhost:3000/session', data = {'student_number': student_num})
      say(f'{response.json()["data"]} \n {command["text"]}')
    else:
      app.client.chat_postEphemeral(channel=channel_id, text=ephemeral_text, user=user_id)

「表示名」が正しい形式かチェックします。
ちなみに、re.matchは正しいとTrueじゃなくて<_sre.SRE_Match object at 0x10d1e98f0>みたいな文字列が返ってきて、正しくないとNoneが返ってきます。なので判定ではcheck_nama != Noneで判定してます。
本来なら学生証の情報から学籍番号を持ってくるのですが、このBOTは学生証をピッてするのを忘れて帰った人用です。いちいち自分の学籍番号を手打ちするのは面倒だと思ったので、学生側に表示名を統一してもらうようにしました。

表示名が正しければ、表示名から学籍番号部分を抽出して入退室管理APIに投げます。
(localhostの3000番ポートでAPIサーバーが立ててあります)
そしてBOTが「(学籍番号)が入室しました」とチャンネル内で発言します。
表示名が正しくなければ、Ephemeralメッセージでこっそり本人に教えてあげます。

工夫した点

BOTからでは学生証を読み込めないので、表示名から取得するようにした。
表示名が正しくないときに全体で注意されるのは嫌だと思ったのでEphemeralメッセージで表示するようにした。

初めて知ったこと

TOKENをそのままGithubにあげると無効化される。

参考

https://qiita.com/hayahaya2/items/0787225d9fa66dbcdf4f

Discussion