詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

GoogleカレンダーとSlackステータスをワンクリックで連携できるアプリをGoogle Apps Scriptで書いた

Googleカレンダーで現在進行中のイベントをSlackステータスに反映させるようにしておくと、チームメンバーに、移動中や不在やミーティング中といった状況を自然に共有できるので便利ですね。そのように設定している人も多いと思います。

f:id:motemen:20170515184041p:plain
似たアイコンが並んでいるように見えますが一方はモザイクです

巷では Google Apps Script でこの連携を行うような方法が公開されていて、自分でも書いて使ってました。これは一度動かしてしまえば大変便利なんですが、インストールの方法はけっこう面倒で、非エンジニアをふくめ会社のみんなに薦めるには少しハードルが高い。

そこで、Google Apps Script を用いて、(初回のインストール手順を除いて)ワンクリックで Google カレンダーと Slack ステータスの連携を行えるウェブアプリを作りました。

GitHub - motemen/gas-google-calendar-to-slack-status-farm

動作イメージ

明らかにワンクリックですね(実際には Slack 側でもう一回クリックする必要がありました)

f:id:motemen:20170515184113p:plain
クリック前

f:id:motemen:20170515184107p:plain
クリック後

動作要件

  • G Suite(Google Apps)のメンバー向け。そうでない場合も使えるかもしれません
  • Slack App として動きます
  • 認証した人の Google アカウントの個人カレンダーから、現在+5分後に進行中のイベントを Slack ステータスに反映します
  • イベントのタイトルによってステータスの絵文字が変わります(Slack おすすめ設定に準じます)
    • デフォルトでは :spiral_calendar_pad: (🗓)になります
    • イベント名に「早退」「遅刻」と入っている場合は :bus: (🚌) になります
    • イベント名に「休」と入っている場合は :palm_tree: (🌴)になります
    • イベント名に「:hospital:」など任意の emoji が入っている場合はそれがステータスに反映されます

設置方法

Apps Script の作成

  1. script.google.com などから新規 Goolge Apps Script を作成。
  2. [Resources] → [Libraries…] メニューより表示されるダイアログに、1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF を追加。(apps-script-oauth2を利用しています)
    • f:id:motemen:20170515182620p:plain
  3. gas-google-calendar-to-slack-status-farmリポジトリより、Code.jsをコピペ。

Slack App の作成

一人で使うスクリプトであれば個人用のトークン(最近はレガシートークンとらしい)で済ますところなのだけど、他のメンバーにも使ってもらうため Slack App として導入します。

  1. Slack API: Applications | Slackより新しい App を作成。
  2. 「OAuth & Permissions」に関して、以下の項目を設定。
  3. Permission Scopes に users.profile:write を追加。
  4. Redirect URLs には、先ほどのスクリプトの OAuth コールバック先として https://script.google.com/macros/d/{スクリプトID}/usercallback を指定。
    • スクリプトIDはスクリプトの [File] → [Project properties…] メニュー → [Script ID] 欄で確認できます
  5. 「App Credentials」の「Client ID」「Client Secret」を、それぞれスクリプトの SLACK_CLIENT_ID SLACK_CLIENT_SECRET として設定。

Apps Script のデプロイ

スクリプトの [Publish] → [Deploy as web app…] メニューより、ウェブアプリとしてデプロイ。

  • 「Execute the app as」は「User accessing the web app」に
  • 「Who has access to the app」は G Suite のドメインのメンバーに公開、などとするとよさそう。

ダイアログに表示されている URL にアクセスすると、ウェブ UI が表示されているのが確認できると思います。「Slack連携する」ボタンをクリックすると1分おきに実行されるトリガが作成されます。カレンダーにイベントを作成するなどして確かめてみてください。

付記

  • スクリプトは Google の OAuth も自動的に利用しますが、その際スクリプト名に「Google」という文字列が含まれていると OAuth アプリ名として利用されない気がしました。
  • スクリプト中の SLACK_LOG_WEBHOOK_URL に Slack の Incoming Webhook の URL を設定すると、ちょっとしたログがチャンネルに流れてきます。

技術的な内容

仕組み

最初にこれを作ろうと思ったとき頭によぎったのは Google Apps Script でやれば(Google 側のユーザ認証やカレンダー情報の取得など)簡単だが、Slack 側のユーザ認証情報や時間ベーストリガの実行権限の管理がうまくおこなえるのか? ということでした。apps-script-oauth2 ライブラリは PropertiesService.getUserProperties() というユーザごとのストレージに OAuth2 トークンを保存できるのですが、1分おきに実行されるトリガがスクリプト作成者の権限で実行されてしまうと、ユーザ別の認証情報にアクセスできなくなってしまうわけです。

結論から言うとこの心配はしなくてよくて、ScriptApp.newTrigger() を使うとそれを実行したユーザのトリガが作られるため、うまいことボタンをクリックしたユーザの権限でステータスの更新のための処理が実行できるのでした。その代わり、スクリプトの所有者からトリガを一覧したり操作したりできません。ここが困りポイントで、現状ではログから設定したユーザを見つけて、声をかけていくしかない……。

TypeScript 型定義ファイル

今回もGoogle Apps Script の TypeScript 型定義ファイルを作った - 詩と創作・思索のひろばで作った型定義ファイルを使ったけど、いくつかミスが見つかったのでとりあえず as any でしのぎつつ Pull Request も送っています