背景
あるWebアプリで、Webアプリ上のイベントをビジネスSNSに通知する機能の要望があり、実現性を調査することになりました。
対象となったのはSlackとTeamsです。
Slackは実装例が豊富で、比較的容易に実現性の確認ができました。
一方Teamsはかなり情報が少なく、本家の重厚なドキュメントと向き合う必要がありました。
結局Teamsのみ見送りになったのですが、せっかくなので調べて分かったことをまとめます。
Teams以外とTeamsの比較
Teams以外の場合
Teams以外の一般的なSNSで今回の要件を実装する場合、このような流れになります。
(※ざっくり処理の流れを伝える図であり、あまり厳密な図ではありません)
Teamsの場合
Teamsが他のSNSと大きく異なるのが、「Bot」の概念です。
Teamsには「Bot Framework」という概念が存在しており、Webアプリ開発者がBotの振る舞いをNode.jsでコーディングするようになっています。
また、実装したBot用のAPIサーバを建てる必要があります。
(本家ドキュメントではAzureAD上に建てるよう紹介されていましたが、どうやら別プラットフォーム上に建てても良いらしい?)
(※ざっくり処理の流れを伝える図であり、あまり厳密な図ではありません)
構築手順(ローカルまで)
以下が今回やりたいことに近い印象だったのでこれを真似しました。
https://docs.microsoft.com/en-us/microsoftteams/platform/sbs-gs-notificationbot?tabs=vscode
1. 開発環境の用意:Teams Toolkitのインストール
Prepare development environment > Install the Teams Toolkit
VSCodeに拡張をインストールします。
インストール終えるとチュートリアルが立ち上がりますが、先述の記事のほうに従いますのでスルーします。

2. 無料のTeams sandbox環境を作成する
Set up your Teams development tenant > Create a free Teams developer tenant (optional)
Slackでは実際のworkspace上で開発を行うのですが、TeamsおよびOffice365にはsandbox環境の仕組みが存在しています。
Create a M365 testing tenant の「Join now」をクリックします。

必要事項を入力し「Next」をクリックします。

使うものをチェックします。
本記事では「Microsoft Teams」のみチェックしました。

sandbox環境の初期データ&管理者ユーザ作成のウィザードが表示されるので従います。
「Instant sandbox」を選択して「Next」

管理者ユーザの名前とPWを入力して「Continue」

電話番号を登録して「Set up」

以上の手順でsandbox環境が立ち上がります。
「Go to subscription」をクリックすると、該当sandboxのOffice365ホーム画面へ移動できます。

「Teams」をクリックします。
(うまく遷移できないかも1)

Teamsに入れました。テストデータが入っているのがわかります。
3. BotのNodeプロジェクトを新規作成する
Build notification bot
Teams Toolkit 拡張を開き、「Create a new Teams app」を選択します。

以下の通り選択します。

・Javascript/TypeScript
・保存場所
をそれぞれ選択します。

アプリ名は適当な名称を入力します。

プロジェクトが作成されるので開きます。
Teams Toolkitを開きます。
「Teams Toolkit > ACCOUNTS > M365にサインインする」を実施し、以下の状態になるようにします。
※「サイドローディングが有効」になっていない場合はこちらの手順を実施します

サインインできたら、デバッガを起動します。

「Debug(Chrome)」を実行してしばらく待つと、Chromeのウィンドウが立ち上がります。
途中でログインを求められた場合は入力します。
以下画面になりましたら、「追加」でアプリを追加します。

ホストマシンで
curl -X POST http://localhost:3978/api/notification
を実行し、以下のようにTeams上にメッセージが送信されたら成功です。

続いて、特定ユーザにメッセージを送るようにします。
botのソースを以下のように変更します。
(ユーザ特定がかなり無理やりなため不安あり)
server.post(
"/api/notification",
...,
async (req, res) => {
for (const target of await bot.notification.installations()) {
if (target.type !== 'Person') {
console.log('target.type mismatch')
continue
}
if (target.conversationReference.user.id !== req.body.user_id) {
console.log('user_id mismatch')
continue
}
await target.sendAdaptiveCard(
AdaptiveCards.declare<CardData>(notificationTemplate).render({
title: req.body.title,
appName: '', // TODO: 隠し方調査(カードの種類変える?)
description: req.body.description,
notificationUrl: '', // TODO: 隠し方調査(カードの種類変える?)
})
);
ホストマシンで
curl -X POST \
-d user_id=xxx \
-d title="Sample Service" \
-d description="豊後 国博 様より [自宅インテリアを3D画像でコーディネートするサービス「インテリアート」](https://example.com/hoge)にコメント" \
http://localhost:3978/api/notification
を実行すると、以下のようにTeams上にメッセージが送信されます。
※user_id
は graph explorerから取れます

ちなみに、ここまで完了するとTeams developer portal のApps画面に「mynotificationbot-local-debug」が追加されているかと思います。
ローカルで実施する分には意識することのない画面ですが、ステージ本番反映する上では操作が必要そうな画面です。

まとめ
今回はローカル環境上でTeamsBotを起動し、curlで任意の通知メッセージを送信するところまで実装しましたが、以下のような未解明事項を残しています。
今後これらの点まで調査できればと思います。
・ユーザを特定する処理
かなり無理矢理なので、そもそもこの記事でご紹介した方針で妥当かは未だ疑問符です。
・アプリ審査
他のOAuth認可と同様、本番反映の際にはMicrosoftの審査を受ける必要があると思われます。
・リモート環境でも正常に動作するか?
本記事でご紹介したローカル環境では、TeamsBotAPIサーバはローカル上に起動しており、ngrokによって上手くTeamsと連携できています。
実際はサーバを建てる必要があり、ドキュメント中ではAzureAD上に建てる方法で紹介されていましたが、AWS上に建ててもよい性質のものかは確認が必要です。
-
ログインアカウントの切り替えがうまく働かないのか、自分が操作した際はもともとログイン中だった非sandboxなアカウントで入ってしまいました。一旦ログインし直すなど必要かもしれません。 ↩