Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ea30af8

Browse files
feat: notify users on template deprecation
1 parent cd92220 commit ea30af8

12 files changed

+167
-1
lines changed

coderd/database/dbauthz/dbauthz.go

+10
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,16 @@ func (q *querier) GetUsersByIDs(ctx context.Context, ids []uuid.UUID) ([]databas
23392339
return q.db.GetUsersByIDs(ctx, ids)
23402340
}
23412341

2342+
func (q *querier) GetUsersWithAccessToTemplateByID(ctx context.Context, id uuid.UUID) ([]uuid.UUID, error) {
2343+
// Ensure we have permission to access this template.
2344+
_, err := q.GetTemplateByID(ctx, id)
2345+
if err != nil {
2346+
return nil, err
2347+
}
2348+
2349+
return q.db.GetUsersWithAccessToTemplateByID(ctx, id)
2350+
}
2351+
23422352
func (q *querier) GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Context, authToken uuid.UUID) (database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error) {
23432353
// This is a system function
23442354
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {

coderd/database/dbauthz/dbauthz_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,10 @@ func (s *MethodTestSuite) TestUser() {
11311131
Asserts(a, policy.ActionRead, b, policy.ActionRead).
11321132
Returns(slice.New(a, b))
11331133
}))
1134+
s.Run("GetUsersWithAccessToTemplateByID", s.Subtest(func(db database.Store, check *expects) {
1135+
a := dbgen.Template(s.T(), db, database.Template{})
1136+
check.Args(a.ID).Asserts(a, policy.ActionRead)
1137+
}))
11341138
s.Run("GetUsers", s.Subtest(func(db database.Store, check *expects) {
11351139
dbgen.User(s.T(), db, database.User{Username: "GetUsers-a-user"})
11361140
dbgen.User(s.T(), db, database.User{Username: "GetUsers-b-user"})

coderd/database/dbmem/dbmem.go

+27
Original file line numberDiff line numberDiff line change
@@ -5669,6 +5669,33 @@ func (q *FakeQuerier) GetUsersByIDs(_ context.Context, ids []uuid.UUID) ([]datab
56695669
return users, nil
56705670
}
56715671

5672+
func (q *FakeQuerier) GetUsersWithAccessToTemplateByID(ctx context.Context, id uuid.UUID) ([]uuid.UUID, error) {
5673+
q.mutex.RLock()
5674+
defer q.mutex.RUnlock()
5675+
5676+
groups := make(map[string]bool, 0)
5677+
for _, template := range q.templates {
5678+
if template.ID != id {
5679+
continue
5680+
}
5681+
5682+
for group := range template.GroupACL {
5683+
groups[group] = true
5684+
}
5685+
}
5686+
5687+
users := make([]uuid.UUID, 0)
5688+
for _, member := range q.organizationMembers {
5689+
if _, ok := groups[member.OrganizationID.String()]; !ok {
5690+
continue
5691+
}
5692+
5693+
users = append(users, member.UserID)
5694+
}
5695+
5696+
return users, nil
5697+
}
5698+
56725699
func (q *FakeQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(_ context.Context, authToken uuid.UUID) (database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error) {
56735700
q.mutex.RLock()
56745701
defer q.mutex.RUnlock()

coderd/database/dbmetrics/dbmetrics.go

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DELETE FROM notification_templates WHERE id = 'f40fae84-55a2-42cd-99fa-b41c1ca64894';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
INSERT INTO notification_templates
2+
(id, name, title_template, body_template, "group", actions)
3+
VALUES (
4+
'f40fae84-55a2-42cd-99fa-b41c1ca64894',
5+
'Template Deprecated',
6+
E'Template **{{.Labels.template}}** has been deprecated',
7+
E'Hello {{.UserName}},\n\n'||
8+
E'The template **{{.Labels.template}}** has been deprecated with the following message:\n\n' ||
9+
E'**{{.Labels.message}}**\n\n' ||
10+
E'New workspaces may not be created from this template. Existing workspaces will continue to function normally.',
11+
'Template Events',
12+
'[]'::jsonb
13+
);

coderd/database/querier.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

+38
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/templates.sql

+15
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,18 @@ SET
199199
WHERE
200200
id = $1
201201
;
202+
203+
-- name: GetUsersWithAccessToTemplateByID :many
204+
SELECT
205+
user_id
206+
FROM
207+
organization_members
208+
WHERE
209+
organization_members.organization_id::text IN (
210+
SELECT
211+
jsonb_object_keys(group_acl)
212+
FROM
213+
templates
214+
WHERE templates.id = $1
215+
)
216+
;

coderd/notifications/events.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ var (
3030

3131
// Template-related events.
3232
var (
33-
TemplateTemplateDeleted = uuid.MustParse("29a09665-2a4c-403f-9648-54301670e7be")
33+
TemplateTemplateDeleted = uuid.MustParse("29a09665-2a4c-403f-9648-54301670e7be")
34+
TemplateTemplateDeprecated = uuid.MustParse("f40fae84-55a2-42cd-99fa-b41c1ca64894")
3435

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

coderd/templates.go

+34
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,12 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
845845
return
846846
}
847847

848+
if template.Deprecated != updated.Deprecated && updated.Deprecated != "" {
849+
if err := api.notifyUsersOfTemplateDeprecation(ctx, updated); err != nil {
850+
api.Logger.Error(ctx, "failed to notify users of template deprecation", slog.Error(err))
851+
}
852+
}
853+
848854
if updated.UpdatedAt.IsZero() {
849855
aReq.New = template
850856
rw.WriteHeader(http.StatusNotModified)
@@ -855,6 +861,34 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
855861
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(updated))
856862
}
857863

864+
func (api *API) notifyUsersOfTemplateDeprecation(ctx context.Context, template database.Template) error {
865+
users, err := api.Database.GetUsersWithAccessToTemplateByID(ctx, template.ID)
866+
if err != nil {
867+
return xerrors.Errorf("get users with access to template by id: %w", err)
868+
}
869+
870+
errs := []error{}
871+
872+
for _, userID := range users {
873+
_, err = api.NotificationsEnqueuer.Enqueue(
874+
//nolint:gocritic // We need the system auth context to be able to send the deprecation notification.
875+
dbauthz.AsSystemRestricted(ctx),
876+
userID,
877+
notifications.TemplateTemplateDeprecated,
878+
map[string]string{
879+
"template": template.Name,
880+
"message": template.Deprecated,
881+
},
882+
"notify-users-of-template-deprecation",
883+
)
884+
if err != nil {
885+
errs = append(errs, xerrors.Errorf("enqueue notification: %w", err))
886+
}
887+
}
888+
889+
return errors.Join(errs...)
890+
}
891+
858892
// @Summary Get template DAUs by ID
859893
// @ID get-template-daus-by-id
860894
// @Security CoderSessionToken

0 commit comments

Comments
 (0)