From ef5759fe2fce5efb60feed8ed534827f64cf56fe Mon Sep 17 00:00:00 2001 From: defelmnq Date: Fri, 21 Mar 2025 01:01:06 +0000 Subject: [PATCH 1/4] update doc and remove plaintext format --- coderd/apidoc/docs.go | 6 ++++++ coderd/apidoc/swagger.json | 6 ++++++ coderd/inboxnotifications.go | 1 + coderd/notifications/dispatch/inbox.go | 13 +------------ docs/reference/api/notifications.md | 11 ++++++----- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 868657683c9c8..eaa1d35085deb 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -1693,6 +1693,12 @@ const docTemplate = `{ "description": "Filter notifications by read status. Possible values: read, unread, all", "name": "read_status", "in": "query" + }, + { + "type": "string", + "description": "ID of the last notification from the current page. Notifications returned will be older than the associated one", + "name": "starting_before", + "in": "query" } ], "responses": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index a82fd53d6b24f..07b9c7e3be376 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -1474,6 +1474,12 @@ "description": "Filter notifications by read status. Possible values: read, unread, all", "name": "read_status", "in": "query" + }, + { + "type": "string", + "description": "ID of the last notification from the current page. Notifications returned will be older than the associated one", + "name": "starting_before", + "in": "query" } ], "responses": { diff --git a/coderd/inboxnotifications.go b/coderd/inboxnotifications.go index 23e1c8479a76b..0065653214d8c 100644 --- a/coderd/inboxnotifications.go +++ b/coderd/inboxnotifications.go @@ -196,6 +196,7 @@ func (api *API) watchInboxNotifications(rw http.ResponseWriter, r *http.Request) // @Param targets query string false "Comma-separated list of target IDs to filter notifications" // @Param templates query string false "Comma-separated list of template IDs to filter notifications" // @Param read_status query string false "Filter notifications by read status. Possible values: read, unread, all" +// @Param starting_before query string false "ID of the last notification from the current page. Notifications returned will be older than the associated one" // @Success 200 {object} codersdk.ListInboxNotificationsResponse // @Router /notifications/inbox [get] func (api *API) listInboxNotifications(rw http.ResponseWriter, r *http.Request) { diff --git a/coderd/notifications/dispatch/inbox.go b/coderd/notifications/dispatch/inbox.go index 9383e89afec3e..63e21acb56b80 100644 --- a/coderd/notifications/dispatch/inbox.go +++ b/coderd/notifications/dispatch/inbox.go @@ -16,7 +16,6 @@ import ( "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/notifications/types" coderdpubsub "github.com/coder/coder/v2/coderd/pubsub" - markdown "github.com/coder/coder/v2/coderd/render" "github.com/coder/coder/v2/codersdk" ) @@ -36,17 +35,7 @@ func NewInboxHandler(log slog.Logger, store InboxStore, ps pubsub.Pubsub) *Inbox } func (s *InboxHandler) Dispatcher(payload types.MessagePayload, titleTmpl, bodyTmpl string, _ template.FuncMap) (DeliveryFunc, error) { - subject, err := markdown.PlaintextFromMarkdown(titleTmpl) - if err != nil { - return nil, xerrors.Errorf("render subject: %w", err) - } - - htmlBody, err := markdown.PlaintextFromMarkdown(bodyTmpl) - if err != nil { - return nil, xerrors.Errorf("render html body: %w", err) - } - - return s.dispatch(payload, subject, htmlBody), nil + return s.dispatch(payload, titleTmpl, bodyTmpl), nil } func (s *InboxHandler) dispatch(payload types.MessagePayload, title, body string) DeliveryFunc { diff --git a/docs/reference/api/notifications.md b/docs/reference/api/notifications.md index 67b61bccb6302..0d83ec91aeb9d 100644 --- a/docs/reference/api/notifications.md +++ b/docs/reference/api/notifications.md @@ -61,11 +61,12 @@ curl -X GET http://coder-server:8080/api/v2/notifications/inbox \ ### Parameters -| Name | In | Type | Required | Description | -|---------------|-------|--------|----------|-------------------------------------------------------------------------| -| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | -| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | -| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | +| Name | In | Type | Required | Description | +|-------------------|-------|--------|----------|-----------------------------------------------------------------------------------------------------------------| +| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | +| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | +| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | +| `starting_before` | query | string | false | ID of the last notification from the current page. Notifications returned will be older than the associated one | ### Example responses From 63ffa9b1c6a5357b86b02fb2f19aed45881e8dcf Mon Sep 17 00:00:00 2001 From: defelmnq Date: Fri, 21 Mar 2025 14:21:03 +0000 Subject: [PATCH 2/4] add format logic into watch endpoint --- coderd/inboxnotifications.go | 25 ++++++++++++++ coderd/inboxnotifications_test.go | 56 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/coderd/inboxnotifications.go b/coderd/inboxnotifications.go index 0065653214d8c..e8f5b0aa8bcdc 100644 --- a/coderd/inboxnotifications.go +++ b/coderd/inboxnotifications.go @@ -17,11 +17,17 @@ import ( "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/pubsub" + markdown "github.com/coder/coder/v2/coderd/render" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/wsjson" "github.com/coder/websocket" ) +const ( + notificationFormatMarkdown = "markdown" + notificationFormatPlaintext = "plaintext" +) + // convertInboxNotificationResponse works as a util function to transform a database.InboxNotification to codersdk.InboxNotification func convertInboxNotificationResponse(ctx context.Context, logger slog.Logger, notif database.InboxNotification) codersdk.InboxNotification { return codersdk.InboxNotification{ @@ -60,6 +66,7 @@ func convertInboxNotificationResponse(ctx context.Context, logger slog.Logger, n // @Param targets query string false "Comma-separated list of target IDs to filter notifications" // @Param templates query string false "Comma-separated list of template IDs to filter notifications" // @Param read_status query string false "Filter notifications by read status. Possible values: read, unread, all" +// @Param format query string false "Define the output format for notifications title and body. Possible values: plaintext, markdown" // @Success 200 {object} codersdk.GetInboxNotificationResponse // @Router /notifications/inbox/watch [get] func (api *API) watchInboxNotifications(rw http.ResponseWriter, r *http.Request) { @@ -73,6 +80,7 @@ func (api *API) watchInboxNotifications(rw http.ResponseWriter, r *http.Request) targets = p.UUIDs(vals, []uuid.UUID{}, "targets") templates = p.UUIDs(vals, []uuid.UUID{}, "templates") readStatus = p.String(vals, "all", "read_status") + format = p.String(vals, notificationFormatMarkdown, "format") ) p.ErrorExcessParams(vals) if len(p.Errors) > 0 { @@ -176,6 +184,23 @@ func (api *API) watchInboxNotifications(rw http.ResponseWriter, r *http.Request) api.Logger.Error(ctx, "failed to count unread inbox notifications", slog.Error(err)) return } + + // By default, notifications are stored as markdown + // We can change the format based on parameter if required + if format == notificationFormatPlaintext { + notif.Title, err = markdown.PlaintextFromMarkdown(notif.Title) + if err != nil { + api.Logger.Error(ctx, "failed to convert notification title to plain text", slog.Error(err)) + return + } + + notif.Content, err = markdown.PlaintextFromMarkdown(notif.Content) + if err != nil { + api.Logger.Error(ctx, "failed to convert notification content to plain text", slog.Error(err)) + return + } + } + if err := encoder.Encode(codersdk.GetInboxNotificationResponse{ Notification: notif, UnreadCount: int(unreadCount), diff --git a/coderd/inboxnotifications_test.go b/coderd/inboxnotifications_test.go index ef095ed72988c..ed0696195cb60 100644 --- a/coderd/inboxnotifications_test.go +++ b/coderd/inboxnotifications_test.go @@ -137,6 +137,62 @@ func TestInboxNotification_Watch(t *testing.T) { require.Equal(t, memberClient.ID, notif.Notification.UserID) }) + t.Run("OK - change format", func(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitLong) + logger := testutil.Logger(t) + + db, ps := dbtestutil.NewDB(t) + + firstClient, _, _ := coderdtest.NewWithAPI(t, &coderdtest.Options{ + Pubsub: ps, + Database: db, + }) + firstUser := coderdtest.CreateFirstUser(t, firstClient) + member, memberClient := coderdtest.CreateAnotherUser(t, firstClient, firstUser.OrganizationID, rbac.RoleTemplateAdmin()) + + u, err := member.URL.Parse("/api/v2/notifications/inbox/watch?format=plaintext") + require.NoError(t, err) + + // nolint:bodyclose + wsConn, resp, err := websocket.Dial(ctx, u.String(), &websocket.DialOptions{ + HTTPHeader: http.Header{ + "Coder-Session-Token": []string{member.SessionToken()}, + }, + }) + if err != nil { + if resp.StatusCode != http.StatusSwitchingProtocols { + err = codersdk.ReadBodyAsError(resp) + } + require.NoError(t, err) + } + defer wsConn.Close(websocket.StatusNormalClosure, "done") + + inboxHandler := dispatch.NewInboxHandler(logger, db, ps) + dispatchFunc, err := inboxHandler.Dispatcher(types.MessagePayload{ + UserID: memberClient.ID.String(), + NotificationTemplateID: notifications.TemplateWorkspaceOutOfMemory.String(), + }, "# Notification Title", "This is the __content__.", nil) + require.NoError(t, err) + + _, err = dispatchFunc(ctx, uuid.New()) + require.NoError(t, err) + + _, message, err := wsConn.Read(ctx) + require.NoError(t, err) + + var notif codersdk.GetInboxNotificationResponse + err = json.Unmarshal(message, ¬if) + require.NoError(t, err) + + require.Equal(t, 1, notif.UnreadCount) + require.Equal(t, memberClient.ID, notif.Notification.UserID) + + require.Equal(t, "Notification Title", notif.Notification.Title) + require.Equal(t, "This is the content.", notif.Notification.Content) + }) + t.Run("OK - filters on templates", func(t *testing.T) { t.Parallel() From 7a19ecedbf653327579c57542aef3eda0b8711a6 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Fri, 21 Mar 2025 14:36:21 +0000 Subject: [PATCH 3/4] gen and fmt --- coderd/apidoc/docs.go | 6 ++++++ coderd/apidoc/swagger.json | 6 ++++++ docs/reference/api/notifications.md | 11 ++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index eaa1d35085deb..61ca20b2579f1 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -1763,6 +1763,12 @@ const docTemplate = `{ "description": "Filter notifications by read status. Possible values: read, unread, all", "name": "read_status", "in": "query" + }, + { + "type": "string", + "description": "Define the output format for notifications title and body. Possible values: plaintext, markdown", + "name": "format", + "in": "query" } ], "responses": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 07b9c7e3be376..a07741153a57e 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -1538,6 +1538,12 @@ "description": "Filter notifications by read status. Possible values: read, unread, all", "name": "read_status", "in": "query" + }, + { + "type": "string", + "description": "Define the output format for notifications title and body. Possible values: plaintext, markdown", + "name": "format", + "in": "query" } ], "responses": { diff --git a/docs/reference/api/notifications.md b/docs/reference/api/notifications.md index 0d83ec91aeb9d..64cb7aadc802c 100644 --- a/docs/reference/api/notifications.md +++ b/docs/reference/api/notifications.md @@ -142,11 +142,12 @@ curl -X GET http://coder-server:8080/api/v2/notifications/inbox/watch \ ### Parameters -| Name | In | Type | Required | Description | -|---------------|-------|--------|----------|-------------------------------------------------------------------------| -| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | -| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | -| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | +| Name | In | Type | Required | Description | +|---------------|-------|--------|----------|-------------------------------------------------------------------------------------------------| +| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | +| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | +| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | +| `format` | query | string | false | Define the output format for notifications title and body. Possible values: plaintext, markdown | ### Example responses From 0babb430ccd9db9c58436211b1b9b18da6a6f851 Mon Sep 17 00:00:00 2001 From: defelmnq Date: Fri, 21 Mar 2025 15:07:28 +0000 Subject: [PATCH 4/4] add better doc description --- coderd/apidoc/docs.go | 7 ++++++- coderd/apidoc/swagger.json | 4 +++- coderd/inboxnotifications.go | 4 ++-- docs/reference/api/notifications.md | 31 ++++++++++++++++++----------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 61ca20b2579f1..fe6aacf84d5dd 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -1696,6 +1696,7 @@ const docTemplate = `{ }, { "type": "string", + "format": "uuid", "description": "ID of the last notification from the current page. Notifications returned will be older than the associated one", "name": "starting_before", "in": "query" @@ -1765,8 +1766,12 @@ const docTemplate = `{ "in": "query" }, { + "enum": [ + "plaintext", + "markdown" + ], "type": "string", - "description": "Define the output format for notifications title and body. Possible values: plaintext, markdown", + "description": "Define the output format for notifications title and body.", "name": "format", "in": "query" } diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index a07741153a57e..7a399a0e044b4 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -1477,6 +1477,7 @@ }, { "type": "string", + "format": "uuid", "description": "ID of the last notification from the current page. Notifications returned will be older than the associated one", "name": "starting_before", "in": "query" @@ -1540,8 +1541,9 @@ "in": "query" }, { + "enum": ["plaintext", "markdown"], "type": "string", - "description": "Define the output format for notifications title and body. Possible values: plaintext, markdown", + "description": "Define the output format for notifications title and body.", "name": "format", "in": "query" } diff --git a/coderd/inboxnotifications.go b/coderd/inboxnotifications.go index e8f5b0aa8bcdc..37ae8905c7d24 100644 --- a/coderd/inboxnotifications.go +++ b/coderd/inboxnotifications.go @@ -66,7 +66,7 @@ func convertInboxNotificationResponse(ctx context.Context, logger slog.Logger, n // @Param targets query string false "Comma-separated list of target IDs to filter notifications" // @Param templates query string false "Comma-separated list of template IDs to filter notifications" // @Param read_status query string false "Filter notifications by read status. Possible values: read, unread, all" -// @Param format query string false "Define the output format for notifications title and body. Possible values: plaintext, markdown" +// @Param format query string false "Define the output format for notifications title and body." enums(plaintext,markdown) // @Success 200 {object} codersdk.GetInboxNotificationResponse // @Router /notifications/inbox/watch [get] func (api *API) watchInboxNotifications(rw http.ResponseWriter, r *http.Request) { @@ -221,7 +221,7 @@ func (api *API) watchInboxNotifications(rw http.ResponseWriter, r *http.Request) // @Param targets query string false "Comma-separated list of target IDs to filter notifications" // @Param templates query string false "Comma-separated list of template IDs to filter notifications" // @Param read_status query string false "Filter notifications by read status. Possible values: read, unread, all" -// @Param starting_before query string false "ID of the last notification from the current page. Notifications returned will be older than the associated one" +// @Param starting_before query string false "ID of the last notification from the current page. Notifications returned will be older than the associated one" format(uuid) // @Success 200 {object} codersdk.ListInboxNotificationsResponse // @Router /notifications/inbox [get] func (api *API) listInboxNotifications(rw http.ResponseWriter, r *http.Request) { diff --git a/docs/reference/api/notifications.md b/docs/reference/api/notifications.md index 64cb7aadc802c..09890d3b17864 100644 --- a/docs/reference/api/notifications.md +++ b/docs/reference/api/notifications.md @@ -61,12 +61,12 @@ curl -X GET http://coder-server:8080/api/v2/notifications/inbox \ ### Parameters -| Name | In | Type | Required | Description | -|-------------------|-------|--------|----------|-----------------------------------------------------------------------------------------------------------------| -| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | -| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | -| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | -| `starting_before` | query | string | false | ID of the last notification from the current page. Notifications returned will be older than the associated one | +| Name | In | Type | Required | Description | +|-------------------|-------|--------------|----------|-----------------------------------------------------------------------------------------------------------------| +| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | +| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | +| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | +| `starting_before` | query | string(uuid) | false | ID of the last notification from the current page. Notifications returned will be older than the associated one | ### Example responses @@ -142,12 +142,19 @@ curl -X GET http://coder-server:8080/api/v2/notifications/inbox/watch \ ### Parameters -| Name | In | Type | Required | Description | -|---------------|-------|--------|----------|-------------------------------------------------------------------------------------------------| -| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | -| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | -| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | -| `format` | query | string | false | Define the output format for notifications title and body. Possible values: plaintext, markdown | +| Name | In | Type | Required | Description | +|---------------|-------|--------|----------|-------------------------------------------------------------------------| +| `targets` | query | string | false | Comma-separated list of target IDs to filter notifications | +| `templates` | query | string | false | Comma-separated list of template IDs to filter notifications | +| `read_status` | query | string | false | Filter notifications by read status. Possible values: read, unread, all | +| `format` | query | string | false | Define the output format for notifications title and body. | + +#### Enumerated Values + +| Parameter | Value | +|-----------|-------------| +| `format` | `plaintext` | +| `format` | `markdown` | ### Example responses pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy