TeamsのAdaptive Cardにプロフィール画像を埋め込んでみた

# はじめに

コミュニケーションツールとして、Slack も使っていますが、Teams も使っています。Teams にも開発フレームワークがあったり、Incoming/Outgoing Webhook の仕組みがあったりするわけですが、どうも情報量が少ないのです。

軽い気持ちで PowerAutomate での Teams 自動投稿にプロフィール画像をセットしようと思ったら、なかなか正解に辿り着かなかったので、今回はその手順を共有させていただきます。

# やりたいこと

公式リファレンス [Adaptive Cards / Samples and Templates (Official Reference)](https://adaptivecards.io/samples/) に掲載されているサンプルのように、プロフィール画像（顔写真）を表示したい。

<img width="851" alt="コメント 2020-05-30 224104.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/ad9cf333-3004-f025-c95b-9f27e8d9c4cd.png">


# とりあえずやってみる

### Power Automate フローの全体像

こんな感じの Power Automate フローを用意しました。トリガーはなんでもいいんですが、今回はプロフィール画像を表示したいユーザのメールアドレスを手動トリガー時にパラメータで渡すことにしました。処理の骨子は以下の通りです。

- **手動でフローをトリガーします**：ここでプロフィール画像を表示したいユーザのメールアドレスを渡す
- **ユーザーの写真のメタデータを取得します**：ここでプロフィール画像データや種別を取得する
- **ユーザープロフィールの取得 (V2)**：あらゆるユーザープロフィールの属性を取得する（プロフィール画像の有無など）
- **独自のアダプティブカードをフローボットとしてチャンネルに投稿する (プレビュー)**：プロフィール画像付きの Adaptive Card を Teams の指定チャネルに投稿する。

![screenshot-japan.flow.microsoft.com-2020.05.30-21_59_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/482c3aa9-2474-ce65-772f-c722ebb4ba01.png)

### どうしても undefined になってしまう

公式サンプルと同じように ``profileImage`` に Twitter のプロフィール画像をセットして自動投稿してみたところ、当然のように正常に表示されました。

**Twitter プロフィール画像のURLを指定した場合**
<img width="746" alt="teams-posted-masked.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/704c3d84-2b02-4e35-c1ee-0cf58b79ba95.png">

続いて、Office のプロフィール画像をセットして自動投稿してみたのですが、画像が表示されるべき領域に Undefined という文字列が表示されてしまい、顔写真が表示されませんでした。

**Office プロフィール画像のURLを指定した場合**
<img width="747" alt="teams-posted-undefined-masked.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/f8a6eb44-f445-4247-60be-040685029457.png">


ちなみに、Office プロフィール画像の取得方法は幾つかありますが、上記の例では、以下の URL を利用しました。

```:Officeプロフィール画像取得URL（GetPersonalPhotoの場合）
https://outlook.office.com/owa/service.svc/s/GetPersonaPhoto?email=yourname@hoge.com&size=HR96x96
```

# 試行錯誤の上、こう解決した

### Office プロフィール画像を表示するための Adaptive Cards

まず、表示する部分ですが、以下のように変数 `url` を参照するように定義しました。あとは、どのような値を `url` にセットするか次第です。
![screenshot-japan.flow.microsoft.com-2020.05.31-10_21_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/6c8ca142-4e9a-9b21-1ab5-0fe155495238.png)

ソースの抜粋は以下です。抜粋部分以外は、公式リファレンスを参考にしてください。

```json:一部抜粋
{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.0",
    "speak": "This is a notification of new documents.",
    "body": [
        {
            "type": "TextBlock",
            "text": "新着ドキュメントのお知らせ",
            "size": "large",
            "weight": "bolder"
        },
        {
            "type": "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "Image",
                            "style": "Person",
                            "url": "@{variables('url')}",
                            "size": "Small"
                        }
                    ],
                    "width": "auto"
                },
```

### URL ではなくデータ URI に変更

パブリックアクセスが可能な Twitter プロフィール画像は表示に成功し、社外からのアクセスが禁止されている Office プロフィール画像は表示に失敗する。この状況から、Teams 投稿時に社内リソースに対するアクセスがブロックされているのではないかと。

Power Automate の多くのタスクは、**個人での接続**を利用しますので、社内リソースに対する適切なアクセス権限を付与された状態でタスクを実行することができます（＝わたし自身が持つ権限内で社内リソースにアクセスする）。ですが、今回は**フローボットとして**チャネルに投稿しているため、社内リソースから見れば「お前、誰やねん」ですよね。

そこで、URL ではなく データ URI として画像を埋め込む方法に切り替えました。式の設定はビジュアルエディタ上で行いますが、実際の値は以下のようになっています。

```xpath:変数の設定
data:@{outputs('ユーザーの写真のメタデータを取得します')?['body/ContentType']};base64,@{body('ユーザーの写真の取得_(V2)')?['body']}
```

実行結果の具体例は以下の通りです。Base64 エンコーディングされた画像データが延々と続くので、途中で割愛しています。

```:実行結果（抜粋）
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAMinpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZhpkuO4EYX/4xQ+ArbEch
```

フロー上の表示は以下の通りです。
![screenshot-japan.flow.microsoft.com-2020.05.30-23_26_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/3327b70b-e2d6-d79b-ddcc-d3b94c35348c.png)


### プロフィール画像が未設定のケースも想定

もう一つ問題が発生しました、、、全員がプロフィール画像をセットしているわけではないのです。プロフィール画像がセットされていない場合、空白として表示されてしまうのです。しかも右側に寄ってしまいました。

**Office プロフィール画像が未設定の場合（対応前）**
<img width="749" alt="teams-posted-blank-masked.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/5dd63622-480b-8e3b-38b9-9658a935a131.png">

そこで、プロフィール画像の設定有無を条件に分岐するようにしました。ご丁寧に ``写真があります`` というフラグ項目があるので、こちらの値で判定しています。「いいえ」の場合は、デフォルト画像を変数にセットするようにしました。

**Office プロフィール画像が未設定の場合（対応後）**
<img width="742" alt="teams-posted-default-masked.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/16944b9a-3d86-1da7-d55b-a27d8a8ebfa6.png">

もちろん、プロフィール画像が設定されている場合は、問題なく表示されます。これにて完成です。

**Office プロフィール画像が設定されている場合**
<img width="746" alt="teams-posted-masked.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/704c3d84-2b02-4e35-c1ee-0cf58b79ba95.png">

# さいごに

公式サンプルが Twitter プロフィール画像だったため、URL からアプローチしたのですが、意外と遠回りしてデータ URI に辿り着きました。いくつかの海外サイトでデータ URI を指定する解決策は提示されていましたが、画像 Raw データ取得してから Base64 エンコードしていることが多く、Power Automate 標準の「ユーザーの写真の取得 (V2)」アクションを利用していませんでした。

プロフィール画像があるだけで、フローボットで自動投稿しつつも、パーソナル感を演出できますよね。ぜひ、みなさんもプレーンテキストやマークダウンだけでなく、Adaptive Card を利用した少しリッチなメッセージを投稿してみてください。

# 参考

[Microsoft Teams 向けアダプティブ カードの概要（公式リファレンス）](https://docs.microsoft.com/ja-jp/power-automate/overview-adaptive-cards)
[Adaptive Cards / Samples and Templates (Official Reference)](https://adaptivecards.io/samples/)