diff --git a/coderd/notifications/dispatch/webhook.go b/coderd/notifications/dispatch/webhook.go index 4a548b40e4c2f..fcad3a7b0eae2 100644 --- a/coderd/notifications/dispatch/webhook.go +++ b/coderd/notifications/dispatch/webhook.go @@ -28,43 +28,47 @@ type WebhookHandler struct { // WebhookPayload describes the JSON payload to be delivered to the configured webhook endpoint. type WebhookPayload struct { - Version string `json:"_version"` - MsgID uuid.UUID `json:"msg_id"` - Payload types.MessagePayload `json:"payload"` - Title string `json:"title"` - Body string `json:"body"` + Version string `json:"_version"` + MsgID uuid.UUID `json:"msg_id"` + Payload types.MessagePayload `json:"payload"` + Title string `json:"title"` + TitleMarkdown string `json:"title_markdown"` + Body string `json:"body"` + BodyMarkdown string `json:"body_markdown"` } func NewWebhookHandler(cfg codersdk.NotificationsWebhookConfig, log slog.Logger) *WebhookHandler { return &WebhookHandler{cfg: cfg, log: log, cl: &http.Client{}} } -func (w *WebhookHandler) Dispatcher(payload types.MessagePayload, titleTmpl, bodyTmpl string) (DeliveryFunc, error) { +func (w *WebhookHandler) Dispatcher(payload types.MessagePayload, titleMarkdown, bodyMarkdown string) (DeliveryFunc, error) { if w.cfg.Endpoint.String() == "" { return nil, xerrors.New("webhook endpoint not defined") } - title, err := markdown.PlaintextFromMarkdown(titleTmpl) + titlePlaintext, err := markdown.PlaintextFromMarkdown(titleMarkdown) if err != nil { return nil, xerrors.Errorf("render title: %w", err) } - body, err := markdown.PlaintextFromMarkdown(bodyTmpl) + bodyPlaintext, err := markdown.PlaintextFromMarkdown(bodyMarkdown) if err != nil { return nil, xerrors.Errorf("render body: %w", err) } - return w.dispatch(payload, title, body, w.cfg.Endpoint.String()), nil + return w.dispatch(payload, titlePlaintext, titleMarkdown, bodyPlaintext, bodyMarkdown, w.cfg.Endpoint.String()), nil } -func (w *WebhookHandler) dispatch(msgPayload types.MessagePayload, title, body, endpoint string) DeliveryFunc { +func (w *WebhookHandler) dispatch(msgPayload types.MessagePayload, titlePlaintext, titleMarkdown, bodyPlaintext, bodyMarkdown, endpoint string) DeliveryFunc { return func(ctx context.Context, msgID uuid.UUID) (retryable bool, err error) { // Prepare payload. payload := WebhookPayload{ - Version: "1.0", - MsgID: msgID, - Title: title, - Body: body, - Payload: msgPayload, + Version: "1.1", + MsgID: msgID, + Title: titlePlaintext, + TitleMarkdown: titleMarkdown, + Body: bodyPlaintext, + BodyMarkdown: bodyMarkdown, + Payload: msgPayload, } m, err := json.Marshal(payload) if err != nil { diff --git a/coderd/notifications/dispatch/webhook_test.go b/coderd/notifications/dispatch/webhook_test.go index 3bfcfd8a2e621..26a78752cfd45 100644 --- a/coderd/notifications/dispatch/webhook_test.go +++ b/coderd/notifications/dispatch/webhook_test.go @@ -28,17 +28,15 @@ func TestWebhook(t *testing.T) { t.Parallel() const ( - titleTemplate = "this is the title ({{.Labels.foo}})" - bodyTemplate = "this is the body ({{.Labels.baz}})" + titlePlaintext = "this is the title" + titleMarkdown = "this *is* _the_ title" + bodyPlaintext = "this is the body" + bodyMarkdown = "~this~ is the `body`" ) msgPayload := types.MessagePayload{ Version: "1.0", NotificationName: "test", - Labels: map[string]string{ - "foo": "bar", - "baz": "quux", - }, } tests := []struct { @@ -61,6 +59,11 @@ func TestWebhook(t *testing.T) { assert.Equal(t, msgID, payload.MsgID) assert.Equal(t, msgID.String(), r.Header.Get("X-Message-Id")) + assert.Equal(t, titlePlaintext, payload.Title) + assert.Equal(t, titleMarkdown, payload.TitleMarkdown) + assert.Equal(t, bodyPlaintext, payload.Body) + assert.Equal(t, bodyMarkdown, payload.BodyMarkdown) + w.WriteHeader(http.StatusOK) _, err = w.Write([]byte(fmt.Sprintf("received %s", payload.MsgID))) assert.NoError(t, err) @@ -138,7 +141,7 @@ func TestWebhook(t *testing.T) { Endpoint: *serpent.URLOf(endpoint), } handler := dispatch.NewWebhookHandler(cfg, logger.With(slog.F("test", tc.name))) - deliveryFn, err := handler.Dispatcher(msgPayload, titleTemplate, bodyTemplate) + deliveryFn, err := handler.Dispatcher(msgPayload, titleMarkdown, bodyMarkdown) require.NoError(t, err) retryable, err := deliveryFn(ctx, msgID) diff --git a/coderd/notifications/notifications_test.go b/coderd/notifications/notifications_test.go index ca1f4f78aad72..e52610c9c5823 100644 --- a/coderd/notifications/notifications_test.go +++ b/coderd/notifications/notifications_test.go @@ -249,7 +249,7 @@ func TestWebhookDispatch(t *testing.T) { // THEN: the webhook is received by the mock server and has the expected contents payload := testutil.RequireRecvCtx(testutil.Context(t, testutil.WaitShort), t, sent) - require.EqualValues(t, "1.0", payload.Version) + require.EqualValues(t, "1.1", payload.Version) require.Equal(t, *msgID, payload.MsgID) require.Equal(t, payload.Payload.Labels, input) require.Equal(t, payload.Payload.UserEmail, email) diff --git a/docs/admin/notifications/slack.md b/docs/admin/notifications/slack.md index aa6a4dcdb5655..554e5c986a39c 100644 --- a/docs/admin/notifications/slack.md +++ b/docs/admin/notifications/slack.md @@ -90,9 +90,11 @@ receiver.router.post("/v1/webhook", async (req, res) => { return res.status(400).send("Error: request body is missing"); } - const { title, body } = req.body; - if (!title || !body) { - return res.status(400).send('Error: missing fields: "title", or "body"'); + const { title_markdown, body_markdown } = req.body; + if (!title_markdown || !body_markdown) { + return res + .status(400) + .send('Error: missing fields: "title_markdown", or "body_markdown"'); } const payload = req.body.payload; @@ -118,11 +120,11 @@ receiver.router.post("/v1/webhook", async (req, res) => { blocks: [ { type: "header", - text: { type: "plain_text", text: title }, + text: { type: "mrkdwn", text: title_markdown }, }, { type: "section", - text: { type: "mrkdwn", text: body }, + text: { type: "mrkdwn", text: body_markdown }, }, ], }; diff --git a/docs/admin/notifications/teams.md b/docs/admin/notifications/teams.md index 92957dd464d46..7accfbe9568a4 100644 --- a/docs/admin/notifications/teams.md +++ b/docs/admin/notifications/teams.md @@ -67,10 +67,10 @@ The process of setting up a Teams workflow consists of three key steps: } } }, - "title": { + "title_markdown": { "type": "string" }, - "body": { + "body_markdown": { "type": "string" } } @@ -108,11 +108,11 @@ The process of setting up a Teams workflow consists of three key steps: }, { "type": "TextBlock", - "text": "**@{replace(body('Parse_JSON')?['title'], '"', '\"')}**" + "text": "**@{replace(body('Parse_JSON')?['title_markdown'], '"', '\"')}**" }, { "type": "TextBlock", - "text": "@{replace(body('Parse_JSON')?['body'], '"', '\"')}", + "text": "@{replace(body('Parse_JSON')?['body_markdown'], '"', '\"')}", "wrap": true }, { 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