Top View


Author matsuyama

Slack から Outlook の会議室予約を実施する

2022/05/20

ユーザーインターフェース

Slack スラッシュコマンドを実行すると、

/reserve

予約候補が出てきて、

Slack による予約

予約する を押すと、予約が取れます。

Outlook での予約表示

システム構成

システム構成図を以下に描きます。

システム構成図

流れとしては、

  • ユーザ: スラッシュコマンド実行
    • Slack: POST リクエスト (Slash Command)
      1. Rails: Slack API でユーザの email を取得
      2. Rails: Microsoft Graph で会議室の空き時間検索
      3. Rails: 予約候補メッセージを返す
  • ユーザー: 予約する ボタンを押す
    • Slack: POST リクエスト (Interactive Component)
      1. Rails: Slack API でユーザの email を取得
      2. Rails: Microsoft Graph で予約作成
      3. Rails: HTTP 200 を返す

という感じです。

注意

  • Slack に登録しているメールアドレスが Outlook のものである必要があります。
    • そうでない場合、Slack と Outlook のアカウントを紐付ける処理が追加で必要です。
  • Microsoft Azure Active Directory アプリの権限付与に管理者の同意が必要です。

Slack まわりの詳しい説明

本システムでは、Slack API の 2 つの機能 Slash CommandInteractive Component を利用しています。
これらが実行されると、それぞれ別の URL に POST リクエストが発行されます。
この 2 つの URL を Rails で作成し、予約候補メッセージと、予約の作成を実現しています。

システム構成図詳細

実装

概要はここまで、次は、実装方法について説明します。
以下の作業が必要です。

  • Slack の設定
    • Slack で Slash CommandsInteractive Components の作成、および、Slack API からユーザのメールアドレスを取得する設定を行います。
  • Microsoft365 の設定
    • Rails で会議室の予定を取得/作成できるようにするための設定を行います。
  • Rails: Slash Command の実装
    • Slash Commands を受けて、会議室の予約ボタン付きメッセージを返します。
  • Rails: Interactive Component の実装
    • Interactive Components を受けて会議室を予約します。

※ Rails の実装に関しては「大体こんな感じ」というレベルの記載です。ご承知おきください。

Slack の設定

本システムに必要な Slack App を作成・設定するために、以下の作業を実施します。

Slash Commands の登録

Slash Command 実行時にリクエストする URL を登録します (Slash Commands 参照)。

Slack Command URL

Interactive Components の登録

予約する ボタンを押した時にリクエストする URL を登録します (Handling user interaction 参照)。

Slack Interactive URL

Scopes の追加

Slack API からユーザのメールアドレスを取得するために、users:readusers:read.email の権限を付与します。

Slack Scopes

Token の取得

Slack API に使用するトークン Bot User OAuth Token を確認します。

Slack Token

Microsoft365 の設定

本システムに必要な Microsoft Azure Active Directory でアプリの作成・設定をする為に、以下の作業を実施します。

アプリを登録する

ポータルでアプリを登録する を参照してください。

アプリへの権限付与

Outlook の予約を読み込み書込みするために登録したアプリに権限 Calendars.ReadWrite を付与します (管理者の同意が必要です)。

API のアクセス許可

User.Read はアプリ登録時に付与されていたものです。今回の実装では使用しません。

Rails: Slash Command の実装

Slash Command が実行された時に動作する /slash/command の処理の流れは、以下です。

  1. Slash Command パラメータの取得
  2. Slack ユーザのメールアドレス取得
  3. Microsoft Graph アクセストークンの取得
  4. 会議室の予定を取得
  5. ボタン付きメッセージの返答

Slash Command パラメータの取得

Slash Command のパラメータから、

  • トークン token: リクエスト元の検証に利用
  • ユーザ ID user_id: ユーザのメールアドレスを取得に利用
  • コマンド引数 text: オプション (開始時刻、利用時間指定など)

を取得します。

Slash Command のリクエストから取得できる情報は Preparing your app to receive Commands を参照。

Slack ユーザのメールアドレス取得

Microsoft Graph の利用において、実行ユーザのメールアドレスが必要なため、Slack API の users.info を使います (users.info 参照)。

を指定します。

前述のとおり、Slack ユーザのメールアドレスが Outlook のものでなければ、別途、Outlook のメールアドレスを取得する処理が必要です。

Microsoft Graph アクセストークンの取得

Microsoft Graph の API を利用するためにアクセストークンを取得します (アクセス トークンを取得する 参照)。

