Support pagination of organizations on user settings pages (#16083)
* Add pagination for user setting orgs * Use FindOrgs instead of GetOrgsByUserID * Remove unnecessary functions and fix test * remove unnecessary code
This commit is contained in:
parent
ed23a6c397
commit
c2ab19888f
7 changed files with 108 additions and 34 deletions
|
@ -116,7 +116,10 @@ func doCheckOrgCounts(username string, orgCounts map[string]int, strict bool, ca
|
||||||
Name: username,
|
Name: username,
|
||||||
}).(*models.User)
|
}).(*models.User)
|
||||||
|
|
||||||
orgs, err := models.GetOrgsByUserID(user.ID, true)
|
orgs, err := models.FindOrgs(models.FindOrgOptions{
|
||||||
|
UserID: user.ID,
|
||||||
|
IncludePrivate: true,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
calcOrgCounts := map[string]int{}
|
calcOrgCounts := map[string]int{}
|
||||||
|
|
|
@ -440,24 +440,6 @@ func getUsersWhoCanCreateOrgRepo(e db.Engine, orgID int64) ([]*User, error) {
|
||||||
And("team_user.org_id = ?", orgID).Asc("`user`.name").Find(&users)
|
And("team_user.org_id = ?", orgID).Asc("`user`.name").Find(&users)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrgsByUserID(e db.Engine, userID int64, showAll bool) ([]*Organization, error) {
|
|
||||||
orgs := make([]*Organization, 0, 10)
|
|
||||||
sess := e.Where("`org_user`.uid=?", userID)
|
|
||||||
if !showAll {
|
|
||||||
sess = sess.And("`org_user`.is_public=?", true)
|
|
||||||
}
|
|
||||||
return orgs, sess.
|
|
||||||
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").
|
|
||||||
Asc("`user`.name").
|
|
||||||
Find(&orgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOrgsByUserID returns a list of organizations that the given user ID
|
|
||||||
// has joined.
|
|
||||||
func GetOrgsByUserID(userID int64, showAll bool) ([]*Organization, error) {
|
|
||||||
return getOrgsByUserID(db.GetEngine(db.DefaultContext), userID, showAll)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinimalOrg represents a simple orgnization with only needed columns
|
// MinimalOrg represents a simple orgnization with only needed columns
|
||||||
type MinimalOrg = Organization
|
type MinimalOrg = Organization
|
||||||
|
|
||||||
|
@ -519,6 +501,51 @@ func GetUserOrgsList(user *User) ([]*MinimalOrg, error) {
|
||||||
return orgs, nil
|
return orgs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindOrgOptions finds orgs options
|
||||||
|
type FindOrgOptions struct {
|
||||||
|
db.ListOptions
|
||||||
|
UserID int64
|
||||||
|
IncludePrivate bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder {
|
||||||
|
var cond = builder.Eq{"uid": userID}
|
||||||
|
if !includePrivate {
|
||||||
|
cond["is_public"] = true
|
||||||
|
}
|
||||||
|
return builder.Select("org_id").From("org_user").Where(cond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts FindOrgOptions) toConds() builder.Cond {
|
||||||
|
var cond = builder.NewCond()
|
||||||
|
if opts.UserID > 0 {
|
||||||
|
cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate)))
|
||||||
|
}
|
||||||
|
if !opts.IncludePrivate {
|
||||||
|
cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic})
|
||||||
|
}
|
||||||
|
return cond
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindOrgs returns a list of organizations according given conditions
|
||||||
|
func FindOrgs(opts FindOrgOptions) ([]*Organization, error) {
|
||||||
|
orgs := make([]*Organization, 0, 10)
|
||||||
|
sess := db.GetEngine(db.DefaultContext).
|
||||||
|
Where(opts.toConds()).
|
||||||
|
Asc("`user`.name")
|
||||||
|
if opts.Page > 0 && opts.PageSize > 0 {
|
||||||
|
sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1))
|
||||||
|
}
|
||||||
|
return orgs, sess.Find(&orgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountOrgs returns total count organizations according options
|
||||||
|
func CountOrgs(opts FindOrgOptions) (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).
|
||||||
|
Where(opts.toConds()).
|
||||||
|
Count(new(User))
|
||||||
|
}
|
||||||
|
|
||||||
func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*User, error) {
|
func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*User, error) {
|
||||||
orgs := make([]*User, 0, 10)
|
orgs := make([]*User, 0, 10)
|
||||||
return orgs, sess.
|
return orgs, sess.
|
||||||
|
|
|
@ -307,18 +307,31 @@ func TestIsPublicMembership(t *testing.T) {
|
||||||
test(unittest.NonexistentID, unittest.NonexistentID, false)
|
test(unittest.NonexistentID, unittest.NonexistentID, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOrgsByUserID(t *testing.T) {
|
func TestFindOrgs(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
orgs, err := GetOrgsByUserID(4, true)
|
orgs, err := FindOrgs(FindOrgOptions{
|
||||||
|
UserID: 4,
|
||||||
|
IncludePrivate: true,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, orgs, 1) {
|
if assert.Len(t, orgs, 1) {
|
||||||
assert.EqualValues(t, 3, orgs[0].ID)
|
assert.EqualValues(t, 3, orgs[0].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
orgs, err = GetOrgsByUserID(4, false)
|
orgs, err = FindOrgs(FindOrgOptions{
|
||||||
|
UserID: 4,
|
||||||
|
IncludePrivate: false,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, orgs, 0)
|
assert.Len(t, orgs, 0)
|
||||||
|
|
||||||
|
total, err := CountOrgs(FindOrgOptions{
|
||||||
|
UserID: 4,
|
||||||
|
IncludePrivate: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, total)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOwnedOrgsByUserID(t *testing.T) {
|
func TestGetOwnedOrgsByUserID(t *testing.T) {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
"code.gitea.io/gitea/routers/api/v1/user"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
@ -20,25 +19,31 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func listUserOrgs(ctx *context.APIContext, u *models.User) {
|
func listUserOrgs(ctx *context.APIContext, u *models.User) {
|
||||||
|
|
||||||
listOptions := utils.GetListOptions(ctx)
|
listOptions := utils.GetListOptions(ctx)
|
||||||
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == u.ID)
|
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == u.ID)
|
||||||
|
|
||||||
orgs, err := models.GetOrgsByUserID(u.ID, showPrivate)
|
var opts = models.FindOrgOptions{
|
||||||
|
ListOptions: listOptions,
|
||||||
|
UserID: u.ID,
|
||||||
|
IncludePrivate: showPrivate,
|
||||||
|
}
|
||||||
|
orgs, err := models.FindOrgs(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetOrgsByUserID", err)
|
ctx.Error(http.StatusInternalServerError, "FindOrgs", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
maxResults, err := models.CountOrgs(opts)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "CountOrgs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
maxResults := len(orgs)
|
|
||||||
orgs, _ = util.PaginateSlice(orgs, listOptions.Page, listOptions.PageSize).([]*models.Organization)
|
|
||||||
|
|
||||||
apiOrgs := make([]*api.Organization, len(orgs))
|
apiOrgs := make([]*api.Organization, len(orgs))
|
||||||
for i := range orgs {
|
for i := range orgs {
|
||||||
apiOrgs[i] = convert.ToOrganization(orgs[i])
|
apiOrgs[i] = convert.ToOrganization(orgs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetLinkHeader(maxResults, listOptions.PageSize)
|
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
|
||||||
ctx.SetTotalCountHeader(int64(maxResults))
|
ctx.SetTotalCountHeader(int64(maxResults))
|
||||||
ctx.JSON(http.StatusOK, &apiOrgs)
|
ctx.JSON(http.StatusOK, &apiOrgs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,9 +167,12 @@ func Profile(ctx *context.Context) {
|
||||||
|
|
||||||
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
|
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
|
||||||
|
|
||||||
orgs, err := models.GetOrgsByUserID(ctxUser.ID, showPrivate)
|
orgs, err := models.FindOrgs(models.FindOrgOptions{
|
||||||
|
UserID: ctxUser.ID,
|
||||||
|
IncludePrivate: showPrivate,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetOrgsByUserIDDesc", err)
|
ctx.ServerError("FindOrgs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,12 +214,34 @@ func DeleteAvatar(ctx *context.Context) {
|
||||||
func Organization(ctx *context.Context) {
|
func Organization(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("settings")
|
ctx.Data["Title"] = ctx.Tr("settings")
|
||||||
ctx.Data["PageIsSettingsOrganization"] = true
|
ctx.Data["PageIsSettingsOrganization"] = true
|
||||||
orgs, err := models.GetOrgsByUserID(ctx.User.ID, ctx.IsSigned)
|
|
||||||
|
opts := models.FindOrgOptions{
|
||||||
|
ListOptions: db.ListOptions{
|
||||||
|
PageSize: setting.UI.Admin.UserPagingNum,
|
||||||
|
Page: ctx.FormInt("page"),
|
||||||
|
},
|
||||||
|
UserID: ctx.User.ID,
|
||||||
|
IncludePrivate: ctx.IsSigned,
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Page <= 0 {
|
||||||
|
opts.Page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
orgs, err := models.FindOrgs(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetOrgsByUserID", err)
|
ctx.ServerError("FindOrgs", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
total, err := models.CountOrgs(opts)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("CountOrgs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["Orgs"] = orgs
|
ctx.Data["Orgs"] = orgs
|
||||||
|
pager := context.NewPagination(int(total), opts.PageSize, opts.Page, 5)
|
||||||
|
pager.SetDefaultParams(ctx)
|
||||||
|
ctx.Data["Page"] = pager
|
||||||
ctx.HTML(http.StatusOK, tplSettingsOrganization)
|
ctx.HTML(http.StatusOK, tplSettingsOrganization)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{template "base/paginate" .}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.i18n.Tr "settings.orgs_none"}}
|
{{.i18n.Tr "settings.orgs_none"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Reference in a new issue