Skip to content

Commit d3ffd1a

Browse files
committed
chore: update custom notification request with a content object
1 parent 203668d commit d3ffd1a

File tree

9 files changed

+98
-34
lines changed

9 files changed

+98
-34
lines changed

cli/notifications.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,11 @@ func (r *RootCmd) customNotifications() *serpent.Command {
125125
r.InitClient(client),
126126
),
127127
Handler: func(inv *serpent.Invocation) error {
128-
err := client.PostCustomNotification(inv.Context(), codersdk.CustomNotification{
129-
Title: inv.Args[0],
130-
Message: inv.Args[1],
128+
err := client.PostCustomNotification(inv.Context(), codersdk.CustomNotificationRequest{
129+
Content: &codersdk.CustomNotificationContent{
130+
Title: inv.Args[0],
131+
Message: inv.Args[1],
132+
},
131133
})
132134
if err != nil {
133135
return xerrors.Errorf("unable to post custom notification: %w", err)

coderd/apidoc/docs.go

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/notifications.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"fmt"
77
"net/http"
8-
"strings"
98

109
"github.com/google/uuid"
1110

@@ -349,7 +348,7 @@ func (api *API) putUserNotificationPreferences(rw http.ResponseWriter, r *http.R
349348
// @Tags Notifications
350349
// @Accept json
351350
// @Produce json
352-
// @Param request body codersdk.CustomNotification true "Provide a non-empty title or message"
351+
// @Param request body codersdk.CustomNotificationRequest true "Provide a non-empty title or message"
353352
// @Success 204 "No Content"
354353
// @Failure 400 {object} codersdk.Response "Invalid request body"
355354
// @Failure 403 {object} codersdk.Response "System users cannot send custom notifications"
@@ -362,17 +361,17 @@ func (api *API) postCustomNotification(rw http.ResponseWriter, r *http.Request)
362361
)
363362

364363
// Parse request
365-
var req codersdk.CustomNotification
364+
var req codersdk.CustomNotificationRequest
366365
if !httpapi.Read(ctx, rw, r, &req) {
367366
return
368367
}
369368

370-
// Require at least one non-empty field
371-
if strings.TrimSpace(req.Title) == "" && strings.TrimSpace(req.Message) == "" {
372-
api.Logger.Error(ctx, "send custom notification: invalid request body")
369+
// Validate request: require `content` and at least one non-empty `title` or `message`.
370+
if err := req.Validate(); err != nil {
371+
api.Logger.Error(ctx, "send custom notification: validation failed", slog.Error(err))
373372
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
374373
Message: "Invalid request body",
375-
Detail: "Provide a non-empty 'title' or 'message'.",
374+
Detail: err.Error(),
376375
})
377376
return
378377
}
@@ -403,8 +402,8 @@ func (api *API) postCustomNotification(rw http.ResponseWriter, r *http.Request)
403402
user.ID,
404403
notifications.TemplateCustomNotification,
405404
map[string]string{
406-
"custom_title": req.Title,
407-
"custom_message": req.Message,
405+
"custom_title": req.Content.Title,
406+
"custom_message": req.Content.Message,
408407
},
409408
user.ID.String(),
410409
); err != nil {

coderd/notifications_test.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -397,9 +397,11 @@ func TestCustomNotification(t *testing.T) {
397397
memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, ownerUser.OrganizationID)
398398

399399
// When: The member user attempts to send a custom notification with empty title and message
400-
err := memberClient.PostCustomNotification(ctx, codersdk.CustomNotification{
401-
Title: "",
402-
Message: "",
400+
err := memberClient.PostCustomNotification(ctx, codersdk.CustomNotificationRequest{
401+
Content: &codersdk.CustomNotificationContent{
402+
Title: "",
403+
Message: "",
404+
},
403405
})
404406

405407
// Then: a bad request error is expected with no notifications sent
@@ -433,9 +435,11 @@ func TestCustomNotification(t *testing.T) {
433435
systemUserClient.SetSessionToken(token)
434436

435437
// When: The system user attempts to send a custom notification
436-
err := systemUserClient.PostCustomNotification(ctx, codersdk.CustomNotification{
437-
Title: "Custom Title",
438-
Message: "Custom Message",
438+
err := systemUserClient.PostCustomNotification(ctx, codersdk.CustomNotificationRequest{
439+
Content: &codersdk.CustomNotificationContent{
440+
Title: "Custom Title",
441+
Message: "Custom Message",
442+
},
439443
})
440444

441445
// Then: a forbidden error is expected with no notifications sent
@@ -465,9 +469,11 @@ func TestCustomNotification(t *testing.T) {
465469
memberClient, memberUser := coderdtest.CreateAnotherUser(t, ownerClient, ownerUser.OrganizationID)
466470

467471
// When: The member user attempts to send a custom notification
468-
err := memberClient.PostCustomNotification(ctx, codersdk.CustomNotification{
469-
Title: "Custom Title",
470-
Message: "Custom Message",
472+
err := memberClient.PostCustomNotification(ctx, codersdk.CustomNotificationRequest{
473+
Content: &codersdk.CustomNotificationContent{
474+
Title: "Custom Title",
475+
Message: "Custom Message",
476+
},
471477
})
472478
require.NoError(t, err)
473479

codersdk/notifications.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"net/http"
9+
"strings"
910
"time"
1011

1112
"github.com/google/uuid"
@@ -281,12 +282,28 @@ func (c *Client) PostTestWebpushMessage(ctx context.Context) error {
281282
return nil
282283
}
283284

284-
type CustomNotification struct {
285+
type CustomNotificationContent struct {
285286
Title string `json:"title"`
286287
Message string `json:"message"`
287288
}
288289

289-
func (c *Client) PostCustomNotification(ctx context.Context, req CustomNotification) error {
290+
type CustomNotificationRequest struct {
291+
Content *CustomNotificationContent `json:"content"`
292+
// TODO(ssncferreira): Add target (user_ids, roles) to support multi-user and role-based delivery.
293+
}
294+
295+
func (c CustomNotificationRequest) Validate() error {
296+
if c.Content == nil {
297+
return xerrors.Errorf("content is required")
298+
}
299+
if strings.TrimSpace(c.Content.Title) == "" &&
300+
strings.TrimSpace(c.Content.Message) == "" {
301+
return xerrors.Errorf("provide a non-empty 'content.title' or 'content.message'")
302+
}
303+
return nil
304+
}
305+
306+
func (c *Client) PostCustomNotification(ctx context.Context, req CustomNotificationRequest) error {
290307
res, err := c.Request(ctx, http.MethodPost, "/api/v2/notifications/custom", req)
291308
if err != nil {
292309
return err

docs/reference/api/notifications.md

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/api/schemas.md

Lines changed: 18 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/api/typesGenerated.ts

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)