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

Commitb55d83c

Browse files
authored
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
1 parenta77da84 commitb55d83c

16 files changed

+308
-133
lines changed

‎cli/userlist.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@ package cli
22

33
import (
44
"fmt"
5-
"time"
65

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

10-
"github.com/coder/coder/cli/cliui"
118
"github.com/coder/coder/codersdk"
129
)
1310

@@ -28,25 +25,11 @@ func userList() *cobra.Command {
2825
returnerr
2926
}
3027

31-
tableWriter:=cliui.Table()
32-
header:= table.Row{"Username","Email","Created At"}
33-
tableWriter.AppendHeader(header)
34-
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header,columns))
35-
tableWriter.SortBy([]table.SortBy{{
36-
Name:"Username",
37-
}})
38-
for_,user:=rangeusers {
39-
tableWriter.AppendRow(table.Row{
40-
user.Username,
41-
user.Email,
42-
user.CreatedAt.Format(time.Stamp),
43-
})
44-
}
45-
_,err=fmt.Fprintln(cmd.OutOrStdout(),tableWriter.Render())
28+
_,err=fmt.Fprintln(cmd.OutOrStdout(),displayUsers(columns,users...))
4629
returnerr
4730
},
4831
}
49-
cmd.Flags().StringArrayVarP(&columns,"column","c",nil,
32+
cmd.Flags().StringArrayVarP(&columns,"column","c",[]string{"username","email","created_at"},
5033
"Specify a column to filter in the table.")
5134
returncmd
5235
}

‎cli/users.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,48 @@
11
package cli
22

3-
import"github.com/spf13/cobra"
3+
import (
4+
"time"
5+
6+
"github.com/jedib0t/go-pretty/v6/table"
7+
"github.com/spf13/cobra"
8+
9+
"github.com/coder/coder/cli/cliui"
10+
"github.com/coder/coder/codersdk"
11+
)
412

513
funcusers()*cobra.Command {
614
cmd:=&cobra.Command{
715
Short:"Create, remove, and list users",
816
Use:"users",
917
}
10-
cmd.AddCommand(userCreate(),userList())
18+
cmd.AddCommand(
19+
userCreate(),
20+
userList(),
21+
createUserStatusCommand(codersdk.UserStatusActive),
22+
createUserStatusCommand(codersdk.UserStatusSuspended),
23+
)
1124
returncmd
1225
}
26+
27+
// displayUsers will return a table displaying all users passed in.
28+
// filterColumns must be a subset of the user fields and will determine which
29+
// columns to display
30+
funcdisplayUsers(filterColumns []string,users...codersdk.User)string {
31+
tableWriter:=cliui.Table()
32+
header:= table.Row{"id","username","email","created_at","status"}
33+
tableWriter.AppendHeader(header)
34+
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header,filterColumns))
35+
tableWriter.SortBy([]table.SortBy{{
36+
Name:"Username",
37+
}})
38+
for_,user:=rangeusers {
39+
tableWriter.AppendRow(table.Row{
40+
user.ID.String(),
41+
user.Username,
42+
user.Email,
43+
user.CreatedAt.Format(time.Stamp),
44+
user.Status,
45+
})
46+
}
47+
returntableWriter.Render()
48+
}

‎cli/userstatus.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
"golang.org/x/xerrors"
8+
9+
"github.com/coder/coder/cli/cliui"
10+
"github.com/coder/coder/codersdk"
11+
)
12+
13+
// createUserStatusCommand sets a user status.
14+
funccreateUserStatusCommand(sdkStatus codersdk.UserStatus)*cobra.Command {
15+
varverbstring
16+
varaliases []string
17+
varshortstring
18+
switchsdkStatus {
19+
casecodersdk.UserStatusActive:
20+
verb="activate"
21+
aliases= []string{"active"}
22+
short="Update a user's status to 'active'. Active users can fully interact with the platform"
23+
casecodersdk.UserStatusSuspended:
24+
verb="suspend"
25+
aliases= []string{"rm","delete"}
26+
short="Update a user's status to 'suspended'. A suspended user cannot log into the platform"
27+
default:
28+
panic(fmt.Sprintf("%s is not supported",sdkStatus))
29+
}
30+
31+
var (
32+
columns []string
33+
)
34+
cmd:=&cobra.Command{
35+
Use:fmt.Sprintf("%s <username|user_id>",verb),
36+
Short:short,
37+
Args:cobra.ExactArgs(1),
38+
Aliases:aliases,
39+
Example:fmt.Sprintf("coder users %s example_user",verb),
40+
RunE:func(cmd*cobra.Command,args []string)error {
41+
client,err:=createClient(cmd)
42+
iferr!=nil {
43+
returnerr
44+
}
45+
46+
identifier:=args[0]
47+
ifidentifier=="" {
48+
returnxerrors.Errorf("user identifier cannot be an empty string")
49+
}
50+
51+
user,err:=client.User(cmd.Context(),identifier)
52+
iferr!=nil {
53+
returnxerrors.Errorf("fetch user: %w",err)
54+
}
55+
56+
// Display the user
57+
_,_=fmt.Fprintln(cmd.OutOrStdout(),displayUsers(columns,user))
58+
59+
// User status is already set to this
60+
ifuser.Status==sdkStatus {
61+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"User status is already %q\n",sdkStatus)
62+
returnnil
63+
}
64+
65+
// Prompt to confirm the action
66+
_,err=cliui.Prompt(cmd, cliui.PromptOptions{
67+
Text:fmt.Sprintf("Are you sure you want to %s this user?",verb),
68+
IsConfirm:true,
69+
Default:"yes",
70+
})
71+
iferr!=nil {
72+
returnerr
73+
}
74+
75+
_,err=client.UpdateUserStatus(cmd.Context(),user.ID.String(),sdkStatus)
76+
iferr!=nil {
77+
returnxerrors.Errorf("%s user: %w",verb,err)
78+
}
79+
returnnil
80+
},
81+
}
82+
cmd.Flags().StringArrayVarP(&columns,"column","c", []string{"username","email","created_at","status"},
83+
"Specify a column to filter in the table.")
84+
returncmd
85+
}

