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

Commit6428a76

Browse files
authored
feat: notify when a user account is deleted (#14113)
1 parent4242fd9 commit6428a76

File tree

5 files changed

+138
-14
lines changed

5 files changed

+138
-14
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DELETEFROM notification_templatesWHERE id='f44d9314-ad03-4bc8-95d0-5cad491da6b6';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
INSERT INTO notification_templates (id, name, title_template, body_template,"group", actions)
2+
VALUES ('f44d9314-ad03-4bc8-95d0-5cad491da6b6','User account deleted', E'User account "{{.Labels.deleted_account_name}}" deleted',
3+
E'Hi {{.UserName}},\n\nUser account **{{.Labels.deleted_account_name}}** has been deleted.',
4+
'User Events','[
5+
{
6+
"label": "View accounts",
7+
"url": "{{ base_url }}/deployment/users?filter=status%3Aactive"
8+
}
9+
]'::jsonb);

‎coderd/notifications/events.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ var (
1717
// Account-related events.
1818
var (
1919
TemplateUserAccountCreated=uuid.MustParse("4e19c0ac-94e1-4532-9515-d1801aa283b2")
20+
TemplateUserAccountDeleted=uuid.MustParse("f44d9314-ad03-4bc8-95d0-5cad491da6b6")
2021
)

‎coderd/users.go‎

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,27 @@ func (api *API) deleteUser(rw http.ResponseWriter, r *http.Request) {
567567
}
568568
user.Deleted=true
569569
aReq.New=user
570+
571+
userAdmins,err:=findUserAdmins(ctx,api.Database)
572+
iferr!=nil {
573+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
574+
Message:"Internal error fetching user admins.",
575+
Detail:err.Error(),
576+
})
577+
return
578+
}
579+
580+
for_,u:=rangeuserAdmins {
581+
if_,err:=api.NotificationsEnqueuer.Enqueue(ctx,u.ID,notifications.TemplateUserAccountDeleted,
582+
map[string]string{
583+
"deleted_account_name":user.Username,
584+
},"api-users-delete",
585+
user.ID,
586+
);err!=nil {
587+
api.Logger.Warn(ctx,"unable to notify about deleted user",slog.F("deleted_user",user.Username),slog.Error(err))
588+
}
589+
}
590+
570591
rw.WriteHeader(http.StatusNoContent)
571592
}
572593

@@ -1287,23 +1308,12 @@ func (api *API) CreateUser(ctx context.Context, store database.Store, req Create
12871308
returnuser,req.OrganizationID,err
12881309
}
12891310

1290-
// Notify all users with user admin permission including owners
1291-
// Notice: we can't scrape the user information in parallel as pq
1292-
// fails with: unexpected describe rows response: 'D'
1293-
owners,err:=store.GetUsers(ctx, database.GetUsersParams{
1294-
RbacRole: []string{codersdk.RoleOwner},
1295-
})
1311+
userAdmins,err:=findUserAdmins(ctx,store)
12961312
iferr!=nil {
1297-
returnuser,req.OrganizationID,xerrors.Errorf("get owners: %w",err)
1298-
}
1299-
userAdmins,err:=store.GetUsers(ctx, database.GetUsersParams{
1300-
RbacRole: []string{codersdk.RoleUserAdmin},
1301-
})
1302-
iferr!=nil {
1303-
returnuser,req.OrganizationID,xerrors.Errorf("get user admins: %w",err)
1313+
returnuser,req.OrganizationID,xerrors.Errorf("find user admins: %w",err)
13041314
}
13051315

1306-
for_,u:=rangeappend(owners,userAdmins...) {
1316+
for_,u:=rangeuserAdmins {
13071317
if_,err:=api.NotificationsEnqueuer.Enqueue(ctx,u.ID,notifications.TemplateUserAccountCreated,
13081318
map[string]string{
13091319
"created_account_name":user.Username,
@@ -1316,6 +1326,25 @@ func (api *API) CreateUser(ctx context.Context, store database.Store, req Create
13161326
returnuser,req.OrganizationID,err
13171327
}
13181328

1329+
// findUserAdmins fetches all users with user admin permission including owners.
1330+
funcfindUserAdmins(ctx context.Context,store database.Store) ([]database.GetUsersRow,error) {
1331+
// Notice: we can't scrape the user information in parallel as pq
1332+
// fails with: unexpected describe rows response: 'D'
1333+
owners,err:=store.GetUsers(ctx, database.GetUsersParams{
1334+
RbacRole: []string{codersdk.RoleOwner},
1335+
})
1336+
iferr!=nil {
1337+
returnnil,xerrors.Errorf("get owners: %w",err)
1338+
}
1339+
userAdmins,err:=store.GetUsers(ctx, database.GetUsersParams{
1340+
RbacRole: []string{codersdk.RoleUserAdmin},
1341+
})
1342+
iferr!=nil {
1343+
returnnil,xerrors.Errorf("get user admins: %w",err)
1344+
}
1345+
returnappend(owners,userAdmins...),nil
1346+
}
1347+
13191348
funcconvertUsers(users []database.User,organizationIDsByUserIDmap[uuid.UUID][]uuid.UUID) []codersdk.User {
13201349
converted:=make([]codersdk.User,0,len(users))
13211350
for_,u:=rangeusers {

‎coderd/users_test.go‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,90 @@ func TestDeleteUser(t *testing.T) {
374374
})
375375
}
376376

377+
funcTestNotifyDeletedUser(t*testing.T) {
378+
t.Parallel()
379+
380+
t.Run("OwnerNotified",func(t*testing.T) {
381+
t.Parallel()
382+
383+
// given
384+
notifyEnq:=&testutil.FakeNotificationsEnqueuer{}
385+
adminClient:=coderdtest.New(t,&coderdtest.Options{
386+
NotificationsEnqueuer:notifyEnq,
387+
})
388+
firstUser:=coderdtest.CreateFirstUser(t,adminClient)
389+
390+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
391+
defercancel()
392+
393+
user,err:=adminClient.CreateUser(ctx, codersdk.CreateUserRequest{
394+
OrganizationID:firstUser.OrganizationID,
395+
Email:"another@user.org",
396+
Username:"someone-else",
397+
Password:"SomeSecurePassword!",
398+
})
399+
require.NoError(t,err)
400+
401+
// when
402+
err=adminClient.DeleteUser(context.Background(),user.ID)
403+
require.NoError(t,err)
404+
405+
// then
406+
require.Len(t,notifyEnq.Sent,2)
407+
// notifyEnq.Sent[0] is create account event
408+
require.Equal(t,notifications.TemplateUserAccountDeleted,notifyEnq.Sent[1].TemplateID)
409+
require.Equal(t,firstUser.UserID,notifyEnq.Sent[1].UserID)
410+
require.Contains(t,notifyEnq.Sent[1].Targets,user.ID)
411+
require.Equal(t,user.Username,notifyEnq.Sent[1].Labels["deleted_account_name"])
412+
})
413+
414+
t.Run("UserAdminNotified",func(t*testing.T) {
415+
t.Parallel()
416+
417+
// given
418+
notifyEnq:=&testutil.FakeNotificationsEnqueuer{}
419+
adminClient:=coderdtest.New(t,&coderdtest.Options{
420+
NotificationsEnqueuer:notifyEnq,
421+
})
422+
firstUser:=coderdtest.CreateFirstUser(t,adminClient)
423+
424+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
425+
defercancel()
426+
427+
_,userAdmin:=coderdtest.CreateAnotherUser(t,adminClient,firstUser.OrganizationID,rbac.RoleUserAdmin())
428+
429+
member,err:=adminClient.CreateUser(ctx, codersdk.CreateUserRequest{
430+
OrganizationID:firstUser.OrganizationID,
431+
Email:"another@user.org",
432+
Username:"someone-else",
433+
Password:"SomeSecurePassword!",
434+
})
435+
require.NoError(t,err)
436+
437+
// when
438+
err=adminClient.DeleteUser(context.Background(),member.ID)
439+
require.NoError(t,err)
440+
441+
// then
442+
require.Len(t,notifyEnq.Sent,5)
443+
// notifyEnq.Sent[0]: "User admin" account created, "owner" notified
444+
// notifyEnq.Sent[1]: "Member" account created, "owner" notified
445+
// notifyEnq.Sent[2]: "Member" account created, "user admin" notified
446+
447+
// "Member" account deleted, "owner" notified
448+
require.Equal(t,notifications.TemplateUserAccountDeleted,notifyEnq.Sent[3].TemplateID)
449+
require.Equal(t,firstUser.UserID,notifyEnq.Sent[3].UserID)
450+
require.Contains(t,notifyEnq.Sent[3].Targets,member.ID)
451+
require.Equal(t,member.Username,notifyEnq.Sent[3].Labels["deleted_account_name"])
452+
453+
// "Member" account deleted, "user admin" notified
454+
require.Equal(t,notifications.TemplateUserAccountDeleted,notifyEnq.Sent[4].TemplateID)
455+
require.Equal(t,userAdmin.ID,notifyEnq.Sent[4].UserID)
456+
require.Contains(t,notifyEnq.Sent[4].Targets,member.ID)
457+
require.Equal(t,member.Username,notifyEnq.Sent[4].Labels["deleted_account_name"])
458+
})
459+
}
460+
377461
funcTestPostLogout(t*testing.T) {
378462
t.Parallel()
379463

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp