Skip to content

Commit 68a5b2b

Browse files
committed
chore: add organization member api + cli
1 parent 44d6913 commit 68a5b2b

File tree

5 files changed

+108
-6
lines changed

5 files changed

+108
-6
lines changed

cli/organization.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ func (r *RootCmd) organizations() *serpent.Command {
2929
r.currentOrganization(),
3030
r.switchOrganization(),
3131
r.createOrganization(),
32-
r.organizationRoles(),
3332
r.organizationMembers(),
33+
r.organizationRoles(),
3434
},
3535
}
3636

cli/organizationmembers.go

+31
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func (r *RootCmd) organizationMembers() *serpent.Command {
1919
Children: []*serpent.Command{
2020
r.listOrganizationMembers(),
2121
r.assignOrganizationRoles(),
22+
r.addOrganizationMember(),
2223
},
2324
Handler: func(inv *serpent.Invocation) error {
2425
return inv.Command.HelpHandler(inv)
@@ -28,6 +29,36 @@ func (r *RootCmd) organizationMembers() *serpent.Command {
2829
return cmd
2930
}
3031

32+
func (r *RootCmd) addOrganizationMember() *serpent.Command {
33+
client := new(codersdk.Client)
34+
35+
cmd := &serpent.Command{
36+
Use: "add <username | user_id>",
37+
Short: "Add a new member to the current organization",
38+
Middleware: serpent.Chain(
39+
r.InitClient(client),
40+
serpent.RequireNArgs(1),
41+
),
42+
Handler: func(inv *serpent.Invocation) error {
43+
ctx := inv.Context()
44+
organization, err := CurrentOrganization(r, inv, client)
45+
if err != nil {
46+
return err
47+
}
48+
user := inv.Args[0]
49+
_, err = client.PostOrganizationMember(ctx, organization.ID, user)
50+
if err != nil {
51+
return xerrors.Errorf("could not add member to organization: %w", err)
52+
}
53+
54+
_, _ = fmt.Fprintln(inv.Stdout, "Organization member added")
55+
return nil
56+
},
57+
}
58+
59+
return cmd
60+
}
61+
3162
func (r *RootCmd) assignOrganizationRoles() *serpent.Command {
3263
client := new(codersdk.Client)
3364

coderd/coderd.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -845,11 +845,20 @@ func New(options *Options) *API {
845845
})
846846

847847
r.Route("/{user}", func(r chi.Router) {
848-
r.Use(
849-
httpmw.ExtractOrganizationMemberParam(options.Database),
850-
)
851-
r.Put("/roles", api.putMemberRoles)
852-
r.Post("/workspaces", api.postWorkspacesByOrganization)
848+
r.Group(func(r chi.Router) {
849+
r.Use(
850+
httpmw.ExtractUserParam(options.Database),
851+
)
852+
r.Post("/", api.postOrganizationMember)
853+
})
854+
855+
r.Group(func(r chi.Router) {
856+
r.Use(
857+
httpmw.ExtractOrganizationMemberParam(options.Database),
858+
)
859+
r.Put("/roles", api.putMemberRoles)
860+
r.Post("/workspaces", api.postWorkspacesByOrganization)
861+
})
853862
})
854863
})
855864
})

coderd/members.go

+48
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,60 @@ import (
99

1010
"github.com/coder/coder/v2/coderd/database"
1111
"github.com/coder/coder/v2/coderd/database/db2sdk"
12+
"github.com/coder/coder/v2/coderd/database/dbtime"
1213
"github.com/coder/coder/v2/coderd/httpapi"
1314
"github.com/coder/coder/v2/coderd/httpmw"
1415
"github.com/coder/coder/v2/coderd/rbac"
1516
"github.com/coder/coder/v2/codersdk"
1617
)
1718

19+
// @Summary Add organization member
20+
// @ID add-organization-member
21+
// @Security CoderSessionToken
22+
// @Accept json
23+
// @Produce json
24+
// @Tags Members
25+
// @Param organization path string true "Organization ID"
26+
// @Param user path string true "User ID, name, or me"
27+
// @Success 200 {object} codersdk.OrganizationMember
28+
// @Router /organizations/{organization}/members/{user} [post]
29+
func (api *API) postOrganizationMember(rw http.ResponseWriter, r *http.Request) {
30+
var (
31+
ctx = r.Context()
32+
organization = httpmw.OrganizationParam(r)
33+
user = httpmw.UserParam(r)
34+
)
35+
36+
member, err := api.Database.InsertOrganizationMember(ctx, database.InsertOrganizationMemberParams{
37+
OrganizationID: organization.ID,
38+
UserID: user.ID,
39+
CreatedAt: dbtime.Now(),
40+
UpdatedAt: dbtime.Now(),
41+
Roles: []string{},
42+
})
43+
if httpapi.Is404Error(err) {
44+
httpapi.ResourceNotFound(rw)
45+
return
46+
}
47+
if err != nil {
48+
httpapi.InternalServerError(rw, err)
49+
return
50+
}
51+
52+
resp, err := convertOrganizationMembers(ctx, api.Database, []database.OrganizationMember{member})
53+
if err != nil {
54+
httpapi.InternalServerError(rw, err)
55+
return
56+
}
57+
58+
if len(resp) == 0 {
59+
httpapi.InternalServerError(rw, xerrors.Errorf("marshal member"))
60+
return
61+
}
62+
63+
httpapi.Write(ctx, rw, http.StatusOK, resp[0])
64+
}
65+
1866
// @Summary List organization members
1967
// @ID list-organization-members
2068
// @Security CoderSessionToken

codersdk/users.go

+14
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,20 @@ func (c *Client) UpdateUserPassword(ctx context.Context, user string, req Update
379379
return nil
380380
}
381381

382+
// PostOrganizationMember adds a user to an organization
383+
func (c *Client) PostOrganizationMember(ctx context.Context, organizationID uuid.UUID, user string) (OrganizationMember, error) {
384+
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/organizations/%s/members/%s", organizationID, user), nil)
385+
if err != nil {
386+
return OrganizationMember{}, err
387+
}
388+
defer res.Body.Close()
389+
if res.StatusCode != http.StatusOK {
390+
return OrganizationMember{}, ReadBodyAsError(res)
391+
}
392+
var member OrganizationMember
393+
return member, json.NewDecoder(res.Body).Decode(&member)
394+
}
395+
382396
// OrganizationMembers lists all members in an organization
383397
func (c *Client) OrganizationMembers(ctx context.Context, organizationID uuid.UUID) ([]OrganizationMemberWithName, error) {
384398
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/members/", organizationID), nil)

0 commit comments

Comments
 (0)