‎cli/userstatus_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package cli_test
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/cli/clitest"
11+
"github.com/coder/coder/coderd/coderdtest"
12+
"github.com/coder/coder/codersdk"
13+
)
14+
15+
funcTestUserStatus(t*testing.T) {
16+
t.Parallel()
17+
client:=coderdtest.New(t,nil)
18+
admin:=coderdtest.CreateFirstUser(t,client)
19+
other:=coderdtest.CreateAnotherUser(t,client,admin.OrganizationID)
20+
otherUser,err:=other.User(context.Background(),codersdk.Me)
21+
require.NoError(t,err,"fetch user")
22+
23+
//nolint:paralleltest
24+
t.Run("StatusSelf",func(t*testing.T) {
25+
cmd,root:=clitest.New(t,"users","suspend","me")
26+
clitest.SetupConfig(t,client,root)
27+
// Yes to the prompt
28+
cmd.SetIn(bytes.NewReader([]byte("yes\n")))
29+
err:=cmd.Execute()
30+
// Expect an error, as you cannot suspend yourself
31+
require.Error(t,err)
32+
require.ErrorContains(t,err,"cannot suspend yourself")
33+
})
34+
35+
//nolint:paralleltest
36+
t.Run("StatusOther",func(t*testing.T) {
37+
require.Equal(t,otherUser.Status,codersdk.UserStatusActive,"start as active")
38+
39+
cmd,root:=clitest.New(t,"users","suspend",otherUser.Username)
40+
clitest.SetupConfig(t,client,root)
41+
// Yes to the prompt
42+
cmd.SetIn(bytes.NewReader([]byte("yes\n")))
43+
err:=cmd.Execute()
44+
require.NoError(t,err,"suspend user")
45+
46+
// Check the user status
47+
otherUser,err=client.User(context.Background(),otherUser.Username)
48+
require.NoError(t,err,"fetch suspended user")
49+
require.Equal(t,otherUser.Status,codersdk.UserStatusSuspended,"suspended user")
50+
51+
// Set back to active. Try using a uuid as well
52+
cmd,root=clitest.New(t,"users","activate",otherUser.ID.String())
53+
clitest.SetupConfig(t,client,root)
54+
// Yes to the prompt
55+
cmd.SetIn(bytes.NewReader([]byte("yes\n")))
56+
err=cmd.Execute()
57+
require.NoError(t,err,"suspend user")
58+
59+
// Check the user status
60+
otherUser,err=client.User(context.Background(),otherUser.ID.String())
61+
require.NoError(t,err,"fetch active user")
62+
require.Equal(t,otherUser.Status,codersdk.UserStatusActive,"active user")
63+
})
64+
}

