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

Commit65d1557

Browse files
committed
chore: implement api layer for listing organization members
1 parent8b1bc7f commit65d1557

File tree

10 files changed

+353
-0
lines changed

10 files changed

+353
-0
lines changed

‎coderd/apidoc/docs.go

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

‎coderd/apidoc/swagger.json

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

‎coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ func New(options *Options) *API {
837837
})
838838
})
839839
r.Route("/members",func(r chi.Router) {
840+
r.Get("/",api.listMembers)
840841
r.Route("/roles",func(r chi.Router) {
841842
r.Get("/",api.assignableOrgRoles)
842843
r.With(httpmw.RequireExperiment(api.Experiments,codersdk.ExperimentCustomRoles)).

‎coderd/members.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package coderd
33
import (
44
"net/http"
55

6+
"github.com/google/uuid"
7+
68
"github.com/coder/coder/v2/coderd/database/db2sdk"
79
"github.com/coder/coder/v2/coderd/rbac"
810

@@ -12,6 +14,36 @@ import (
1214
"github.com/coder/coder/v2/codersdk"
1315
)
1416

17+
// @Summary List organization members
18+
// @ID list-organization-members
19+
// @Security CoderSessionToken
20+
// @Produce json
21+
// @Tags Members
22+
// @Param organization path string true "Organization ID"
23+
// @Success 200 {object} []codersdk.OrganizationMemberWithName
24+
// @Router /organizations/{organization}/members [get]
25+
func (api*API)listMembers(rw http.ResponseWriter,r*http.Request) {
26+
var (
27+
ctx=r.Context()
28+
organization=httpmw.OrganizationParam(r)
29+
)
30+
31+
members,err:=api.Database.OrganizationMembers(ctx, database.OrganizationMembersParams{
32+
OrganizationID:organization.ID,
33+
UserID:uuid.Nil,
34+
})
35+
ifhttpapi.Is404Error(err) {
36+
httpapi.ResourceNotFound(rw)
37+
return
38+
}
39+
iferr!=nil {
40+
httpapi.InternalServerError(rw,err)
41+
return
42+
}
43+
44+
httpapi.Write(ctx,rw,http.StatusOK,db2sdk.List(members,convertOrganizationMemberRow))
45+
}
46+
1547
// @Summary Assign role to organization member
1648
// @ID assign-role-to-organization-member
1749
// @Security CoderSessionToken
@@ -73,3 +105,12 @@ func convertOrganizationMember(mem database.OrganizationMember) codersdk.Organiz
73105
}
74106
returnconvertedMember
75107
}
108+
109+
funcconvertOrganizationMemberRow(row database.OrganizationMembersRow) codersdk.OrganizationMemberWithName {
110+
convertedMember:= codersdk.OrganizationMemberWithName{
111+
Username:row.Username,
112+
OrganizationMember:convertOrganizationMember(row.OrganizationMember),
113+
}
114+
115+
returnconvertedMember
116+
}

‎coderd/members_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package coderd_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/uuid"
7+
"github.com/stretchr/testify/require"
8+
9+
"github.com/coder/coder/v2/coderd/coderdtest"
10+
"github.com/coder/coder/v2/coderd/database/db2sdk"
11+
"github.com/coder/coder/v2/coderd/rbac"
12+
"github.com/coder/coder/v2/codersdk"
13+
"github.com/coder/coder/v2/testutil"
14+
)
15+
16+
funcTestListMembers(t*testing.T) {
17+
t.Parallel()
18+
19+
t.Run("OK",func(t*testing.T) {
20+
t.Parallel()
21+
owner:=coderdtest.New(t,nil)
22+
first:=coderdtest.CreateFirstUser(t,owner)
23+
24+
client,user:=coderdtest.CreateAnotherUser(t,owner,first.OrganizationID,rbac.ScopedRoleOrgAdmin(first.OrganizationID))
25+
26+
ctx:=testutil.Context(t,testutil.WaitLong)
27+
members,err:=client.OrganizationMembers(ctx,first.OrganizationID)
28+
require.NoError(t,err)
29+
require.Len(t,members,2)
30+
require.ElementsMatch(t,
31+
[]uuid.UUID{first.UserID,user.ID},
32+
db2sdk.List(members,onlyIDs))
33+
})
34+
35+
// Calling it from a user without the org access.
36+
t.Run("NotInOrg",func(t*testing.T) {
37+
t.Parallel()
38+
owner:=coderdtest.New(t,nil)
39+
first:=coderdtest.CreateFirstUser(t,owner)
40+
41+
client,_:=coderdtest.CreateAnotherUser(t,owner,first.OrganizationID,rbac.ScopedRoleOrgAdmin(first.OrganizationID))
42+
43+
ctx:=testutil.Context(t,testutil.WaitLong)
44+
org,err:=owner.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
45+
Name:"test",
46+
DisplayName:"",
47+
Description:"",
48+
})
49+
require.NoError(t,err,"create organization")
50+
51+
// 404 error is expected instead of a 403/401 to not leak existence of
52+
// an organization.
53+
_,err=client.OrganizationMembers(ctx,org.ID)
54+
require.ErrorContains(t,err,"404")
55+
})
56+
}
57+
58+
funconlyIDs(u codersdk.OrganizationMemberWithName) uuid.UUID {
59+
returnu.UserID
60+
}

‎codersdk/organizations.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ type OrganizationMember struct {
5757
Roles []SlimRole`db:"roles" json:"roles"`
5858
}
5959

60+
typeOrganizationMemberWithNamestruct {
61+
Usernamestring`table:"username,default_sort" json:"username"`
62+
OrganizationMember`table:"m,recursive_inline"`
63+
}
64+
6065
typeCreateOrganizationRequeststruct {
6166
Namestring`json:"name" validate:"required,organization_name"`
6267
// DisplayName will default to the same value as `Name` if not provided.

‎codersdk/users.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,20 @@ func (c *Client) UpdateUserPassword(ctx context.Context, user string, req Update
379379
returnnil
380380
}
381381

382+
// OrganizationMembers lists all members in an organization
383+
func (c*Client)OrganizationMembers(ctx context.Context,organizationID uuid.UUID) ([]OrganizationMemberWithName,error) {
384+
res,err:=c.Request(ctx,http.MethodGet,fmt.Sprintf("/api/v2/organizations/%s/members/",organizationID),nil)
385+
iferr!=nil {
386+
returnnil,err
387+
}
388+
deferres.Body.Close()
389+
ifres.StatusCode!=http.StatusOK {
390+
returnnil,ReadBodyAsError(res)
391+
}
392+
varmembers []OrganizationMemberWithName
393+
returnmembers,json.NewDecoder(res.Body).Decode(&members)
394+
}
395+
382396
// UpdateUserRoles grants the userID the specified roles.
383397
// Include ALL roles the user has.
384398
func (c*Client)UpdateUserRoles(ctx context.Context,userstring,reqUpdateRoles) (User,error) {

‎docs/api/members.md

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp