Skip to content

Commit fcf02e4

Browse files
ethantkoeniglunny
authored andcommitted
API Endpoints for organization members (#645)
1 parent 3c4d5e1 commit fcf02e4

File tree

3 files changed

+155
-2
lines changed

3 files changed

+155
-2
lines changed

models/user.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,8 +1052,10 @@ func GetUserEmailsByNames(names []string) []string {
10521052
// GetUsersByIDs returns all resolved users from a list of Ids.
10531053
func GetUsersByIDs(ids []int64) ([]*User, error) {
10541054
ous := make([]*User, 0, len(ids))
1055-
err := x.
1056-
In("id", ids).
1055+
if len(ids) == 0 {
1056+
return ous, nil
1057+
}
1058+
err := x.In("id", ids).
10571059
Asc("name").
10581060
Find(&ous)
10591061
return ous, err

routers/api/v1/api.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,16 @@ func RegisterRoutes(m *macaron.Macaron) {
395395
m.Get("/users/:username/orgs", org.ListUserOrgs)
396396
m.Group("/orgs/:orgname", func() {
397397
m.Combo("").Get(org.Get).Patch(bind(api.EditOrgOption{}), org.Edit)
398+
m.Group("/members", func() {
399+
m.Get("", org.ListMembers)
400+
m.Combo("/:username").Get(org.IsMember).Delete(org.DeleteMember)
401+
})
402+
m.Group("/public_members", func() {
403+
m.Get("", org.ListPublicMembers)
404+
m.Combo("/:username").Get(org.IsPublicMember).
405+
Put(org.PublicizeMember).
406+
Delete(org.ConcealMember)
407+
})
398408
m.Combo("/teams").Get(org.ListTeams)
399409
m.Group("/hooks", func() {
400410
m.Combo("").Get(org.ListHooks).

routers/api/v1/org/member.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Copyright 2017 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package org
6+
7+
import (
8+
"fmt"
9+
10+
api "code.gitea.io/sdk/gitea"
11+
12+
"code.gitea.io/gitea/models"
13+
"code.gitea.io/gitea/modules/context"
14+
"code.gitea.io/gitea/modules/setting"
15+
"code.gitea.io/gitea/routers/api/v1/user"
16+
)
17+
18+
// listMembers list an organization's members
19+
func listMembers(ctx *context.APIContext, publicOnly bool) {
20+
var members []*models.User
21+
if publicOnly {
22+
orgUsers, err := models.GetOrgUsersByOrgID(ctx.Org.Organization.ID)
23+
if err != nil {
24+
ctx.Error(500, "GetOrgUsersByOrgID", err)
25+
return
26+
}
27+
28+
memberIDs := make([]int64, 0, len(orgUsers))
29+
for _, orgUser := range orgUsers {
30+
if orgUser.IsPublic {
31+
memberIDs = append(memberIDs, orgUser.UID)
32+
}
33+
}
34+
35+
if members, err = models.GetUsersByIDs(memberIDs); err != nil {
36+
ctx.Error(500, "GetUsersByIDs", err)
37+
return
38+
}
39+
} else {
40+
if err := ctx.Org.Organization.GetMembers(); err != nil {
41+
ctx.Error(500, "GetMembers", err)
42+
return
43+
}
44+
members = ctx.Org.Organization.Members
45+
}
46+
47+
apiMembers := make([]*api.User, len(members))
48+
for i, member := range members {
49+
apiMembers[i] = member.APIFormat()
50+
}
51+
ctx.JSON(200, apiMembers)
52+
}
53+
54+
// ListMembers list an organization's members
55+
func ListMembers(ctx *context.APIContext) {
56+
listMembers(ctx, !ctx.Org.Organization.IsOrgMember(ctx.User.ID))
57+
}
58+
59+
// ListPublicMembers list an organization's public members
60+
func ListPublicMembers(ctx *context.APIContext) {
61+
listMembers(ctx, true)
62+
}
63+
64+
// IsMember check if a user is a member of an organization
65+
func IsMember(ctx *context.APIContext) {
66+
org := ctx.Org.Organization
67+
requester := ctx.User
68+
userToCheck := user.GetUserByParams(ctx)
69+
if org.IsOrgMember(requester.ID) {
70+
if org.IsOrgMember(userToCheck.ID) {
71+
ctx.Status(204)
72+
} else {
73+
ctx.Status(404)
74+
}
75+
} else if requester.ID == userToCheck.ID {
76+
ctx.Status(404)
77+
} else {
78+
redirectURL := fmt.Sprintf("%sapi/v1/orgs/%s/public_members/%s",
79+
setting.AppURL, org.Name, userToCheck.Name)
80+
ctx.Redirect(redirectURL, 302)
81+
}
82+
}
83+
84+
// IsPublicMember check if a user is a public member of an organization
85+
func IsPublicMember(ctx *context.APIContext) {
86+
userToCheck := user.GetUserByParams(ctx)
87+
if userToCheck.IsPublicMember(ctx.Org.Organization.ID) {
88+
ctx.Status(204)
89+
} else {
90+
ctx.Status(404)
91+
}
92+
}
93+
94+
// PublicizeMember make a member's membership public
95+
func PublicizeMember(ctx *context.APIContext) {
96+
userToPublicize := user.GetUserByParams(ctx)
97+
if userToPublicize.ID != ctx.User.ID {
98+
ctx.Error(403, "", "Cannot publicize another member")
99+
return
100+
} else if !ctx.Org.Organization.IsOrgMember(userToPublicize.ID) {
101+
ctx.Error(403, "", "Must be a member of the organization")
102+
return
103+
}
104+
err := models.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToPublicize.ID, true)
105+
if err != nil {
106+
ctx.Error(500, "ChangeOrgUserStatus", err)
107+
return
108+
}
109+
ctx.Status(204)
110+
}
111+
112+
// ConcealMember make a member's membership not public
113+
func ConcealMember(ctx *context.APIContext) {
114+
userToConceal := user.GetUserByParams(ctx)
115+
if userToConceal.ID != ctx.User.ID {
116+
ctx.Error(403, "", "Cannot conceal another member")
117+
return
118+
} else if !ctx.Org.Organization.IsOrgMember(userToConceal.ID) {
119+
ctx.Error(403, "", "Must be a member of the organization")
120+
return
121+
}
122+
err := models.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToConceal.ID, false)
123+
if err != nil {
124+
ctx.Error(500, "ChangeOrgUserStatus", err)
125+
return
126+
}
127+
ctx.Status(204)
128+
}
129+
130+
// DeleteMember remove a member from an organization
131+
func DeleteMember(ctx *context.APIContext) {
132+
org := ctx.Org.Organization
133+
if !org.IsOwnedBy(ctx.User.ID) {
134+
ctx.Error(403, "", "You must be an owner of the organization.")
135+
return
136+
}
137+
if err := org.RemoveMember(user.GetUserByParams(ctx).ID); err != nil {
138+
ctx.Error(500, "RemoveMember", err)
139+
}
140+
ctx.Status(204)
141+
}

0 commit comments

Comments
 (0)