BoxとServiceNow連携：ファイル共有依頼（Box AIにて事前分析）

# 概要
Boxにあるファイルは簡単に共有できますが、秘密情報が入っているファイルを共有する前に承認を依頼する時があります。[Box Relay](https://www.box.com/ja-jp/collaboration/relay-workflow)で承認依頼フローを作ることができますが、この記事ではServiceNowでファイル共有の承認を依頼する方法を紹介します。

イメージとして、ユーザーがあるファイルを共有したく、ServiceNowで共有承認を依頼します。承認者は判断する前に、Box AIにてファイルを分析して、秘密情報が入っているかどうか確認します。その確認の結果を承認依頼のコメントに記載します。

# 準備

本記事では、Boxカスタムアプリ、ServiceNowのアプリケーションレジストリとRESTメッセージが作成・設定されたことを仮定します。それらの設定について、「[BoxとServiceNow連携：認証方法](https://qiita.com/mshcruz/items/5e3f8e72d5550b0c3937)」を参考してください。

# 実装

ファイル共有承認前のBox AIにて分析を実現するために、以下のステップを実装します：
1. ファイル共有依頼のテーブルを作成
2. レコードプロデューサーを作成
3. 「Box AI メタデータを抽出（構造化）」のHTTPメソッドを追加
4. ワークフローアクションを作成
5. ワークフローを作成

最後に動作確認を行います。

## フォルダ作成依頼情報のテーブルを作成

まずはBoxファイル共有依頼の情報を保管するテーブルを作成します：
- ラベル：<任意>（例：Boxファイル共有依頼）
- 名前：<任意>（例：u_box_file_sharing_request）

![Boxファイル共有依頼テーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/f10b0b15-ce61-4ffe-fd3b-d119a15f29bb.png)

新規レコードを保存すると、以下の列を追加します：
- 「BoxファイルID」列
  - タイプ：文字列 (完全な UTF-8)
  - 列ラベル：<任意>（例：フォルダ名）
  - 列名：<任意>（例：u_box_file_id）
- 「承認」列
  - タイプ：選択肢
  - 列ラベル：<任意>（例：承認）
  - 列名：<任意>（例：u_approval）
- 「承認履歴」列
  - タイプ：ジャーナル
  - 列ラベル：<任意>（例：承認履歴）
  - 列名：<任意>（例：u_approval_journal）

![テーブル列.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/820de2fc-57f1-d7d3-9cd7-2a12ba7bbbe7.png)

:::note warn
この記事では、なるべくわかりやすくするため、必要な列だけを追加し、テーブル列の設定を極力省いています。
本番の実装で、要件に従って適切な列（例えば、依頼説明や承認者など）を追加し、細かくテーブルを設定することをお勧めします（例えば、列タイプや最大長など）。
:::

## レコードプロデューサーを作成

次は、サービスカタログで利用するレコードプロデューサーを作成します：
- 名前：<任意>（例：Boxファイル共有依頼）
- テーブル名：前のステップで作成したテーブル（例：u_box_file_sharing_request）

![レコードプロデューサー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/09d20b53-b4d0-9f3f-e12d-5f43ecfe852e.png)

レコードを保存すると、画面の下に「変数」タブが表示され、依頼フォームの項目を設定することができます。今回は非常にシンプルなフォームを作成し、共有したいファイルIDだけ設定します：
- 「BoxファイルID」変数
  - フィールドにマップ：チェック
  - タイプ：1行テキスト
  - フィールド：BoxファイルID
  - 「質問」タブで「質問」：<任意>（例：BoxファイルID）
  - 「質問」タブで「名前」：前のステップで作成したフォルダ名のテーブル列名（例：u_box_file_id）

![レコードプロデューサー変数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/476e055e-7dbf-416b-1e0c-f9f7e62a7b35.png)

最後に、レコードプロデューサーの「カタログ」タブで「サービスカタログ」を追加し、「カテゴリ」タブで適切なカテゴリを選択します（例：セキュリティとアクセス）。

![レコードプロデューサーカタログ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/e573d650-a26e-633f-db09-03b331b0c5c8.png)

サービスカタログで作成したレコードプロデューサーを検索すると、フォームの見た目などを確認することができます。テスト値を入力して送信すると、プロデューサーの該当テーブルでレコードが作成されたことも確認できます。

## 「Box AI メタデータを抽出（構造化）」のHTTPメソッドを追加

Box AIにてファイルを分析するには、「メタデータを抽出 (構造化)」のAPIエンドポイントを使います：`https://api.box.com/2.0/ai/extract_structured`（[ガイド](https://ja.developer.box.com/reference/post-ai-extract-structured/)）。
Boxメタデータを設定する前にこのエンドポイントを使うことが多いですが、ファイルに対する構造データを取得したい場合でも便利です。

パラメータとして、共有したいファイルのIDと取得したい情報（フィールド）の定義を指定します。今回は秘密情報についてデータを取得しますが、様々なケースで同じメソッドを使うために、フィールドを変数として渡します。

上記のエンドポイントへリクエストを送信するために、事前に作成されたRESTメッセージで新規なHTTPメソッドを追加します。新規HTTPメソッド画面で以下のように設定します（詳細設定は[Box APIガイド](https://ja.developer.box.com/reference/post-ai-extract-structured/)で確認だきます）：
- 名前：<任意>（例：Box AI メタデータを抽出（構造化））
- HTTP メソッド：POST
- REST エンドポイント：https://api.box.com/2.0/ai/extract_structured
- 「HTTP要求」タブの「コンテンツ」の内容は以下のJSONです。JSONでは`fileId`と`fields`を変数として指定します

```JSON
{
  "items": [
    {
      "id": "${fileId}",
      "type": "file"
    }
  ],
  "fields": ${fields}
}
```

:::note warn
`${fields}`は配列ですので、クオーテーションで囲まれません。
:::

![Box AI メタデータを抽出（構造化）メソッド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/c074b4a2-b55e-a81b-6caf-a61ddc7397e4.png)

レコードを保存すると、画面の下に「REST メッセージ関数パラメーター」タブが表示されます。「関連リンク」の「変数の自動生成」をクリックすると、JSONで指定した変数がパラメーターとして設定されます。

![HTTPメソッド変数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/10e3585b-359e-92fc-720b-9229d9378efa.png)

## ワークフローアクションを作成
ファイル共有承認を依頼されたら、ワークフローでBox AIにての分析を行いますので、上記で作成した「Box AI メタデータを抽出（構造化）」のHTTPメソッドを利用するフローアクションを作成します。

アクションの入力として、ファイルIDを渡します：
- ラベル：<任意> （例：ファイルID）
- 名前：<任意> （例：fileid）
- タイプ：String

![アクション入力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/06f0e2d9-ed57-eac3-c795-629cbf02ee3e.png)

アクションに新しいスクリプトステップを追加し、以下のように入力変数を設定します：
- 名前：<任意> （例：id）
- 値：action➛ファイルID

スクリプトボックスで、以下のコードを設定します：

```javascript
(function execute(inputs, outputs) {
    // 取得する情報を定義
    var metadataExtractionFields = [
        {
            key: "personalInformation",
            description: "個人情報有無",
            displayName: "個人情報",
            prompt: "ファイルに次のような個人に関する情報が含まれる場合は、値をtrueにしてください：氏名、他のデータと組み合わせて個人を特定できる部分的な名前、住所（部分住所や郵便番号を含む）、電話番号、メールアドレス、社会保障番号、運転免許証番号、または国民ID。一般的な用語（例: 'カスタマーサービス'）や匿名のプレースホルダー（例: '山田太郎'）は含めないでください。個人を特定できる情報が含まれていない場合は、falseに設定してください。",
            type: "boolean"
        },
        {
            key: "financialInformation",
            description: "金融情報有無",
            displayName: "金融情報",
            prompt: "ファイルに次のような機密性の高い金融データが含まれる場合は、値をtrueにしてください：クレジットカード番号（例: 16桁の数字列）、銀行口座番号、ルーティング番号、取引記録、口座残高、税務書類、給与明細、または財務諸表。一般的な価格表や「予算の議論」のような非機密データは除外してください。機密性の高い金融データが見つからない場合は、falseに設定してください。",
            type: "boolean"
        },
        {
            key: "businessInformation",
            description: "機密ビジネス情報有無",
            displayName: "機密ビジネス情報",
            prompt: "ファイルに次のような機密性の高いビジネス情報が含まれる場合は、値をtrueにしてください：独自情報、営業秘密、詳細な製品設計、ビジネス戦略、業務計画、顧客リスト、または非公開の財務報告書。「機密」「専有」といったラベルが付けられたデータも含めてください。一般公開されているマーケティング資料や非専有情報は除外してください。機密ビジネス情報が見つからない場合は、falseに設定してください。",
            type: "boolean"
        },
        {
            key: "healthInformation",
            description: "健康情報有無",
            displayName: "健康情報",
            prompt: "ファイルに次のような健康関連情報が含まれる場合は、値をtrueにしてください：医療記録、処方箋、検査結果、保険情報、診断コード、または規制（例: HIPAA）の対象となるデータ。「患者123が胸痛を訴えた」のような機密メモも含めてください。特定の個人に関連しない健康アドバイスや一般的なフィットネスのヒントは除外してください。健康情報が見つからない場合は、falseに設定してください。",
            type: "boolean"
        },
        {
            key: "authenticationInformation",
            description: "認証情報有無",
            displayName: "認証情報",
            prompt: "ファイルに次のような認証情報が含まれる場合は、値をtrueにしてください：ユーザー名、パスワード、APIキー、OAuthトークン、暗号化キー、またはその他のアクセス制御に使用されるデータ。デフォルトまたはプレースホルダーの認証情報（例: 'admin/admin'）も、悪用される可能性がある場合は含めてください。認証情報が含まれない設定データや無関係な数字列は除外してください。認証情報が見つからない場合は、falseに設定してください。",
            type: "boolean"
        }
    ];

    // 作成したHTTPメソッドでBox AI APIへリクエストを送信
    var r = new sn_ws.RESTMessageV2('Box', 'Box AI メタデータを抽出（構造）');
    r.setStringParameterNoEscape('fileId', inputs.id);
    r.setStringParameterNoEscape('fields', JSON.stringify(metadataExtractionFields));
    var response = r.execute();
    var responseBody = JSON.parse(response.getBody());

    // 結果をパースして、ファイル共有依頼に記載するコメントを用意
    var result = "--Box AIによるファイル情報分析--";
    result += "<br/>個人情報：";
    result +=  responseBody.personalInformation ? "有" : "無";
    result += "<br/>金融情報：";
    result +=  responseBody.financialInformation ? "有" : "無";
    result += "<br/>機密ビジネス情報：";
    result +=  responseBody.businessInformation ? "有" : "無";
    result += "<br/>健康情報：";
    result +=  responseBody.healthInformation ? "有" : "無";
    result += "<br/>認証情報：";
    result +=  responseBody.authenticationInformation ? "有" : "無";

    outputs.result = result;
})(inputs, outputs);
```
:::note warn
この記事では、内容をわかりやすく伝えることを目的として、説明用の簡略化されたコードを掲載しています。
そのため、セキュリティ対策やエラーハンドリングといった重要な非機能要件については意図的に省略しています。
実際にコードを実装・運用する際には、これらの要件を十分に考慮し、適切な対策を講じることが開発者に求められます。
:::

:::note warn
分析対象のファイルと取得したい情報によって、フィールドやプロンプトを編集る必要があります。
:::

出力変数として、以下を設定します：
- ラベル：<任意> （例：分析結果）
- 名前：<任意> （例：result）
- タイプ：String

![アクションスクリプト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/ebd44fa9-4ab4-0d44-073b-a06e1a6de478.png)

アクションの出力を設定します：
- ラベル：<任意> （例：分析結果）
- 名前：<任意> （例：result）
- タイプ：String

![アクション出力変数定義.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/a4f5a671-30c5-86cc-52af-dbb71c91badb.png)

そして、出力変数の値をスクリプトステップの出力にします。
- 分析結果：step➛スクリプト step➛分析結果

![アクション出力変数値.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/40721e2e-bc8e-eb1e-cf19-f69db0276cf3.png)

最後に、アクションを保存と公開して、次に作成するフローで使います。

## ワークフローを作成

ファイル共有承認を依頼されたら、フローを起動して、Box AIにて分析して、結果を依頼の承認履歴にコメントとして記載します。

そのため、まずはトリガーを設定します。
- トリガー：作成時
- テーブル：以前作成したテーブル（例：Boxファイル共有依頼 [u_box_file_sharing_request]）

![フロートリガー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/ffec145e-013f-e354-302a-30c4805ab434.png)

次に、フローのアクションを設定します。

最初のアクションは作成しておいた「Box AIにてファイル分析」です。パラメータとして、トリガーレコードのファイルIDです：
- アクション：Box AIにてファイル分析
- ファイルID：トリガー - Record 作成時➛Boxファイル共有依頼 Record➛BoxファイルID

![Box AIにてファイル分析アクション設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/76222742-e1ee-dfe6-3f00-b3c171d06dc4.png)

2つ目のアクションはBox AIの分析結果をレコードの承認履歴フィールドに追加します。
- アクション：レコードを更新（Update Record）
- レコード：トリガー - Record 作成時➛Boxファイル共有依頼 Record
- テーブル：以前作成したテーブル（例：Boxファイル共有依頼 [u_box_file_sharing_request]）
- フィールド名：承認履歴 
- フィールド値： 1 - Box AIにてファイル分析➛分析結果

![レコード更新アクション設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/407a3502-6622-84fe-e0c5-33c16e988383.png)


最後のアクションは実際の承認依頼のため、「承認を求める」アクションを使います：
- アクション：承認を求める（Ask for Approval）
- レコード：トリガー - Record 作成時➛Boxファイル共有依頼 Record
- テーブル：以前作成したテーブル（例：Boxファイル共有依頼 [u_box_file_sharing_request]）
- 承認フィールド：承認
- ジャーナルフィールド：承認履歴
- ルール：承認または却下
- ルール時期：任意の人が承認または却下、適切な承認者を選択します（例：System Administrator）

![承認を求めるアクション設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/230d0a75-f5d3-9050-a33f-91a533abc1cd.png)

アクションの設定ができたら、フローを保存と有効化します。

## 動作確認

実装したステップは正常に実行されることを確認するには、テスト書類（請求書）を用意し、サービスカタログでBoxファイル共有承認を依頼します。

![請求書.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/8fb04e43-bdcf-36c3-9f9a-b84c64c10452.png)

![サービスカタログでBoxファイル共有承認を依頼.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/db94a5ef-c73d-14da-5589-b99470a5587a.png)

依頼を送信して、ServiceNowの承認一覧を確認すると、承認依頼があります。

![承認依頼.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/623bc363-1a1a-cacb-30ff-913afeeffbcb.png)

その依頼の詳細を見ると、Box AIの分析結果はコメントとして承認履歴に記載されていることが確認できます。

![承認履歴.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895687/66475199-753c-0397-919c-9997ef378877.png)

# まとめ

この記事では、ServiceNowからBoxファイルを共有承認を依頼する方法について説明しました。

最終的に、承認者は判断しますが、Box AIで事前分析を行なって、秘密情報などが入っているかより早くわかると思います。

このように、BoxにあるコンテンツをBox AIで分析や要約をして、ServiceNow管理する業務プロセスの効率化・自動化できると考えられます。