Skip to content

Commit c8eacc6

Browse files
authored
chore!: allow CreateUser to accept multiple organizations (#14383)
* chore: allow CreateUser to accept multiple organizations In a multi-org deployment, it makes more sense to allow for multiple org memberships to be assigned at create. The legacy param will still be honored. * Handle sdk deprecation better by maintaining cli functions
1 parent af125c3 commit c8eacc6

File tree

28 files changed

+597
-367
lines changed

28 files changed

+597
-367
lines changed

cli/clitest/golden.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212
"testing"
1313

14+
"github.com/google/uuid"
1415
"github.com/stretchr/testify/require"
1516

1617
"github.com/coder/coder/v2/cli/config"
@@ -183,11 +184,11 @@ func prepareTestData(t *testing.T) (*codersdk.Client, map[string]string) {
183184
IncludeProvisionerDaemon: true,
184185
})
185186
firstUser := coderdtest.CreateFirstUser(t, rootClient)
186-
secondUser, err := rootClient.CreateUser(ctx, codersdk.CreateUserRequest{
187-
Email: "testuser2@coder.com",
188-
Username: "testuser2",
189-
Password: coderdtest.FirstUserParams.Password,
190-
OrganizationID: firstUser.OrganizationID,
187+
secondUser, err := rootClient.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
188+
Email: "testuser2@coder.com",
189+
Username: "testuser2",
190+
Password: coderdtest.FirstUserParams.Password,
191+
OrganizationIDs: []uuid.UUID{firstUser.OrganizationID},
191192
})
192193
require.NoError(t, err)
193194
version := coderdtest.CreateTemplateVersion(t, rootClient, firstUser.OrganizationID, nil)

