Skip to content

Commit e6a0ec0

Browse files
committed
codersdk client functions, tests
1 parent 0ea9a12 commit e6a0ec0

File tree

5 files changed

+150
-27
lines changed

5 files changed

+150
-27
lines changed

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ func (s *MethodTestSuite) TestOrganization() {
624624
s.Run("InsertOrganization", s.Subtest(func(db database.Store, check *expects) {
625625
check.Args(database.InsertOrganizationParams{
626626
ID: uuid.New(),
627-
Name: "random",
627+
Name: "new-org",
628628
}).Asserts(rbac.ResourceOrganization, policy.ActionCreate)
629629
}))
630630
s.Run("InsertOrganizationMember", s.Subtest(func(db database.Store, check *expects) {
@@ -639,6 +639,29 @@ func (s *MethodTestSuite) TestOrganization() {
639639
rbac.ResourceAssignRole.InOrg(o.ID), policy.ActionAssign,
640640
rbac.ResourceOrganizationMember.InOrg(o.ID).WithID(u.ID), policy.ActionCreate)
641641
}))
642+
s.Run("UpdateOrganization", s.Subtest(func(db database.Store, check *expects) {
643+
ctx := testutil.Context(s.T(), testutil.WaitShort)
644+
o, err := db.InsertOrganization(ctx, database.InsertOrganizationParams{
645+
ID: uuid.New(),
646+
Name: "something-unique",
647+
})
648+
require.NoError(s.T(), err)
649+
check.Args(database.UpdateOrganizationParams{
650+
ID: o.ID,
651+
Name: "something-different",
652+
}).Asserts(rbac.ResourceOrganization, policy.ActionUpdate)
653+
}))
654+
s.Run("DeleteOrganization", s.Subtest(func(db database.Store, check *expects) {
655+
ctx := testutil.Context(s.T(), testutil.WaitShort)
656+
o, err := db.InsertOrganization(ctx, database.InsertOrganizationParams{
657+
ID: uuid.New(),
658+
Name: "doomed",
659+
})
660+
require.NoError(s.T(), err)
661+
check.Args(
662+
o.ID,
663+
).Asserts(rbac.ResourceOrganization, policy.ActionDelete)
664+
}))
642665
s.Run("UpdateMemberRoles", s.Subtest(func(db database.Store, check *expects) {
643666
o := dbgen.Organization(s.T(), db, database.Organization{})
644667
u := dbgen.User(s.T(), db, database.User{})

coderd/organizations.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,14 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
124124
// @Accept json
125125
// @Produce json
126126
// @Tags Organizations
127-
// @Param request body codersdk.PatchOrganizationRequest true "Patch organization request"
127+
// @Param request body codersdk.UpdateOrganizationRequest true "Patch organization request"
128128
// @Success 200 {object} codersdk.Organization
129129
// @Router /organizations/{organization} [patch]
130130
func (api *API) patchOrganization(rw http.ResponseWriter, r *http.Request) {
131131
ctx := r.Context()
132132
organization := httpmw.OrganizationParam(r)
133133

134-
var req codersdk.PatchOrganizationRequest
134+
var req codersdk.UpdateOrganizationRequest
135135
if !httpapi.Read(ctx, rw, r, &req) {
136136
return
137137
}

coderd/organizations_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,70 @@ func TestPostOrganizationsByUser(t *testing.T) {
140140
require.NoError(t, err)
141141
})
142142
}
143+
144+
func TestPatchOrganizationsByUser(t *testing.T) {
145+
t.Parallel()
146+
t.Run("Conflict", func(t *testing.T) {
147+
t.Parallel()
148+
client := coderdtest.New(t, nil)
149+
user := coderdtest.CreateFirstUser(t, client)
150+
151+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
152+
defer cancel()
153+
154+
originalOrg, err := client.Organization(ctx, user.OrganizationID)
155+
require.NoError(t, err)
156+
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
157+
Name: "something-unique",
158+
})
159+
require.NoError(t, err)
160+
161+
_, err = client.UpdateOrganization(ctx, o.ID.String(), codersdk.UpdateOrganizationRequest{
162+
Name: originalOrg.Name,
163+
})
164+
var apiErr *codersdk.Error
165+
require.ErrorAs(t, err, &apiErr)
166+
require.Equal(t, http.StatusConflict, apiErr.StatusCode())
167+
})
168+
169+
t.Run("ReservedName", func(t *testing.T) {
170+
t.Parallel()
171+
client := coderdtest.New(t, nil)
172+
_ = coderdtest.CreateFirstUser(t, client)
173+
174+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
175+
defer cancel()
176+
177+
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
178+
Name: "something-unique",
179+
})
180+
require.NoError(t, err)
181+
182+
_, err = client.UpdateOrganization(ctx, o.ID.String(), codersdk.UpdateOrganizationRequest{
183+
Name: codersdk.DefaultOrganization,
184+
})
185+
var apiErr *codersdk.Error
186+
require.ErrorAs(t, err, &apiErr)
187+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
188+
})
189+
190+
t.Run("Update", func(t *testing.T) {
191+
t.Parallel()
192+
client := coderdtest.New(t, nil)
193+
_ = coderdtest.CreateFirstUser(t, client)
194+
195+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
196+
defer cancel()
197+
198+
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
199+
Name: "new",
200+
})
201+
require.NoError(t, err)
202+
203+
o, err = client.UpdateOrganization(ctx, o.Name, codersdk.UpdateOrganizationRequest{
204+
Name: "new-new",
205+
})
206+
require.NoError(t, err)
207+
require.Equal(t, "new-new", o.Name)
208+
})
209+
}

codersdk/organizations.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ type OrganizationMember struct {
5555
Roles []Role `db:"roles" json:"roles"`
5656
}
5757

58+
type CreateOrganizationRequest struct {
59+
Name string `json:"name" validate:"required,username"`
60+
}
61+
62+
type UpdateOrganizationRequest struct {
63+
Name string `json:"name" validate:"required,username"`
64+
}
65+
5866
// CreateTemplateVersionRequest enables callers to create a new Template Version.
5967
type CreateTemplateVersionRequest struct {
6068
Name string `json:"name,omitempty" validate:"omitempty,template_version_name"`
@@ -187,6 +195,55 @@ func (c *Client) Organization(ctx context.Context, id uuid.UUID) (Organization,
187195
return c.OrganizationByName(ctx, id.String())
188196
}
189197

198+
// CreateOrganization creates an organization and adds the provided user as an admin.
199+
func (c *Client) CreateOrganization(ctx context.Context, req CreateOrganizationRequest) (Organization, error) {
200+
res, err := c.Request(ctx, http.MethodPost, "/api/v2/organizations", req)
201+
if err != nil {
202+
return Organization{}, err
203+
}
204+
defer res.Body.Close()
205+
206+
if res.StatusCode != http.StatusCreated {
207+
return Organization{}, ReadBodyAsError(res)
208+
}
209+
210+
var org Organization
211+
return org, json.NewDecoder(res.Body).Decode(&org)
212+
}
213+
214+
// UpdateOrganization will update information about the corresponding organization, based on
215+
// the UUID/name provided as `orgID`.
216+
func (c *Client) UpdateOrganization(ctx context.Context, orgID string, req UpdateOrganizationRequest) (Organization, error) {
217+
res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/organizations/%s", orgID), req)
218+
if err != nil {
219+
return Organization{}, xerrors.Errorf("execute request: %w", err)
220+
}
221+
defer res.Body.Close()
222+
223+
if res.StatusCode != http.StatusOK {
224+
return Organization{}, ReadBodyAsError(res)
225+
}
226+
227+
var organization Organization
228+
return organization, json.NewDecoder(res.Body).Decode(&organization)
229+
}
230+
231+
// DeleteOrganization will remove the corresponding organization from the deployment, based on
232+
// the UUID/name provided as `orgID`.
233+
func (c *Client) DeleteOrganization(ctx context.Context, orgID string) error {
234+
res, err := c.Request(ctx, http.MethodDelete, fmt.Sprintf("/api/v2/organizations/%s", orgID), nil)
235+
if err != nil {
236+
return xerrors.Errorf("execute request: %w", err)
237+
}
238+
defer res.Body.Close()
239+
240+
if res.StatusCode != http.StatusOK {
241+
return ReadBodyAsError(res)
242+
}
243+
244+
return nil
245+
}
246+
190247
// ProvisionerDaemons returns provisioner daemons available.
191248
func (c *Client) ProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) {
192249
res, err := c.Request(ctx, http.MethodGet,

codersdk/users.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,6 @@ type OAuthConversionResponse struct {
203203
UserID uuid.UUID `json:"user_id" format:"uuid"`
204204
}
205205

206-
type CreateOrganizationRequest struct {
207-
Name string `json:"name" validate:"required,username"`
208-
}
209-
210-
type PatchOrganizationRequest struct {
211-
Name string `json:"name" validate:"required,username"`
212-
}
213-
214206
// AuthMethods contains authentication method information like whether they are enabled or not or custom text, etc.
215207
type AuthMethods struct {
216208
TermsOfServiceURL string `json:"terms_of_service_url,omitempty"`
@@ -591,22 +583,6 @@ func (c *Client) OrganizationByUserAndName(ctx context.Context, user string, nam
591583
return org, json.NewDecoder(res.Body).Decode(&org)
592584
}
593585

594-
// CreateOrganization creates an organization and adds the provided user as an admin.
595-
func (c *Client) CreateOrganization(ctx context.Context, req CreateOrganizationRequest) (Organization, error) {
596-
res, err := c.Request(ctx, http.MethodPost, "/api/v2/organizations", req)
597-
if err != nil {
598-
return Organization{}, err
599-
}
600-
defer res.Body.Close()
601-
602-
if res.StatusCode != http.StatusCreated {
603-
return Organization{}, ReadBodyAsError(res)
604-
}
605-
606-
var org Organization
607-
return org, json.NewDecoder(res.Body).Decode(&org)
608-
}
609-
610586
// AuthMethods returns types of authentication available to the user.
611587
func (c *Client) AuthMethods(ctx context.Context) (AuthMethods, error) {
612588
res, err := c.Request(ctx, http.MethodGet, "/api/v2/users/authmethods", nil)

0 commit comments

Comments
 (0)