* Only show part of members on orgnization dashboard and add paging for orgnization members page * fix test * fix typotags/v1.11.0-rc1
- `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page. | - `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page. | ||||
- `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues). | - `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues). | ||||
- `MEMBERS_PAGING_NUM`: **20**: Number of members that are shown in organization members. | |||||
- `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed. | - `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed. | ||||
- `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph. | - `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph. | ||||
- `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install. | - `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install. |
- `EXPLORE_PAGING_NUM`: 探索页面每页显示的仓库数量。 | - `EXPLORE_PAGING_NUM`: 探索页面每页显示的仓库数量。 | ||||
- `ISSUE_PAGING_NUM`: 工单页面每页显示的工单数量。 | - `ISSUE_PAGING_NUM`: 工单页面每页显示的工单数量。 | ||||
- `MEMBERS_PAGING_NUM`: **20**: 组织成员页面每页显示的成员数量。 | |||||
- `FEED_MAX_COMMIT_NUM`: 活动流页面显示的最大提交数量。 | - `FEED_MAX_COMMIT_NUM`: 活动流页面显示的最大提交数量。 | ||||
### UI - Admin (`ui.admin`) | ### UI - Admin (`ui.admin`) |
} | } | ||||
// GetMembers returns all members of organization. | // GetMembers returns all members of organization. | ||||
func (org *User) GetMembers() error { | |||||
ous, err := GetOrgUsersByOrgID(org.ID) | |||||
func (org *User) GetMembers() (err error) { | |||||
org.Members, org.MembersIsPublic, err = FindOrgMembers(FindOrgMembersOpts{ | |||||
OrgID: org.ID, | |||||
}) | |||||
return | |||||
} | |||||
// FindOrgMembersOpts represensts find org members condtions | |||||
type FindOrgMembersOpts struct { | |||||
OrgID int64 | |||||
PublicOnly bool | |||||
Start int | |||||
Limit int | |||||
} | |||||
// CountOrgMembers counts the organization's members | |||||
func CountOrgMembers(opts FindOrgMembersOpts) (int64, error) { | |||||
sess := x.Where("org_id=?", opts.OrgID) | |||||
if opts.PublicOnly { | |||||
sess.And("is_public = ?", true) | |||||
} | |||||
return sess.Count(new(OrgUser)) | |||||
} | |||||
// FindOrgMembers loads organization members according conditions | |||||
func FindOrgMembers(opts FindOrgMembersOpts) (UserList, map[int64]bool, error) { | |||||
ous, err := GetOrgUsersByOrgID(opts.OrgID, opts.PublicOnly, opts.Start, opts.Limit) | |||||
if err != nil { | if err != nil { | ||||
return err | |||||
return nil, nil, err | |||||
} | } | ||||
var ids = make([]int64, len(ous)) | var ids = make([]int64, len(ous)) | ||||
ids[i] = ou.UID | ids[i] = ou.UID | ||||
idsIsPublic[ou.UID] = ou.IsPublic | idsIsPublic[ou.UID] = ou.IsPublic | ||||
} | } | ||||
org.MembersIsPublic = idsIsPublic | |||||
org.Members, err = GetUsersByIDs(ids) | |||||
return err | |||||
users, err := GetUsersByIDs(ids) | |||||
if err != nil { | |||||
return nil, nil, err | |||||
} | |||||
return users, idsIsPublic, nil | |||||
} | } | ||||
// AddMember adds new member to organization. | // AddMember adds new member to organization. | ||||
} | } | ||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID. | // GetOrgUsersByOrgID returns all organization-user relations by organization ID. | ||||
func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) { | |||||
return getOrgUsersByOrgID(x, orgID) | |||||
func GetOrgUsersByOrgID(orgID int64, publicOnly bool, start, limit int) ([]*OrgUser, error) { | |||||
return getOrgUsersByOrgID(x, orgID, publicOnly, start, limit) | |||||
} | } | ||||
func getOrgUsersByOrgID(e Engine, orgID int64) ([]*OrgUser, error) { | |||||
func getOrgUsersByOrgID(e Engine, orgID int64, publicOnly bool, start, limit int) ([]*OrgUser, error) { | |||||
ous := make([]*OrgUser, 0, 10) | ous := make([]*OrgUser, 0, 10) | ||||
err := e. | |||||
Where("org_id=?", orgID). | |||||
Find(&ous) | |||||
sess := e.Where("org_id=?", orgID) | |||||
if publicOnly { | |||||
sess.And("is_public = ?", true) | |||||
} | |||||
if limit > 0 { | |||||
sess.Limit(limit, start) | |||||
} | |||||
err := sess.Find(&ous) | |||||
return ous, err | return ous, err | ||||
} | } | ||||
func TestGetOrgUsersByOrgID(t *testing.T) { | func TestGetOrgUsersByOrgID(t *testing.T) { | ||||
assert.NoError(t, PrepareTestDatabase()) | assert.NoError(t, PrepareTestDatabase()) | ||||
orgUsers, err := GetOrgUsersByOrgID(3) | |||||
orgUsers, err := GetOrgUsersByOrgID(3, false, 0, 0) | |||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
if assert.Len(t, orgUsers, 3) { | if assert.Len(t, orgUsers, 3) { | ||||
assert.Equal(t, OrgUser{ | assert.Equal(t, OrgUser{ | ||||
IsPublic: false}, *orgUsers[1]) | IsPublic: false}, *orgUsers[1]) | ||||
} | } | ||||
orgUsers, err = GetOrgUsersByOrgID(NonexistentID) | |||||
orgUsers, err = GetOrgUsersByOrgID(NonexistentID, false, 0, 0) | |||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
assert.Len(t, orgUsers, 0) | assert.Len(t, orgUsers, 0) | ||||
} | } |
ExplorePagingNum int | ExplorePagingNum int | ||||
IssuePagingNum int | IssuePagingNum int | ||||
RepoSearchPagingNum int | RepoSearchPagingNum int | ||||
MembersPagingNum int | |||||
FeedMaxCommitNum int | FeedMaxCommitNum int | ||||
GraphMaxCommitNum int | GraphMaxCommitNum int | ||||
CodeCommentLines int | CodeCommentLines int | ||||
ExplorePagingNum: 20, | ExplorePagingNum: 20, | ||||
IssuePagingNum: 10, | IssuePagingNum: 10, | ||||
RepoSearchPagingNum: 10, | RepoSearchPagingNum: 10, | ||||
MembersPagingNum: 20, | |||||
FeedMaxCommitNum: 5, | FeedMaxCommitNum: 5, | ||||
GraphMaxCommitNum: 100, | GraphMaxCommitNum: 100, | ||||
CodeCommentLines: 4, | CodeCommentLines: 4, |
// listMembers list an organization's members | // listMembers list an organization's members | ||||
func listMembers(ctx *context.APIContext, publicOnly bool) { | func listMembers(ctx *context.APIContext, publicOnly bool) { | ||||
var members []*models.User | var members []*models.User | ||||
if publicOnly { | |||||
orgUsers, err := models.GetOrgUsersByOrgID(ctx.Org.Organization.ID) | |||||
if err != nil { | |||||
ctx.Error(500, "GetOrgUsersByOrgID", err) | |||||
return | |||||
} | |||||
memberIDs := make([]int64, 0, len(orgUsers)) | |||||
for _, orgUser := range orgUsers { | |||||
if orgUser.IsPublic { | |||||
memberIDs = append(memberIDs, orgUser.UID) | |||||
} | |||||
} | |||||
if members, err = models.GetUsersByIDs(memberIDs); err != nil { | |||||
ctx.Error(500, "GetUsersByIDs", err) | |||||
return | |||||
} | |||||
} else { | |||||
if err := ctx.Org.Organization.GetMembers(); err != nil { | |||||
ctx.Error(500, "GetMembers", err) | |||||
return | |||||
} | |||||
members = ctx.Org.Organization.Members | |||||
members, _, err := models.FindOrgMembers(models.FindOrgMembersOpts{ | |||||
OrgID: ctx.Org.Organization.ID, | |||||
PublicOnly: publicOnly, | |||||
}) | |||||
if err != nil { | |||||
ctx.Error(500, "GetUsersByIDs", err) | |||||
return | |||||
} | } | ||||
apiMembers := make([]*api.User, len(members)) | apiMembers := make([]*api.User, len(members)) |
ctx.Data["Title"] = org.FullName | ctx.Data["Title"] = org.FullName | ||||
ctx.Data["PageIsOrgMembers"] = true | ctx.Data["PageIsOrgMembers"] = true | ||||
if err := org.GetMembers(); err != nil { | |||||
page := ctx.QueryInt("page") | |||||
if page <= 1 { | |||||
page = 1 | |||||
} | |||||
var opts = models.FindOrgMembersOpts{ | |||||
OrgID: org.ID, | |||||
PublicOnly: true, | |||||
} | |||||
if ctx.User != nil { | |||||
isMember, err := ctx.Org.Organization.IsOrgMember(ctx.User.ID) | |||||
if err != nil { | |||||
ctx.Error(500, "IsOrgMember") | |||||
return | |||||
} | |||||
opts.PublicOnly = !isMember | |||||
} | |||||
total, err := models.CountOrgMembers(opts) | |||||
if err != nil { | |||||
ctx.Error(500, "CountOrgMembers") | |||||
return | |||||
} | |||||
pager := context.NewPagination(int(total), setting.UI.MembersPagingNum, page, 5) | |||||
opts.Start = (page - 1) * setting.UI.MembersPagingNum | |||||
opts.Limit = setting.UI.MembersPagingNum | |||||
members, membersIsPublic, err := models.FindOrgMembers(opts) | |||||
if err != nil { | |||||
ctx.ServerError("GetMembers", err) | ctx.ServerError("GetMembers", err) | ||||
return | return | ||||
} | } | ||||
ctx.Data["Members"] = org.Members | |||||
ctx.Data["MembersIsPublicMember"] = org.MembersIsPublic | |||||
ctx.Data["MembersIsUserOrgOwner"] = org.Members.IsUserOrgOwner(org.ID) | |||||
ctx.Data["MembersTwoFaStatus"] = org.Members.GetTwoFaStatus() | |||||
ctx.Data["Page"] = pager | |||||
ctx.Data["Members"] = members | |||||
ctx.Data["MembersIsPublicMember"] = membersIsPublic | |||||
ctx.Data["MembersIsUserOrgOwner"] = members.IsUserOrgOwner(org.ID) | |||||
ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus() | |||||
ctx.HTML(200, tplMembers) | ctx.HTML(200, tplMembers) | ||||
} | } |
return | return | ||||
} | } | ||||
if err := org.GetMembers(); err != nil { | |||||
ctx.ServerError("GetMembers", err) | |||||
var opts = models.FindOrgMembersOpts{ | |||||
OrgID: org.ID, | |||||
PublicOnly: true, | |||||
Limit: 25, | |||||
} | |||||
if ctx.User != nil { | |||||
isMember, err := org.IsOrgMember(ctx.User.ID) | |||||
if err != nil { | |||||
ctx.Error(500, "IsOrgMember") | |||||
return | |||||
} | |||||
opts.PublicOnly = !isMember | |||||
} | |||||
members, _, err := models.FindOrgMembers(opts) | |||||
if err != nil { | |||||
ctx.ServerError("FindOrgMembers", err) | |||||
return | |||||
} | |||||
membersCount, err := models.CountOrgMembers(opts) | |||||
if err != nil { | |||||
ctx.ServerError("CountOrgMembers", err) | |||||
return | return | ||||
} | } | ||||
ctx.Data["Repos"] = repos | ctx.Data["Repos"] = repos | ||||
ctx.Data["Total"] = count | ctx.Data["Total"] = count | ||||
ctx.Data["Members"] = org.Members | |||||
ctx.Data["MembersTotal"] = membersCount | |||||
ctx.Data["Members"] = members | |||||
ctx.Data["Teams"] = org.Teams | ctx.Data["Teams"] = org.Teams | ||||
pager := context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5) | pager := context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5) |
</div> | </div> | ||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
{{template "base/paginate" .}} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
{{template "base/footer" .}} | {{template "base/footer" .}} |