Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: Add suspend/active user to cli#1422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Emyrk merged 16 commits intomainfromstevenmasley/user_cli_suspend_2
May 16, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
16 commits
Select commitHold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 2 additions & 19 deletionscli/userlist.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,12 +2,9 @@ package cli

import (
"fmt"
"time"

"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"

"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
)

Expand All@@ -28,25 +25,11 @@ func userList() *cobra.Command {
return err
}

tableWriter := cliui.Table()
header := table.Row{"Username", "Email", "Created At"}
tableWriter.AppendHeader(header)
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, columns))
tableWriter.SortBy([]table.SortBy{{
Name: "Username",
}})
for _, user := range users {
tableWriter.AppendRow(table.Row{
user.Username,
user.Email,
user.CreatedAt.Format(time.Stamp),
})
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), tableWriter.Render())
_, err = fmt.Fprintln(cmd.OutOrStdout(), displayUsers(columns, users...))
return err
},
}
cmd.Flags().StringArrayVarP(&columns, "column", "c",nil,
cmd.Flags().StringArrayVarP(&columns, "column", "c",[]string{"username", "email", "created_at"},
"Specify a column to filter in the table.")
return cmd
}
40 changes: 38 additions & 2 deletionscli/users.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,48 @@
package cli

import "github.com/spf13/cobra"
import (
"time"

"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"

"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
)

func users() *cobra.Command {
cmd := &cobra.Command{
Short: "Create, remove, and list users",
Use: "users",
}
cmd.AddCommand(userCreate(), userList())
cmd.AddCommand(
userCreate(),
userList(),
createUserStatusCommand(codersdk.UserStatusActive),
createUserStatusCommand(codersdk.UserStatusSuspended),
)
return cmd
}

// displayUsers will return a table displaying all users passed in.
// filterColumns must be a subset of the user fields and will determine which
// columns to display
func displayUsers(filterColumns []string, users ...codersdk.User) string {
tableWriter := cliui.Table()
header := table.Row{"id", "username", "email", "created_at", "status"}
tableWriter.AppendHeader(header)
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, filterColumns))
tableWriter.SortBy([]table.SortBy{{
Name: "Username",
}})
for _, user := range users {
tableWriter.AppendRow(table.Row{
user.ID.String(),
user.Username,
user.Email,
user.CreatedAt.Format(time.Stamp),
user.Status,
})
}
return tableWriter.Render()
}
85 changes: 85 additions & 0 deletionscli/userstatus.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
package cli

import (
"fmt"

"github.com/spf13/cobra"
"golang.org/x/xerrors"

"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
)

// createUserStatusCommand sets a user status.
func createUserStatusCommand(sdkStatus codersdk.UserStatus) *cobra.Command {
var verb string
var aliases []string
var short string
switch sdkStatus {
case codersdk.UserStatusActive:
verb = "activate"
aliases = []string{"active"}
short = "Update a user's status to 'active'. Active users can fully interact with the platform"
case codersdk.UserStatusSuspended:
verb = "suspend"
aliases = []string{"rm", "delete"}
short = "Update a user's status to 'suspended'. A suspended user cannot log into the platform"
default:
panic(fmt.Sprintf("%s is not supported", sdkStatus))
}

var (
columns []string
)
cmd := &cobra.Command{
Use: fmt.Sprintf("%s <username|user_id>", verb),
Short: short,
Args: cobra.ExactArgs(1),
Aliases: aliases,
Example: fmt.Sprintf("coder users %s example_user", verb),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return err
}

identifier := args[0]
if identifier == "" {
return xerrors.Errorf("user identifier cannot be an empty string")
}

user, err := client.User(cmd.Context(), identifier)
if err != nil {
return xerrors.Errorf("fetch user: %w", err)
}

// Display the user
_, _ = fmt.Fprintln(cmd.OutOrStdout(), displayUsers(columns, user))

// User status is already set to this
if user.Status == sdkStatus {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "User status is already %q\n", sdkStatus)
return nil
}

// Prompt to confirm the action
_, err = cliui.Prompt(cmd, cliui.PromptOptions{
Text: fmt.Sprintf("Are you sure you want to %s this user?", verb),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The use of this verb is really nice here!

IsConfirm: true,
Default: "yes",
})
if err != nil {
return err
}

_, err = client.UpdateUserStatus(cmd.Context(), user.ID.String(), sdkStatus)
if err != nil {
return xerrors.Errorf("%s user: %w", verb, err)
}
return nil
},
}
cmd.Flags().StringArrayVarP(&columns, "column", "c", []string{"username", "email", "created_at", "status"},
"Specify a column to filter in the table.")
return cmd
}
64 changes: 64 additions & 0 deletionscli/userstatus_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
package cli_test

import (
"bytes"
"context"
"testing"

"github.com/stretchr/testify/require"

"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/codersdk"
)

func TestUserStatus(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
admin := coderdtest.CreateFirstUser(t, client)
other := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
otherUser, err := other.User(context.Background(), codersdk.Me)
require.NoError(t, err, "fetch user")

//nolint:paralleltest
t.Run("StatusSelf", func(t *testing.T) {
cmd, root := clitest.New(t, "users", "suspend", "me")
clitest.SetupConfig(t, client, root)
// Yes to the prompt
cmd.SetIn(bytes.NewReader([]byte("yes\n")))
err := cmd.Execute()
// Expect an error, as you cannot suspend yourself
require.Error(t, err)
require.ErrorContains(t, err, "cannot suspend yourself")
})

//nolint:paralleltest
t.Run("StatusOther", func(t *testing.T) {
require.Equal(t, otherUser.Status, codersdk.UserStatusActive, "start as active")

cmd, root := clitest.New(t, "users", "suspend", otherUser.Username)
clitest.SetupConfig(t, client, root)
// Yes to the prompt
cmd.SetIn(bytes.NewReader([]byte("yes\n")))
err := cmd.Execute()
require.NoError(t, err, "suspend user")

// Check the user status
otherUser, err = client.User(context.Background(), otherUser.Username)
require.NoError(t, err, "fetch suspended user")
require.Equal(t, otherUser.Status, codersdk.UserStatusSuspended, "suspended user")

// Set back to active. Try using a uuid as well
cmd, root = clitest.New(t, "users", "activate", otherUser.ID.String())
clitest.SetupConfig(t, client, root)
// Yes to the prompt
cmd.SetIn(bytes.NewReader([]byte("yes\n")))
err = cmd.Execute()
require.NoError(t, err, "suspend user")

// Check the user status
otherUser, err = client.User(context.Background(), otherUser.ID.String())
require.NoError(t, err, "fetch active user")
require.Equal(t, otherUser.Status, codersdk.UserStatusActive, "active user")
})
}
2 changes: 1 addition & 1 deletioncoderd/autobuild/executor/lifecycle_executor_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)

Expand Down
5 changes: 4 additions & 1 deletioncoderd/coderd.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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))
Expand Down
4 changes: 2 additions & 2 deletionscoderd/coderdtest/coderdtest.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -254,15 +254,15 @@ 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
for orgID, roles := range orgRoles {
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")
}
Expand Down
12 changes: 6 additions & 6 deletionscoderd/gitsshkey_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
})
Expand All@@ -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)
})
Expand All@@ -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)
})
Expand All@@ -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)
})
Expand All@@ -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)
Expand Down
2 changes: 1 addition & 1 deletioncoderd/roles_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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")
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp