詩と創作・思索のひろば

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

Fork me on GitHub

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 も送っています

はてな記法 ⇔ Markdownコンバータ(pandoc のはてな記法対応)

最近の若者ははてな記法を書けないらしい……などと言っているだけではアレなのでコンバータを書いてみた。リストを書こうとして見出し(*)になっちゃうんですよね。あるある。

タイトルにあるとおり、pandoc という有名なマークアップコンバータにはてな記法を実装してみた形です。

github.com

フォークした1ブランチとしてソースコードがあるのみで、バイナリの配布とかはしてない。Haskell 製なので Stack をインストール(Homebrew なら haskell-stack)しておいて、make したらビルドできると思います。

pandoc の reader(マークアップの読み取り)および writer(マークアップの書き出し)として hatena を追加しているので、

pandoc -f hatena -t markdown_github < file.hatena

のように引数に指定して記法を変換できます。Markdown と書いたけど、pandoc がすごいので HTML や他のフォーマットにも変換可能。

parsec の思い出

pandoc の記法リーダの実装は parsec というライブラリに依っている。自分は Pugs という Haskell で書かれた Perl6 実装が話題になったころに Haskell でナイーブな JavaScript のインタプリタを書いてみたときに使って、そのとき以来触った覚えはなかったのだけど、意外とハマることも少なくすんなり実装できた。パフォーマンスはともかく。

調べてみたら Pugs は 10 年も前の話で、その頃の知識が今もまだ使えていることになんだか不思議な感じがある。

ミニマルはてな記法

先日のそうだGo、京都。でも話があったらしいが、はてな記法は実装の数だけ存在していて、単純なマークアップの範疇を越える仕事もしているので(:title による自動ページタイトル取得など)簡単に統一することはできないのだけど、そうは言っても実装する人たちの中で共通している認識はあるはずだと思っている。それをミニマルはてな記法と勝手に呼んで、それを実装してみた。公式なものではありません。

できれば仕様を書きたかったのだけど、大変なので、さしあたり以下のサンプルを用意した。これを意図通りに読み書きできるようなものとして実装した。pandoc を使って Markdown に変換したものもあわせて Gist に載せているので、どんなふうに解釈されるかわかりやすいと思う。

YAPC::Kansai 2017 OSAKAで『はてなシステムの考古学』というトークをおこないました #yapcjapan

先日開催された YAPC::Kansai 2017 OSAKAで、『はてなシステムの考古学』というタイトルで発表しました。

スライド中のリンクが効かないのであまり意味がないのですが、一応 Speakerdeck にも上げてあります: はてなシステムの考古学 / History of development at Hatena // Speaker Deck

はてなの開発の歴史を Perl エンジニア視点からふり返るというもので、どちらかというと『はてなの開発の歴史学』とでも読んだほうがしっくりくる内容になりました。

具体的な成果物を伴わない話をするのは苦手なほうだと思っていましたが、今回はあえてこんな内容でトークすることになりました。その背景には、いつの間にか自分が社内でも古参のエンジニアになっていたこと、また、事業や組織の拡大とともに開発のあり方が多様化してきて、それまで暗黙的に共有されてきたものに頼ることが困難になってきた感覚があったのだと思います。

なぜ歴史を語るのか

発表の参考にした『歴史とは何か』より、

歴史とは歴史家と事実との間の相互作用の不断の過程であり、現在と過去との間の尽きることを知らぬ対話なのであります。

と発表中に引用したとおり、歴史とは過去を語るだけでなく、過去のほうからも現在(と自分自身)を語ることでもあります。たとえばスライドでいうところの近代以降、フレームワークは時代の空気とでも呼べるものになったわけですが、普通にしていては明らかではないその実体に、歴史を通じて光を当てることができるのではないかという試みでもありました。

また同書より、

歴史というのは、獲得された技術が世代から世代へと伝達されて行くことを通じての進歩ということなのです。

歴史における進歩は、[…]獲得された資産の伝達を基礎とすること、[…]この資産は、物質的所有物と、自分の環境を支配し変更し利用する能力との両方を含んでいます。

……ということで、継承されてきた技術や思想、という観点から現在の自分たちの開発の現状を省みることで、新たに入社した人たちにもなぜ今がそうあり、未来にどうなっていくべきなのかということが、点ではなく線のようにイメージできるのではないかと考えたのでした。

準備にあたっては、エンジニアたちの過去の発表資料が当時を語るものとして非常に役に立ちました。少し前までは、はてなのエンジニアの大きな発表機会といえば YAPC::Asia で、京都から何人も出張するのでお祭り感があった(今もそうだけど)ものでしたが、つい最近であれば try! Swift や DroidKaigi ほか、それぞれの言語や技術分野コミュニティの大きな集まりにエンジニアたちが積極的に顔を出していて、あるべき姿に多様化してきているのだなと感じます。

そして振り返ってみるとこういう外部への発表こそが、自分たちの内に暗黙知として蓄えられていたものを整理する、SECIモデルでいうところの形式知への表出化の機会でもあったのかな、とも思います(この発表も、それがないとここまでちゃんと考えなかっただろうということも含めて)。

歴史とは何か (岩波新書)

歴史とは何か (岩波新書)

知識創造企業

知識創造企業

リンク集

スライド中で言及した・作成の参考にした資料へのリンクを記しておきます。

はてなで一緒に働きませんか?