Skip to content

Commit d4c7536

Browse files
committed
feat: Add suspend user endpoint
1 parent c4404cb commit d4c7536

File tree

4 files changed

+55
-6
lines changed

4 files changed

+55
-6
lines changed

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ func New(options *Options) (http.Handler, func()) {
173173
r.Use(httpmw.ExtractUserParam(options.Database))
174174
r.Get("/", api.userByName)
175175
r.Put("/profile", api.putUserProfile)
176+
r.Put("/suspend", api.putUserSuspend)
176177
r.Get("/organizations", api.organizationsByUser)
177178
r.Post("/organizations", api.postOrganizationsByUser)
178179
r.Post("/keys", api.postAPIKey)

coderd/users.go

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

286+
func (api *api) putUserSuspend(rw http.ResponseWriter, r *http.Request) {
287+
user := httpmw.UserParam(r)
288+
289+
suspendedUser, err := api.Database.UpdateUserSuspended(r.Context(), database.UpdateUserSuspendedParams{
290+
ID: user.ID,
291+
Suspended: sql.NullBool{Bool: true},
292+
UpdatedAt: database.Now(),
293+
})
294+
295+
if err != nil {
296+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
297+
Message: fmt.Sprintf("put user suspended: %s", err.Error()),
298+
})
299+
return
300+
}
301+
302+
httpapi.Write(rw, http.StatusOK, convertUser(suspendedUser))
303+
}
304+
286305
// Returns organizations the parameterized user has access to.
287306
func (api *api) organizationsByUser(rw http.ResponseWriter, r *http.Request) {
288307
user := httpmw.UserParam(r)

coderd/users_test.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,31 @@ func TestUpdateUserProfile(t *testing.T) {
274274
t.Parallel()
275275
client := coderdtest.New(t, nil)
276276
coderdtest.CreateFirstUser(t, client)
277-
me, _ := client.User(context.Background(), codersdk.Me)
278-
userProfile, err := client.UpdateUserProfile(context.Background(), codersdk.Me, codersdk.UpdateUserProfileRequest{
279-
Username: me.Username,
280-
Email: "newemail@coder.com",
277+
user := coderdtest.CreateFirstUser(t, client)
278+
anotherUser, err := client.CreateUser(context.Background(), codersdk.CreateUserRequest{
279+
Email: "bruno@coder.com",
280+
Username: "bruno",
281+
Password: "password",
282+
OrganizationID: user.OrganizationID,
281283
})
284+
suspendedUser, err := client.SuspendUser(context.Background(), anotherUser.ID)
282285
require.NoError(t, err)
283-
require.Equal(t, userProfile.Username, me.Username)
284-
require.Equal(t, userProfile.Email, "newemail@coder.com")
286+
require.Equal(t, suspendedUser.Suspended, true)
285287
})
286288
}
287289

290+
func TestPutUserSuspend(t *testing.T) {
291+
client := coderdtest.New(t, nil)
292+
coderdtest.CreateFirstUser(t, client)
293+
userProfile, err := client.UpdateUserProfile(context.Background(), codersdk.Me, codersdk.UpdateUserProfileRequest{
294+
Username: "newusername",
295+
Email: "newemail@coder.com",
296+
})
297+
require.NoError(t, err)
298+
require.Equal(t, userProfile.Username, "newusername")
299+
require.Equal(t, userProfile.Email, "newemail@coder.com")
300+
}
301+
288302
func TestUserByName(t *testing.T) {
289303
t.Parallel()
290304
client := coderdtest.New(t, nil)

codersdk/users.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type User struct {
3434
Email string `json:"email" validate:"required"`
3535
CreatedAt time.Time `json:"created_at" validate:"required"`
3636
Username string `json:"username" validate:"required"`
37+
Suspended bool `json:"suspended"`
3738
}
3839

3940
type CreateFirstUserRequest struct {
@@ -155,6 +156,20 @@ func (c *Client) UpdateUserProfile(ctx context.Context, userID uuid.UUID, req Up
155156
return user, json.NewDecoder(res.Body).Decode(&user)
156157
}
157158

159+
// SuspendUser enables callers to suspend a user
160+
func (c *Client) SuspendUser(ctx context.Context, userID uuid.UUID) (User, error) {
161+
res, err := c.request(ctx, http.MethodPut, fmt.Sprintf("/api/v2/users/%s/suspend", uuidOrMe(userID)), nil)
162+
if err != nil {
163+
return User{}, err
164+
}
165+
defer res.Body.Close()
166+
if res.StatusCode != http.StatusOK {
167+
return User{}, readBodyAsError(res)
168+
}
169+
var user User
170+
return user, json.NewDecoder(res.Body).Decode(&user)
171+
}
172+
158173
// CreateAPIKey generates an API key for the user ID provided.
159174
func (c *Client) CreateAPIKey(ctx context.Context, userID uuid.UUID) (*GenerateAPIKeyResponse, error) {
160175
res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/users/%s/keys", uuidOrMe(userID)), nil)

0 commit comments

Comments
 (0)