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

Commit6996ff5

Browse files
BrunoQuaresmakylecarbs
authored andcommitted
feat: add PUT /api/v2/users/:user-id/suspend endpoint (#1154)
1 parentcc6cfb2 commit6996ff5

File tree

14 files changed

+202
-25
lines changed

14 files changed

+202
-25
lines changed

‎coderd/audit/table.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var AuditableResources = auditMap(map[any]map[string]Action{
4141
"hashed_password":ActionSecret,// A user can change their own password.
4242
"created_at":ActionIgnore,// Never changes.
4343
"updated_at":ActionIgnore,// Changes, but is implicit and not helpful in a diff.
44+
"status":ActionTrack,// A user can update another user status
4445
},
4546
&database.Workspace{}: {
4647
"id":ActionIgnore,// Never changes.

‎coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ func New(options *Options) (http.Handler, func()) {
182182
r.Use(httpmw.ExtractUserParam(options.Database))
183183
r.Get("/",api.userByName)
184184
r.Put("/profile",api.putUserProfile)
185+
r.Put("/suspend",api.putUserSuspend)
185186
r.Get("/organizations",api.organizationsByUser)
186187
r.Post("/organizations",api.postOrganizationsByUser)
187188
r.Post("/keys",api.postAPIKey)

‎coderd/database/databasefake/databasefake.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,7 @@ func (q *fakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParam
11381138
CreatedAt:arg.CreatedAt,
11391139
UpdatedAt:arg.UpdatedAt,
11401140
Username:arg.Username,
1141+
Status:database.UserStatusActive,
11411142
}
11421143
q.users=append(q.users,user)
11431144
returnuser,nil
@@ -1159,6 +1160,22 @@ func (q *fakeQuerier) UpdateUserProfile(_ context.Context, arg database.UpdateUs
11591160
return database.User{},sql.ErrNoRows
11601161
}
11611162

1163+
func (q*fakeQuerier)UpdateUserStatus(_ context.Context,arg database.UpdateUserStatusParams) (database.User,error) {
1164+
q.mutex.Lock()
1165+
deferq.mutex.Unlock()
1166+
1167+
forindex,user:=rangeq.users {
1168+
ifuser.ID!=arg.ID {
1169+
continue
1170+
}
1171+
user.Status=arg.Status
1172+
user.UpdatedAt=arg.UpdatedAt
1173+
q.users[index]=user
1174+
returnuser,nil
1175+
}
1176+
return database.User{},sql.ErrNoRows
1177+
}
1178+
11621179
func (q*fakeQuerier)InsertWorkspace(_ context.Context,arg database.InsertWorkspaceParams) (database.Workspace,error) {
11631180
q.mutex.Lock()
11641181
deferq.mutex.Unlock()

‎coderd/database/dump.sql

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ALTERTABLE ONLY users
2+
DROP COLUMN IF EXISTS status;
3+
4+
DROPTYPE user_status;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CREATETYPEuser_statusAS ENUM ('active','suspended');
2+
3+
ALTERTABLE ONLY users
4+
ADD COLUMN IF NOT EXISTS status user_statusNOT NULL DEFAULT'active';

‎coderd/database/models.go

Lines changed: 26 additions & 6 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

Lines changed: 41 additions & 5 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/users.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,12 @@ ORDER BY
9090
LIMIT
9191
-- A null limit means "no limit", so -1 means return all
9292
NULLIF(@limit_opt ::int,-1);
93+
94+
-- name: UpdateUserStatus :one
95+
UPDATE
96+
users
97+
SET
98+
status= $2,
99+
updated_at= $3
100+
WHERE
101+
id= $1 RETURNING*;

‎coderd/users.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,25 @@ func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) {
281281
httpapi.Write(rw,http.StatusOK,convertUser(updatedUserProfile))
282282
}
283283

284+
func (api*api)putUserSuspend(rw http.ResponseWriter,r*http.Request) {
285+
user:=httpmw.UserParam(r)
286+
287+
suspendedUser,err:=api.Database.UpdateUserStatus(r.Context(), database.UpdateUserStatusParams{
288+
ID:user.ID,
289+
Status:database.UserStatusSuspended,
290+
UpdatedAt:database.Now(),
291+
})
292+
293+
iferr!=nil {
294+
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{
295+
Message:fmt.Sprintf("put user suspended: %s",err.Error()),
296+
})
297+
return
298+
}
299+
300+
httpapi.Write(rw,http.StatusOK,convertUser(suspendedUser))
301+
}
302+
284303
// Returns organizations the parameterized user has access to.
285304
func (api*api)organizationsByUser(rw http.ResponseWriter,r*http.Request) {
286305
user:=httpmw.UserParam(r)
@@ -613,6 +632,7 @@ func convertUser(user database.User) codersdk.User {
613632
Email:user.Email,
614633
CreatedAt:user.CreatedAt,
615634
Username:user.Username,
635+
Status:codersdk.UserStatus(user.Status),
616636
}
617637
}
618638

‎coderd/users_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,38 @@ func TestUpdateUserProfile(t *testing.T) {
286286
})
287287
}
288288

289+
funcTestPutUserSuspend(t*testing.T) {
290+
t.Parallel()
291+
292+
t.Run("SuspendAnotherUser",func(t*testing.T) {
293+
t.Skip()
294+
t.Parallel()
295+
client:=coderdtest.New(t,nil)
296+
me:=coderdtest.CreateFirstUser(t,client)
297+
client.User(context.Background(),codersdk.Me)
298+
user,_:=client.CreateUser(context.Background(), codersdk.CreateUserRequest{
299+
Email:"bruno@coder.com",
300+
Username:"bruno",
301+
Password:"password",
302+
OrganizationID:me.OrganizationID,
303+
})
304+
user,err:=client.SuspendUser(context.Background(),user.ID)
305+
require.NoError(t,err)
306+
require.Equal(t,user.Status,codersdk.UserStatusSuspended)
307+
})
308+
309+
t.Run("SuspendItSelf",func(t*testing.T) {
310+
t.Parallel()
311+
client:=coderdtest.New(t,nil)
312+
coderdtest.CreateFirstUser(t,client)
313+
client.User(context.Background(),codersdk.Me)
314+
suspendedUser,err:=client.SuspendUser(context.Background(),codersdk.Me)
315+
316+
require.NoError(t,err)
317+
require.Equal(t,suspendedUser.Status,codersdk.UserStatusSuspended)
318+
})
319+
}
320+
289321
funcTestUserByName(t*testing.T) {
290322
t.Parallel()
291323
client:=coderdtest.New(t,nil)

‎codersdk/users.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,20 @@ type UsersRequest struct {
2828
Offsetint`json:"offset"`
2929
}
3030

31+
typeUserStatusstring
32+
33+
const (
34+
UserStatusActiveUserStatus="active"
35+
UserStatusSuspendedUserStatus="suspended"
36+
)
37+
3138
// User represents a user in Coder.
3239
typeUserstruct {
33-
ID uuid.UUID`json:"id" validate:"required"`
34-
Emailstring`json:"email" validate:"required"`
35-
CreatedAt time.Time`json:"created_at" validate:"required"`
36-
Usernamestring`json:"username" validate:"required"`
40+
ID uuid.UUID`json:"id" validate:"required"`
41+
Emailstring`json:"email" validate:"required"`
42+
CreatedAt time.Time`json:"created_at" validate:"required"`
43+
Usernamestring`json:"username" validate:"required"`
44+
StatusUserStatus`json:"status"`
3745
}
3846

3947
typeCreateFirstUserRequeststruct {
@@ -146,6 +154,20 @@ func (c *Client) UpdateUserProfile(ctx context.Context, userID uuid.UUID, req Up
146154
returnuser,json.NewDecoder(res.Body).Decode(&user)
147155
}
148156

157+
// SuspendUser enables callers to suspend a user
158+
func (c*Client)SuspendUser(ctx context.Context,userID uuid.UUID) (User,error) {
159+
res,err:=c.request(ctx,http.MethodPut,fmt.Sprintf("/api/v2/users/%s/suspend",uuidOrMe(userID)),nil)
160+
iferr!=nil {
161+
returnUser{},err
162+
}
163+
deferres.Body.Close()
164+
ifres.StatusCode!=http.StatusOK {
165+
returnUser{},readBodyAsError(res)
166+
}
167+
varuserUser
168+
returnuser,json.NewDecoder(res.Body).Decode(&user)
169+
}
170+
149171
// CreateAPIKey generates an API key for the user ID provided.
150172
func (c*Client)CreateAPIKey(ctx context.Context,userID uuid.UUID) (*GenerateAPIKeyResponse,error) {
151173
res,err:=c.request(ctx,http.MethodPost,fmt.Sprintf("/api/v2/users/%s/keys",uuidOrMe(userID)),nil)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp