Skip to content

Commit 53ff126

Browse files
committed
prevent duplicate group adds
1 parent c18379e commit 53ff126

File tree

5 files changed

+36
-1
lines changed

5 files changed

+36
-1
lines changed

coderd/database/dump.sql

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

coderd/database/migrations/000055_template_acl.up.sql

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ CREATE TABLE group_members (
2121
user_id uuid NOT NULL,
2222
group_id uuid NOT NULL,
2323
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
24-
FOREIGN KEY(group_id) REFERENCES groups(id) ON DELETE CASCADE
24+
FOREIGN KEY(group_id) REFERENCES groups(id) ON DELETE CASCADE,
25+
UNIQUE(user_id, group_id)
2526
);
2627

2728
COMMIT;

coderd/database/unique_constraint.go

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

coderd/groups.go

+7
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
135135
}
136136
return nil
137137
})
138+
if database.IsUniqueViolation(err) {
139+
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
140+
Message: "Cannot add the same user to a group twice!",
141+
Detail: err.Error(),
142+
})
143+
return
144+
}
138145
if xerrors.Is(err, sql.ErrNoRows) {
139146
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
140147
Message: "Failed to add or remove non-existent group member",

coderd/groups_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,29 @@ func TestPatchGroup(t *testing.T) {
171171
require.True(t, ok)
172172
require.Equal(t, http.StatusBadRequest, cerr.StatusCode())
173173
})
174+
175+
t.Run("AddDuplicateUser", func(t *testing.T) {
176+
t.Parallel()
177+
178+
client := coderdtest.New(t, nil)
179+
user := coderdtest.CreateFirstUser(t, client)
180+
181+
_, user2 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
182+
183+
ctx, _ := testutil.Context(t)
184+
group, err := client.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
185+
Name: "hi",
186+
})
187+
require.NoError(t, err)
188+
189+
group, err = client.PatchGroup(ctx, group.ID, codersdk.PatchGroupRequest{
190+
AddUsers: []string{user2.ID.String(), user2.ID.String()},
191+
})
192+
require.Error(t, err)
193+
cerr, ok := codersdk.AsError(err)
194+
require.True(t, ok)
195+
require.Equal(t, http.StatusPreconditionFailed, cerr.StatusCode())
196+
})
174197
}
175198

176199
// TODO: test auth.

0 commit comments

Comments
 (0)