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
This commit is contained in:
Steven Masley
2024-08-23 21:23:51 +00:00
committed by GitHub
parent af125c3795
commit c8eacc6df7
28 changed files with 597 additions and 367 deletions
+5 -5
View File
@@ -757,11 +757,11 @@ func TestGroup(t *testing.T) {
require.Contains(t, group.Members, user2.ReducedUser)
// cannot explicitly set a dormant user status so must create a new user
anotherUser, err := userAdminClient.CreateUser(ctx, codersdk.CreateUserRequest{
Email: "coder@coder.com",
Username: "coder",
Password: "SomeStrongPassword!",
OrganizationID: user.OrganizationID,
anotherUser, err := userAdminClient.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
Email: "coder@coder.com",
Username: "coder",
Password: "SomeStrongPassword!",
OrganizationIDs: []uuid.UUID{user.OrganizationID},
})
require.NoError(t, err)
+5 -5
View File
@@ -228,11 +228,11 @@ func (api *API) scimPostUser(rw http.ResponseWriter, r *http.Request) {
}
//nolint:gocritic // needed for SCIM
dbUser, _, err = api.AGPL.CreateUser(dbauthz.AsSystemRestricted(ctx), api.Database, agpl.CreateUserRequest{
CreateUserRequest: codersdk.CreateUserRequest{
Username: sUser.UserName,
Email: email,
OrganizationID: defaultOrganization.ID,
dbUser, err = api.AGPL.CreateUser(dbauthz.AsSystemRestricted(ctx), api.Database, agpl.CreateUserRequest{
CreateUserRequestWithOrgs: codersdk.CreateUserRequestWithOrgs{
Username: sUser.UserName,
Email: email,
OrganizationIDs: []uuid.UUID{defaultOrganization.ID},
},
LoginType: database.LoginTypeOIDC,
// Do not send notifications to user admins as SCIM endpoint might be called sequentially to all users.
+2 -2
View File
@@ -717,7 +717,7 @@ func TestEnterpriseUserLogin(t *testing.T) {
Name: customRole.Name,
OrganizationID: owner.OrganizationID,
},
}, func(r *codersdk.CreateUserRequest) {
}, func(r *codersdk.CreateUserRequestWithOrgs) {
r.Password = "SomeSecurePassword!"
r.UserLoginType = codersdk.LoginTypePassword
})
@@ -752,7 +752,7 @@ func TestEnterpriseUserLogin(t *testing.T) {
},
})
anotherClient, anotherUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequest) {
anotherClient, anotherUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequestWithOrgs) {
r.Password = "SomeSecurePassword!"
r.UserLoginType = codersdk.LoginTypePassword
})
+53 -15
View File
@@ -7,7 +7,6 @@ import (
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/coderdtest"
@@ -509,11 +508,11 @@ func TestEnterprisePostUser(t *testing.T) {
request.Name = "another"
})
_, err := notInOrg.CreateUser(ctx, codersdk.CreateUserRequest{
Email: "some@domain.com",
Username: "anotheruser",
Password: "SomeSecurePassword!",
OrganizationID: org.ID,
_, err := notInOrg.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
Email: "some@domain.com",
Username: "anotheruser",
Password: "SomeSecurePassword!",
OrganizationIDs: []uuid.UUID{org.ID},
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
@@ -543,11 +542,11 @@ func TestEnterprisePostUser(t *testing.T) {
org := coderdenttest.CreateOrganization(t, other, coderdenttest.CreateOrganizationOptions{})
_, err := notInOrg.CreateUser(ctx, codersdk.CreateUserRequest{
Email: "some@domain.com",
Username: "anotheruser",
Password: "SomeSecurePassword!",
OrganizationID: org.ID,
_, err := notInOrg.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
Email: "some@domain.com",
Username: "anotheruser",
Password: "SomeSecurePassword!",
OrganizationIDs: []uuid.UUID{org.ID},
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
@@ -559,7 +558,7 @@ func TestEnterprisePostUser(t *testing.T) {
dv := coderdtest.DeploymentValues(t)
dv.Experiments = []string{string(codersdk.ExperimentMultiOrganization)}
client, firstUser := coderdenttest.New(t, &coderdenttest.Options{
client, _ := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
@@ -578,14 +577,53 @@ func TestEnterprisePostUser(t *testing.T) {
// nolint:gocritic // intentional using the owner.
// Manually making a user with the request instead of the coderdtest util
user, err := client.CreateUser(ctx, codersdk.CreateUserRequest{
_, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
Email: "another@user.org",
Username: "someone-else",
Password: "SomeSecurePassword!",
})
require.ErrorContains(t, err, "No organization specified")
})
t.Run("MultipleOrganizations", func(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
dv.Experiments = []string{string(codersdk.ExperimentMultiOrganization)}
client, _ := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureMultipleOrganizations: 1,
},
},
})
// Add an extra org to assign member into
second := coderdenttest.CreateOrganization(t, client, coderdenttest.CreateOrganizationOptions{})
third := coderdenttest.CreateOrganization(t, client, coderdenttest.CreateOrganizationOptions{})
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
// nolint:gocritic // intentional using the owner.
// Manually making a user with the request instead of the coderdtest util
user, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
Email: "another@user.org",
Username: "someone-else",
Password: "SomeSecurePassword!",
OrganizationIDs: []uuid.UUID{
second.ID,
third.ID,
},
})
require.NoError(t, err)
require.Len(t, user.OrganizationIDs, 1)
assert.Equal(t, firstUser.OrganizationID, user.OrganizationIDs[0])
memberedOrgs, err := client.OrganizationsByUser(ctx, user.ID.String())
require.NoError(t, err)
require.Len(t, memberedOrgs, 2)
require.ElementsMatch(t, []uuid.UUID{second.ID, third.ID}, []uuid.UUID{memberedOrgs[0].ID, memberedOrgs[1].ID})
})
}