feat: Add suspend/active user to cli (#1422)

* feat: Add suspend/active user to cli
* UserID is now a string and allows for username too
This commit is contained in:
Steven Masley
2022-05-16 15:29:27 -05:00
committed by GitHub
parent a77da8445e
commit b55d83ca82
16 changed files with 308 additions and 133 deletions

View File

@ -78,7 +78,7 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) {
require.Empty(t, workspace.AutostartSchedule)
// Given: the workspace template has been updated
orgs, err := client.OrganizationsByUser(ctx, workspace.OwnerID)
orgs, err := client.OrganizationsByUser(ctx, workspace.OwnerID.String())
require.NoError(t, err)
require.Len(t, orgs, 1)

View File

@ -239,7 +239,10 @@ func New(options *Options) (http.Handler, func()) {
r.Use(httpmw.ExtractUserParam(options.Database))
r.Get("/", api.userByName)
r.Put("/profile", api.putUserProfile)
r.Put("/suspend", api.putUserSuspend)
r.Route("/status", func(r chi.Router) {
r.Put("/suspend", api.putUserStatus(database.UserStatusSuspended))
r.Put("/active", api.putUserStatus(database.UserStatusActive))
})
r.Route("/password", func(r chi.Router) {
r.Use(httpmw.WithRBACObject(rbac.ResourceUserPasswordRole))
r.Put("/", authorize(api.putUserPassword, rbac.ActionUpdate))

View File

@ -254,7 +254,7 @@ func CreateAnotherUser(t *testing.T, client *codersdk.Client, organizationID uui
}
// TODO: @emyrk switch "other" to "client" when we support updating other
// users.
_, err := other.UpdateUserRoles(context.Background(), user.ID, codersdk.UpdateRoles{Roles: siteRoles})
_, err := other.UpdateUserRoles(context.Background(), user.ID.String(), codersdk.UpdateRoles{Roles: siteRoles})
require.NoError(t, err, "update site roles")
// Update org roles
@ -262,7 +262,7 @@ func CreateAnotherUser(t *testing.T, client *codersdk.Client, organizationID uui
organizationID, err := uuid.Parse(orgID)
require.NoError(t, err, fmt.Sprintf("parse org id %q", orgID))
// TODO: @Emyrk add the member to the organization if they do not already belong.
_, err = other.UpdateOrganizationMemberRoles(context.Background(), organizationID, user.ID,
_, err = other.UpdateOrganizationMemberRoles(context.Background(), organizationID, user.ID.String(),
codersdk.UpdateRoles{Roles: append(roles, rbac.RoleOrgMember(organizationID))})
require.NoError(t, err, "update org membership roles")
}

View File

@ -21,7 +21,7 @@ func TestGitSSHKey(t *testing.T) {
ctx := context.Background()
client := coderdtest.New(t, nil)
res := coderdtest.CreateFirstUser(t, client)
key, err := client.GitSSHKey(ctx, res.UserID)
key, err := client.GitSSHKey(ctx, res.UserID.String())
require.NoError(t, err)
require.NotEmpty(t, key.PublicKey)
})
@ -32,7 +32,7 @@ func TestGitSSHKey(t *testing.T) {
SSHKeygenAlgorithm: gitsshkey.AlgorithmEd25519,
})
res := coderdtest.CreateFirstUser(t, client)
key, err := client.GitSSHKey(ctx, res.UserID)
key, err := client.GitSSHKey(ctx, res.UserID.String())
require.NoError(t, err)
require.NotEmpty(t, key.PublicKey)
})
@ -43,7 +43,7 @@ func TestGitSSHKey(t *testing.T) {
SSHKeygenAlgorithm: gitsshkey.AlgorithmECDSA,
})
res := coderdtest.CreateFirstUser(t, client)
key, err := client.GitSSHKey(ctx, res.UserID)
key, err := client.GitSSHKey(ctx, res.UserID.String())
require.NoError(t, err)
require.NotEmpty(t, key.PublicKey)
})
@ -54,7 +54,7 @@ func TestGitSSHKey(t *testing.T) {
SSHKeygenAlgorithm: gitsshkey.AlgorithmRSA4096,
})
res := coderdtest.CreateFirstUser(t, client)
key, err := client.GitSSHKey(ctx, res.UserID)
key, err := client.GitSSHKey(ctx, res.UserID.String())
require.NoError(t, err)
require.NotEmpty(t, key.PublicKey)
})
@ -65,10 +65,10 @@ func TestGitSSHKey(t *testing.T) {
SSHKeygenAlgorithm: gitsshkey.AlgorithmEd25519,
})
res := coderdtest.CreateFirstUser(t, client)
key1, err := client.GitSSHKey(ctx, res.UserID)
key1, err := client.GitSSHKey(ctx, res.UserID.String())
require.NoError(t, err)
require.NotEmpty(t, key1.PublicKey)
key2, err := client.RegenerateGitSSHKey(ctx, res.UserID)
key2, err := client.RegenerateGitSSHKey(ctx, res.UserID.String())
require.NoError(t, err)
require.GreaterOrEqual(t, key2.UpdatedAt, key1.UpdatedAt)
require.NotEmpty(t, key2.PublicKey)

