Skip to content

feat: add notification for suspended/activated account #14367

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Aug 22, 2024
Prev Previous commit
Next Next commit
notify
  • Loading branch information
mtojek committed Aug 20, 2024
commit 62cf15fd6c69b4002e73ffc59c2929b13f053706
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ VALUES ('b02ddd82-4733-4d02-a2d7-c36f3598997d', 'User account suspended', E'User
}
]'::jsonb);
INSERT INTO notification_templates (id, name, title_template, body_template, "group", actions)
VALUES ('9f5af851-8408-4e73-a7a1-c6502ba46689', 'User account reactivated', E'User account "{{.Labels.reactivated_account_name}}" reactivated',
E'Hi {{.UserName}},\n\User account **{{.Labels.reactivated_account_name}}** has been reactivated.',
VALUES ('9f5af851-8408-4e73-a7a1-c6502ba46689', 'User account activated', E'User account "{{.Labels.activated_account_name}}" activated',
E'Hi {{.UserName}},\n\User account **{{.Labels.activated_account_name}}** has been activated.',
'Workspace Events', '[
{
"label": "View accounts",
Expand Down
3 changes: 3 additions & 0 deletions coderd/notifications/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ var (
var (
TemplateUserAccountCreated = uuid.MustParse("4e19c0ac-94e1-4532-9515-d1801aa283b2")
TemplateUserAccountDeleted = uuid.MustParse("f44d9314-ad03-4bc8-95d0-5cad491da6b6")

TemplateUserAccountSuspended = uuid.MustParse("b02ddd82-4733-4d02-a2d7-c36f3598997d")
TemplateUserAccountActivated = uuid.MustParse("9f5af851-8408-4e73-a7a1-c6502ba46689")
)

// Template-related events.
Expand Down
60 changes: 56 additions & 4 deletions coderd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
}
}

suspendedUser, err := api.Database.UpdateUserStatus(ctx, database.UpdateUserStatusParams{
updatedUser, err := api.Database.UpdateUserStatus(ctx, database.UpdateUserStatusParams{
ID: user.ID,
Status: status,
UpdatedAt: dbtime.Now(),
Expand All @@ -857,8 +857,61 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
})
return
}
aReq.New = suspendedUser
aReq.New = updatedUser

// Notify about the change of user status
var key string
var templateID uuid.UUID
switch status {
case database.UserStatusSuspended:
key = "suspended_account_name"
templateID = notifications.TemplateUserAccountSuspended
case database.UserStatusActive:
key = "activated_account_name"
templateID = notifications.TemplateUserAccountSuspended
default:
api.Logger.Error(ctx, "unable to notify admins as the user status is unsupported", slog.F("username", user.Username), slog.F("user_status", string(status)))

httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error preparing notifications",
})
}

// Fetch all users with user admin permissions
owners, err := api.Database.GetUsers(ctx, database.GetUsersParams{
RbacRole: []string{codersdk.RoleOwner},
})
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching owners",
Detail: err.Error(),
})
return
}
userAdmins, err := api.Database.GetUsers(ctx, database.GetUsersParams{
RbacRole: []string{codersdk.RoleUserAdmin},
})
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching user admins",
Detail: err.Error(),
})
return
}

// Send notifications to user admins and affected user
for _, u := range append(append(owners, userAdmins...), database.GetUsersRow{ID: user.ID}) {
if _, err := api.NotificationsEnqueuer.Enqueue(ctx, u.ID, templateID,
map[string]string{
key: user.Username,
}, "api-put-user-status",
user.ID,
); err != nil {
api.Logger.Warn(ctx, "unable to notify about changed user status", slog.F("affected_user", user.Username), slog.Error(err))
}
}

// Finish: build final response
organizations, err := userOrganizationIDs(ctx, api, user)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Expand All @@ -867,8 +920,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
})
return
}

httpapi.Write(ctx, rw, http.StatusOK, db2sdk.User(suspendedUser, organizations))
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.User(updatedUser, organizations))
}
}

Expand Down
Loading