‎coderd/autobuild/executor/lifecycle_executor_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) {
7878
require.Empty(t,workspace.AutostartSchedule)
7979

8080
// Given: the workspace template has been updated
81-
orgs,err:=client.OrganizationsByUser(ctx,workspace.OwnerID)
81+
orgs,err:=client.OrganizationsByUser(ctx,workspace.OwnerID.String())
8282
require.NoError(t,err)
8383
require.Len(t,orgs,1)
8484

‎coderd/coderd.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,10 @@ func New(options *Options) (http.Handler, func()) {
239239
r.Use(httpmw.ExtractUserParam(options.Database))
240240
r.Get("/",api.userByName)
241241
r.Put("/profile",api.putUserProfile)
242-
r.Put("/suspend",api.putUserSuspend)
242+
r.Route("/status",func(r chi.Router) {
243+
r.Put("/suspend",api.putUserStatus(database.UserStatusSuspended))
244+
r.Put("/active",api.putUserStatus(database.UserStatusActive))
245+
})
243246
r.Route("/password",func(r chi.Router) {
244247
r.Use(httpmw.WithRBACObject(rbac.ResourceUserPasswordRole))
245248
r.Put("/",authorize(api.putUserPassword,rbac.ActionUpdate))

‎coderd/coderdtest/coderdtest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,15 +254,15 @@ func CreateAnotherUser(t *testing.T, client *codersdk.Client, organizationID uui
254254
}
255255
// TODO: @emyrk switch "other" to "client" when we support updating other
256256
//users.
257-
_,err:=other.UpdateUserRoles(context.Background(),user.ID, codersdk.UpdateRoles{Roles:siteRoles})
257+
_,err:=other.UpdateUserRoles(context.Background(),user.ID.String(), codersdk.UpdateRoles{Roles:siteRoles})
258258
require.NoError(t,err,"update site roles")
259259

260260
// Update org roles
261261
fororgID,roles:=rangeorgRoles {
262262
organizationID,err:=uuid.Parse(orgID)
263263
require.NoError(t,err,fmt.Sprintf("parse org id %q",orgID))
264264
// TODO: @Emyrk add the member to the organization if they do not already belong.
265-
_,err=other.UpdateOrganizationMemberRoles(context.Background(),organizationID,user.ID,
265+
_,err=other.UpdateOrganizationMemberRoles(context.Background(),organizationID,user.ID.String(),
266266
codersdk.UpdateRoles{Roles:append(roles,rbac.RoleOrgMember(organizationID))})
267267
require.NoError(t,err,"update org membership roles")
268268
}

‎coderd/gitsshkey_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestGitSSHKey(t *testing.T) {
2121
ctx:=context.Background()
2222
client:=coderdtest.New(t,nil)
2323
res:=coderdtest.CreateFirstUser(t,client)
24-
key,err:=client.GitSSHKey(ctx,res.UserID)
24+
key,err:=client.GitSSHKey(ctx,res.UserID.String())
2525
require.NoError(t,err)
2626
require.NotEmpty(t,key.PublicKey)
2727
})
@@ -32,7 +32,7 @@ func TestGitSSHKey(t *testing.T) {
3232
SSHKeygenAlgorithm:gitsshkey.AlgorithmEd25519,
3333
})
3434
res:=coderdtest.CreateFirstUser(t,client)
35-
key,err:=client.GitSSHKey(ctx,res.UserID)
35+
key,err:=client.GitSSHKey(ctx,res.UserID.String())
3636
require.NoError(t,err)
3737
require.NotEmpty(t,key.PublicKey)
3838
})
@@ -43,7 +43,7 @@ func TestGitSSHKey(t *testing.T) {
4343
SSHKeygenAlgorithm:gitsshkey.AlgorithmECDSA,
4444
})
4545
res:=coderdtest.CreateFirstUser(t,client)
46-
key,err:=client.GitSSHKey(ctx,res.UserID)
46+
key,err:=client.GitSSHKey(ctx,res.UserID.String())
4747
require.NoError(t,err)
4848
require.NotEmpty(t,key.PublicKey)
4949
})
@@ -54,7 +54,7 @@ func TestGitSSHKey(t *testing.T) {
5454
SSHKeygenAlgorithm:gitsshkey.AlgorithmRSA4096,
5555
})
5656
res:=coderdtest.CreateFirstUser(t,client)
57-
key,err:=client.GitSSHKey(ctx,res.UserID)
57+
key,err:=client.GitSSHKey(ctx,res.UserID.String())
5858
require.NoError(t,err)
5959
require.NotEmpty(t,key.PublicKey)
6060
})
@@ -65,10 +65,10 @@ func TestGitSSHKey(t *testing.T) {
6565
SSHKeygenAlgorithm:gitsshkey.AlgorithmEd25519,
6666
})
6767
res:=coderdtest.CreateFirstUser(t,client)
68-
key1,err:=client.GitSSHKey(ctx,res.UserID)
68+
key1,err:=client.GitSSHKey(ctx,res.UserID.String())
6969
require.NoError(t,err)
7070
require.NotEmpty(t,key1.PublicKey)
71-
key2,err:=client.RegenerateGitSSHKey(ctx,res.UserID)
71+
key2,err:=client.RegenerateGitSSHKey(ctx,res.UserID.String())
7272
require.NoError(t,err)
7373
require.GreaterOrEqual(t,key2.UpdatedAt,key1.UpdatedAt)
7474
require.NotEmpty(t,key2.PublicKey)

‎coderd/roles_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func TestListRoles(t *testing.T) {
107107
member:=coderdtest.CreateAnotherUser(t,client,admin.OrganizationID)
108108
orgAdmin:=coderdtest.CreateAnotherUser(t,client,admin.OrganizationID,rbac.RoleOrgAdmin(admin.OrganizationID))
109109

110-
otherOrg,err:=client.CreateOrganization(ctx,admin.UserID, codersdk.CreateOrganizationRequest{
110+
otherOrg,err:=client.CreateOrganization(ctx,admin.UserID.String(), codersdk.CreateOrganizationRequest{
111111
Name:"other",
112112
})
113113
require.NoError(t,err,"create org")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp