@cap-js/notificationsプラグインでSAP Build Work Zoneに通知を送る

## はじめに
この記事は [SAP Advent Calendar 2023](https://adventar.org/calendars/8870)の 12月5日分の記事として執筆しています。

### SAP Build Work Zoneの通知機能とは
SAP Build Work Zone, standard editionでは、ユーザに対してアプリケーションなどから通知を送ることができます。通知はシェルバーのベルのアイコンをクリックすると表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/ae3e0d5e-b090-19d0-c70f-15175d191d36.png)

サイトの設定で"Show Notifications"に"Yes"を設定することで、通知を受け取れるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c660b64b-bdb4-1497-de3f-3d6a1491fe45.png)

### @cap-js/notificationsプラグインとは
アプリケーションから通知を送る場合、従来は以下のブログにあるような方法でコードを書く必要がありました。
[Sending Notifications from SAP BTP Applications to the SAP Fiori Launchpad](https://blogs.sap.com/2021/07/06/sending-notifications-from-sap-btp-applications-to-the-sap-fiori-launchpad/)

この後で説明しますが、通知を送るには①テンプレートを登録し、②テンプレートを使って通知を送る、というステップが必要になります。さらにCSRFトークンの取得も行う必要があるため、いわゆる"boilerplate code"が多くなります。

[@cap-js/notifications](https://github.com/cap-js/notifications)プラグインは、そのような「必要だがビジネスロジックには関係ない」処理を裏で行ってくれます。これにより、通知を送るために開発者が書くコードは以下のように最小限で済みます。

```javascript
const alert = await cds.connect.to('notifications');
alert.notify({
  recipients: [ ...supporters() ],
  priority: "HIGH",
  title: "New high priority incident is assigned to you!",
  description: "Incident titled 'Engine overheating' created by 'customer X' with priority high is assigned to you!"
});
```
## 通知を送る手順
@cap-js/notificationsを使う前に、通知を送るための基本的な手順について理解しておきましょう。

参考：[Developing Cloud Foundry Applications With Notifications | SAP Help Portal](
https://help.sap.com/docs/build-work-zone-standard-edition/sap-build-work-zone-standard-edition/developing-cloud-foundry-applications-with-notifications)

### 1. Notification Typeを登録
Notification Typeとは、通知に表示する文言や実行可能なアクションを定義したテンプレートです。NotificationのAPIエンドポイント：`<HOST>/v2/NotificationType.svc/NotificationType`にPOSTリクエストを送ってNotification Typeを登録します。Notification Typeの中身は以下のようなJSONオブジェクトです。（各プロパティの定義は[ドキュメント](https://help.sap.com/docs/build-work-zone-standard-edition/sap-build-work-zone-standard-edition/developing-cloud-foundry-applications-with-notifications)を参照）

```json:Notification Typeのサンプル
{
    "NotificationTypeKey": "LeaveRequest",
    "NotificationTypeVersion": "0.3",
    "Templates": [
        {
            "Language": "en",
            "TemplatePublic": "A new leave request needs ur attention!",
            "TemplateSensitive": "Leave Request by {{requester_email}} from {{from}} to {{to}}",
            "TemplateGrouped": "You have {{_group_count}} leave request(s) for approval",
            "TemplateLanguage": "Mustache",
            "Subtitle": "Leave Request",
            "Description": "Leave Request notification",
            "EmailSubject": "There is a Leave Request",
            "EmailText": "This is a Leave Request. It needs your attention",
            "EmailHtml": "<html><body><p>This is a Leave Request. It needs your attention</p></body></html>"
        }
    ],
    "Actions": [
        {
            "ActionId": "AcceptLRActionKey",
            "Language": "en",
            "ActionText": "Accept",
            "GroupActionText": "Accept All",
            "Nature": "POSITIVE"
        },
        {
            "ActionId": "RejectLRActionKey",
            "Language": "en",
            "ActionText": "Reject",
            "GroupActionText": "Reject All",
            "Nature": "NEGATIVE"
        }
    ],
    "DeliveryChannels": [
        {
            "Type": "MAIL",
            "Enabled": true
        }
    ]
}
```
### 2. Notificationを送信
NotificationのAPIエンドポイント：`<HOST>/v2/Notification.svc/Notifications`にPOSTリクエストを送り、通知をSAP Build Work Zoneに送信します。この結果、SAP Build Work Zoneのシェルバーに通知が表示されます。

```json
{
    "OriginId": "leave-req-dest",
    "NotificationTypeKey": "LeaveRequest",
    "NotificationTypeVersion": "0.3",
    "NavigationTargetAction": "display",
    "NavigationTargetObject": "LeaveRequest",
    "Priority": "High",
    "ActorId": "NAIRA",
    "ActorType": "",
    "ActorDisplayText": "",
    "ActorImageURL": "https://scn.sap.com/people/guest/avatar/NAIRA.png",
    "Properties": [
        {
            "Key": "requester_email",
            "Language": "en",
            "Value": "me@sap.com",
            "Type": "String",
            "IsSensitive": false
        },
        {
            "Key": "from",
            "Language": "en",
            "Value": "05-01-2021",
            "Type": "String",
            "IsSensitive": true
        },
        {
            "Key": "to",
            "Language": "en",
            "Value": "05-01-2022",
            "Type": "String",
            "IsSensitive": true
        }
    ],
    "Recipients": [
        {
            "RecipientId": "<通知受信者のメールアドレス>"
        }
    ]
}
```

## 通知を送るための設定
次に、@cap-js/notificationsを使う場合も使わない場合も必要となる、通知を送信するための設定について確認します。

参考：[Enabling Notifications for Custom Apps on SAP BTP Cloud Foundry | SAP Help Portal](https://help.sap.com/docs/build-work-zone-standard-edition/sap-build-work-zone-standard-edition/enabling-notifications-for-custom-apps-on-sap-btp-cloud-foundry)

### 1. 認証情報の生成
Site Managerで"Settings"のアイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/2714baaa-c1d5-b912-ef25-a67e5eeeaa3b.png)

"**Notificaions**"タブを開き、"**Authentication Identifier**"にEmailまたはUser IDを選択します。どちらを選ぶかはIdentity Providerの設定により決めます。
"**Generate**"をクリックして認証情報を生成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/77475715-d539-656b-2649-33c5eaada86a.png)
以下の情報が生成されます。再び画面を開いた時には表示されないため、これらの情報をコピーしておきます。
- Host
- Client ID
- Client Secret
- Authorization Endpoint
- Token Endpoint

### 2. Destinationの登録
1. で生成した情報をもとにDestinationを登録します。以下のヘルプの通りに登録します。
[Configure the destination to the notifications service](https://help.sap.com/docs/build-work-zone-standard-edition/sap-build-work-zone-standard-edition/enabling-notifications-for-custom-apps-on-sap-btp-cloud-foundry)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/f06bc0b3-1381-dbcb-6daf-7090a8cdbb74.png)
※注意：ヘルプでは、URLが`https://notifications.cfapps.sap.hana.ondemand.com`となっていますが、ホスト部分は1.で表示されたHostと一致するようにします（例：`https://notifications.cfapps.us10.hana.ondemand.com`）

## @cap-js/notificationsを使用
ここからは、@cap-js/notificationsプラグインを使用して通知を送る方法について説明します。（ソースは[Gitリポジトリ](https://github.com/miyasuta/cap-js-notifications)にあります）

### 1. プロジェクトにプラグインを追加
以下のコマンドでプラグインを追加します。
```
 npm add @cap-js/notifications
 ```

 ### 2. 通知送信のコードを追加
以下では、イベントハンドラで新しいOrderが登録された後に通知を送信するようにします。
 ```javascript:例
        this.after('CREATE', 'Orders', async(results, req) => {
            console.log(results);
            const alert = await cds.connect.to('notifications');

            alert.notify({
                recipients: [ '<宛先ユーザのメールアドレス>' ],
                priority: "HIGH", //optional
                title: "New Order has been created!",
                description: `An Order from customer ${req.data.customer} has been created!`
              });
        })
 ```

### 3. デプロイの設定
`cds add mta`コマンドを実行すると、mta.yamlファイルに`notification-content-deployment`というモジュールが追加されます。このモジュール（タスク）はデプロイ時に実行され、Notification Typeを登録します。このモジュールの設定に以下の変更を加えます。

- タスクのdisk-quotaを2GBに増やす（スペースが足りずデプロイ時にエラーになっため）

変更後の設定内容は以下です。

```yaml
- name: notification-content-deployment
  type: nodejs
  path: gen/srv
  requires:
  - name: cap-js-notifications-destination
  parameters:
    disk-quota: 256MB
    memory: 256MB
    no-route: true
    no-start: true
    tasks:
    - command: node node_modules/@cap-js/notifications/lib/content-deployment.js
      disk-quota: 2GB #256MBから変更
      memory: 256MB
      name: notification-content-deployment
```
※mta.yamlファイルが存在する状態で`npm add @cap-js/notifications`を実行した場合、上記の設定は追加されませんでした。プラグインを追加してからmta.yamlを生成する必要があるようです。

### 4. デプロイ後
MTAアプリケーションをデプロイしたあと、`<HOST>/v2/NotificationType.svc/NotificationTypes`のエンドポイントでNotification Typeを取得すると、"Default"という名前のNotification Typeが登録されていました。

```json
{
    "d": {
        "results": [
            {
                "__metadata": {
                    "id": "https://notifications.cfapps.us10.hana.ondemand.com:443/v2/NotificationType.svc/NotificationTypes(guid'14abc9e3-c088-456c-aed4-6950cf246682')",
                    "uri": "https://notifications.cfapps.us10.hana.ondemand.com:443/v2/NotificationType.svc/NotificationTypes(guid'14abc9e3-c088-456c-aed4-6950cf246682')",
                    "type": "com.SAP.OData.V2.NotificationTypeService.NotificationType"
                },
                "NotificationTypeId": "14abc9e3-c088-456c-aed4-6950cf246682",
                "NotificationTypeKey": "Default",
                "NotificationTypeVersion": "1",
                "IsGroupable": true,
                "Templates": {
                    "__deferred": {
                        "uri": "https://notifications.cfapps.us10.hana.ondemand.com:443/v2/NotificationType.svc/NotificationTypes(guid'14abc9e3-c088-456c-aed4-6950cf246682')/Templates"
                    }
                },
                "Actions": {
                    "__deferred": {
                        "uri": "https://notifications.cfapps.us10.hana.ondemand.com:443/v2/NotificationType.svc/NotificationTypes(guid'14abc9e3-c088-456c-aed4-6950cf246682')/Actions"
                    }
                },
                "DeliveryChannels": {
                    "__deferred": {
                        "uri": "https://notifications.cfapps.us10.hana.ondemand.com:443/v2/NotificationType.svc/NotificationTypes(guid'14abc9e3-c088-456c-aed4-6950cf246682')/DeliveryChannels"
                    }
                }
            },
```
### 5. 動作確認
SAP Build Work Zone, standard editionにアプリケーションを追加し、Orderを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/04cd9cd3-158b-096d-8cdb-5ae21535d772.png)
登録すると即座に通知が表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/0f80cf00-38d3-2210-c578-ab951bdc37cf.png)

## おわりに
@cap-js/notificationsにより、SAP Build Work Zoneに簡単に通知を送ることができました。CAPのプラグインの仕組みは（私の知る限り）[今年の4月に初めて紹介され](https://blogs.sap.com/2023/04/30/reusable-components-for-cap-with-cds-plugin/)、それ以降、`@cap-js`または`@cap-js-community`で始まるプラグインが順次登場しています。これにより、Node.jsでのCAPプロジェクトの開発はますます便利になりそうです。利用可能なプラグインは以下のページで見ることができます。
[Best of cap-js](https://bestofcapjs.org/#/packages)

次回はもう少し、プラグイン自体の仕組みについて掘り下げて調べてみたいと思います。