Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add tool to send a test notification#16611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
DanielleMaywood merged 10 commits intomainfromdm-test-notification
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletionscli/notifications.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,10 @@ func (r *RootCmd) notifications() *serpent.Command {
Description: "Resume Coder notifications",
Command: "coder notifications resume",
},
Example{
Description: "Send a test notification. Administrators can use this to verify the notification target settings.",
Command: "coder notifications test",
},
),
Aliases: []string{"notification"},
Handler: func(inv *serpent.Invocation) error {
Expand All@@ -31,6 +35,7 @@ func (r *RootCmd) notifications() *serpent.Command {
Children: []*serpent.Command{
r.pauseNotifications(),
r.resumeNotifications(),
r.testNotifications(),
},
}
return cmd
Expand DownExpand Up@@ -83,3 +88,24 @@ func (r *RootCmd) resumeNotifications() *serpent.Command {
}
return cmd
}

func (r *RootCmd) testNotifications() *serpent.Command {
client := new(codersdk.Client)
cmd := &serpent.Command{
Use: "test",
Short: "Send a test notification",
Middleware: serpent.Chain(
serpent.RequireNArgs(0),
r.InitClient(client),
),
Handler: func(inv *serpent.Invocation) error {
if err := client.PostTestNotification(inv.Context()); err != nil {
return xerrors.Errorf("unable to post test notification: %w", err)
}

_, _ = fmt.Fprintln(inv.Stderr, "A test notification has been sent. If you don't receive the notification, check Coder's logs for any errors.")
return nil
},
}
return cmd
}
58 changes: 58 additions & 0 deletionscli/notifications_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,8 @@ import (

"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/notifications/notificationstest"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/testutil"
)
Expand DownExpand Up@@ -109,3 +111,59 @@ func TestPauseNotifications_RegularUser(t *testing.T) {
require.NoError(t, err)
require.False(t, settings.NotifierPaused) // still running
}

func TestNotificationsTest(t *testing.T) {
t.Parallel()

t.Run("OwnerCanSendTestNotification", func(t *testing.T) {
t.Parallel()

notifyEnq := &notificationstest.FakeEnqueuer{}

// Given: An owner user.
ownerClient := coderdtest.New(t, &coderdtest.Options{
DeploymentValues: coderdtest.DeploymentValues(t),
NotificationsEnqueuer: notifyEnq,
})
_ = coderdtest.CreateFirstUser(t, ownerClient)

// When: The owner user attempts to send the test notification.
inv, root := clitest.New(t, "notifications", "test")
clitest.SetupConfig(t, ownerClient, root)

// Then: we expect a notification to be sent.
err := inv.Run()
require.NoError(t, err)

sent := notifyEnq.Sent(notificationstest.WithTemplateID(notifications.TemplateTestNotification))
require.Len(t, sent, 1)
})

t.Run("MemberCannotSendTestNotification", func(t *testing.T) {
t.Parallel()

notifyEnq := &notificationstest.FakeEnqueuer{}

// Given: A member user.
ownerClient := coderdtest.New(t, &coderdtest.Options{
DeploymentValues: coderdtest.DeploymentValues(t),
NotificationsEnqueuer: notifyEnq,
})
ownerUser := coderdtest.CreateFirstUser(t, ownerClient)
memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, ownerUser.OrganizationID)

// When: The member user attempts to send the test notification.
inv, root := clitest.New(t, "notifications", "test")
clitest.SetupConfig(t, memberClient, root)

// Then: we expect an error and no notifications to be sent.
err := inv.Run()
var sdkError *codersdk.Error
require.Error(t, err)
require.ErrorAsf(t, err, &sdkError, "error should be of type *codersdk.Error")
assert.Equal(t, http.StatusForbidden, sdkError.StatusCode())

sent := notifyEnq.Sent(notificationstest.WithTemplateID(notifications.TemplateTestNotification))
require.Len(t, sent, 0)
})
}
7 changes: 7 additions & 0 deletionscli/testdata/coder_notifications_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,10 +19,17 @@ USAGE:
- Resume Coder notifications:

$ coder notifications resume

- Send a test notification. Administrators can use this to verify the
notification
target settings.:

$ coder notifications test

SUBCOMMANDS:
pause Pause notifications
resume Resume notifications
test Send a test notification

———
Run `coder --help` for a list of global options.
9 changes: 9 additions & 0 deletionscli/testdata/coder_notifications_test_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
coder v0.0.0-devel

USAGE:
coder notifications test

Send a test notification

———
Run `coder --help` for a list of global options.
19 changes: 19 additions & 0 deletionscoderd/apidoc/docs.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

17 changes: 17 additions & 0 deletionscoderd/apidoc/swagger.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

