From ddfe488e5c63ee598a2d132a753d2d8e853e8178 Mon Sep 17 00:00:00 2001 From: Erwan Guyader Date: Thu, 4 Jan 2024 13:32:44 +0100 Subject: [PATCH] feat: Allow sending notifications via admin route --- docs/admin.md | 64 +++++++++++++++++++ docs/notifications.md | 2 +- .../center/notification_center.go | 11 ++++ web/instances/instances.go | 31 +++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) diff --git a/docs/admin.md b/docs/admin.md index 78ebe30cfcc..71d037cb4c1 100644 --- a/docs/admin.md +++ b/docs/admin.md @@ -484,6 +484,70 @@ Content-Type: application/zip Content-Disposition: attachment; filename="alice.cozy.localhost - part001.zip" ``` +### POST /instances/:domain/notifications + +This endpoint allows to send a notification via the notification center. Both +the notification declaration and its properties need to be passed in the body. +These notifications cannot use templates defined in cozy-stack though so their +e-mail content must be provided directly (at least in HTML). + +When the request is successful, the generated notification object is returned. + +```http +POST /instances/alice.cozy.localhost/notifications HTTP/1.1 +Authorization: Bearer ... +Content-Type: application/json +``` + +```json +{ + "notification": { + "category": "account-balance", + "category_id": "my-bank", + "title": "Your account balance is not OK", + "message": "Warning: we have detected a negative balance in your my-bank", + "priority": "high", + "state": "-1", + "preferred_channels": ["mobile"], + "content": "Hello,\r\nWe have detected a negative balance in your my-bank account.", + "content_html": "\r\n\t\r\n\t

Hello,
We have detected a negative balance in your my-bank account.

\r\n\t\r\n\t" + }, + "properties": { + "description": "Alert the user when its account balance is negative", + "collapsible": true, + "multiple": true, + "stateful": true, + "default_priority": "high" + } +} +``` + +#### Response + +```http +HTTP/1.1 201 Created +Content-Type: application/json +``` + +```json +{ + "_id": "c57a548c-7602-11e7-933b-6f27603d27da", + "_rev": "1-1f2903f9a867", + "source_id": "cozy/cli//account-balance/my-bank", + "originator": "cli", + "category": "account-balance", + "category_id": "my-bank", + "created_at": "2024-01-04T15:23:01.832Z", + "last_sent": "2024-01-04T15:23:01.832Z", + "title": "Your account balance is not OK", + "message": "Warning: we have detected a negative balance in your my-bank", + "priority": "high", + "state": "-1", + "content": "Hello,\r\nWe have detected a negative balance in your my-bank account.", + "contentHTML": "\r\n\t\r\n\t

Hello,
We have detected a negative balance in your my-bank account.

\r\n\t\r\n\t" +} +``` + ## Contexts ### GET /instances/contexts diff --git a/docs/notifications.md b/docs/notifications.md index 566cc0970d3..5347d30f47e 100644 --- a/docs/notifications.md +++ b/docs/notifications.md @@ -100,7 +100,7 @@ This endpoint can be used to push a new notification to the user. Notifications fields are: - `category` (string): name of the notification category -- `category_id` (string): category name if the category is multiple +- `category_id` (string): name of the notification sub-category if relevant (optional) - `title` (string): title of the notification - `message` (string): message of of the notification (optional) - `priority` (string): priority of the notification (`high` or `normal`), sent diff --git a/model/notification/center/notification_center.go b/model/notification/center/notification_center.go index f6f9fdeb153..49e468edb3e 100644 --- a/model/notification/center/notification_center.go +++ b/model/notification/center/notification_center.go @@ -126,6 +126,17 @@ func PushStack(domain string, category string, n *notification.Notification) err return makePush(inst, p, n) } +// PushCLI creates and sends a new notification where the source is a CLI +// client which provides both the notification content and its properties. +func PushCLI(domain string, p *notification.Properties, n *notification.Notification) error { + inst, err := lifecycle.GetInstance(domain) + if err != nil { + return err + } + n.Originator = "cli" + return makePush(inst, p, n) +} + // Push creates and sends a new notification in database. This method verifies // the permissions associated with this creation in order to check that it is // granted to create a notification and to extract its source. diff --git a/web/instances/instances.go b/web/instances/instances.go index 2830746692d..10c33c89c3c 100644 --- a/web/instances/instances.go +++ b/web/instances/instances.go @@ -15,6 +15,8 @@ import ( "github.com/cozy/cozy-stack/model/app" "github.com/cozy/cozy-stack/model/instance" "github.com/cozy/cozy-stack/model/instance/lifecycle" + "github.com/cozy/cozy-stack/model/notification" + "github.com/cozy/cozy-stack/model/notification/center" "github.com/cozy/cozy-stack/model/oauth" "github.com/cozy/cozy-stack/model/session" "github.com/cozy/cozy-stack/model/sharing" @@ -604,6 +606,34 @@ func diskUsage(c echo.Context) error { return c.JSON(http.StatusOK, result) } +func sendNotification(c echo.Context) error { + domain := c.Param("domain") + instance, err := lifecycle.GetInstance(domain) + if err != nil { + return err + } + + m := map[string]json.RawMessage{} + if err := json.NewDecoder(c.Request().Body).Decode(&m); err != nil { + return err + } + + p := ¬ification.Properties{} + if err := json.Unmarshal(m["properties"], &p); err != nil { + return err + } + + n := ¬ification.Notification{} + if err := json.Unmarshal(m["notification"], &n); err != nil { + return err + } + + if err := center.PushCLI(instance.DomainName(), p, n); err != nil { + return err + } + return c.JSON(http.StatusCreated, n) +} + func showPrefix(c echo.Context) error { domain := c.Param("domain") @@ -730,6 +760,7 @@ func Routes(router *echo.Group) { router.GET("/:domain/prefix", showPrefix) router.GET("/:domain/swift-prefix", getSwiftBucketName) router.GET("/:domain/sharings/:sharing-id/unxor/:doc-id", unxorID) + router.POST("/:domain/notifications", sendNotification) // Config router.POST("/redis", rebuildRedis)