diff options
author | SpaWn2KiLl <SpaWn2KiLl@users.noreply.github.com> | 2020-01-24 19:00:29 +0000 |
---|---|---|
committer | techknowlogick <techknowlogick@gitea.io> | 2020-01-24 14:00:29 -0500 |
commit | 1f01f53c53ea75634f981611635be49c69e1920b (patch) | |
tree | dd99285ba1d9a8a888f8deccef7865e53901d859 /models | |
parent | 333401e0fdca1abe096257479e7090c6e69985ec (diff) | |
download | gitea-1f01f53c53ea75634f981611635be49c69e1920b.tar.gz gitea-1f01f53c53ea75634f981611635be49c69e1920b.zip |
API add/generalize pagination (#9452)
* paginate results
* fixed deadlock
* prevented breaking change
* updated swagger
* go fmt
* fixed find topic
* go mod tidy
* go mod vendor with go1.13.5
* fixed repo find topics
* fixed unit test
* added Limit method to Engine struct; use engine variable when provided; fixed gitignore
* use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors
* set Page value on Home route
* improved memory allocations
* fixed response headers
* removed logfiles
* fixed import order
* import order
* improved swagger
* added function to get models.ListOptions from context
* removed pagesize diff on unit test
* fixed imports
* removed unnecessary struct field
* fixed go fmt
* scoped PR
* code improvements
* code improvements
* go mod tidy
* fixed import order
* fixed commit statuses session
* fixed files headers
* fixed headers; added pagination for notifications
* go mod tidy
* go fmt
* removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list
* Apply suggestions from code review
Co-Authored-By: 6543 <6543@obermui.de>
Co-Authored-By: zeripath <art27@cantab.net>
* fixed build error
* CI.restart()
* fixed merge conflicts resolve
* fixed conflicts resolve
* improved FindTrackedTimesOptions.ToOptions() method
* added backwards compatibility on ListReleases request; fixed issue tracked time ToSession
* fixed build error; fixed swagger template
* fixed swagger template
* fixed ListReleases backwards compatibility
* added page to user search route
Co-authored-by: techknowlogick <matti@mdranta.net>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
Diffstat (limited to 'models')
47 files changed, 506 insertions, 285 deletions
diff --git a/models/access.go b/models/access.go index 94defbb196..c509867062 100644 --- a/models/access.go +++ b/models/access.go @@ -215,7 +215,7 @@ func (repo *Repository) refreshAccesses(e Engine, accessMap map[int64]*userAcces // refreshCollaboratorAccesses retrieves repository collaborations with their access modes. func (repo *Repository) refreshCollaboratorAccesses(e Engine, accessMap map[int64]*userAccess) error { - collaborators, err := repo.getCollaborators(e) + collaborators, err := repo.getCollaborators(e, ListOptions{}) if err != nil { return fmt.Errorf("getCollaborations: %v", err) } diff --git a/models/commit_status.go b/models/commit_status.go index 4102e731e1..ed6f8702c5 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -104,7 +104,7 @@ func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus { // CommitStatusOptions holds the options for query commit statuses type CommitStatusOptions struct { - Page int + ListOptions State string SortType string } @@ -114,18 +114,22 @@ func GetCommitStatuses(repo *Repository, sha string, opts *CommitStatusOptions) if opts.Page <= 0 { opts.Page = 1 } + if opts.PageSize <= 0 { + opts.Page = ItemsPerPage + } countSession := listCommitStatusesStatement(repo, sha, opts) + countSession = opts.setSessionPagination(countSession) maxResults, err := countSession.Count(new(CommitStatus)) if err != nil { log.Error("Count PRs: %v", err) return nil, maxResults, err } - statuses := make([]*CommitStatus, 0, ItemsPerPage) + statuses := make([]*CommitStatus, 0, opts.PageSize) findSession := listCommitStatusesStatement(repo, sha, opts) + findSession = opts.setSessionPagination(findSession) sortCommitStatusesSession(findSession, opts.SortType) - findSession.Limit(ItemsPerPage, (opts.Page-1)*ItemsPerPage) return statuses, maxResults, findSession.Find(&statuses) } diff --git a/models/gpg_key.go b/models/gpg_key.go index 58eaa61e22..643aa6822c 100644 --- a/models/gpg_key.go +++ b/models/gpg_key.go @@ -64,9 +64,14 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) { } // ListGPGKeys returns a list of public keys belongs to given user. -func ListGPGKeys(uid int64) ([]*GPGKey, error) { - keys := make([]*GPGKey, 0, 5) - return keys, x.Where("owner_id=? AND primary_key_id=''", uid).Find(&keys) +func ListGPGKeys(uid int64, listOptions ListOptions) ([]*GPGKey, error) { + sess := x.Where("owner_id=? AND primary_key_id=''", uid) + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + } + + keys := make([]*GPGKey, 0, 2) + return keys, sess.Find(&keys) } // GetGPGKeyByID returns public key by given ID. @@ -628,7 +633,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification { // Now try to associate the signature with the committer, if present if committer.ID != 0 { - keys, err := ListGPGKeys(committer.ID) + keys, err := ListGPGKeys(committer.ID, ListOptions{}) if err != nil { //Skipping failed to get gpg keys of user log.Error("ListGPGKeys: %v", err) return &CommitVerification{ diff --git a/models/issue.go b/models/issue.go index 7976366058..c0be987ac9 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1103,13 +1103,12 @@ func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { // IssuesOptions represents options of an issue. type IssuesOptions struct { + ListOptions RepoIDs []int64 // include all repos if empty AssigneeID int64 PosterID int64 MentionedID int64 MilestoneID int64 - Page int - PageSize int IsClosed util.OptionalBool IsPull util.OptionalBool LabelIDs []int64 diff --git a/models/issue_comment.go b/models/issue_comment.go index a2e1987746..4abc3f9c1f 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -777,6 +777,7 @@ func GetCommentByID(id int64) (*Comment, error) { // FindCommentsOptions describes the conditions to Find comments type FindCommentsOptions struct { + ListOptions RepoID int64 IssueID int64 ReviewID int64 @@ -814,6 +815,11 @@ func findComments(e Engine, opts FindCommentsOptions) ([]*Comment, error) { if opts.RepoID > 0 { sess.Join("INNER", "issue", "issue.id = comment.issue_id") } + + if opts.Page != 0 { + sess = opts.setSessionPagination(sess) + } + return comments, sess. Asc("comment.created_unix"). Asc("comment.id"). diff --git a/models/issue_label.go b/models/issue_label.go index 66f93f4f48..abf0521cea 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -1,4 +1,5 @@ // Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2020 The Gitea Authors. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -298,7 +299,7 @@ func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) { Find(&labels) } -func getLabelsByRepoID(e Engine, repoID int64, sortType string) ([]*Label, error) { +func getLabelsByRepoID(e Engine, repoID int64, sortType string, listOptions ListOptions) ([]*Label, error) { labels := make([]*Label, 0, 10) sess := e.Where("repo_id = ?", repoID) @@ -313,12 +314,16 @@ func getLabelsByRepoID(e Engine, repoID int64, sortType string) ([]*Label, error sess.Asc("name") } + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + } + return labels, sess.Find(&labels) } // GetLabelsByRepoID returns all labels that belong to given repository by ID. -func GetLabelsByRepoID(repoID int64, sortType string) ([]*Label, error) { - return getLabelsByRepoID(x, repoID, sortType) +func GetLabelsByRepoID(repoID int64, sortType string, listOptions ListOptions) ([]*Label, error) { + return getLabelsByRepoID(x, repoID, sortType, listOptions) } func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) { diff --git a/models/issue_label_test.go b/models/issue_label_test.go index 3cf6cc0e57..e0aaf82f76 100644 --- a/models/issue_label_test.go +++ b/models/issue_label_test.go @@ -131,7 +131,7 @@ func TestGetLabelsInRepoByIDs(t *testing.T) { func TestGetLabelsByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) testSuccess := func(repoID int64, sortType string, expectedIssueIDs []int64) { - labels, err := GetLabelsByRepoID(repoID, sortType) + labels, err := GetLabelsByRepoID(repoID, sortType, ListOptions{}) assert.NoError(t, err) assert.Len(t, labels, len(expectedIssueIDs)) for i, label := range labels { diff --git a/models/issue_milestone.go b/models/issue_milestone.go index f33ad19ada..68a568b51a 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -221,7 +221,7 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 { } // GetMilestonesByRepoID returns all opened milestones of a repository. -func GetMilestonesByRepoID(repoID int64, state api.StateType) (MilestoneList, error) { +func GetMilestonesByRepoID(repoID int64, state api.StateType, listOptions ListOptions) (MilestoneList, error) { sess := x.Where("repo_id = ?", repoID) switch state { @@ -238,7 +238,11 @@ func GetMilestonesByRepoID(repoID int64, state api.StateType) (MilestoneList, er sess = sess.And("is_closed = ?", false) } - miles := make([]*Milestone, 0, 10) + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + } + + miles := make([]*Milestone, 0, listOptions.PageSize) return miles, sess.Asc("deadline_unix").Asc("id").Find(&miles) } diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go index 5b7d19aa4d..1b7999d40e 100644 --- a/models/issue_milestone_test.go +++ b/models/issue_milestone_test.go @@ -71,7 +71,7 @@ func TestGetMilestonesByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(repoID int64, state api.StateType) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - milestones, err := GetMilestonesByRepoID(repo.ID, state) + milestones, err := GetMilestonesByRepoID(repo.ID, state, ListOptions{}) assert.NoError(t, err) var n int @@ -105,7 +105,7 @@ func TestGetMilestonesByRepoID(t *testing.T) { test(3, api.StateClosed) test(3, api.StateAll) - milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen) + milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen, ListOptions{}) assert.NoError(t, err) assert.Len(t, milestones, 0) } diff --git a/models/issue_reaction.go b/models/issue_reaction.go index 5c3bf9d06e..50b9d6848a 100644 --- a/models/issue_reaction.go +++ b/models/issue_reaction.go @@ -30,6 +30,7 @@ type Reaction struct { // FindReactionsOptions describes the conditions to Find reactions type FindReactionsOptions struct { + ListOptions IssueID int64 CommentID int64 UserID int64 @@ -71,20 +72,28 @@ func FindCommentReactions(comment *Comment) (ReactionList, error) { } // FindIssueReactions returns a ReactionList of all reactions from an issue -func FindIssueReactions(issue *Issue) (ReactionList, error) { +func FindIssueReactions(issue *Issue, listOptions ListOptions) (ReactionList, error) { return findReactions(x, FindReactionsOptions{ - IssueID: issue.ID, - CommentID: -1, + ListOptions: listOptions, + IssueID: issue.ID, + CommentID: -1, }) } func findReactions(e Engine, opts FindReactionsOptions) ([]*Reaction, error) { - reactions := make([]*Reaction, 0, 10) - sess := e.Where(opts.toConds()) - return reactions, sess. + e = e. + Where(opts.toConds()). In("reaction.`type`", setting.UI.Reactions). - Asc("reaction.issue_id", "reaction.comment_id", "reaction.created_unix", "reaction.id"). - Find(&reactions) + Asc("reaction.issue_id", "reaction.comment_id", "reaction.created_unix", "reaction.id") + if opts.Page != 0 { + e = opts.setEnginePagination(e) + + reactions := make([]*Reaction, 0, opts.PageSize) + return reactions, e.Find(&reactions) + } + + reactions := make([]*Reaction, 0, 10) + return reactions, e.Find(&reactions) } func createReaction(e *xorm.Session, opts *ReactionOptions) (*Reaction, error) { diff --git a/models/issue_stopwatch.go b/models/issue_stopwatch.go index 8047f122b5..ca92141157 100644 --- a/models/issue_stopwatch.go +++ b/models/issue_stopwatch.go @@ -33,9 +33,14 @@ func getStopwatch(e Engine, userID, issueID int64) (sw *Stopwatch, exists bool, } // GetUserStopwatches return list of all stopwatches of a user -func GetUserStopwatches(userID int64) (sws *Stopwatches, err error) { - sws = new(Stopwatches) - err = x.Where("stopwatch.user_id = ?", userID).Find(sws) +func GetUserStopwatches(userID int64, listOptions ListOptions) (*Stopwatches, error) { + sws := new(Stopwatches) + sess := x.Where("stopwatch.user_id = ?", userID) + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + } + + err := sess.Find(sws) if err != nil { return nil, err } diff --git a/models/issue_test.go b/models/issue_test.go index d65345a508..681ef8441a 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -139,24 +139,30 @@ func TestIssues(t *testing.T) { IssuesOptions{ RepoIDs: []int64{1, 3}, SortType: "oldest", - Page: 1, - PageSize: 4, + ListOptions: ListOptions{ + Page: 1, + PageSize: 4, + }, }, []int64{1, 2, 3, 5}, }, { IssuesOptions{ LabelIDs: []int64{1}, - Page: 1, - PageSize: 4, + ListOptions: ListOptions{ + Page: 1, + PageSize: 4, + }, }, []int64{2, 1}, }, { IssuesOptions{ LabelIDs: []int64{1, 2}, - Page: 1, - PageSize: 4, + ListOptions: ListOptions{ + Page: 1, + PageSize: 4, + }, }, []int64{}, // issues with **both** label 1 and 2, none of these issues matches, TODO: add more tests }, diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go index 55e8baacd7..49fefd3279 100644 --- a/models/issue_tracked_time.go +++ b/models/issue_tracked_time.go @@ -10,7 +10,6 @@ import ( "code.gitea.io/gitea/modules/setting" "xorm.io/builder" - "xorm.io/xorm" ) // TrackedTime represents a time that was spent for a specific issue. @@ -71,6 +70,7 @@ func (tl TrackedTimeList) LoadAttributes() (err error) { // FindTrackedTimesOptions represent the filters for tracked times. If an ID is 0 it will be ignored. type FindTrackedTimesOptions struct { + ListOptions IssueID int64 UserID int64 RepositoryID int64 @@ -104,11 +104,19 @@ func (opts *FindTrackedTimesOptions) ToCond() builder.Cond { } // ToSession will convert the given options to a xorm Session by using the conditions from ToCond and joining with issue table if required -func (opts *FindTrackedTimesOptions) ToSession(e Engine) *xorm.Session { +func (opts *FindTrackedTimesOptions) ToSession(e Engine) Engine { + sess := e if opts.RepositoryID > 0 || opts.MilestoneID > 0 { - return e.Join("INNER", "issue", "issue.id = tracked_time.issue_id").Where(opts.ToCond()) + sess = e.Join("INNER", "issue", "issue.id = tracked_time.issue_id") } - return e.Where(opts.ToCond()) + + sess = sess.Where(opts.ToCond()) + + if opts.Page != 0 { + sess = opts.setEnginePagination(sess) + } + + return sess } func getTrackedTimes(e Engine, options FindTrackedTimesOptions) (trackedTimes TrackedTimeList, err error) { diff --git a/models/issue_watch.go b/models/issue_watch.go index 6144d6cafe..343ad16cde 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -77,18 +77,22 @@ func GetIssueWatchersIDs(issueID int64) ([]int64, error) { } // GetIssueWatchers returns watchers/unwatchers of a given issue -func GetIssueWatchers(issueID int64) (IssueWatchList, error) { - return getIssueWatchers(x, issueID) +func GetIssueWatchers(issueID int64, listOptions ListOptions) (IssueWatchList, error) { + return getIssueWatchers(x, issueID, listOptions) } -func getIssueWatchers(e Engine, issueID int64) (watches IssueWatchList, err error) { - err = e. +func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions) (watches IssueWatchList, err error) { + sess := e. Where("`issue_watch`.issue_id = ?", issueID). And("`issue_watch`.is_watching = ?", true). And("`user`.is_active = ?", true). And("`user`.prohibit_login = ?", false). - Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id"). - Find(&watches) + Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id") + + if listOptions.Page == 0 { + sess = listOptions.setSessionPagination(sess) + } + err = sess.Find(&watches) return } diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index 90140591bf..762b1486c6 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -42,22 +42,22 @@ func TestGetIssueWatch(t *testing.T) { func TestGetIssueWatchers(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - iws, err := GetIssueWatchers(1) + iws, err := GetIssueWatchers(1, ListOptions{}) assert.NoError(t, err) // Watcher is inactive, thus 0 assert.Len(t, iws, 0) - iws, err = GetIssueWatchers(2) + iws, err = GetIssueWatchers(2, ListOptions{}) assert.NoError(t, err) // Watcher is explicit not watching assert.Len(t, iws, 0) - iws, err = GetIssueWatchers(5) + iws, err = GetIssueWatchers(5, ListOptions{}) assert.NoError(t, err) // Issue has no Watchers assert.Len(t, iws, 0) - iws, err = GetIssueWatchers(7) + iws, err = GetIssueWatchers(7, ListOptions{}) assert.NoError(t, err) // Issue has one watcher assert.Len(t, iws, 1) diff --git a/models/list_options.go b/models/list_options.go new file mode 100644 index 0000000000..91c4298c85 --- /dev/null +++ b/models/list_options.go @@ -0,0 +1,44 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" +) + +// ListOptions options to paginate results +type ListOptions struct { + PageSize int + Page int +} + +func (opts ListOptions) getPaginatedSession() *xorm.Session { + opts.setDefaultValues() + + return x.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) +} + +func (opts ListOptions) setSessionPagination(sess *xorm.Session) *xorm.Session { + opts.setDefaultValues() + + return sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) +} + +func (opts ListOptions) setEnginePagination(e Engine) Engine { + opts.setDefaultValues() + + return e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) +} + +func (opts ListOptions) setDefaultValues() { + if opts.PageSize <= 0 || opts.PageSize > setting.API.MaxResponseItems { + opts.PageSize = setting.API.MaxResponseItems + } + if opts.Page <= 0 { + opts.Page = 1 + } +} diff --git a/models/models.go b/models/models.go index 74680d847a..239a9cf280 100644 --- a/models/models.go +++ b/models/models.go @@ -44,6 +44,8 @@ type Engine interface { SQL(interface{}, ...interface{}) *xorm.Session Where(interface{}, ...interface{}) *xorm.Session Asc(colNames ...string) *xorm.Session + Limit(limit int, start ...int) *xorm.Session + SumInt(bean interface{}, columnName string) (res int64, err error) } var ( diff --git a/models/notification.go b/models/notification.go index 403c53243d..e7217a6e04 100644 --- a/models/notification.go +++ b/models/notification.go @@ -68,6 +68,7 @@ type Notification struct { // FindNotificationOptions represent the filters for notifications. If an ID is 0 it will be ignored. type FindNotificationOptions struct { + ListOptions UserID int64 RepoID int64 IssueID int64 @@ -102,7 +103,7 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond { // ToSession will convert the given options to a xorm Session by using the conditions from ToCond and joining with issue table if required func (opts *FindNotificationOptions) ToSession(e Engine) *xorm.Session { - return e.Where(opts.ToCond()) + return opts.setSessionPagination(e.Where(opts.ToCond())) } func getNotifications(e Engine, options FindNotificationOptions) (nl NotificationList, err error) { @@ -132,7 +133,7 @@ func CreateOrUpdateIssueNotifications(issueID, commentID int64, notificationAuth } func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notificationAuthorID int64) error { - issueWatches, err := getIssueWatchers(e, issueID) + issueWatches, err := getIssueWatchers(e, issueID, ListOptions{}) if err != nil { return err } diff --git a/models/org.go b/models/org.go index d79c0db84e..176a51ef94 100644 --- a/models/org.go +++ b/models/org.go @@ -62,14 +62,18 @@ func (org *User) getTeams(e Engine) error { Find(&org.Teams) } -// GetTeams returns all teams that belong to organization. -func (org *User) GetTeams() error { +// GetTeams returns paginated teams that belong to organization. +func (org *User) GetTeams(opts *SearchTeamOptions) error { + if opts.Page != 0 { + return org.getTeams(opts.getPaginatedSession()) + } + return org.getTeams(x) } // GetMembers returns all members of organization. func (org *User) GetMembers() (err error) { - org.Members, org.MembersIsPublic, err = FindOrgMembers(FindOrgMembersOpts{ + org.Members, org.MembersIsPublic, err = FindOrgMembers(&FindOrgMembersOpts{ OrgID: org.ID, }) return @@ -77,10 +81,9 @@ func (org *User) GetMembers() (err error) { // FindOrgMembersOpts represensts find org members condtions type FindOrgMembersOpts struct { + ListOptions OrgID int64 PublicOnly bool - Start int - Limit int } // CountOrgMembers counts the organization's members @@ -93,8 +96,8 @@ func CountOrgMembers(opts FindOrgMembersOpts) (int64, error) { } // 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) +func FindOrgMembers(opts *FindOrgMembersOpts) (UserList, map[int64]bool, error) { + ous, err := GetOrgUsersByOrgID(opts) if err != nil { return nil, nil, err } @@ -479,15 +482,20 @@ func GetOrgsCanCreateRepoByUserID(userID int64) ([]*User, error) { } // GetOrgUsersByUserID returns all organization-user relations by user ID. -func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) { +func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUser, error) { ous := make([]*OrgUser, 0, 10) sess := x. Join("LEFT", "`user`", "`org_user`.org_id=`user`.id"). Where("`org_user`.uid=?", uid) - if !all { + if !opts.All { // Only show public organizations sess.And("is_public=?", true) } + + if opts.PageSize != 0 { + sess = opts.setSessionPagination(sess) + } + err := sess. Asc("`user`.name"). Find(&ous) @@ -495,21 +503,24 @@ func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) { } // GetOrgUsersByOrgID returns all organization-user relations by organization ID. -func GetOrgUsersByOrgID(orgID int64, publicOnly bool, start, limit int) ([]*OrgUser, error) { - return getOrgUsersByOrgID(x, orgID, publicOnly, start, limit) +func GetOrgUsersByOrgID(opts *FindOrgMembersOpts) ([]*OrgUser, error) { + return getOrgUsersByOrgID(x, opts) } -func getOrgUsersByOrgID(e Engine, orgID int64, publicOnly bool, start, limit int) ([]*OrgUser, error) { - ous := make([]*OrgUser, 0, 10) - sess := e.Where("org_id=?", orgID) - if publicOnly { +func getOrgUsersByOrgID(e Engine, opts *FindOrgMembersOpts) ([]*OrgUser, error) { + sess := e.Where("org_id=?", opts.OrgID) + if opts.PublicOnly { sess.And("is_public = ?", true) } - if limit > 0 { - sess.Limit(limit, start) + if opts.ListOptions.PageSize > 0 { + sess = opts.setSessionPagination(sess) + + ous := make([]*OrgUser, 0, opts.PageSize) + return ous, sess.Find(&ous) } - err := sess.Find(&ous) - return ous, err + + var ous []*OrgUser + return ous, sess.Find(&ous) } // ChangeOrgUserStatus changes public or private membership status. diff --git a/models/org_team.go b/models/org_team.go index 0c0a1e7b79..214790703c 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -39,12 +39,16 @@ type Team struct { // SearchTeamOptions holds the search options type SearchTeamOptions struct { + ListOptions UserID int64 Keyword string OrgID int64 IncludeDesc bool - PageSize int - Page int +} + +// SearchMembersOptions holds the search options +type SearchMembersOptions struct { + ListOptions } // SearchTeam search for teams. Caller is responsible to check permissions. @@ -160,9 +164,13 @@ func (t *Team) getRepositories(e Engine) error { Find(&t.Repos) } -// GetRepositories returns all repositories in team of organization. -func (t *Team) GetRepositories() error { - return t.getRepositories(x) +// GetRepositories returns paginated repositories in team of organization. +func (t *Team) GetRepositories(opts *SearchTeamOptions) error { + if opts.Page == 0 { + return t.getRepositories(x) + } + + return t.getRepositories(opts.getPaginatedSession()) } func (t *Team) getMembers(e Engine) (err error) { @@ -170,9 +178,13 @@ func (t *Team) getMembers(e Engine) (err error) { return err } -// GetMembers returns all members in team of organization. -func (t *Team) GetMembers() (err error) { - return t.getMembers(x) +// GetMembers returns paginated members in team of organization. +func (t *Team) GetMembers(opts *SearchMembersOptions) (err error) { + if opts.Page == 0 { + return t.getMembers(x) + } + + return t.getMembers(opts.getPaginatedSession()) } // AddMember adds new membership of the team to the organization, @@ -642,7 +654,7 @@ func UpdateTeam(t *Team, authChanged bool, includeAllChanged bool) (err error) { // DeleteTeam deletes given team. // It's caller's responsibility to assign organization ID. func DeleteTeam(t *Team) error { - if err := t.GetRepositories(); err != nil { + if err := t.GetRepositories(&SearchTeamOptions{}); err != nil { return err } @@ -747,11 +759,14 @@ func GetTeamMembers(teamID int64) ([]*User, error) { return getTeamMembers(x, teamID) } -func getUserTeams(e Engine, userID int64) (teams []*Team, err error) { - return teams, e. +func getUserTeams(e Engine, userID int64, listOptions ListOptions) (teams []*Team, err error) { + sess := e. Join("INNER", "team_user", "team_user.team_id = team.id"). - Where("team_user.uid=?", userID). - Find(&teams) + Where("team_user.uid=?", userID) + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + } + return teams, sess.Find(&teams) } func getUserOrgTeams(e Engine, orgID, userID int64) (teams []*Team, err error) { @@ -778,8 +793,8 @@ func GetUserOrgTeams(orgID, userID int64) ([]*Team, error) { } // GetUserTeams returns all teams that user belongs across all organizations. -func GetUserTeams(userID int64) ([]*Team, error) { - return getUserTeams(x, userID) +func GetUserTeams(userID int64, listOptions ListOptions) ([]*Team, error) { + return getUserTeams(x, userID, listOptions) } // AddTeamMember adds new membership of given team to given organization, @@ -795,7 +810,7 @@ func AddTeamMember(team *Team, userID int64) error { } // Get team and its repositories. - if err := team.GetRepositories(); err != nil { + if err := team.GetRepositories(&SearchTeamOptions{}); err != nil { return err } diff --git a/models/org_team_test.go b/models/org_team_test.go index 249e50b072..41040651b4 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -40,7 +40,7 @@ func TestTeam_GetRepositories(t *testing.T) { test := func(teamID int64) { team := AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) - assert.NoError(t, team.GetRepositories()) + assert.NoError(t, team.GetRepositories(&SearchTeamOptions{})) assert.Len(t, team.Repos, team.NumRepos) for _, repo := range team.Repos { AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repo.ID}) @@ -55,7 +55,7 @@ func TestTeam_GetMembers(t *testing.T) { test := func(teamID int64) { team := AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) - assert.NoError(t, team.GetMembers()) + assert.NoError(t, team.GetMembers(&SearchMembersOptions{})) assert.Len(t, team.Members, team.NumMembers) for _, member := range team.Members { AssertExistsAndLoadBean(t, &TeamUser{UID: member.ID, TeamID: teamID}) @@ -286,7 +286,7 @@ func TestGetTeamMembers(t *testing.T) { func TestGetUserTeams(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(userID int64) { - teams, err := GetUserTeams(userID) + teams, err := GetUserTeams(userID, ListOptions{}) assert.NoError(t, err) for _, team := range teams { AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID}) diff --git a/models/org_test.go b/models/org_test.go index ac1a239917..934d5bc4a2 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -86,7 +86,7 @@ func TestUser_GetOwnerTeam(t *testing.T) { func TestUser_GetTeams(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) - assert.NoError(t, org.GetTeams()) + assert.NoError(t, org.GetTeams(&SearchTeamOptions{})) if assert.Len(t, org.Teams, 4) { assert.Equal(t, int64(1), org.Teams[0].ID) assert.Equal(t, int64(2), org.Teams[1].ID) @@ -367,7 +367,7 @@ func TestGetOwnedOrgsByUserIDDesc(t *testing.T) { func TestGetOrgUsersByUserID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - orgUsers, err := GetOrgUsersByUserID(5, true) + orgUsers, err := GetOrgUsersByUserID(5, &SearchOrganizationsOptions{All: true}) assert.NoError(t, err) if assert.Len(t, orgUsers, 2) { assert.Equal(t, OrgUser{ @@ -382,12 +382,12 @@ func TestGetOrgUsersByUserID(t *testing.T) { IsPublic: false}, *orgUsers[1]) } - publicOrgUsers, err := GetOrgUsersByUserID(5, false) + publicOrgUsers, err := GetOrgUsersByUserID(5, &SearchOrganizationsOptions{All: false}) assert.NoError(t, err) assert.Len(t, publicOrgUsers, 1) assert.Equal(t, *orgUsers[0], *publicOrgUsers[0]) - orgUsers, err = GetOrgUsersByUserID(1, true) + orgUsers, err = GetOrgUsersByUserID(1, &SearchOrganizationsOptions{All: true}) assert.NoError(t, err) assert.Len(t, orgUsers, 0) } @@ -395,7 +395,11 @@ func TestGetOrgUsersByUserID(t *testing.T) { func TestGetOrgUsersByOrgID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - orgUsers, err := GetOrgUsersByOrgID(3, false, 0, 0) + orgUsers, err := GetOrgUsersByOrgID(&FindOrgMembersOpts{ + ListOptions: ListOptions{}, + OrgID: 3, + PublicOnly: false, + }) assert.NoError(t, err) if assert.Len(t, orgUsers, 3) { assert.Equal(t, OrgUser{ @@ -410,7 +414,11 @@ func TestGetOrgUsersByOrgID(t *testing.T) { IsPublic: false}, *orgUsers[1]) } - orgUsers, err = GetOrgUsersByOrgID(NonexistentID, false, 0, 0) + orgUsers, err = GetOrgUsersByOrgID(&FindOrgMembersOpts{ + ListOptions: ListOptions{}, + OrgID: NonexistentID, + PublicOnly: false, + }) assert.NoError(t, err) assert.Len(t, orgUsers, 0) } diff --git a/models/pull_list.go b/models/pull_list.go index 1376978353..989de46891 100644 --- a/models/pull_list.go +++ b/models/pull_list.go @@ -16,7 +16,7 @@ import ( // PullRequestsOptions holds the options for PRs type PullRequestsOptions struct { - Page int + ListOptions State string SortType string Labels []string @@ -94,14 +94,14 @@ func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, return nil, maxResults, err } - prs := make([]*PullRequest, 0, ItemsPerPage) findSession, err := listPullRequestStatement(baseRepoID, opts) sortIssuesSession(findSession, opts.SortType, 0) if err != nil { log.Error("listPullRequestStatement: %v", err) return nil, maxResults, err } - findSession.Limit(ItemsPerPage, (opts.Page-1)*ItemsPerPage) + findSession = opts.setSessionPagination(findSession) + prs := make([]*PullRequest, 0, opts.PageSize) return prs, maxResults, findSession.Find(&prs) } diff --git a/models/pull_sign.go b/models/pull_sign.go index 1d3474abe7..6ac2152722 100644 --- a/models/pull_sign.go +++ b/models/pull_sign.go @@ -34,7 +34,7 @@ func (pr *PullRequest) SignMerge(u *User, tmpBasePath, baseCommit, headCommit st case always: break case pubkey: - keys, err := ListGPGKeys(u.ID) + keys, err := ListGPGKeys(u.ID, ListOptions{}) if err != nil { return false, "", err } diff --git a/models/pull_test.go b/models/pull_test.go index 6ceeae6653..0dc3bb86d7 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -55,7 +55,9 @@ func TestPullRequest_GetHeadRepo(t *testing.T) { func TestPullRequestsNewest(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) prs, count, err := PullRequests(1, &PullRequestsOptions{ - Page: 1, + ListOptions: ListOptions{ + Page: 1, + }, State: "open", SortType: "newest", Labels: []string{}, @@ -72,7 +74,9 @@ func TestPullRequestsNewest(t *testing.T) { func TestPullRequestsOldest(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) prs, count, err := PullRequests(1, &PullRequestsOptions{ - Page: 1, + ListOptions: ListOptions{ + Page: 1, + }, State: "open", SortType: "oldest", Labels: []string{}, diff --git a/models/release.go b/models/release.go index 46f9e88752..ebd2b6d384 100644 --- a/models/release.go +++ b/models/release.go @@ -175,6 +175,7 @@ func GetReleaseByID(id int64) (*Release, error) { // FindReleasesOptions describes the conditions to Find releases type FindReleasesOptions struct { + ListOptions IncludeDrafts bool IncludeTags bool TagNames []string @@ -197,17 +198,17 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond { } // GetReleasesByRepoID returns a list of releases of repository. -func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions, page, pageSize int) (rels []*Release, err error) { - if page <= 0 { - page = 1 +func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, error) { + sess := x. + Desc("created_unix", "id"). + Where(opts.toConds(repoID)) + + if opts.PageSize != 0 { + sess = opts.setSessionPagination(sess) } - err = x. - Desc("created_unix", "id"). - Limit(pageSize, (page-1)*pageSize). - Where(opts.toConds(repoID)). - Find(&rels) - return rels, err + rels := make([]*Release, 0, opts.PageSize) + return rels, sess.Find(&rels) } // GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames. diff --git a/models/repo.go b/models/repo.go index ecff8482a7..aa7639e4ba 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1024,7 +1024,7 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error // Give access to all members in teams with access to all repositories. if u.IsOrganization() { - if err := u.GetTeams(); err != nil { + if err := u.GetTeams(&SearchTeamOptions{}); err != nil { return fmt.Errorf("GetTeams: %v", err) } for _, t := range u.Teams { @@ -1141,7 +1141,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } // Remove redundant collaborators. - collaborators, err := repo.getCollaborators(sess) + collaborators, err := repo.getCollaborators(sess, ListOptions{}) if err != nil { return fmt.Errorf("getCollaborators: %v", err) } @@ -1171,7 +1171,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } if newOwner.IsOrganization() { - if err := newOwner.GetTeams(); err != nil { + if err := newOwner.GetTeams(&SearchTeamOptions{}); err != nil { return fmt.Errorf("GetTeams: %v", err) } for _, t := range newOwner.Teams { @@ -1422,7 +1422,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { return err } if org.IsOrganization() { - if err = org.GetTeams(); err != nil { + if err = org.GetTeams(&SearchTeamOptions{}); err != nil { return err } } @@ -1442,7 +1442,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { } // Delete Deploy Keys - deployKeys, err := listDeployKeys(sess, repo.ID) + deployKeys, err := listDeployKeys(sess, repo.ID, ListOptions{}) if err != nil { return fmt.Errorf("listDeployKeys: %v", err) } @@ -1701,25 +1701,22 @@ func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) { } // GetUserRepositories returns a list of repositories of given user. -func GetUserRepositories(userID int64, private bool, page, pageSize int, orderBy string) ([]*Repository, error) { - if len(orderBy) == 0 { - orderBy = "updated_unix DESC" +func GetUserRepositories(opts *SearchRepoOptions) ([]*Repository, error) { + if len(opts.OrderBy) == 0 { + opts.OrderBy = "updated_unix DESC" } sess := x. - Where("owner_id = ?", userID). - OrderBy(orderBy) - if !private { + Where("owner_id = ?", opts.Actor.ID). + OrderBy(opts.OrderBy.String()) + if !opts.Private { sess.And("is_private=?", false) } - if page <= 0 { - page = 1 - } - sess.Limit(pageSize, (page-1)*pageSize) + sess = opts.setSessionPagination(sess) - repos := make([]*Repository, 0, pageSize) - return repos, sess.Find(&repos) + repos := make([]*Repository, 0, opts.PageSize) + return repos, opts.setSessionPagination(sess).Find(&repos) } // GetUserMirrorRepositories returns a list of mirror repositories of given user. @@ -2029,9 +2026,15 @@ func CopyLFS(ctx DBContext, newRepo, oldRepo *Repository) error { } // GetForks returns all the forks of the repository -func (repo *Repository) GetForks() ([]*Repository, error) { - forks := make([]*Repository, 0, repo.NumForks) - return forks, x.Find(&forks, &Repository{ForkID: repo.ID}) +func (repo *Repository) GetForks(listOptions ListOptions) ([]*Repository, error) { + if listOptions.Page == 0 { + forks := make([]*Repository, 0, repo.NumForks) + return forks, x.Find(&forks, &Repository{ForkID: repo.ID}) + } + + sess := listOptions.getPaginatedSession() + forks := make([]*Repository, 0, listOptions.PageSize) + return forks, sess.Find(&forks, &Repository{ForkID: repo.ID}) } // GetUserFork return user forked repository from this repository, if not forked return nil diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index f04507f3e8..8c6ef36230 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -1,4 +1,5 @@ // Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2020 The Gitea Authors. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -52,8 +53,15 @@ func (repo *Repository) AddCollaborator(u *User) error { return sess.Commit() } -func (repo *Repository) getCollaborations(e Engine) ([]*Collaboration, error) { - var collaborations []*Collaboration +func (repo *Repository) getCollaborations(e Engine, listOptions ListOptions) ([]*Collaboration, error) { + if listOptions.Page == 0 { + collaborations := make([]*Collaboration, 0, 8) + return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID}) + } + + e = listOptions.setEnginePagination(e) + + collaborations := make([]*Collaboration, 0, listOptions.PageSize) return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID}) } @@ -63,8 +71,8 @@ type Collaborator struct { Collaboration *Collaboration } -func (repo *Repository) getCollaborators(e Engine) ([]*Collaborator, error) { - collaborations, err := repo.getCollaborations(e) +func (repo *Repository) getCollaborators(e Engine, listOptions ListOptions) ([]*Collaborator, error) { + collaborations, err := repo.getCollaborations(e, listOptions) if err != nil { return nil, fmt.Errorf("getCollaborations: %v", err) } @@ -84,8 +92,8 @@ func (repo *Repository) getCollaborators(e Engine) ([]*Collaborator, error) { } // GetCollaborators returns the collaborators for a repository -func (repo *Repository) GetCollaborators() ([]*Collaborator, error) { - return repo.getCollaborators(x) +func (repo *Repository) GetCollaborators(listOptions ListOptions) ([]*Collaborator, error) { + return repo.getCollaborators(x, listOptions) } func (repo *Repository) getCollaboration(e Engine, uid int64) (*Collaboration, error) { diff --git a/models/repo_collaboration_test.go b/models/repo_collaboration_test.go index 0842212460..7bae27bce0 100644 --- a/models/repo_collaboration_test.go +++ b/models/repo_collaboration_test.go @@ -29,7 +29,7 @@ func TestRepository_GetCollaborators(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(repoID int64) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - collaborators, err := repo.GetCollaborators() + collaborators, err := repo.GetCollaborators(ListOptions{}) assert.NoError(t, err) expectedLen, err := x.Count(&Collaboration{RepoID: repoID}) assert.NoError(t, err) diff --git a/models/repo_generate.go b/models/repo_generate.go index b3230acd06..480683cd4a 100644 --- a/models/repo_generate.go +++ b/models/repo_generate.go @@ -110,7 +110,7 @@ func GenerateGitHooks(ctx DBContext, templateRepo, generateRepo *Repository) err // GenerateWebhooks generates webhooks from a template repository func GenerateWebhooks(ctx DBContext, templateRepo, generateRepo *Repository) error { - templateWebhooks, err := GetWebhooksByRepoID(templateRepo.ID) + templateWebhooks, err := GetWebhooksByRepoID(templateRepo.ID, ListOptions{}) if err != nil { return err } @@ -148,7 +148,7 @@ func GenerateAvatar(ctx DBContext, templateRepo, generateRepo *Repository) error // GenerateIssueLabels generates issue labels from a template repository func GenerateIssueLabels(ctx DBContext, templateRepo, generateRepo *Repository) error { - templateLabels, err := getLabelsByRepoID(ctx.e, templateRepo.ID, "") + templateLabels, err := getLabelsByRepoID(ctx.e, templateRepo.ID, "", ListOptions{}) if err != nil { return err } diff --git a/models/repo_list.go b/models/repo_list.go index 45a506698a..3644b01d82 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -111,6 +111,7 @@ func (repos MirrorRepositoryList) LoadAttributes() error { // SearchRepoOptions holds the search options type SearchRepoOptions struct { + ListOptions Actor *User Keyword string OwnerID int64 @@ -118,11 +119,9 @@ type SearchRepoOptions struct { OrderBy SearchOrderBy Private bool // Include private repositories in results StarredByID int64 - Page int IsProfile bool AllPublic bool // Include also all public repositories of users and public organisations AllLimited bool // Include also all public repositories of limited organisations - PageSize int // Can be smaller than or equal to setting.ExplorePagingNum // None -> include collaborative AND non-collaborative // True -> include just collaborative // False -> incude just non-collaborative diff --git a/models/repo_list_test.go b/models/repo_list_test.go index 07f84207e2..ff8b7eb592 100644 --- a/models/repo_list_test.go +++ b/models/repo_list_test.go @@ -17,9 +17,11 @@ func TestSearchRepository(t *testing.T) { // test search public repository on explore page repos, count, err := SearchRepositoryByName(&SearchRepoOptions{ + ListOptions: ListOptions{ + Page: 1, + PageSize: 10, + }, Keyword: "repo_12", - Page: 1, - PageSize: 10, Collaborate: util.OptionalBoolFalse, }) @@ -30,9 +32,11 @@ func TestSearchRepository(t *testing.T) { assert.Equal(t, int64(1), count) repos, count, err = SearchRepositoryByName(&SearchRepoOptions{ + ListOptions: ListOptions{ + Page: 1, + PageSize: 10, + }, Keyword: "test_repo", - Page: 1, - PageSize: 10, Collaborate: util.OptionalBoolFalse, }) @@ -42,9 +46,11 @@ func TestSearchRepository(t *testing.T) { // test search private repository on explore page repos, count, err = SearchRepositoryByName(&SearchRepoOptions{ + ListOptions: ListOptions{ + Page: 1, + PageSize: 10, + }, Keyword: "repo_13", - Page: 1, - PageSize: 10, Private: true, Collaborate: util.OptionalBoolFalse, }) @@ -56,9 +62,11 @@ func TestSearchRepository(t *testing.T) { assert.Equal(t, int64(1), count) repos, count, err = SearchRepositoryByName(&SearchRepoOptions{ + ListOptions: ListOptions{ + Page: 1, + PageSize: 10, + }, Keyword: "test_repo", - Page: 1, - PageSize: 10, Private: true, Collaborate: util.OptionalBoolFalse, }) @@ -76,9 +84,11 @@ func TestSearchRepository(t *testing.T) { // Test search within description repos, count, err = SearchRepository(&SearchRepoOptions{ + ListOptions: ListOptions{ + Page: 1, + PageSize: 10, + }, Keyword: "description_14", - Page: 1, - PageSize: 10, Collaborate: util.OptionalBoolFalse, IncludeDescription: true, }) @@ -91,9 +101,11 @@ func TestSearchRepository(t *testing.T) { // Test NOT search within description repos, count, err = SearchRepository(&SearchRepoOptions{ + ListOptions: ListOptions{ + Page: 1, + PageSize: 10, + }, Keyword: "description_14", - Page: 1, - PageSize: 10, Collaborate: util.OptionalBoolFalse, IncludeDescription: false, }) @@ -108,88 +120,88 @@ func TestSearchRepository(t *testing.T) { count int }{ {name: "PublicRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", PageSize: 10, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse}, count: 7}, {name: "PublicAndPrivateRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", Page: 1, PageSize: 10, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14}, {name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage", - opts: &SearchRepoOptions{Keyword: "big_test_", Page: 1, PageSize: 5, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14}, {name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage", - opts: &SearchRepoOptions{Keyword: "big_test_", Page: 2, PageSize: 5, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14}, {name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage", - opts: &SearchRepoOptions{Keyword: "big_test_", Page: 3, PageSize: 5, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14}, {name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage", - opts: &SearchRepoOptions{Keyword: "big_test_", Page: 3, PageSize: 5, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14}, {name: "PublicRepositoriesOfUser", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse}, count: 2}, {name: "PublicRepositoriesOfUser2", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse}, count: 0}, {name: "PublicRepositoriesOfUser3", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse}, count: 2}, {name: "PublicAndPrivateRepositoriesOfUser", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse}, count: 4}, {name: "PublicAndPrivateRepositoriesOfUser2", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse}, count: 0}, {name: "PublicAndPrivateRepositoriesOfUser3", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse}, count: 4}, {name: "PublicRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15}, count: 5}, {name: "PublicRepositoriesOfUser2IncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 18}, count: 1}, {name: "PublicRepositoriesOfUser3IncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 20}, count: 3}, {name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true}, count: 9}, {name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true}, count: 4}, {name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true}, count: 7}, {name: "PublicRepositoriesOfOrganization", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, count: 1}, {name: "PublicAndPrivateRepositoriesOfOrganization", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse}, count: 2}, {name: "AllPublic/PublicRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", PageSize: 10, AllPublic: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse}, count: 7}, {name: "AllPublic/PublicAndPrivateRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", Page: 1, PageSize: 10, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse}, count: 14}, {name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, count: 25}, {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, count: 30}, {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", - opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, + opts: &SearchRepoOptions{Keyword: "test", ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true}, count: 15}, {name: "AllPublic/PublicAndPrivateRepositoriesOfUser2IncludingCollaborativeByName", - opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 18, Private: true, AllPublic: true}, + opts: &SearchRepoOptions{Keyword: "test", ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, AllPublic: true}, count: 13}, {name: "AllPublic/PublicRepositoriesOfOrganization", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, count: 25}, {name: "AllTemplates", - opts: &SearchRepoOptions{Page: 1, PageSize: 10, Template: util.OptionalBoolTrue}, + opts: &SearchRepoOptions{ListOptions: ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue}, count: 2}, } diff --git a/models/repo_sign.go b/models/repo_sign.go index 64f70ac7bd..8913620fa0 100644 --- a/models/repo_sign.go +++ b/models/repo_sign.go @@ -110,7 +110,7 @@ func SignInitialCommit(repoPath string, u *User) (bool, string, error) { case always: break case pubkey: - keys, err := ListGPGKeys(u.ID) + keys, err := ListGPGKeys(u.ID, ListOptions{}) if err != nil { return false, "", err } @@ -145,7 +145,7 @@ func (repo *Repository) SignWikiCommit(u *User) (bool, string, error) { case always: break case pubkey: - keys, err := ListGPGKeys(u.ID) + keys, err := ListGPGKeys(u.ID, ListOptions{}) if err != nil { return false, "", err } @@ -197,7 +197,7 @@ func (repo *Repository) SignCRUDAction(u *User, tmpBasePath, parentCommit string case always: break case pubkey: - keys, err := ListGPGKeys(u.ID) + keys, err := ListGPGKeys(u.ID, ListOptions{}) if err != nil { return false, "", err } diff --git a/models/repo_watch.go b/models/repo_watch.go index 9b3659dbf5..a9d56eff03 100644 --- a/models/repo_watch.go +++ b/models/repo_watch.go @@ -153,14 +153,18 @@ func GetRepoWatchersIDs(repoID int64) ([]int64, error) { } // GetWatchers returns range of users watching given repository. -func (repo *Repository) GetWatchers(page int) ([]*User, error) { - users := make([]*User, 0, ItemsPerPage) +func (repo *Repository) GetWatchers(opts ListOptions) ([]*User, error) { sess := x.Where("watch.repo_id=?", repo.ID). Join("LEFT", "watch", "`user`.id=`watch`.user_id"). And("`watch`.mode<>?", RepoWatchModeDont) - if page > 0 { - sess = sess.Limit(ItemsPerPage, (page-1)*ItemsPerPage) + if opts.Page > 0 { + sess = opts.setSessionPagination(sess) + users := make([]*User, 0, opts.PageSize) + + return users, sess.Find(&users) } + + users := make([]*User, 0, 8) return users, sess.Find(&users) } diff --git a/models/repo_watch_test.go b/models/repo_watch_test.go index c3d40ec919..e1bbc40238 100644 --- a/models/repo_watch_test.go +++ b/models/repo_watch_test.go @@ -59,7 +59,7 @@ func TestRepository_GetWatchers(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watchers, err := repo.GetWatchers(1) + watchers, err := repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) for _, watcher := range watchers { @@ -67,7 +67,7 @@ func TestRepository_GetWatchers(t *testing.T) { } repo = AssertExistsAndLoadBean(t, &Repository{ID: 9}).(*Repository) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, 0) } @@ -113,7 +113,7 @@ func TestWatchIfAuto(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watchers, err := repo.GetWatchers(1) + watchers, err := repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) @@ -123,13 +123,13 @@ func TestWatchIfAuto(t *testing.T) { // Must not add watch assert.NoError(t, WatchIfAuto(8, 1, true)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch assert.NoError(t, WatchIfAuto(10, 1, true)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) @@ -137,31 +137,31 @@ func TestWatchIfAuto(t *testing.T) { // Must not add watch assert.NoError(t, WatchIfAuto(8, 1, true)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch assert.NoError(t, WatchIfAuto(12, 1, false)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should add watch assert.NoError(t, WatchIfAuto(12, 1, true)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount+1) // Should remove watch, inhibit from adding auto assert.NoError(t, WatchRepo(12, 1, false)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Must not add watch assert.NoError(t, WatchIfAuto(12, 1, true)) - watchers, err = repo.GetWatchers(1) + watchers, err = repo.GetWatchers(ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) } diff --git a/models/ssh_key.go b/models/ssh_key.go index f441c3e42c..d3e9de5770 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -567,11 +567,17 @@ func SearchPublicKey(uid int64, fingerprint string) ([]*PublicKey, error) { } // ListPublicKeys returns a list of public keys belongs to given user. -func ListPublicKeys(uid int64) ([]*PublicKey, error) { +func ListPublicKeys(uid int64, listOptions ListOptions) ([]*PublicKey, error) { + sess := x.Where("owner_id = ?", uid) + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + + keys := make([]*PublicKey, 0, listOptions.PageSize) + return keys, sess.Find(&keys) + } + keys := make([]*PublicKey, 0, 5) - return keys, x. - Where("owner_id = ?", uid). - Find(&keys) + return keys, sess.Find(&keys) } // ListPublicLdapSSHKeys returns a list of synchronized public ldap ssh keys belongs to given user and login source. @@ -970,15 +976,21 @@ func deleteDeployKey(sess Engine, doer *User, id int64) error { } // ListDeployKeys returns all deploy keys by given repository ID. -func ListDeployKeys(repoID int64) ([]*DeployKey, error) { - return listDeployKeys(x, repoID) +func ListDeployKeys(repoID int64, listOptions ListOptions) ([]*DeployKey, error) { + return listDeployKeys(x, repoID, listOptions) } -func listDeployKeys(e Engine, repoID int64) ([]*DeployKey, error) { +func listDeployKeys(e Engine, repoID int64, listOptions ListOptions) ([]*DeployKey, error) { + sess := e.Where("repo_id = ?", repoID) + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + + keys := make([]*DeployKey, 0, listOptions.PageSize) + return keys, sess.Find(&keys) + } + keys := make([]*DeployKey, 0, 5) - return keys, e. - Where("repo_id = ?", repoID). - Find(&keys) + return keys, sess.Find(&keys) } // SearchDeployKeys returns a list of deploy keys matching the provided arguments. diff --git a/models/star.go b/models/star.go index 18d28b558a..4e84a6e4d5 100644 --- a/models/star.go +++ b/models/star.go @@ -64,13 +64,17 @@ func isStaring(e Engine, userID, repoID int64) bool { } // GetStargazers returns the users that starred the repo. -func (repo *Repository) GetStargazers(page int) ([]*User, error) { - users := make([]*User, 0, ItemsPerPage) +func (repo *Repository) GetStargazers(opts ListOptions) ([]*User, error) { sess := x.Where("star.repo_id = ?", repo.ID). Join("LEFT", "star", "`user`.id = star.uid") - if page > 0 { - sess = sess.Limit(ItemsPerPage, (page-1)*ItemsPerPage) + if opts.Page > 0 { + sess = opts.setSessionPagination(sess) + + users := make([]*User, 0, opts.PageSize) + return users, sess.Find(&users) } + + users := make([]*User, 0, 8) return users, sess.Find(&users) } diff --git a/models/star_test.go b/models/star_test.go index 55b4a1cfac..9629238008 100644 --- a/models/star_test.go +++ b/models/star_test.go @@ -33,7 +33,7 @@ func TestRepository_GetStargazers(t *testing.T) { // repo with stargazers assert.NoError(t, PrepareTestDatabase()) repo := AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) - gazers, err := repo.GetStargazers(0) + gazers, err := repo.GetStargazers(ListOptions{Page: 0}) assert.NoError(t, err) if assert.Len(t, gazers, 1) { assert.Equal(t, int64(2), gazers[0].ID) @@ -44,7 +44,7 @@ func TestRepository_GetStargazers2(t *testing.T) { // repo with stargazers assert.NoError(t, PrepareTestDatabase()) repo := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) - gazers, err := repo.GetStargazers(0) + gazers, err := repo.GetStargazers(ListOptions{Page: 0}) assert.NoError(t, err) assert.Len(t, gazers, 0) } diff --git a/models/token.go b/models/token.go index 8bd20a6916..ce3218d8d6 100644 --- a/models/token.go +++ b/models/token.go @@ -78,12 +78,20 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) { } // ListAccessTokens returns a list of access tokens belongs to given user. -func ListAccessTokens(uid int64) ([]*AccessToken, error) { - tokens := make([]*AccessToken, 0, 5) - return tokens, x. +func ListAccessTokens(uid int64, listOptions ListOptions) ([]*AccessToken, error) { + sess := x. Where("uid=?", uid). - Desc("id"). - Find(&tokens) + Desc("id") + + if listOptions.Page == 0 { + sess = listOptions.setSessionPagination(sess) + + tokens := make([]*AccessToken, 0, listOptions.PageSize) + return tokens, sess.Find(&tokens) + } + + tokens := make([]*AccessToken, 0, 5) + return tokens, sess.Find(&tokens) } // UpdateAccessToken updates information of access token. diff --git a/models/token_test.go b/models/token_test.go index a74de8f818..45f50a1b82 100644 --- a/models/token_test.go +++ b/models/token_test.go @@ -47,7 +47,7 @@ func TestGetAccessTokenBySHA(t *testing.T) { func TestListAccessTokens(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - tokens, err := ListAccessTokens(1) + tokens, err := ListAccessTokens(1, ListOptions{}) assert.NoError(t, err) if assert.Len(t, tokens, 2) { assert.Equal(t, int64(1), tokens[0].UID) @@ -56,14 +56,14 @@ func TestListAccessTokens(t *testing.T) { assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B") } - tokens, err = ListAccessTokens(2) + tokens, err = ListAccessTokens(2, ListOptions{}) assert.NoError(t, err) if assert.Len(t, tokens, 1) { assert.Equal(t, int64(2), tokens[0].UID) assert.Equal(t, "Token A", tokens[0].Name) } - tokens, err = ListAccessTokens(100) + tokens, err = ListAccessTokens(100, ListOptions{}) assert.NoError(t, err) assert.Empty(t, tokens) } diff --git a/models/topic.go b/models/topic.go index e4fda03fc4..1a76c49156 100644 --- a/models/topic.go +++ b/models/topic.go @@ -147,10 +147,9 @@ func removeTopicFromRepo(repoID int64, topic *Topic, e Engine) error { // FindTopicOptions represents the options when fdin topics type FindTopicOptions struct { + ListOptions RepoID int64 Keyword string - Limit int - Page int } func (opts *FindTopicOptions) toConds() builder.Cond { @@ -172,8 +171,8 @@ func FindTopics(opts *FindTopicOptions) (topics []*Topic, err error) { if opts.RepoID > 0 { sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") } - if opts.Limit > 0 { - sess.Limit(opts.Limit, opts.Page*opts.Limit) + if opts.PageSize != 0 && opts.Page != 0 { + sess = opts.setSessionPagination(sess) } return topics, sess.Desc("topic.repo_count").Find(&topics) } diff --git a/models/topic_test.go b/models/topic_test.go index c173c7bf2a..b6ef8f565c 100644 --- a/models/topic_test.go +++ b/models/topic_test.go @@ -22,7 +22,7 @@ func TestAddTopic(t *testing.T) { assert.EqualValues(t, totalNrOfTopics, len(topics)) topics, err = FindTopics(&FindTopicOptions{ - Limit: 2, + ListOptions: ListOptions{Page: 1, PageSize: 2}, }) assert.NoError(t, err) assert.EqualValues(t, 2, len(topics)) diff --git a/models/user.go b/models/user.go index c2631d5dd2..d10d2cbff8 100644 --- a/models/user.go +++ b/models/user.go @@ -163,6 +163,12 @@ type User struct { Theme string `xorm:"NOT NULL DEFAULT ''"` } +// SearchOrganizationsOptions options to filter organizations +type SearchOrganizationsOptions struct { + ListOptions + All bool +} + // ColorFormat writes a colored string to identify this struct func (u *User) ColorFormat(s fmt.State) { log.ColorFprintf(s, "%d:%s", @@ -430,12 +436,19 @@ func (u *User) AvatarLink() string { } // GetFollowers returns range of user's followers. -func (u *User) GetFollowers(page int) ([]*User, error) { - users := make([]*User, 0, ItemsPerPage) +func (u *User) GetFollowers(listOptions ListOptions) ([]*User, error) { sess := x. - Limit(ItemsPerPage, (page-1)*ItemsPerPage). Where("follow.follow_id=?", u.ID). Join("LEFT", "follow", "`user`.id=follow.user_id") + + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + + users := make([]*User, 0, listOptions.PageSize) + return users, sess.Find(&users) + } + + users := make([]*User, 0, 8) return users, sess.Find(&users) } @@ -445,12 +458,19 @@ func (u *User) IsFollowing(followID int64) bool { } // GetFollowing returns range of user's following. -func (u *User) GetFollowing(page int) ([]*User, error) { - users := make([]*User, 0, ItemsPerPage) +func (u *User) GetFollowing(listOptions ListOptions) ([]*User, error) { sess := x. - Limit(ItemsPerPage, (page-1)*ItemsPerPage). Where("follow.user_id=?", u.ID). Join("LEFT", "follow", "`user`.id=follow.follow_id") + + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + + users := make([]*User, 0, listOptions.PageSize) + return users, sess.Find(&users) + } + + users := make([]*User, 0, 8) return users, sess.Find(&users) } @@ -616,8 +636,8 @@ func (u *User) GetOrganizationCount() (int64, error) { } // GetRepositories returns repositories that user owns, including private repositories. -func (u *User) GetRepositories(page, pageSize int) (err error) { - u.Repos, err = GetUserRepositories(u.ID, true, page, pageSize, "") +func (u *User) GetRepositories(listOpts ListOptions) (err error) { + u.Repos, err = GetUserRepositories(&SearchRepoOptions{Actor: u, Private: true, ListOptions: listOpts}) return err } @@ -682,9 +702,9 @@ func (u *User) GetOwnedOrganizations() (err error) { return err } -// GetOrganizations returns all organizations that user belongs to. -func (u *User) GetOrganizations(all bool) error { - ous, err := GetOrgUsersByUserID(u.ID, all) +// GetOrganizations returns paginated organizations that user belongs to. +func (u *User) GetOrganizations(opts *SearchOrganizationsOptions) error { + ous, err := GetOrgUsersByUserID(u.ID, opts) if err != nil { return err } @@ -1477,14 +1497,13 @@ func GetUser(user *User) (bool, error) { // SearchUserOptions contains the options for searching type SearchUserOptions struct { + ListOptions Keyword string Type UserType UID int64 OrderBy SearchOrderBy - Page int Visible []structs.VisibleType Actor *User // The user doing the search - PageSize int // Can be smaller than or equal to setting.UI.ExplorePagingNum IsActive util.OptionalBool SearchByEmail bool // Search by email as well as username/full name } @@ -1552,57 +1571,56 @@ func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) { return nil, 0, fmt.Errorf("Count: %v", err) } - if opts.PageSize == 0 || opts.PageSize > setting.UI.ExplorePagingNum { - opts.PageSize = setting.UI.ExplorePagingNum - } - if opts.Page <= 0 { - opts.Page = 1 - } if len(opts.OrderBy) == 0 { opts.OrderBy = SearchOrderByAlphabetically } - sess := x.Where(cond) - if opts.PageSize > 0 { - sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - if opts.PageSize == -1 { - opts.PageSize = int(count) + sess := x.Where(cond).OrderBy(opts.OrderBy.String()) + if opts.Page != 0 { + sess = opts.setSessionPagination(sess) } users = make([]*User, 0, opts.PageSize) - return users, count, sess.OrderBy(opts.OrderBy.String()).Find(&users) + return users, count, sess.Find(&users) } // GetStarredRepos returns the repos starred by a particular user -func GetStarredRepos(userID int64, private bool) ([]*Repository, error) { +func GetStarredRepos(userID int64, private bool, listOptions ListOptions) ([]*Repository, error) { sess := x.Where("star.uid=?", userID). Join("LEFT", "star", "`repository`.id=`star`.repo_id") if !private { sess = sess.And("is_private=?", false) } - repos := make([]*Repository, 0, 10) - err := sess.Find(&repos) - if err != nil { - return nil, err + + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + + repos := make([]*Repository, 0, listOptions.PageSize) + return repos, sess.Find(&repos) } - return repos, nil + + repos := make([]*Repository, 0, 10) + return repos, sess.Find(&repos) } // GetWatchedRepos returns the repos watched by a particular user -func GetWatchedRepos(userID int64, private bool) ([]*Repository, error) { +func GetWatchedRepos(userID int64, private bool, listOptions ListOptions) ([]*Repository, error) { sess := x.Where("watch.user_id=?", userID). And("`watch`.mode<>?", RepoWatchModeDont). Join("LEFT", "watch", "`repository`.id=`watch`.repo_id") if !private { sess = sess.And("is_private=?", false) } - repos := make([]*Repository, 0, 10) - err := sess.Find(&repos) - if err != nil { - return nil, err + + if listOptions.Page != 0 { + sess = listOptions.setSessionPagination(sess) + + repos := make([]*Repository, 0, listOptions.PageSize) + return repos, sess.Find(&repos) } - return repos, nil + + repos := make([]*Repository, 0, 10) + return repos, sess.Find(&repos) } // deleteKeysMarkedForDeletion returns true if ssh keys needs update diff --git a/models/user_test.go b/models/user_test.go index 2232d59963..fa1b0048e1 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -131,19 +131,19 @@ func TestSearchUsers(t *testing.T) { testSuccess(opts, expectedOrgIDs) } - testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 1, PageSize: 2}, + testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1, PageSize: 2}}, []int64{3, 6}) - testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 2, PageSize: 2}, + testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 2, PageSize: 2}}, []int64{7, 17}) - testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 3, PageSize: 2}, + testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 3, PageSize: 2}}, []int64{19, 25}) - testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 4, PageSize: 2}, + testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 4, PageSize: 2}}, []int64{26}) - testOrgSuccess(&SearchUserOptions{Page: 5, PageSize: 2}, + testOrgSuccess(&SearchUserOptions{ListOptions: ListOptions{Page: 5, PageSize: 2}}, []int64{}) // test users @@ -152,20 +152,20 @@ func TestSearchUsers(t *testing.T) { testSuccess(opts, expectedUserIDs) } - testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 1}, + testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}}, []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29}) - testUserSuccess(&SearchUserOptions{Page: 1, IsActive: util.OptionalBoolFalse}, + testUserSuccess(&SearchUserOptions{ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse}, []int64{9}) - testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 1, IsActive: util.OptionalBoolTrue}, + testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 28, 29}) - testUserSuccess(&SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", Page: 1, IsActive: util.OptionalBoolTrue}, + testUserSuccess(&SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, []int64{1, 10, 11, 12, 13, 14, 15, 16, 18}) // order by name asc default - testUserSuccess(&SearchUserOptions{Keyword: "user1", Page: 1, IsActive: util.OptionalBoolTrue}, + testUserSuccess(&SearchUserOptions{Keyword: "user1", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, []int64{1, 10, 11, 12, 13, 14, 15, 16, 18}) } diff --git a/models/userlist.go b/models/userlist.go index 16ec6fee55..7e6cab50ba 100644 --- a/models/userlist.go +++ b/models/userlist.go @@ -97,7 +97,7 @@ func (users UserList) loadTwoFactorStatus(e Engine) (map[int64]*TwoFactor, error //APIFormat return list of users in api format func (users UserList) APIFormat() []*api.User { - var result []*api.User + result := make([]*api.User, 0, len(users)) for _, u := range users { result = append(result, u.APIFormat()) } diff --git a/models/webhook.go b/models/webhook.go index 7eb17caaf6..55f58c64a1 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -274,9 +274,16 @@ func getActiveWebhooksByRepoID(e Engine, repoID int64) ([]*Webhook, error) { } // GetWebhooksByRepoID returns all webhooks of a repository. -func GetWebhooksByRepoID(repoID int64) ([]*Webhook, error) { - webhooks := make([]*Webhook, 0, 5) - return webhooks, x.Find(&webhooks, &Webhook{RepoID: repoID}) +func GetWebhooksByRepoID(repoID int64, listOptions ListOptions) ([]*Webhook, error) { + if listOptions.Page == 0 { + webhooks := make([]*Webhook, 0, 5) + return webhooks, x.Find(&webhooks, &Webhook{RepoID: repoID}) + } + + sess := listOptions.getPaginatedSession() + webhooks := make([]*Webhook, 0, listOptions.PageSize) + + return webhooks, sess.Find(&webhooks, &Webhook{RepoID: repoID}) } // GetActiveWebhooksByOrgID returns all active webhooks for an organization. @@ -292,10 +299,16 @@ func getActiveWebhooksByOrgID(e Engine, orgID int64) (ws []*Webhook, err error) return ws, err } -// GetWebhooksByOrgID returns all webhooks for an organization. -func GetWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) { - err = x.Find(&ws, &Webhook{OrgID: orgID}) - return ws, err +// GetWebhooksByOrgID returns paginated webhooks for an organization. +func GetWebhooksByOrgID(orgID int64, listOptions ListOptions) ([]*Webhook, error) { + if listOptions.Page == 0 { + ws := make([]*Webhook, 0, 5) + return ws, x.Find(&ws, &Webhook{OrgID: orgID}) + } + + sess := listOptions.getPaginatedSession() + ws := make([]*Webhook, 0, listOptions.PageSize) + return ws, sess.Find(&ws, &Webhook{OrgID: orgID}) } // GetDefaultWebhook returns admin-default webhook by given ID. diff --git a/models/webhook_test.go b/models/webhook_test.go index 0fd9b245ca..f8e4234299 100644 --- a/models/webhook_test.go +++ b/models/webhook_test.go @@ -120,7 +120,7 @@ func TestGetActiveWebhooksByRepoID(t *testing.T) { func TestGetWebhooksByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - hooks, err := GetWebhooksByRepoID(1) + hooks, err := GetWebhooksByRepoID(1, ListOptions{}) assert.NoError(t, err) if assert.Len(t, hooks, 2) { assert.Equal(t, int64(1), hooks[0].ID) @@ -140,7 +140,7 @@ func TestGetActiveWebhooksByOrgID(t *testing.T) { func TestGetWebhooksByOrgID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - hooks, err := GetWebhooksByOrgID(3) + hooks, err := GetWebhooksByOrgID(3, ListOptions{}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(3), hooks[0].ID) |