1 change: 1 addition & 0 deletionscoderd/coderd.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1370,6 +1370,7 @@ func New(options *Options) *API {
r.Get("/system", api.systemNotificationTemplates)
})
r.Get("/dispatch-methods", api.notificationDispatchMethods)
r.Post("/test", api.postTestNotification)
})
r.Route("/tailnet", func(r chi.Router) {
r.Use(apiKeyMiddleware)
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
DELETE FROM notification_templates WHERE id = 'c425f63e-716a-4bf4-ae24-78348f706c3f';
16 changes: 16 additions & 0 deletionscoderd/database/migrations/000295_test_notification.up.sql
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
INSERT INTO notification_templates
(id, name, title_template, body_template, "group", actions)
VALUES (
'c425f63e-716a-4bf4-ae24-78348f706c3f',
'Test Notification',
E'A test notification',
E'Hi {{.UserName}},\n\n'||
E'This is a test notification.',
'Notification Events',
'[
{
"label": "View notification settings",
"url": "{{base_url}}/deployment/notifications?tab=settings"
}
]'::jsonb
);
50 changes: 50 additions & 0 deletionscoderd/notifications.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,9 +11,12 @@ import (

"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/codersdk"
)

Expand DownExpand Up@@ -163,6 +166,53 @@ func (api *API) notificationDispatchMethods(rw http.ResponseWriter, r *http.Requ
})
}

// @Summary Send a test notification
// @ID send-a-test-notification
// @Security CoderSessionToken
// @Tags Notifications
// @Success 200
// @Router /notifications/test [post]
func (api *API) postTestNotification(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
key = httpmw.APIKey(r)
)

if !api.Authorize(r, policy.ActionUpdate, rbac.ResourceDeploymentConfig) {
httpapi.Forbidden(rw)
return
}

if _, err := api.NotificationsEnqueuer.EnqueueWithData(
//nolint:gocritic // We need to be notifier to send the notification.
dbauthz.AsNotifier(ctx),
key.UserID,
notifications.TemplateTestNotification,
map[string]string{},
map[string]any{
// NOTE(DanielleMaywood):
// When notifications are enqueued, they are checked to be
// unique within a single day. This means that if we attempt
// to send two test notifications to the same user on
// the same day, the enqueuer will prevent us from sending
// a second one. We are injecting a timestamp to make the
// notifications appear different enough to circumvent this
// deduplication logic.
"timestamp": api.Clock.Now(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

🥇

},
"send-test-notification",
); err != nil {
api.Logger.Error(ctx, "send notification", slog.Error(err))
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to send test notification",
Detail: err.Error(),
})
return
}

httpapi.Write(ctx, rw, http.StatusOK, nil)
}

// @Summary Get user notification preferences
// @ID get-user-notification-preferences
// @Security CoderSessionToken
Expand Down
5 changes: 5 additions & 0 deletionscoderd/notifications/events.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,3 +39,8 @@ var (

TemplateWorkspaceBuildsFailedReport = uuid.MustParse("34a20db2-e9cc-4a93-b0e4-8569699d7a00")
)

// Notification-related events.
var (
TemplateTestNotification = uuid.MustParse("c425f63e-716a-4bf4-ae24-78348f706c3f")
)
10 changes: 10 additions & 0 deletionscoderd/notifications/notifications_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1125,6 +1125,16 @@ func TestNotificationTemplates_Golden(t *testing.T) {
},
},
},
{
name: "TemplateTestNotification",
id: notifications.TemplateTestNotification,
payload: types.MessagePayload{
UserName: "Bobby",
UserEmail: "bobby@coder.com",
UserUsername: "bobby",
Labels: map[string]string{},
},
},
}

// We must have a test case for every notification_template. This is enforced below:
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
From: system@coder.com
To: bobby@coder.com
Subject: A test notification
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
Date: Fri, 11 Oct 2024 09:03:06 +0000
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
MIME-Version: 1.0

--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8

Hi Bobby,

This is a test notification.


View notification settings: http://test.com/deployment/notifications?tab=3D=
settings

--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8

<!doctype html>
<html lang=3D"en">
<head>
<meta charset=3D"UTF-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
=3D1.0" />
<title>A test notification</title>
</head>
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
; background: #f8fafc;">
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
n: left; font-size: 14px; line-height: 1.5;">
<div style=3D"text-align: center;">
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
er Logo" style=3D"height: 40px;" />
</div>
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
argin: 8px 0 32px; line-height: 1.5;">
A test notification
</h1>
<div style=3D"line-height: 1.5;">
<p>Hi Bobby,</p>

<p>This is a test notification.</p>
</div>
<div style=3D"text-align: center; margin-top: 32px;">
=20
<a href=3D"http://test.com/deployment/notifications?tab=3Dsettings"=
style=3D"display: inline-block; padding: 13px 24px; background-color: #020=
617; color: #f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4=
px;">
View notification settings
</a>
=20
</div>
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
<p>&copy;&nbsp;2024&nbsp;Coder. All rights reserved&nbsp;-&nbsp;<a =
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
ttp://test.com</a></p>
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
r: #2563eb; text-decoration: none;">Click here to manage your notification =
settings</a></p>
<p><a href=3D"http://test.com/settings/notifications?disabled=3Dc42=
5f63e-716a-4bf4-ae24-78348f706c3f" style=3D"color: #2563eb; text-decoration=
: none;">Stop receiving emails like this</a></p>
</div>
</div>
</body>
</html>

--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp