Skip to content

feat: add PUT /api/v2/users/:user-id/suspend endpoint #1154

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 26, 2022
Prev Previous commit
Next Next commit
feat: Add suspend user endpoint
  • Loading branch information
BrunoQuaresma committed Apr 25, 2022
commit d4c75367ad02bcdc65107da4f752a2c116f1fef3
1 change: 1 addition & 0 deletions coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ 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.Get("/organizations", api.organizationsByUser)
r.Post("/organizations", api.postOrganizationsByUser)
r.Post("/keys", api.postAPIKey)
Expand Down
19 changes: 19 additions & 0 deletions coderd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,25 @@ func (api *api) putUserProfile(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(rw, http.StatusOK, convertUser(updatedUserProfile))
}

func (api *api) putUserSuspend(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)

suspendedUser, err := api.Database.UpdateUserSuspended(r.Context(), database.UpdateUserSuspendedParams{
ID: user.ID,
Suspended: sql.NullBool{Bool: true},
UpdatedAt: database.Now(),
})

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))
}

// Returns organizations the parameterized user has access to.
func (api *api) organizationsByUser(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)
Expand Down
26 changes: 20 additions & 6 deletions coderd/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,31 @@ func TestUpdateUserProfile(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
me, _ := client.User(context.Background(), codersdk.Me)
userProfile, err := client.UpdateUserProfile(context.Background(), codersdk.Me, codersdk.UpdateUserProfileRequest{
Username: me.Username,
Email: "newemail@coder.com",
user := coderdtest.CreateFirstUser(t, client)
anotherUser, err := client.CreateUser(context.Background(), codersdk.CreateUserRequest{
Email: "bruno@coder.com",
Username: "bruno",
Password: "password",
OrganizationID: user.OrganizationID,
})
suspendedUser, err := client.SuspendUser(context.Background(), anotherUser.ID)
require.NoError(t, err)
require.Equal(t, userProfile.Username, me.Username)
require.Equal(t, userProfile.Email, "newemail@coder.com")
require.Equal(t, suspendedUser.Suspended, true)
})
}

func TestPutUserSuspend(t *testing.T) {
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
userProfile, err := client.UpdateUserProfile(context.Background(), codersdk.Me, codersdk.UpdateUserProfileRequest{
Username: "newusername",
Email: "newemail@coder.com",
})
require.NoError(t, err)
require.Equal(t, userProfile.Username, "newusername")
require.Equal(t, userProfile.Email, "newemail@coder.com")
}

func TestUserByName(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
Expand Down
15 changes: 15 additions & 0 deletions codersdk/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type User struct {
Email string `json:"email" validate:"required"`
CreatedAt time.Time `json:"created_at" validate:"required"`
Username string `json:"username" validate:"required"`
Suspended bool `json:"suspended"`
}

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

// SuspendUser enables callers to suspend a user
func (c *Client) SuspendUser(ctx context.Context, userID uuid.UUID) (User, error) {
res, err := c.request(ctx, http.MethodPut, fmt.Sprintf("/api/v2/users/%s/suspend", uuidOrMe(userID)), nil)
if err != nil {
return User{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return User{}, readBodyAsError(res)
}
var user User
return user, json.NewDecoder(res.Body).Decode(&user)
}

// CreateAPIKey generates an API key for the user ID provided.
func (c *Client) CreateAPIKey(ctx context.Context, userID uuid.UUID) (*GenerateAPIKeyResponse, error) {
res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/users/%s/keys", uuidOrMe(userID)), nil)
Expand Down