Power Appsでモダンなチャットアプリを作ってみる (2)

# はじめに
この記事は[Power Appsでモダンなチャットアプリを作ってみる (1)](https://qiita.com/DEmodoriGatsuO/items/e58f136cb963d0d4c229)の続きです。
主に`Power Automate`について解説していきたいと思います。

https://qiita.com/DEmodoriGatsuO/items/e58f136cb963d0d4c229

Power Automateでは

1. `JSON ファイル` **コンテンツを取得する親フロー**
1. `JSON ファイル`を**作成または更新する親フロー**
1. 上記二つのフローで使用する**ファイルの存在の確認、コンテンツを返す子フロー**

合計三つのフローを用意します。

## 1. `JSON ファイル` **コンテンツを取得する親フロー**
ほぼ処理は`子フロー`が実施しています。

1. `MessageID`を`Power Apps`から受け取り
1. 子フローから`JSON ファイルコンテンツ`を受け取り
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/87c915d5-f3a9-6838-c031-2868c7bf89cf.png)

1. `Power Apps`に`JSONファイル コンテンツ`返す
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/537f94cd-b204-87dd-e23e-91952f3e0e33.png)

詳細は割愛します。

## 2. `JSON ファイル`を**作成または更新する親フロー**
まずは図解です。

```mermaid
graph TD
    A[Power Apps V2 トリガー] --> B[JSONの解析 メタデータ]
    A --> C[JSONの解析 Chatの履歴]
    B --> D[条件 ファイルの存在により分岐]
    C --> D
    D -->|新規作成| E[ファイルの作成]
    E -->F[変数の設定 作成 ItemID]
    D -->|更新| H[ファイルの更新]
    F --> I[ファイルのプロパティの更新]
    H --> I
    I --> J[Power App またはフローに応答する]
```

**■ Power Apps がフローを呼び出したとき (V2)**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/69d87f00-c39b-ecc8-7e2b-dd3a58f440c5.png)

- `spMetaData`: SharePointのドキュメント ライブラリに設定するメタデータ
- `objChat`: チャットの履歴

`Power Apps`から`JSON`文字列とファイルに設定するメタデータを受け取ります。
個人的に複数の値をPower AppsからPower Automateに渡す際は[JSON 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-json)で私はまとめてしまっています。

https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-json


**JSON の解析**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/581b87f8-4a24-bf31-a84d-bc32023365b4.png)

**■ JSON の解析 メタデータ**
ファイルのメタデータとして定義する値です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/fbaaef9a-528a-b6ea-fd89-fd1a7ec857bc.png)

```json:Schema
{
    "type": "object",
    "properties": {
        "CreateBy": {
            "type": "string"
        },
        "CreatedTime": {
            "type": "string"
        },
        "Fill": {
            "type": "string"
        },
        "FontColor": {
            "type": "string"
        },
        "LastMessageText": {
            "type": "string"
        },
        "LastMessageTime": {
            "type": "string"
        },
        "LastSender": {
            "type": "string"
        },
        "MessageCount": {
            "type": "integer"
        },
        "MessageID": {
            "type": "string"
        },
        "Subject": {
            "type": "string"
        },
        "UpdatedTime": {
            "type": "string"
        }
    }
}
```

:::note info
JSONにすることで複数の設定値をまとめていますが、型が変わってしまった際や、Null対策の必要があります。今回の設定値は`Null`が渡されない前提で設定しています。
:::

**■ JSON の解析 Chatの履歴**
こちらはチャットの内容です。`Log`というキーに対して配列が設定されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/4c537c6d-22a7-a80e-2c10-04830daa74dc.png)

```json:Schema
{
    "type": "object",
    "properties": {
        "Log": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "MessageIndex": {
                        "type": "integer"
                    },
                    "MessageText": {
                        "type": "string"
                    },
                    "SenderName": {
                        "type": "string"
                    },
                    "TimeStamp": {
                        "type": "string"
                    }
                },
                "required": [
                    "MessageIndex",
                    "MessageText",
                    "SenderName",
                    "TimeStamp"
                ]
            }
        }
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b85bbcb8-dd23-b89f-427b-deb86764eb6f.png)

取得した`MessageID`を引数にして、過去のJSONファイルの参照を実施します。
こちらにて、チャットの履歴ファイルの`ItemID`やファイルコンテンツを取得しています。

チャットの履歴となるJSONファイルが存在しない場合は、[ファイルの作成](https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)、
そうでない場合は、[ファイルの更新](https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%9B%B4%E6%96%B0)を実施します。

https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90

https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%9B%B4%E6%96%B0

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/7dc29d17-76b0-b0f8-94f2-8c019fc73e3e.png)

### [ファイルの作成](https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)の場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/52ed86a5-3c3e-e838-0bc5-c4ba581dc948.png)

ファイル名は`MessageID`.json、ファイル コンテンツは`JSON` `@{body('JSON_の解析_Chatの履歴')}`を指定します。
**新規作成**に該当するため、`ドキュメント ライブラリ`の`ItemID`を取得しておきます。
`ItemID`に`@{outputs('ファイルの作成')?['body/ItemId']}`を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/4a6b07ec-0d72-385f-648a-876153e8053a.png)

### [ファイルの更新](https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%9B%B4%E6%96%B0)の場合
`子フロー`から取得した`identifier`を`ファイル識別子`に設定、ファイルコンテンツは`新規作成`と同様に`@{body('JSON_の解析_Chatの履歴')}`を設定します。

### [ファイルのプロパティの更新](https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E6%9B%B4%E6%96%B0)

`ドキュメント ライブラリ`のメタデータを更新します。

https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E6%9B%B4%E6%96%B0

列数が多いと`JSON`で複数まとめて設定できる方法が個人的に活きるなと感じます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/7b0b9019-af08-a06d-942b-04c6aaeb5d0b.png)

最後にフローへの応答を設定して完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/45458a73-b986-6bb4-9076-afe2e018ddee.png)

# 子フロー
このフローの役割は
1. `MessageID`から`ファイルの存在を確認する`
1. ファイルが存在する場合、`ファイルコンテンツ`と`ファイル識別子`、`ItemID`を返す

この二ポイントです。

```mermaid
graph TD
    A[フローを手動でトリガーする MessageIDを受信] --> B[変数を初期化 strObject]
    A --> C[変数を初期化 ItemID]
    A --> D[変数を初期化 Identifier]
    B --> E[ファイルの取得 プロパティのみ]
    C --> E
    D --> E
    E --> F[作成 ファイルの数]
    F --> G[条件 ファイルが存在するか]
    G -->H[変数の設定 ItemID]
    G -->I[変数の設定 Identifier]
    H --> J[ファイル コンテンツの取得]
    I --> J
    J --> K[変数の設定 strObject]
    K --> M[Respond to a Power App or flow]
    G --> |存在しない| M
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/d2d7f68c-d1e8-1caf-138e-f6769f594933.png)

変数は下記の三点です。
- `strObject` : `String`、ファイルが存在する場合にファイルコンテンツを文字列で格納
- `ItemID` : `Integer`、ドキュメント ライブラリの`ItemID`
- `Identifier` : `String`、ファイル識別子

**■ [ファイルの取得 プロパティのみ](https://learn.microsoft.com/ja-jp/connectors/sharepoint/)**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/c565912a-1531-8995-57a7-7dbfb9913ca8.png)

条件に合致するファイルの一覧を返します。
フィルター クエリを下記のように指定することで、一意である`MessageID`でファイルを特定させます。

```plaintext:フィルタークエリ
MessageID eq '@{triggerBody()['text']}'
```

:::note info
考え方がわかれそうですが、メタデータでファイル管理するのは本当に楽です。
ファイル名とかやめたほうがいいと思います。（個人の意見）
:::

https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%82%92%E5%8F%96%E5%BE%97-(%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E3%81%BF)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/1071b599-9860-1b07-d3e2-d2225a98666f.png)

ファイルの数は`@{length(outputs('ファイルの取得_(プロパティのみ)')?['body/value'])}`で取得します。

■ ファイルが存在する場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/dd8b0a9f-5ff5-b72f-b023-3b4f7792175c.png)

変数の設定で`ItemID`と`Identifier`を設定しましょう。

`ItemID` - `@{first(outputs('ファイルの取得_(プロパティのみ)')?['body/value'])?['ID']}`
`Identifier` - `@{first(outputs('ファイルの取得_(プロパティのみ)')?['body/value'])?['{Identifier}']}`

そして[ファイルコンテンツを取得](https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%81%AE%E5%8F%96%E5%BE%97)します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/7fba64a5-6f95-1869-6a70-04648a1c1fa2.png)

JSONの型が正確ではないと、値が正確に返ってきません。`コンテンツ タイプの推測`をオフにすれば取得できなくもないですが、おすすめはできないですね。

https://learn.microsoft.com/ja-jp/connectors/sharepoint/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%81%AE%E5%8F%96%E5%BE%97

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/6ff6f79c-987f-7434-e932-034fbe20b270.png)

戻り値は`文字列変数`として`strObject`に設定します。`@{string(outputs('ファイル_コンテンツの取得')?['body'])}`

そしてそれぞれ値を返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/2c7cb070-ef03-8679-6ea6-c18c0eb50531.png)

こちらによってフローがそろいました！

# 完成！
こちらを[Power Appsでモダンなチャットアプリを作ってみる (1)](https://qiita.com/DEmodoriGatsuO/items/e58f136cb963d0d4c229)と合わせて使うと、簡易的ですがチャットアプリができます。
`Teams`コネクタを使った統合もできそうですが、こういったやり方もあるんだな、位にみてください！

https://qiita.com/DEmodoriGatsuO/items/e58f136cb963d0d4c229

それではよいPower Lifeを！