ポータルから取得した、

  • クライアント ID client_id
  • クライアントシークレット client_secret
  • テナント ID tenant

を指定します。

アクセストークンには、期限がありますので、 access_token と同時に返される expires_in の値を確認し、期限が切れたら取り直しが必要です。

会議室の予定を取得

会議室の予定を取得するために、Microsoft Graph の API calendar: getSchedule を使います (空き時間スケジュールを取得する 参照)。

  • 実行者のメールアドレス userPrincipalName: Slack ユーザのメールアドレス取得
  • 会議室のメールアドレスリスト schedules: 事前に確認
  • 取得開始時刻 startTime: 現在時刻 など
  • 取得終了時刻 endTime: 定時 など
  • 取得インターバル availabilityViewInterval: 30 (分) など

を指定します。

レスポンスは以下のようなものが返ってくるのですが、今回は、availabilityView を利用します。

{
  "scheduleId": "sample@fusic.co.jp",
  "availabilityView": "2000000",
  "scheduleItems": [
    {
      "isPrivate": false,
      "status": "busy",
      "subject": "オンライン会議",
      "location": "会議室 1",
      "isMeeting": true,
      "isRecurring": false,
      "isException": false,
      "isReminderSet": false,
      "start": {
        "dateTime": "2022-04-18T15:00:00.0000000",
        "timeZone": "Tokyo Standard Time"
      },
      "end": {
        "dateTime": "2022-04-18T16:00:00.0000000",
        "timeZone": "Tokyo Standard Time"
      }
    }
  ]
}

availabilityView2000000 のように、予定状況が数値列で返ってきます。
各数値の意味は、0= free, 1= tentative, 2= busy, 3= out of office, 4= working elsewhere です。

たとえば、

  • 取得開始時刻: 12:00
  • 取得終了時刻: 14:00
  • 取得インターバル: 30

を指定して、

  • availabilityView: 2200

だと、12:00-13:00 は予定があって、13:00-14:00 は空いている、という意味になります。

一見分かりづらいですが、各予定の開始・終了時刻を一個ずつ見ていくよりは楽だと思います。

ボタン付きメッセージの返答

今回は、以下のような json でレスポンスを返しています。

blocks: [
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "*satellite-1:* 12:00 - 12:30"
    },
    "accessory": {
      "type": "button", 
      "text": {
        "type": "plain_text",
        "emoji": true,
        "text": "予約する"
      },
      "style": "primary", 
      "value": "reserve_satellite-1_12:00-12:30"
    }
  }
]

mrkdwn 形式の text の後に、button を配置しています。
value の値が 予約する ボタンを押したときの POST リクエストで渡ってくるので、必要な情報を埋め込みます。
今回は アクション部屋名開始時刻-終了時刻value に設定しています。

詳細は Button element を参照してください。

Block Kit Builder という、Slack の Block メッセージをお試しできるサイトがあるので、そこで、 「メッセージがどう表示されるか」と「ボタンを押したときにどのような値が入るのか」が試せます。

Rails: Interactive Component の実装

予約する ボタンが押された時に動作する /slack/interactive-endpoint の処理の流れは、以下です。

  1. Interactive Component パラメータの取得
  2. Slack ユーザのメールアドレス取得
  3. Microsoft Graph アクセストークンの取得
  4. 会議室を予約する

2.3. の処理は Slash Commands の実装と同じです。

Interactive Component パラメータの取得

Interactive Component のパラメータ (payload) から、

  • トークン payload['token']: リクエスト元の検証に利用
  • ユーザ ID payload['user']['id']: ユーザのメールアドレスを取得に利用
  • ボタンの値 payload['actions'][0]['value']: 会議室の予約に利用

を取得します。

ここの注意点としては、パラメータ payload が json で与えられるので、json をパースする必要があるということです (私はハマりました)。

会議室を予約する

会議室を予約するために、Microsoft Graph の API events を利用します (イベントを作成する 参照)。

/users/<実行者のメールアドレス>/events に対して、attendees に会議室のメールアドレスと以下を指定し、POST します。

  • タイトル subject: テキトー
  • 開始時刻 start: ボタンの値より取得
  • 終了時刻 end: ボタンの値より取得

予約ができたら、HTTP 200 OK となるようにテキトーにレスポンスを返します (メッセージを返しても Slack 上では表示されません)。

うまく実装できていれば、ちゃんと動くはずです!

まとめ

  • Slack でボタンとか作れるよ!
  • 管理者同意済みのアプリなら、ログインなしで色々できるよ!
matsuyama

matsuyama

最近 Unity 触ってます