View File

@ -107,7 +107,7 @@ func TestListRoles(t *testing.T) {
member := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
orgAdmin := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID, rbac.RoleOrgAdmin(admin.OrganizationID))
otherOrg, err := client.CreateOrganization(ctx, admin.UserID, codersdk.CreateOrganizationRequest{
otherOrg, err := client.CreateOrganization(ctx, admin.UserID.String(), codersdk.CreateOrganizationRequest{
Name: "other",
})
require.NoError(t, err, "create org")

View File

@ -303,31 +303,40 @@ func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(rw, http.StatusOK, convertUser(updatedUserProfile, organizationIDs))
}
func (api *api) putUserSuspend(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)
func (api *api) putUserStatus(status database.UserStatus) func(rw http.ResponseWriter, r *http.Request) {
return func(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)
apiKey := httpmw.APIKey(r)
if status == database.UserStatusSuspended && user.ID == apiKey.UserID {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "You cannot suspend yourself",
})
return
}
suspendedUser, err := api.Database.UpdateUserStatus(r.Context(), database.UpdateUserStatusParams{
ID: user.ID,
Status: database.UserStatusSuspended,
UpdatedAt: database.Now(),
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("put user suspended: %s", err.Error()),
suspendedUser, err := api.Database.UpdateUserStatus(r.Context(), database.UpdateUserStatusParams{
ID: user.ID,
Status: status,
UpdatedAt: database.Now(),
})
return
}
organizations, err := userOrganizationIDs(r.Context(), api, user)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get organization IDs: %s", err.Error()),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("put user suspended: %s", err.Error()),
})
return
}
httpapi.Write(rw, http.StatusOK, convertUser(suspendedUser, organizations))
organizations, err := userOrganizationIDs(r.Context(), api, user)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get organization IDs: %s", err.Error()),
})
return
}
httpapi.Write(rw, http.StatusOK, convertUser(suspendedUser, organizations))
}
}
func (api *api) putUserPassword(rw http.ResponseWriter, r *http.Request) {

View File

@ -209,7 +209,7 @@ func TestUpdateUserProfile(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
_, err := client.UpdateUserProfile(context.Background(), uuid.New(), codersdk.UpdateUserProfileRequest{
_, err := client.UpdateUserProfile(context.Background(), uuid.New().String(), codersdk.UpdateUserProfileRequest{
Username: "newusername",
Email: "newemail@coder.com",
})
@ -295,7 +295,7 @@ func TestUpdateUserPassword(t *testing.T) {
client := coderdtest.New(t, nil)
admin := coderdtest.CreateFirstUser(t, client)
member := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
err := member.UpdateUserPassword(context.Background(), admin.UserID, codersdk.UpdateUserPasswordRequest{
err := member.UpdateUserPassword(context.Background(), admin.UserID.String(), codersdk.UpdateUserPasswordRequest{
Password: "newpassword",
})
require.Error(t, err, "member should not be able to update admin password")
@ -312,7 +312,7 @@ func TestUpdateUserPassword(t *testing.T) {
OrganizationID: admin.OrganizationID,
})
require.NoError(t, err, "create member")
err = client.UpdateUserPassword(context.Background(), member.ID, codersdk.UpdateUserPasswordRequest{
err = client.UpdateUserPassword(context.Background(), member.ID.String(), codersdk.UpdateUserPasswordRequest{
Password: "newpassword",
})
require.NoError(t, err, "admin should be able to update member password")
@ -339,7 +339,7 @@ func TestGrantRoles(t *testing.T) {
})
require.Error(t, err, "org role in site")
_, err = admin.UpdateUserRoles(ctx, uuid.New(), codersdk.UpdateRoles{
_, err = admin.UpdateUserRoles(ctx, uuid.New().String(), codersdk.UpdateRoles{
Roles: []string{rbac.RoleOrgMember(first.OrganizationID)},
})
require.Error(t, err, "user does not exist")
@ -354,12 +354,12 @@ func TestGrantRoles(t *testing.T) {
})
require.Error(t, err, "role in org without membership")
_, err = member.UpdateUserRoles(ctx, first.UserID, codersdk.UpdateRoles{
_, err = member.UpdateUserRoles(ctx, first.UserID.String(), codersdk.UpdateRoles{
Roles: []string{rbac.RoleMember()},
})
require.Error(t, err, "member cannot change other's roles")
_, err = member.UpdateOrganizationMemberRoles(ctx, first.OrganizationID, first.UserID, codersdk.UpdateRoles{
_, err = member.UpdateOrganizationMemberRoles(ctx, first.OrganizationID, first.UserID.String(), codersdk.UpdateRoles{
Roles: []string{rbac.RoleMember()},
})
require.Error(t, err, "member cannot change other's org roles")
@ -452,7 +452,7 @@ func TestPutUserSuspend(t *testing.T) {
Password: "password",
OrganizationID: me.OrganizationID,
})
user, err := client.SuspendUser(context.Background(), user.ID)
user, err := client.UpdateUserStatus(context.Background(), user.Username, codersdk.UserStatusSuspended)
require.NoError(t, err)
require.Equal(t, user.Status, codersdk.UserStatusSuspended)
})
@ -462,10 +462,9 @@ func TestPutUserSuspend(t *testing.T) {
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
client.User(context.Background(), codersdk.Me)
suspendedUser, err := client.SuspendUser(context.Background(), codersdk.Me)
_, err := client.UpdateUserStatus(context.Background(), codersdk.Me, codersdk.UserStatusSuspended)
require.NoError(t, err)
require.Equal(t, suspendedUser.Status, codersdk.UserStatusSuspended)
require.ErrorContains(t, err, "suspend yourself", "cannot suspend yourself")
})
}
@ -490,7 +489,7 @@ func TestGetUser(t *testing.T) {
client := coderdtest.New(t, nil)
firstUser := coderdtest.CreateFirstUser(t, client)
user, err := client.User(context.Background(), firstUser.UserID)
user, err := client.User(context.Background(), firstUser.UserID.String())
require.NoError(t, err)
require.Equal(t, firstUser.UserID, user.ID)
require.Equal(t, firstUser.OrganizationID, user.OrganizationIDs[0])
@ -501,10 +500,10 @@ func TestGetUser(t *testing.T) {
client := coderdtest.New(t, nil)
firstUser := coderdtest.CreateFirstUser(t, client)
exp, err := client.User(context.Background(), firstUser.UserID)
exp, err := client.User(context.Background(), firstUser.UserID.String())
require.NoError(t, err)
user, err := client.UserByUsername(context.Background(), exp.Username)
user, err := client.User(context.Background(), exp.Username)
require.NoError(t, err)
require.Equal(t, exp, user)
})
@ -530,9 +529,15 @@ func TestGetUsers(t *testing.T) {
})
t.Run("ActiveUsers", func(t *testing.T) {
t.Parallel()
active := make([]codersdk.User, 0)
client := coderdtest.New(t, nil)
first := coderdtest.CreateFirstUser(t, client)
active := make([]codersdk.User, 0)
firstUser, err := client.User(context.Background(), first.UserID.String())
require.NoError(t, err, "")
active = append(active, firstUser)
// Alice will be suspended
alice, err := client.CreateUser(context.Background(), codersdk.CreateUserRequest{
Email: "alice@email.com",
Username: "alice",
@ -540,7 +545,6 @@ func TestGetUsers(t *testing.T) {
OrganizationID: first.OrganizationID,
})
require.NoError(t, err)
active = append(active, alice)
bruno, err := client.CreateUser(context.Background(), codersdk.CreateUserRequest{
Email: "bruno@email.com",
@ -551,7 +555,7 @@ func TestGetUsers(t *testing.T) {
require.NoError(t, err)
active = append(active, bruno)
_, err = client.SuspendUser(context.Background(), first.UserID)
_, err = client.UpdateUserStatus(context.Background(), alice.Username, codersdk.UserStatusSuspended)
require.NoError(t, err)
users, err := client.Users(context.Background(), codersdk.UsersRequest{

View File

@ -297,7 +297,7 @@ func TestPostWorkspaceBuild(t *testing.T) {
require.Equal(t, workspace.LatestBuild.ID.String(), build.BeforeID.String())
coderdtest.AwaitWorkspaceBuildJob(t, client, build.ID)
workspaces, err := client.WorkspacesByOwner(context.Background(), user.OrganizationID, user.UserID)
workspaces, err := client.WorkspacesByOwner(context.Background(), user.OrganizationID, user.UserID.String())
require.NoError(t, err)
require.Len(t, workspaces, 0)
})