cli/schedule_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func setupTestSchedule(t *testing.T, sched *cron.Schedule) (ownerClient, memberC
3535

3636
ownerClient, db = coderdtest.NewWithDatabase(t, nil)
3737
owner := coderdtest.CreateFirstUser(t, ownerClient)
38-
memberClient, memberUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequest) {
38+
memberClient, memberUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequestWithOrgs) {
3939
r.Username = "testuser2" // ensure deterministic ordering
4040
})
4141
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{

cli/server_createadminuser.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
8383

8484
validateInputs := func(username, email, password string) error {
8585
// Use the validator tags so we match the API's validation.
86-
req := codersdk.CreateUserRequest{
87-
Username: "username",
88-
Name: "Admin User",
89-
Email: "email@coder.com",
90-
Password: "ValidPa$$word123!",
91-
OrganizationID: uuid.New(),
86+
req := codersdk.CreateUserRequestWithOrgs{
87+
Username: "username",
88+
Name: "Admin User",
89+
Email: "email@coder.com",
90+
Password: "ValidPa$$word123!",
91+
OrganizationIDs: []uuid.UUID{uuid.New()},
9292
}
9393
if username != "" {
9494
req.Username = username

cli/user_delete_test.go

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/google/uuid"
78
"github.com/stretchr/testify/require"
89

910
"github.com/coder/coder/v2/cli/clitest"
@@ -26,13 +27,12 @@ func TestUserDelete(t *testing.T) {
2627
pw, err := cryptorand.String(16)
2728
require.NoError(t, err)
2829

29-
_, err = client.CreateUser(ctx, codersdk.CreateUserRequest{
30-
Email: "colin5@coder.com",
31-
Username: "coolin",
32-
Password: pw,
33-
UserLoginType: codersdk.LoginTypePassword,
34-
OrganizationID: owner.OrganizationID,
35-
DisableLogin: false,
30+
_, err = client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
31+
Email: "colin5@coder.com",
32+
Username: "coolin",
33+
Password: pw,
34+
UserLoginType: codersdk.LoginTypePassword,
35+
OrganizationIDs: []uuid.UUID{owner.OrganizationID},
3636
})
3737
require.NoError(t, err)
3838

@@ -57,13 +57,12 @@ func TestUserDelete(t *testing.T) {
5757
pw, err := cryptorand.String(16)
5858
require.NoError(t, err)
5959

60-
user, err := client.CreateUser(ctx, codersdk.CreateUserRequest{
61-
Email: "colin5@coder.com",
62-
Username: "coolin",
63-
Password: pw,
64-
UserLoginType: codersdk.LoginTypePassword,
65-
OrganizationID: owner.OrganizationID,
66-
DisableLogin: false,
60+
user, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
61+
Email: "colin5@coder.com",
62+
Username: "coolin",
63+
Password: pw,
64+
UserLoginType: codersdk.LoginTypePassword,
65+
OrganizationIDs: []uuid.UUID{owner.OrganizationID},
6766
})
6867
require.NoError(t, err)
6968

@@ -88,13 +87,12 @@ func TestUserDelete(t *testing.T) {
8887
pw, err := cryptorand.String(16)
8988
require.NoError(t, err)
9089

91-
user, err := client.CreateUser(ctx, codersdk.CreateUserRequest{
92-
Email: "colin5@coder.com",
93-
Username: "coolin",
94-
Password: pw,
95-
UserLoginType: codersdk.LoginTypePassword,
96-
OrganizationID: owner.OrganizationID,
97-
DisableLogin: false,
90+
user, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
91+
Email: "colin5@coder.com",
92+
Username: "coolin",
93+
Password: pw,
94+
UserLoginType: codersdk.LoginTypePassword,
95+
OrganizationIDs: []uuid.UUID{owner.OrganizationID},
9896
})
9997
require.NoError(t, err)
10098

@@ -121,13 +119,12 @@ func TestUserDelete(t *testing.T) {
121119
// pw, err := cryptorand.String(16)
122120
// require.NoError(t, err)
123121

124-
// toDelete, err := client.CreateUser(ctx, codersdk.CreateUserRequest{
122+
// toDelete, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
125123
// Email: "colin5@coder.com",
126124
// Username: "coolin",
127125
// Password: pw,
128126
// UserLoginType: codersdk.LoginTypePassword,
129127
// OrganizationID: aUser.OrganizationID,
130-
// DisableLogin: false,
131128
// })
132129
// require.NoError(t, err)
133130

cli/usercreate.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"strings"
66

77
"github.com/go-playground/validator/v10"
8+
"github.com/google/uuid"
89
"golang.org/x/xerrors"
910

1011
"github.com/coder/pretty"
@@ -94,13 +95,13 @@ func (r *RootCmd) userCreate() *serpent.Command {
9495
}
9596
}
9697

97-
_, err = client.CreateUser(inv.Context(), codersdk.CreateUserRequest{
98-
Email: email,
99-
Username: username,
100-
Name: name,
101-
Password: password,
102-
OrganizationID: organization.ID,
103-
UserLoginType: userLoginType,
98+
_, err = client.CreateUserWithOrgs(inv.Context(), codersdk.CreateUserRequestWithOrgs{
99+
Email: email,
100+
Username: username,
101+
Name: name,
102+
Password: password,
103+
OrganizationIDs: []uuid.UUID{organization.ID},
104+
UserLoginType: userLoginType,
104105
})
105106
if err != nil {
106107
return err

coderd/apidoc/docs.go

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderdtest/coderdtest.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -648,11 +648,11 @@ func CreateFirstUser(t testing.TB, client *codersdk.Client) codersdk.CreateFirst
648648
// CreateAnotherUser creates and authenticates a new user.
649649
// Roles can include org scoped roles with 'roleName:<organization_id>'
650650
func CreateAnotherUser(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, roles ...rbac.RoleIdentifier) (*codersdk.Client, codersdk.User) {
651-
return createAnotherUserRetry(t, client, organizationID, 5, roles)
651+
return createAnotherUserRetry(t, client, []uuid.UUID{organizationID}, 5, roles)
652652
}
653653

654-
func CreateAnotherUserMutators(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, roles []rbac.RoleIdentifier, mutators ...func(r *codersdk.CreateUserRequest)) (*codersdk.Client, codersdk.User) {
655-
return createAnotherUserRetry(t, client, organizationID, 5, roles, mutators...)
654+
func CreateAnotherUserMutators(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, roles []rbac.RoleIdentifier, mutators ...func(r *codersdk.CreateUserRequestWithOrgs)) (*codersdk.Client, codersdk.User) {
655+
return createAnotherUserRetry(t, client, []uuid.UUID{organizationID}, 5, roles, mutators...)
656656
}
657657

658658
// AuthzUserSubject does not include the user's groups.
@@ -678,31 +678,31 @@ func AuthzUserSubject(user codersdk.User, orgID uuid.UUID) rbac.Subject {
678678
}
679679
}
680680

681-
func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, retries int, roles []rbac.RoleIdentifier, mutators ...func(r *codersdk.CreateUserRequest)) (*codersdk.Client, codersdk.User) {
682-
req := codersdk.CreateUserRequest{
683-
Email: namesgenerator.GetRandomName(10) + "@coder.com",
684-
Username: RandomUsername(t),
685-
Name: RandomName(t),
686-
Password: "SomeSecurePassword!",
687-
OrganizationID: organizationID,
681+
func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationIDs []uuid.UUID, retries int, roles []rbac.RoleIdentifier, mutators ...func(r *codersdk.CreateUserRequestWithOrgs)) (*codersdk.Client, codersdk.User) {
682+
req := codersdk.CreateUserRequestWithOrgs{
683+
Email: namesgenerator.GetRandomName(10) + "@coder.com",
684+
Username: RandomUsername(t),
685+
Name: RandomName(t),
686+
Password: "SomeSecurePassword!",
687+
OrganizationIDs: organizationIDs,
688688
}
689689
for _, m := range mutators {
690690
m(&req)
691691
}
692692

693-
user, err := client.CreateUser(context.Background(), req)
693+
user, err := client.CreateUserWithOrgs(context.Background(), req)
694694
var apiError *codersdk.Error
695695
// If the user already exists by username or email conflict, try again up to "retries" times.
696696
if err != nil && retries >= 0 && xerrors.As(err, &apiError) {
697697
if apiError.StatusCode() == http.StatusConflict {
698698
retries--
699-
return createAnotherUserRetry(t, client, organizationID, retries, roles)
699+
return createAnotherUserRetry(t, client, organizationIDs, retries, roles)
700700
}
701701
}
702702
require.NoError(t, err)
703703

704704
var sessionToken string
705-
if req.DisableLogin || req.UserLoginType == codersdk.LoginTypeNone {
705+
if req.UserLoginType == codersdk.LoginTypeNone {
706706
// Cannot log in with a disabled login user. So make it an api key from
707707
// the client making this user.
708708
token, err := client.CreateToken(context.Background(), user.ID.String(), codersdk.CreateTokenRequest{
@@ -765,8 +765,9 @@ func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationI
765765
require.NoError(t, err, "update site roles")
766766

767767
// isMember keeps track of which orgs the user was added to as a member
768-
isMember := map[uuid.UUID]bool{
769-
organizationID: true,
768+
isMember := make(map[uuid.UUID]bool)
769+
for _, orgID := range organizationIDs {
770+
isMember[orgID] = true
770771
}
771772

772773
// Update org roles

coderd/insights_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ func TestTemplateInsights_Golden(t *testing.T) {
523523

524524
// Prepare all test users.
525525
for _, user := range users {
526-
user.client, user.sdk = coderdtest.CreateAnotherUserMutators(t, client, firstUser.OrganizationID, nil, func(r *codersdk.CreateUserRequest) {
526+
user.client, user.sdk = coderdtest.CreateAnotherUserMutators(t, client, firstUser.OrganizationID, nil, func(r *codersdk.CreateUserRequestWithOrgs) {
527527
r.Username = user.name
528528
})
529529
user.client.SetLogger(logger.Named("user").With(slog.Field{Name: "name", Value: user.name}))

coderd/userauth.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,11 +1436,11 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C
14361436
}
14371437

14381438
//nolint:gocritic
1439-
user, _, err = api.CreateUser(dbauthz.AsSystemRestricted(ctx), tx, CreateUserRequest{
1440-
CreateUserRequest: codersdk.CreateUserRequest{
1441-
Email: params.Email,
1442-
Username: params.Username,
1443-
OrganizationID: defaultOrganization.ID,
1439+
user, err = api.CreateUser(dbauthz.AsSystemRestricted(ctx), tx, CreateUserRequest{
1440+
CreateUserRequestWithOrgs: codersdk.CreateUserRequestWithOrgs{
1441+
Email: params.Email,
1442+
Username: params.Username,
1443+
OrganizationIDs: []uuid.UUID{defaultOrganization.ID},
14441444
},
14451445
LoginType: params.LoginType,
14461446
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy