* Add info about list endpoints to CONTRIBUTING.md * Let all list endpoints return X-Total-Count header * Add TODOs for GetCombinedCommitStatusByRef * Fix models/issue_stopwatch.go * Rrefactor models.ListDeployKeys * Introduce helper func and use them for SetLinkHeader related functags/v1.16.0-rc1
@@ -207,6 +207,10 @@ In general, HTTP methods are chosen as follows: | |||
An endpoint which changes/edits an object expects all fields to be optional (except ones to identify the object, which are required). | |||
### Endpoints returning lists should | |||
* support pagination (`page` & `limit` options in query) | |||
* set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444)) | |||
## Developer Certificate of Origin (DCO) | |||
@@ -231,8 +235,8 @@ on, finishing, and issuing releases. The overall goal is to make a | |||
minor release every three or four months, which breaks down into two or three months of | |||
general development followed by one month of testing and polishing | |||
known as the release freeze. All the feature pull requests should be | |||
merged before feature freeze. And, during the frozen period, a corresponding | |||
release branch is open for fixes backported from main branch. Release candidates | |||
merged before feature freeze. And, during the frozen period, a corresponding | |||
release branch is open for fixes backported from main branch. Release candidates | |||
are made during this period for user testing to | |||
obtain a final version that is maintained in this branch. A release is | |||
maintained by issuing patch releases to only correct critical problems |
@@ -30,7 +30,7 @@ func TestAPIGetTrackedTimes(t *testing.T) { | |||
resp := session.MakeRequest(t, req, http.StatusOK) | |||
var apiTimes api.TrackedTimeList | |||
DecodeJSON(t, resp, &apiTimes) | |||
expect, err := models.GetTrackedTimes(models.FindTrackedTimesOptions{IssueID: issue2.ID}) | |||
expect, err := models.GetTrackedTimes(&models.FindTrackedTimesOptions{IssueID: issue2.ID}) | |||
assert.NoError(t, err) | |||
assert.Len(t, apiTimes, 3) | |||
@@ -7,6 +7,7 @@ package integrations | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"net/url" | |||
"testing" | |||
"code.gitea.io/gitea/models" | |||
@@ -15,6 +16,38 @@ import ( | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestAPITopicSearch(t *testing.T) { | |||
defer prepareTestEnv(t)() | |||
searchURL, _ := url.Parse("/api/v1/topics/search") | |||
var topics struct { | |||
TopicNames []*api.TopicResponse `json:"topics"` | |||
} | |||
query := url.Values{"page": []string{"1"}, "limit": []string{"4"}} | |||
searchURL.RawQuery = query.Encode() | |||
res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) | |||
DecodeJSON(t, res, &topics) | |||
assert.Len(t, topics.TopicNames, 4) | |||
assert.EqualValues(t, "6", res.Header().Get("x-total-count")) | |||
query.Add("q", "topic") | |||
searchURL.RawQuery = query.Encode() | |||
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) | |||
DecodeJSON(t, res, &topics) | |||
assert.Len(t, topics.TopicNames, 2) | |||
query.Set("q", "database") | |||
searchURL.RawQuery = query.Encode() | |||
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) | |||
DecodeJSON(t, res, &topics) | |||
if assert.Len(t, topics.TopicNames, 1) { | |||
assert.EqualValues(t, 2, topics.TopicNames[0].ID) | |||
assert.EqualValues(t, "database", topics.TopicNames[0].Name) | |||
assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount) | |||
} | |||
} | |||
func TestAPIRepoTopic(t *testing.T) { | |||
defer prepareTestEnv(t)() | |||
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) // owner of repo2 |
@@ -246,7 +246,7 @@ func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err | |||
return fmt.Errorf("refreshCollaboratorAccesses: %v", err) | |||
} | |||
if err = repo.Owner.getTeams(e); err != nil { | |||
if err = repo.Owner.loadTeams(e); err != nil { | |||
return err | |||
} | |||
@@ -159,7 +159,7 @@ func getLatestCommitStatus(e Engine, repoID int64, sha string, listOptions ListO | |||
if len(ids) == 0 { | |||
return statuses, nil | |||
} | |||
return statuses, x.In("id", ids).Find(&statuses) | |||
return statuses, e.In("id", ids).Find(&statuses) | |||
} | |||
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts |
@@ -71,6 +71,11 @@ func listGPGKeys(e Engine, uid int64, listOptions ListOptions) ([]*GPGKey, error | |||
return keys, sess.Find(&keys) | |||
} | |||
// CountUserGPGKeys return number of gpg keys a user own | |||
func CountUserGPGKeys(userID int64) (int64, error) { | |||
return x.Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{}) | |||
} | |||
// GetGPGKeyByID returns public key by given ID. | |||
func GetGPGKeyByID(keyID int64) (*GPGKey, error) { | |||
key := new(GPGKey) |
@@ -89,7 +89,7 @@ func init() { | |||
func (issue *Issue) loadTotalTimes(e Engine) (err error) { | |||
opts := FindTrackedTimesOptions{IssueID: issue.ID} | |||
issue.TotalTrackedTime, err = opts.ToSession(e).SumInt(&TrackedTime{}, "time") | |||
issue.TotalTrackedTime, err = opts.toSession(e).SumInt(&TrackedTime{}, "time") | |||
if err != nil { | |||
return err | |||
} | |||
@@ -214,7 +214,7 @@ func (issue *Issue) loadCommentsByType(e Engine, tp CommentType) (err error) { | |||
if issue.Comments != nil { | |||
return nil | |||
} | |||
issue.Comments, err = findComments(e, FindCommentsOptions{ | |||
issue.Comments, err = findComments(e, &FindCommentsOptions{ | |||
IssueID: issue.ID, | |||
Type: tp, | |||
}) |
@@ -999,7 +999,7 @@ func (opts *FindCommentsOptions) toConds() builder.Cond { | |||
return cond | |||
} | |||
func findComments(e Engine, opts FindCommentsOptions) ([]*Comment, error) { | |||
func findComments(e Engine, opts *FindCommentsOptions) ([]*Comment, error) { | |||
comments := make([]*Comment, 0, 10) | |||
sess := e.Where(opts.toConds()) | |||
if opts.RepoID > 0 { | |||
@@ -1019,10 +1019,19 @@ func findComments(e Engine, opts FindCommentsOptions) ([]*Comment, error) { | |||
} | |||
// FindComments returns all comments according options | |||
func FindComments(opts FindCommentsOptions) ([]*Comment, error) { | |||
func FindComments(opts *FindCommentsOptions) ([]*Comment, error) { | |||
return findComments(x, opts) | |||
} | |||
// CountComments count all comments according options by ignoring pagination | |||
func CountComments(opts *FindCommentsOptions) (int64, error) { | |||
sess := x.Where(opts.toConds()) | |||
if opts.RepoID > 0 { | |||
sess.Join("INNER", "issue", "issue.id = comment.issue_id") | |||
} | |||
return sess.Count(&Comment{}) | |||
} | |||
// UpdateComment updates information of comment. | |||
func UpdateComment(c *Comment, doer *User) error { | |||
sess := x.NewSession() |
@@ -444,6 +444,11 @@ func GetLabelsByRepoID(repoID int64, sortType string, listOptions ListOptions) ( | |||
return getLabelsByRepoID(x, repoID, sortType, listOptions) | |||
} | |||
// CountLabelsByRepoID count number of all labels that belong to given repository by ID. | |||
func CountLabelsByRepoID(repoID int64) (int64, error) { | |||
return x.Where("repo_id = ?", repoID).Count(&Label{}) | |||
} | |||
// ________ | |||
// \_____ \_______ ____ | |||
// / | \_ __ \/ ___\ | |||
@@ -556,6 +561,11 @@ func GetLabelsByOrgID(orgID int64, sortType string, listOptions ListOptions) ([] | |||
return getLabelsByOrgID(x, orgID, sortType, listOptions) | |||
} | |||
// CountLabelsByOrgID count all labels that belong to given organization by ID. | |||
func CountLabelsByOrgID(orgID int64) (int64, error) { | |||
return x.Where("org_id = ?", orgID).Count(&Label{}) | |||
} | |||
// .___ | |||
// | | ______ ________ __ ____ | |||
// | |/ ___// ___/ | \_/ __ \ |
@@ -380,24 +380,33 @@ type GetMilestonesOption struct { | |||
SortType string | |||
} | |||
// GetMilestones returns milestones filtered by GetMilestonesOption's | |||
func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) { | |||
sess := x.Where("repo_id = ?", opts.RepoID) | |||
func (opts GetMilestonesOption) toCond() builder.Cond { | |||
cond := builder.NewCond() | |||
if opts.RepoID != 0 { | |||
cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) | |||
} | |||
switch opts.State { | |||
case api.StateClosed: | |||
sess = sess.And("is_closed = ?", true) | |||
cond = cond.And(builder.Eq{"is_closed": true}) | |||
case api.StateAll: | |||
break | |||
// api.StateOpen: | |||
default: | |||
sess = sess.And("is_closed = ?", false) | |||
cond = cond.And(builder.Eq{"is_closed": false}) | |||
} | |||
if len(opts.Name) != 0 { | |||
sess = sess.And(builder.Like{"name", opts.Name}) | |||
cond = cond.And(builder.Like{"name", opts.Name}) | |||
} | |||
return cond | |||
} | |||
// GetMilestones returns milestones filtered by GetMilestonesOption's | |||
func GetMilestones(opts GetMilestonesOption) (MilestoneList, int64, error) { | |||
sess := x.Where(opts.toCond()) | |||
if opts.Page != 0 { | |||
sess = opts.setSessionPagination(sess) | |||
} | |||
@@ -420,7 +429,8 @@ func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) { | |||
} | |||
miles := make([]*Milestone, 0, opts.PageSize) | |||
return miles, sess.Find(&miles) | |||
total, err := sess.FindAndCount(&miles) | |||
return miles, total, err | |||
} | |||
// SearchMilestones search milestones |
@@ -50,7 +50,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 := GetMilestones(GetMilestonesOption{ | |||
milestones, _, err := GetMilestones(GetMilestonesOption{ | |||
RepoID: repo.ID, | |||
State: state, | |||
}) | |||
@@ -87,7 +87,7 @@ func TestGetMilestonesByRepoID(t *testing.T) { | |||
test(3, api.StateClosed) | |||
test(3, api.StateAll) | |||
milestones, err := GetMilestones(GetMilestonesOption{ | |||
milestones, _, err := GetMilestones(GetMilestonesOption{ | |||
RepoID: NonexistentID, | |||
State: api.StateOpen, | |||
}) | |||
@@ -100,7 +100,7 @@ func TestGetMilestones(t *testing.T) { | |||
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) | |||
test := func(sortType string, sortCond func(*Milestone) int) { | |||
for _, page := range []int{0, 1} { | |||
milestones, err := GetMilestones(GetMilestonesOption{ | |||
milestones, _, err := GetMilestones(GetMilestonesOption{ | |||
ListOptions: ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.IssuePagingNum, | |||
@@ -117,7 +117,7 @@ func TestGetMilestones(t *testing.T) { | |||
} | |||
assert.True(t, sort.IntsAreSorted(values)) | |||
milestones, err = GetMilestones(GetMilestonesOption{ | |||
milestones, _, err = GetMilestones(GetMilestonesOption{ | |||
ListOptions: ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.IssuePagingNum, |
@@ -55,6 +55,11 @@ func GetUserStopwatches(userID int64, listOptions ListOptions) ([]*Stopwatch, er | |||
return sws, nil | |||
} | |||
// CountUserStopwatches return count of all stopwatches of a user | |||
func CountUserStopwatches(userID int64) (int64, error) { | |||
return x.Where("user_id = ?", userID).Count(&Stopwatch{}) | |||
} | |||
// StopwatchExists returns true if the stopwatch exists | |||
func StopwatchExists(userID, issueID int64) bool { | |||
_, exists, _ := getStopwatch(x, userID, issueID) |
@@ -79,8 +79,8 @@ type FindTrackedTimesOptions struct { | |||
CreatedBeforeUnix int64 | |||
} | |||
// ToCond will convert each condition into a xorm-Cond | |||
func (opts *FindTrackedTimesOptions) ToCond() builder.Cond { | |||
// toCond will convert each condition into a xorm-Cond | |||
func (opts *FindTrackedTimesOptions) toCond() builder.Cond { | |||
cond := builder.NewCond().And(builder.Eq{"tracked_time.deleted": false}) | |||
if opts.IssueID != 0 { | |||
cond = cond.And(builder.Eq{"issue_id": opts.IssueID}) | |||
@@ -103,14 +103,14 @@ func (opts *FindTrackedTimesOptions) ToCond() builder.Cond { | |||
return 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) Engine { | |||
// 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) Engine { | |||
sess := e | |||
if opts.RepositoryID > 0 || opts.MilestoneID > 0 { | |||
sess = e.Join("INNER", "issue", "issue.id = tracked_time.issue_id") | |||
} | |||
sess = sess.Where(opts.ToCond()) | |||
sess = sess.Where(opts.toCond()) | |||
if opts.Page != 0 { | |||
sess = opts.setEnginePagination(sess) | |||
@@ -119,18 +119,27 @@ func (opts *FindTrackedTimesOptions) ToSession(e Engine) Engine { | |||
return sess | |||
} | |||
func getTrackedTimes(e Engine, options FindTrackedTimesOptions) (trackedTimes TrackedTimeList, err error) { | |||
err = options.ToSession(e).Find(&trackedTimes) | |||
func getTrackedTimes(e Engine, options *FindTrackedTimesOptions) (trackedTimes TrackedTimeList, err error) { | |||
err = options.toSession(e).Find(&trackedTimes) | |||
return | |||
} | |||
// GetTrackedTimes returns all tracked times that fit to the given options. | |||
func GetTrackedTimes(opts FindTrackedTimesOptions) (TrackedTimeList, error) { | |||
func GetTrackedTimes(opts *FindTrackedTimesOptions) (TrackedTimeList, error) { | |||
return getTrackedTimes(x, opts) | |||
} | |||
// CountTrackedTimes returns count of tracked times that fit to the given options. | |||
func CountTrackedTimes(opts *FindTrackedTimesOptions) (int64, error) { | |||
sess := x.Where(opts.toCond()) | |||
if opts.RepositoryID > 0 || opts.MilestoneID > 0 { | |||
sess = sess.Join("INNER", "issue", "issue.id = tracked_time.issue_id") | |||
} | |||
return sess.Count(&TrackedTime{}) | |||
} | |||
func getTrackedSeconds(e Engine, opts FindTrackedTimesOptions) (trackedSeconds int64, err error) { | |||
return opts.ToSession(e).SumInt(&TrackedTime{}, "time") | |||
return opts.toSession(e).SumInt(&TrackedTime{}, "time") | |||
} | |||
// GetTrackedSeconds return sum of seconds | |||
@@ -188,7 +197,7 @@ func addTime(e Engine, user *User, issue *Issue, amount int64, created time.Time | |||
} | |||
// TotalTimes returns the spent time for each user by an issue | |||
func TotalTimes(options FindTrackedTimesOptions) (map[*User]string, error) { | |||
func TotalTimes(options *FindTrackedTimesOptions) (map[*User]string, error) { | |||
trackedTimes, err := GetTrackedTimes(options) | |||
if err != nil { | |||
return nil, err | |||
@@ -288,7 +297,7 @@ func deleteTimes(e Engine, opts FindTrackedTimesOptions) (removedTime int64, err | |||
return | |||
} | |||
_, err = opts.ToSession(e).Table("tracked_time").Cols("deleted").Update(&TrackedTime{Deleted: true}) | |||
_, err = opts.toSession(e).Table("tracked_time").Cols("deleted").Update(&TrackedTime{Deleted: true}) | |||
return | |||
} | |||
@@ -38,27 +38,27 @@ func TestGetTrackedTimes(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
// by Issue | |||
times, err := GetTrackedTimes(FindTrackedTimesOptions{IssueID: 1}) | |||
times, err := GetTrackedTimes(&FindTrackedTimesOptions{IssueID: 1}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 1) | |||
assert.Equal(t, int64(400), times[0].Time) | |||
times, err = GetTrackedTimes(FindTrackedTimesOptions{IssueID: -1}) | |||
times, err = GetTrackedTimes(&FindTrackedTimesOptions{IssueID: -1}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 0) | |||
// by User | |||
times, err = GetTrackedTimes(FindTrackedTimesOptions{UserID: 1}) | |||
times, err = GetTrackedTimes(&FindTrackedTimesOptions{UserID: 1}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 3) | |||
assert.Equal(t, int64(400), times[0].Time) | |||
times, err = GetTrackedTimes(FindTrackedTimesOptions{UserID: 3}) | |||
times, err = GetTrackedTimes(&FindTrackedTimesOptions{UserID: 3}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 0) | |||
// by Repo | |||
times, err = GetTrackedTimes(FindTrackedTimesOptions{RepositoryID: 2}) | |||
times, err = GetTrackedTimes(&FindTrackedTimesOptions{RepositoryID: 2}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 3) | |||
assert.Equal(t, int64(1), times[0].Time) | |||
@@ -66,11 +66,11 @@ func TestGetTrackedTimes(t *testing.T) { | |||
assert.NoError(t, err) | |||
assert.Equal(t, issue.RepoID, int64(2)) | |||
times, err = GetTrackedTimes(FindTrackedTimesOptions{RepositoryID: 1}) | |||
times, err = GetTrackedTimes(&FindTrackedTimesOptions{RepositoryID: 1}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 5) | |||
times, err = GetTrackedTimes(FindTrackedTimesOptions{RepositoryID: 10}) | |||
times, err = GetTrackedTimes(&FindTrackedTimesOptions{RepositoryID: 10}) | |||
assert.NoError(t, err) | |||
assert.Len(t, times, 0) | |||
} | |||
@@ -78,7 +78,7 @@ func TestGetTrackedTimes(t *testing.T) { | |||
func TestTotalTimes(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
total, err := TotalTimes(FindTrackedTimesOptions{IssueID: 1}) | |||
total, err := TotalTimes(&FindTrackedTimesOptions{IssueID: 1}) | |||
assert.NoError(t, err) | |||
assert.Len(t, total, 1) | |||
for user, time := range total { | |||
@@ -86,7 +86,7 @@ func TestTotalTimes(t *testing.T) { | |||
assert.Equal(t, "6min 40s", time) | |||
} | |||
total, err = TotalTimes(FindTrackedTimesOptions{IssueID: 2}) | |||
total, err = TotalTimes(&FindTrackedTimesOptions{IssueID: 2}) | |||
assert.NoError(t, err) | |||
assert.Len(t, total, 2) | |||
for user, time := range total { | |||
@@ -99,7 +99,7 @@ func TestTotalTimes(t *testing.T) { | |||
} | |||
} | |||
total, err = TotalTimes(FindTrackedTimesOptions{IssueID: 5}) | |||
total, err = TotalTimes(&FindTrackedTimesOptions{IssueID: 5}) | |||
assert.NoError(t, err) | |||
assert.Len(t, total, 1) | |||
for user, time := range total { | |||
@@ -107,7 +107,7 @@ func TestTotalTimes(t *testing.T) { | |||
assert.Equal(t, "1s", time) | |||
} | |||
total, err = TotalTimes(FindTrackedTimesOptions{IssueID: 4}) | |||
total, err = TotalTimes(&FindTrackedTimesOptions{IssueID: 4}) | |||
assert.NoError(t, err) | |||
assert.Len(t, total, 2) | |||
} |
@@ -125,6 +125,11 @@ func GetNotifications(opts *FindNotificationOptions) (NotificationList, error) { | |||
return getNotifications(x, opts) | |||
} | |||
// CountNotifications count all notifications that fit to the given options and ignore pagination. | |||
func CountNotifications(opts *FindNotificationOptions) (int64, error) { | |||
return x.Where(opts.ToCond()).Count(&Notification{}) | |||
} | |||
// CreateRepoTransferNotification creates notification for the user a repository was transferred to | |||
func CreateRepoTransferNotification(doer, newOwner *User, repo *Repository) error { | |||
sess := x.NewSession() |
@@ -269,7 +269,7 @@ func DeleteOAuth2Application(id, userid int64) error { | |||
} | |||
// ListOAuth2Applications returns a list of oauth2 applications belongs to given user. | |||
func ListOAuth2Applications(uid int64, listOptions ListOptions) ([]*OAuth2Application, error) { | |||
func ListOAuth2Applications(uid int64, listOptions ListOptions) ([]*OAuth2Application, int64, error) { | |||
sess := x. | |||
Where("uid=?", uid). | |||
Desc("id") | |||
@@ -278,11 +278,13 @@ func ListOAuth2Applications(uid int64, listOptions ListOptions) ([]*OAuth2Applic | |||
sess = listOptions.setSessionPagination(sess) | |||
apps := make([]*OAuth2Application, 0, listOptions.PageSize) | |||
return apps, sess.Find(&apps) | |||
total, err := sess.FindAndCount(&apps) | |||
return apps, total, err | |||
} | |||
apps := make([]*OAuth2Application, 0, 5) | |||
return apps, sess.Find(&apps) | |||
total, err := sess.FindAndCount(&apps) | |||
return apps, total, err | |||
} | |||
////////////////////////////////////////////////////// |
@@ -52,7 +52,7 @@ func (org *User) GetOwnerTeam() (*Team, error) { | |||
return org.getOwnerTeam(x) | |||
} | |||
func (org *User) getTeams(e Engine) error { | |||
func (org *User) loadTeams(e Engine) error { | |||
if org.Teams != nil { | |||
return nil | |||
} | |||
@@ -62,13 +62,9 @@ func (org *User) getTeams(e Engine) error { | |||
Find(&org.Teams) | |||
} | |||
// 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) | |||
// LoadTeams load teams if not loaded. | |||
func (org *User) LoadTeams() error { | |||
return org.loadTeams(x) | |||
} | |||
// GetMembers returns all members of organization. | |||
@@ -87,7 +83,7 @@ type FindOrgMembersOpts struct { | |||
} | |||
// CountOrgMembers counts the organization's members | |||
func CountOrgMembers(opts FindOrgMembersOpts) (int64, error) { | |||
func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) { | |||
sess := x.Where("org_id=?", opts.OrgID) | |||
if opts.PublicOnly { | |||
sess.And("is_public = ?", true) |
@@ -790,16 +790,6 @@ func GetTeamMembers(teamID int64) ([]*User, error) { | |||
return getTeamMembers(x, teamID) | |||
} | |||
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) | |||
if listOptions.Page != 0 { | |||
sess = listOptions.setSessionPagination(sess) | |||
} | |||
return teams, sess.Find(&teams) | |||
} | |||
func getUserOrgTeams(e Engine, orgID, userID int64) (teams []*Team, err error) { | |||
return teams, e. | |||
Join("INNER", "team_user", "team_user.team_id = team.id"). | |||
@@ -823,11 +813,6 @@ func GetUserOrgTeams(orgID, userID int64) ([]*Team, error) { | |||
return getUserOrgTeams(x, orgID, userID) | |||
} | |||
// GetUserTeams returns all teams that user belongs across all organizations. | |||
func GetUserTeams(userID int64, listOptions ListOptions) ([]*Team, error) { | |||
return getUserTeams(x, userID, listOptions) | |||
} | |||
// AddTeamMember adds new membership of given team to given organization, | |||
// the user will have membership to given organization automatically when needed. | |||
func AddTeamMember(team *Team, userID int64) error { |
@@ -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, ListOptions{}) | |||
teams, _, err := SearchTeam(&SearchTeamOptions{UserID: userID}) | |||
assert.NoError(t, err) | |||
for _, team := range teams { | |||
AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID}) |
@@ -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(&SearchTeamOptions{})) | |||
assert.NoError(t, org.LoadTeams()) | |||
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) |
@@ -1125,8 +1125,8 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository, overwriteO | |||
// Give access to all members in teams with access to all repositories. | |||
if u.IsOrganization() { | |||
if err := u.getTeams(ctx.e); err != nil { | |||
return fmt.Errorf("GetTeams: %v", err) | |||
if err := u.loadTeams(ctx.e); err != nil { | |||
return fmt.Errorf("loadTeams: %v", err) | |||
} | |||
for _, t := range u.Teams { | |||
if t.IncludesAllRepositories { | |||
@@ -1439,7 +1439,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
return err | |||
} | |||
if org.IsOrganization() { | |||
if err = org.getTeams(sess); err != nil { | |||
if err = org.loadTeams(sess); err != nil { | |||
return err | |||
} | |||
} | |||
@@ -1453,7 +1453,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
} | |||
// Delete Deploy Keys | |||
deployKeys, err := listDeployKeys(sess, repo.ID, ListOptions{}) | |||
deployKeys, err := listDeployKeys(sess, &ListDeployKeysOptions{RepoID: repoID}) | |||
if err != nil { | |||
return fmt.Errorf("listDeployKeys: %v", err) | |||
} |
@@ -102,6 +102,11 @@ func (repo *Repository) GetCollaborators(listOptions ListOptions) ([]*Collaborat | |||
return repo.getCollaborators(x, listOptions) | |||
} | |||
// CountCollaborators returns total number of collaborators for a repository | |||
func (repo *Repository) CountCollaborators() (int64, error) { | |||
return x.Where("repo_id = ? ", repo.ID).Count(&Collaboration{}) | |||
} | |||
func (repo *Repository) getCollaboration(e Engine, uid int64) (*Collaboration, error) { | |||
collaboration := &Collaboration{ | |||
RepoID: repo.ID, |
@@ -111,7 +111,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, ListOptions{}) | |||
templateWebhooks, err := ListWebhooksByOpts(&ListWebhookOptions{RepoID: templateRepo.ID}) | |||
if err != nil { | |||
return err | |||
} |
@@ -291,8 +291,8 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e | |||
} | |||
if newOwner.IsOrganization() { | |||
if err := newOwner.getTeams(sess); err != nil { | |||
return fmt.Errorf("GetTeams: %v", err) | |||
if err := newOwner.loadTeams(sess); err != nil { | |||
return fmt.Errorf("LoadTeams: %v", err) | |||
} | |||
for _, t := range newOwner.Teams { | |||
if t.IncludesAllRepositories { |
@@ -208,6 +208,11 @@ func FindReviews(opts FindReviewOptions) ([]*Review, error) { | |||
return findReviews(x, opts) | |||
} | |||
// CountReviews returns count of reviews passing FindReviewOptions | |||
func CountReviews(opts FindReviewOptions) (int64, error) { | |||
return x.Where(opts.toCond()).Count(&Review{}) | |||
} | |||
// CreateReviewOptions represent the options to create a review. Type, Issue and Reviewer are required. | |||
type CreateReviewOptions struct { | |||
Content string |
@@ -205,6 +205,12 @@ func ListPublicKeys(uid int64, listOptions ListOptions) ([]*PublicKey, error) { | |||
return keys, sess.Find(&keys) | |||
} | |||
// CountPublicKeys count public keys a user has | |||
func CountPublicKeys(userID int64) (int64, error) { | |||
sess := x.Where("owner_id = ? AND type != ?", userID, KeyTypePrincipal) | |||
return sess.Count(&PublicKey{}) | |||
} | |||
// ListPublicKeysBySource returns a list of synchronized public keys for a given user and login source. | |||
func ListPublicKeysBySource(uid, loginSourceID int64) ([]*PublicKey, error) { | |||
keys := make([]*PublicKey, 0, 5) |
@@ -264,17 +264,40 @@ func deleteDeployKey(sess Engine, doer *User, id int64) error { | |||
return nil | |||
} | |||
// ListDeployKeys returns all deploy keys by given repository ID. | |||
func ListDeployKeys(repoID int64, listOptions ListOptions) ([]*DeployKey, error) { | |||
return listDeployKeys(x, repoID, listOptions) | |||
// ListDeployKeysOptions are options for ListDeployKeys | |||
type ListDeployKeysOptions struct { | |||
ListOptions | |||
RepoID int64 | |||
KeyID int64 | |||
Fingerprint string | |||
} | |||
func (opt ListDeployKeysOptions) toCond() builder.Cond { | |||
cond := builder.NewCond() | |||
if opt.RepoID != 0 { | |||
cond = cond.And(builder.Eq{"repo_id": opt.RepoID}) | |||
} | |||
if opt.KeyID != 0 { | |||
cond = cond.And(builder.Eq{"key_id": opt.KeyID}) | |||
} | |||
if opt.Fingerprint != "" { | |||
cond = cond.And(builder.Eq{"fingerprint": opt.Fingerprint}) | |||
} | |||
return cond | |||
} | |||
func listDeployKeys(e Engine, repoID int64, listOptions ListOptions) ([]*DeployKey, error) { | |||
sess := e.Where("repo_id = ?", repoID) | |||
if listOptions.Page != 0 { | |||
sess = listOptions.setSessionPagination(sess) | |||
// ListDeployKeys returns a list of deploy keys matching the provided arguments. | |||
func ListDeployKeys(opts *ListDeployKeysOptions) ([]*DeployKey, error) { | |||
return listDeployKeys(x, opts) | |||
} | |||
keys := make([]*DeployKey, 0, listOptions.PageSize) | |||
func listDeployKeys(e Engine, opts *ListDeployKeysOptions) ([]*DeployKey, error) { | |||
sess := e.Where(opts.toCond()) | |||
if opts.Page != 0 { | |||
sess = opts.setSessionPagination(sess) | |||
keys := make([]*DeployKey, 0, opts.PageSize) | |||
return keys, sess.Find(&keys) | |||
} | |||
@@ -282,18 +305,7 @@ func listDeployKeys(e Engine, repoID int64, listOptions ListOptions) ([]*DeployK | |||
return keys, sess.Find(&keys) | |||
} | |||
// SearchDeployKeys returns a list of deploy keys matching the provided arguments. | |||
func SearchDeployKeys(repoID, keyID int64, fingerprint string) ([]*DeployKey, error) { | |||
keys := make([]*DeployKey, 0, 5) | |||
cond := builder.NewCond() | |||
if repoID != 0 { | |||
cond = cond.And(builder.Eq{"repo_id": repoID}) | |||
} | |||
if keyID != 0 { | |||
cond = cond.And(builder.Eq{"key_id": keyID}) | |||
} | |||
if fingerprint != "" { | |||
cond = cond.And(builder.Eq{"fingerprint": fingerprint}) | |||
} | |||
return keys, x.Where(cond).Find(&keys) | |||
// CountDeployKeys returns count deploy keys matching the provided arguments. | |||
func CountDeployKeys(opts *ListDeployKeysOptions) (int64, error) { | |||
return x.Where(opts.toCond()).Count(&DeployKey{}) | |||
} |
@@ -122,6 +122,15 @@ func UpdateAccessToken(t *AccessToken) error { | |||
return err | |||
} | |||
// CountAccessTokens count access tokens belongs to given user by options | |||
func CountAccessTokens(opts ListAccessTokensOptions) (int64, error) { | |||
sess := x.Where("uid=?", opts.UserID) | |||
if len(opts.Name) != 0 { | |||
sess = sess.Where("name=?", opts.Name) | |||
} | |||
return sess.Count(&AccessToken{}) | |||
} | |||
// DeleteAccessTokenByID deletes access token by given ID. | |||
func DeleteAccessTokenByID(id, userID int64) error { | |||
cnt, err := x.ID(id).Delete(&AccessToken{ |
@@ -184,7 +184,7 @@ func (opts *FindTopicOptions) toConds() builder.Cond { | |||
} | |||
// FindTopics retrieves the topics via FindTopicOptions | |||
func FindTopics(opts *FindTopicOptions) (topics []*Topic, err error) { | |||
func FindTopics(opts *FindTopicOptions) ([]*Topic, int64, error) { | |||
sess := x.Select("topic.*").Where(opts.toConds()) | |||
if opts.RepoID > 0 { | |||
sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") | |||
@@ -192,7 +192,18 @@ func FindTopics(opts *FindTopicOptions) (topics []*Topic, err error) { | |||
if opts.PageSize != 0 && opts.Page != 0 { | |||
sess = opts.setSessionPagination(sess) | |||
} | |||
return topics, sess.Desc("topic.repo_count").Find(&topics) | |||
topics := make([]*Topic, 0, 10) | |||
total, err := sess.Desc("topic.repo_count").FindAndCount(&topics) | |||
return topics, total, err | |||
} | |||
// CountTopics counts the number of topics matching the FindTopicOptions | |||
func CountTopics(opts *FindTopicOptions) (int64, error) { | |||
sess := x.Where(opts.toConds()) | |||
if opts.RepoID > 0 { | |||
sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") | |||
} | |||
return sess.Count(new(Topic)) | |||
} | |||
// GetRepoTopicByName retrieves topic from name for a repo if it exist | |||
@@ -269,7 +280,7 @@ func DeleteTopic(repoID int64, topicName string) (*Topic, error) { | |||
// SaveTopics save topics to a repository | |||
func SaveTopics(repoID int64, topicNames ...string) error { | |||
topics, err := FindTopics(&FindTopicOptions{ | |||
topics, _, err := FindTopics(&FindTopicOptions{ | |||
RepoID: repoID, | |||
}) | |||
if err != nil { |
@@ -17,17 +17,18 @@ func TestAddTopic(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
topics, err := FindTopics(&FindTopicOptions{}) | |||
topics, _, err := FindTopics(&FindTopicOptions{}) | |||
assert.NoError(t, err) | |||
assert.Len(t, topics, totalNrOfTopics) | |||
topics, err = FindTopics(&FindTopicOptions{ | |||
topics, total, err := FindTopics(&FindTopicOptions{ | |||
ListOptions: ListOptions{Page: 1, PageSize: 2}, | |||
}) | |||
assert.NoError(t, err) | |||
assert.Len(t, topics, 2) | |||
assert.EqualValues(t, 6, total) | |||
topics, err = FindTopics(&FindTopicOptions{ | |||
topics, _, err = FindTopics(&FindTopicOptions{ | |||
RepoID: 1, | |||
}) | |||
assert.NoError(t, err) | |||
@@ -35,11 +36,11 @@ func TestAddTopic(t *testing.T) { | |||
assert.NoError(t, SaveTopics(2, "golang")) | |||
repo2NrOfTopics = 1 | |||
topics, err = FindTopics(&FindTopicOptions{}) | |||
topics, _, err = FindTopics(&FindTopicOptions{}) | |||
assert.NoError(t, err) | |||
assert.Len(t, topics, totalNrOfTopics) | |||
topics, err = FindTopics(&FindTopicOptions{ | |||
topics, _, err = FindTopics(&FindTopicOptions{ | |||
RepoID: 2, | |||
}) | |||
assert.NoError(t, err) | |||
@@ -52,11 +53,11 @@ func TestAddTopic(t *testing.T) { | |||
assert.NoError(t, err) | |||
assert.EqualValues(t, 1, topic.RepoCount) | |||
topics, err = FindTopics(&FindTopicOptions{}) | |||
topics, _, err = FindTopics(&FindTopicOptions{}) | |||
assert.NoError(t, err) | |||
assert.Len(t, topics, totalNrOfTopics) | |||
topics, err = FindTopics(&FindTopicOptions{ | |||
topics, _, err = FindTopics(&FindTopicOptions{ | |||
RepoID: 2, | |||
}) | |||
assert.NoError(t, err) |
@@ -1704,7 +1704,7 @@ func GetStarredRepos(userID int64, private bool, listOptions ListOptions) ([]*Re | |||
} | |||
// GetWatchedRepos returns the repos watched by a particular user | |||
func GetWatchedRepos(userID int64, private bool, listOptions ListOptions) ([]*Repository, error) { | |||
func GetWatchedRepos(userID int64, private bool, listOptions ListOptions) ([]*Repository, int64, error) { | |||
sess := x.Where("watch.user_id=?", userID). | |||
And("`watch`.mode<>?", RepoWatchModeDont). | |||
Join("LEFT", "watch", "`repository`.id=`watch`.repo_id") | |||
@@ -1716,11 +1716,13 @@ func GetWatchedRepos(userID int64, private bool, listOptions ListOptions) ([]*Re | |||
sess = listOptions.setSessionPagination(sess) | |||
repos := make([]*Repository, 0, listOptions.PageSize) | |||
return repos, sess.Find(&repos) | |||
total, err := sess.FindAndCount(&repos) | |||
return repos, total, err | |||
} | |||
repos := make([]*Repository, 0, 10) | |||
return repos, sess.Find(&repos) | |||
total, err := sess.FindAndCount(&repos) | |||
return repos, total, err | |||
} | |||
// IterateUser iterate users |
@@ -16,8 +16,10 @@ import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"code.gitea.io/gitea/modules/util" | |||
gouuid "github.com/google/uuid" | |||
"xorm.io/builder" | |||
) | |||
// HookContentType is the content type of a web hook | |||
@@ -387,53 +389,51 @@ func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) { | |||
}) | |||
} | |||
// GetActiveWebhooksByRepoID returns all active webhooks of repository. | |||
func GetActiveWebhooksByRepoID(repoID int64) ([]*Webhook, error) { | |||
return getActiveWebhooksByRepoID(x, repoID) | |||
// ListWebhookOptions are options to filter webhooks on ListWebhooksByOpts | |||
type ListWebhookOptions struct { | |||
ListOptions | |||
RepoID int64 | |||
OrgID int64 | |||
IsActive util.OptionalBool | |||
} | |||
func getActiveWebhooksByRepoID(e Engine, repoID int64) ([]*Webhook, error) { | |||
webhooks := make([]*Webhook, 0, 5) | |||
return webhooks, e.Where("is_active=?", true). | |||
Find(&webhooks, &Webhook{RepoID: repoID}) | |||
} | |||
// GetWebhooksByRepoID returns all webhooks of a repository. | |||
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}) | |||
func (opts *ListWebhookOptions) toCond() builder.Cond { | |||
cond := builder.NewCond() | |||
if opts.RepoID != 0 { | |||
cond = cond.And(builder.Eq{"webhook.repo_id": opts.RepoID}) | |||
} | |||
if opts.OrgID != 0 { | |||
cond = cond.And(builder.Eq{"webhook.org_id": opts.OrgID}) | |||
} | |||
if !opts.IsActive.IsNone() { | |||
cond = cond.And(builder.Eq{"webhook.is_active": opts.IsActive.IsTrue()}) | |||
} | |||
return cond | |||
} | |||
sess := listOptions.getPaginatedSession() | |||
webhooks := make([]*Webhook, 0, listOptions.PageSize) | |||
func listWebhooksByOpts(e Engine, opts *ListWebhookOptions) ([]*Webhook, error) { | |||
sess := e.Where(opts.toCond()) | |||
return webhooks, sess.Find(&webhooks, &Webhook{RepoID: repoID}) | |||
} | |||
if opts.Page != 0 { | |||
sess = opts.setSessionPagination(sess) | |||
webhooks := make([]*Webhook, 0, opts.PageSize) | |||
err := sess.Find(&webhooks) | |||
return webhooks, err | |||
} | |||
// GetActiveWebhooksByOrgID returns all active webhooks for an organization. | |||
func GetActiveWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) { | |||
return getActiveWebhooksByOrgID(x, orgID) | |||
webhooks := make([]*Webhook, 0, 10) | |||
err := sess.Find(&webhooks) | |||
return webhooks, err | |||
} | |||
func getActiveWebhooksByOrgID(e Engine, orgID int64) (ws []*Webhook, err error) { | |||
err = e. | |||
Where("org_id=?", orgID). | |||
And("is_active=?", true). | |||
Find(&ws) | |||
return ws, err | |||
// ListWebhooksByOpts return webhooks based on options | |||
func ListWebhooksByOpts(opts *ListWebhookOptions) ([]*Webhook, error) { | |||
return listWebhooksByOpts(x, opts) | |||
} | |||
// 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}) | |||
// CountWebhooksByOpts count webhooks based on options and ignore pagination | |||
func CountWebhooksByOpts(opts *ListWebhookOptions) (int64, error) { | |||
return x.Where(opts.toCond()).Count(&Webhook{}) | |||
} | |||
// GetDefaultWebhooks returns all admin-default webhooks. |
@@ -11,6 +11,7 @@ import ( | |||
"code.gitea.io/gitea/modules/json" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/util" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
@@ -118,7 +119,7 @@ func TestGetWebhookByOrgID(t *testing.T) { | |||
func TestGetActiveWebhooksByRepoID(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
hooks, err := GetActiveWebhooksByRepoID(1) | |||
hooks, err := ListWebhooksByOpts(&ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue}) | |||
assert.NoError(t, err) | |||
if assert.Len(t, hooks, 1) { | |||
assert.Equal(t, int64(1), hooks[0].ID) | |||
@@ -128,7 +129,7 @@ func TestGetActiveWebhooksByRepoID(t *testing.T) { | |||
func TestGetWebhooksByRepoID(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
hooks, err := GetWebhooksByRepoID(1, ListOptions{}) | |||
hooks, err := ListWebhooksByOpts(&ListWebhookOptions{RepoID: 1}) | |||
assert.NoError(t, err) | |||
if assert.Len(t, hooks, 2) { | |||
assert.Equal(t, int64(1), hooks[0].ID) | |||
@@ -138,7 +139,7 @@ func TestGetWebhooksByRepoID(t *testing.T) { | |||
func TestGetActiveWebhooksByOrgID(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
hooks, err := GetActiveWebhooksByOrgID(3) | |||
hooks, err := ListWebhooksByOpts(&ListWebhookOptions{OrgID: 3, IsActive: util.OptionalBoolTrue}) | |||
assert.NoError(t, err) | |||
if assert.Len(t, hooks, 1) { | |||
assert.Equal(t, int64(3), hooks[0].ID) | |||
@@ -148,7 +149,7 @@ func TestGetActiveWebhooksByOrgID(t *testing.T) { | |||
func TestGetWebhooksByOrgID(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
hooks, err := GetWebhooksByOrgID(3, ListOptions{}) | |||
hooks, err := ListWebhooksByOpts(&ListWebhookOptions{OrgID: 3}) | |||
assert.NoError(t, err) | |||
if assert.Len(t, hooks, 1) { | |||
assert.Equal(t, int64(3), hooks[0].ID) |
@@ -181,6 +181,23 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) { | |||
if len(links) > 0 { | |||
ctx.Header().Set("Link", strings.Join(links, ",")) | |||
ctx.AppendAccessControlExposeHeaders("Link") | |||
} | |||
} | |||
// SetTotalCountHeader set "X-Total-Count" header | |||
func (ctx *APIContext) SetTotalCountHeader(total int64) { | |||
ctx.Header().Set("X-Total-Count", fmt.Sprint(total)) | |||
ctx.AppendAccessControlExposeHeaders("X-Total-Count") | |||
} | |||
// AppendAccessControlExposeHeaders append headers by name to "Access-Control-Expose-Headers" header | |||
func (ctx *APIContext) AppendAccessControlExposeHeaders(names ...string) { | |||
val := ctx.Header().Get("Access-Control-Expose-Headers") | |||
if len(val) != 0 { | |||
ctx.Header().Set("Access-Control-Expose-Headers", fmt.Sprintf("%s, %s", val, strings.Join(names, ", "))) | |||
} else { | |||
ctx.Header().Set("Access-Control-Expose-Headers", strings.Join(names, ", ")) | |||
} | |||
} | |||
@@ -123,8 +123,8 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { | |||
// Team. | |||
if ctx.Org.IsMember { | |||
if ctx.Org.IsOwner { | |||
if err := org.GetTeams(&models.SearchTeamOptions{}); err != nil { | |||
ctx.ServerError("GetTeams", err) | |||
if err := org.LoadTeams(); err != nil { | |||
ctx.ServerError("LoadTeams", err) | |||
return | |||
} | |||
} else { |
@@ -10,6 +10,7 @@ import ( | |||
"strings" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/util" | |||
) | |||
// TagPrefix tags prefix path on the repository | |||
@@ -160,24 +161,18 @@ func (repo *Repository) GetTag(name string) (*Tag, error) { | |||
} | |||
// GetTagInfos returns all tag infos of the repository. | |||
func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, error) { | |||
func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) { | |||
// TODO this a slow implementation, makes one git command per tag | |||
stdout, err := NewCommand("tag").RunInDir(repo.Path) | |||
if err != nil { | |||
return nil, err | |||
return nil, 0, err | |||
} | |||
tagNames := strings.Split(strings.TrimRight(stdout, "\n"), "\n") | |||
tagsTotal := len(tagNames) | |||
if page != 0 { | |||
skip := (page - 1) * pageSize | |||
if skip >= len(tagNames) { | |||
return nil, nil | |||
} | |||
if (len(tagNames) - skip) < pageSize { | |||
pageSize = len(tagNames) - skip | |||
} | |||
tagNames = tagNames[skip : skip+pageSize] | |||
tagNames = util.PaginateSlice(tagNames, page, pageSize).([]string) | |||
} | |||
var tags = make([]*Tag, 0, len(tagNames)) | |||
@@ -189,13 +184,13 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, error) { | |||
tag, err := repo.GetTag(tagName) | |||
if err != nil { | |||
return nil, err | |||
return nil, tagsTotal, err | |||
} | |||
tag.Name = tagName | |||
tags = append(tags, tag) | |||
} | |||
sortTagsByTime(tags) | |||
return tags, nil | |||
return tags, tagsTotal, nil | |||
} | |||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) |
@@ -18,9 +18,10 @@ func TestRepository_GetTags(t *testing.T) { | |||
assert.NoError(t, err) | |||
defer bareRepo1.Close() | |||
tags, err := bareRepo1.GetTagInfos(0, 0) | |||
tags, total, err := bareRepo1.GetTagInfos(0, 0) | |||
assert.NoError(t, err) | |||
assert.Len(t, tags, 1) | |||
assert.Equal(t, len(tags), total) | |||
assert.EqualValues(t, "test", tags[0].Name) | |||
assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[0].ID.String()) | |||
assert.EqualValues(t, "tag", tags[0].Type) |
@@ -54,14 +54,14 @@ func TestGiteaUploadRepo(t *testing.T) { | |||
assert.True(t, repo.HasWiki()) | |||
assert.EqualValues(t, models.RepositoryReady, repo.Status) | |||
milestones, err := models.GetMilestones(models.GetMilestonesOption{ | |||
milestones, _, err := models.GetMilestones(models.GetMilestonesOption{ | |||
RepoID: repo.ID, | |||
State: structs.StateOpen, | |||
}) | |||
assert.NoError(t, err) | |||
assert.Len(t, milestones, 1) | |||
milestones, err = models.GetMilestones(models.GetMilestonesOption{ | |||
milestones, _, err = models.GetMilestones(models.GetMilestonesOption{ | |||
RepoID: repo.ID, | |||
State: structs.StateClosed, | |||
}) |
@@ -5,7 +5,6 @@ | |||
package admin | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
@@ -47,8 +46,7 @@ func ListUnadoptedRepositories(ctx *context.APIContext) { | |||
ctx.InternalServerError(err) | |||
} | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", count)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count") | |||
ctx.SetTotalCountHeader(int64(count)) | |||
ctx.JSON(http.StatusOK, repoNames) | |||
} |
@@ -11,6 +11,7 @@ import ( | |||
"code.gitea.io/gitea/modules/cron" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/util" | |||
"code.gitea.io/gitea/routers/api/v1/utils" | |||
) | |||
@@ -36,12 +37,10 @@ func ListCronTasks(ctx *context.APIContext) { | |||
// "403": | |||
// "$ref": "#/responses/forbidden" | |||
tasks := cron.ListTasks() | |||
listOpts := utils.GetListOptions(ctx) | |||
start, end := listOpts.GetStartEnd() | |||
count := len(tasks) | |||
if len(tasks) > listOpts.PageSize { | |||
tasks = tasks[start:end] | |||
} | |||
listOpts := utils.GetListOptions(ctx) | |||
tasks = util.PaginateSlice(tasks, listOpts.Page, listOpts.PageSize).(cron.TaskTable) | |||
res := make([]structs.Cron, len(tasks)) | |||
for i, task := range tasks { | |||
@@ -53,6 +52,8 @@ func ListCronTasks(ctx *context.APIContext) { | |||
ExecTimes: task.ExecTimes, | |||
} | |||
} | |||
ctx.SetTotalCountHeader(int64(count)) | |||
ctx.JSON(http.StatusOK, res) | |||
} | |||
@@ -6,7 +6,6 @@ | |||
package admin | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
@@ -121,7 +120,6 @@ func GetAllOrgs(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, &orgs) | |||
} |
@@ -423,7 +423,6 @@ func GetAllUsers(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, &results) | |||
} |
@@ -108,6 +108,12 @@ func ListRepoNotifications(ctx *context.APIContext) { | |||
} | |||
opts.RepoID = ctx.Repo.Repository.ID | |||
totalCount, err := models.CountNotifications(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
nl, err := models.GetNotifications(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
@@ -119,6 +125,8 @@ func ListRepoNotifications(ctx *context.APIContext) { | |||
return | |||
} | |||
ctx.SetTotalCountHeader(totalCount) | |||
ctx.JSON(http.StatusOK, convert.ToNotifications(nl)) | |||
} | |||
@@ -68,6 +68,12 @@ func ListNotifications(ctx *context.APIContext) { | |||
return | |||
} | |||
totalCount, err := models.CountNotifications(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
nl, err := models.GetNotifications(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
@@ -79,6 +85,7 @@ func ListNotifications(ctx *context.APIContext) { | |||
return | |||
} | |||
ctx.SetTotalCountHeader(totalCount) | |||
ctx.JSON(http.StatusOK, convert.ToNotifications(nl)) | |||
} | |||
@@ -40,16 +40,29 @@ func ListHooks(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/HookList" | |||
org := ctx.Org.Organization | |||
orgHooks, err := models.GetWebhooksByOrgID(org.ID, utils.GetListOptions(ctx)) | |||
opts := &models.ListWebhookOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
OrgID: ctx.Org.Organization.ID, | |||
} | |||
count, err := models.CountWebhooksByOpts(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetWebhooksByOrgID", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
orgHooks, err := models.ListWebhooksByOpts(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
hooks := make([]*api.Hook, len(orgHooks)) | |||
for i, hook := range orgHooks { | |||
hooks[i] = convert.ToHook(org.HomeLink(), hook) | |||
hooks[i] = convert.ToHook(ctx.Org.Organization.HomeLink(), hook) | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, hooks) | |||
} | |||
@@ -49,6 +49,13 @@ func ListLabels(ctx *context.APIContext) { | |||
return | |||
} | |||
count, err := models.CountLabelsByOrgID(ctx.Org.Organization.ID) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToLabelList(labels)) | |||
} | |||
@@ -18,15 +18,21 @@ import ( | |||
// listMembers list an organization's members | |||
func listMembers(ctx *context.APIContext, publicOnly bool) { | |||
var members []*models.User | |||
members, _, err := models.FindOrgMembers(&models.FindOrgMembersOpts{ | |||
opts := &models.FindOrgMembersOpts{ | |||
OrgID: ctx.Org.Organization.ID, | |||
PublicOnly: publicOnly, | |||
ListOptions: utils.GetListOptions(ctx), | |||
}) | |||
} | |||
count, err := models.CountOrgMembers(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
members, _, err := models.FindOrgMembers(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetUsersByIDs", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
@@ -35,6 +41,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) { | |||
apiMembers[i] = convert.ToUser(member, ctx.User) | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, apiMembers) | |||
} | |||
@@ -6,7 +6,6 @@ | |||
package org | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
@@ -38,9 +37,8 @@ func listUserOrgs(ctx *context.APIContext, u *models.User) { | |||
apiOrgs[i] = convert.ToOrganization(orgs[i]) | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetLinkHeader(maxResults, listOptions.PageSize) | |||
ctx.SetTotalCountHeader(int64(maxResults)) | |||
ctx.JSON(http.StatusOK, &apiOrgs) | |||
} | |||
@@ -145,8 +143,7 @@ func GetAll(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, &orgs) | |||
} | |||
@@ -6,7 +6,6 @@ | |||
package org | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
@@ -44,23 +43,27 @@ func ListTeams(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/TeamList" | |||
org := ctx.Org.Organization | |||
if err := org.GetTeams(&models.SearchTeamOptions{ | |||
teams, count, err := models.SearchTeam(&models.SearchTeamOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
}); err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetTeams", err) | |||
OrgID: ctx.Org.Organization.ID, | |||
}) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "LoadTeams", err) | |||
return | |||
} | |||
apiTeams := make([]*api.Team, len(org.Teams)) | |||
for i := range org.Teams { | |||
if err := org.Teams[i].GetUnits(); err != nil { | |||
apiTeams := make([]*api.Team, len(teams)) | |||
for i := range teams { | |||
if err := teams[i].GetUnits(); err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetUnits", err) | |||
return | |||
} | |||
apiTeams[i] = convert.ToTeam(org.Teams[i]) | |||
apiTeams[i] = convert.ToTeam(teams[i]) | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, apiTeams) | |||
} | |||
@@ -84,7 +87,10 @@ func ListUserTeams(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/TeamList" | |||
teams, err := models.GetUserTeams(ctx.User.ID, utils.GetListOptions(ctx)) | |||
teams, count, err := models.SearchTeam(&models.SearchTeamOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
UserID: ctx.User.ID, | |||
}) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetUserTeams", err) | |||
return | |||
@@ -106,6 +112,8 @@ func ListUserTeams(ctx *context.APIContext) { | |||
apiTeams[i] = convert.ToTeam(teams[i]) | |||
apiTeams[i].Organization = apiOrg | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, apiTeams) | |||
} | |||
@@ -327,17 +335,19 @@ func GetTeamMembers(ctx *context.APIContext) { | |||
ctx.NotFound() | |||
return | |||
} | |||
team := ctx.Org.Team | |||
if err := team.GetMembers(&models.SearchMembersOptions{ | |||
if err := ctx.Org.Team.GetMembers(&models.SearchMembersOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
}); err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetTeamMembers", err) | |||
return | |||
} | |||
members := make([]*api.User, len(team.Members)) | |||
for i, member := range team.Members { | |||
members := make([]*api.User, len(ctx.Org.Team.Members)) | |||
for i, member := range ctx.Org.Team.Members { | |||
members[i] = convert.ToUser(member, ctx.User) | |||
} | |||
ctx.SetTotalCountHeader(int64(ctx.Org.Team.NumMembers)) | |||
ctx.JSON(http.StatusOK, members) | |||
} | |||
@@ -687,8 +697,7 @@ func SearchTeam(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"ok": true, | |||
"data": apiTeams, |
@@ -282,9 +282,8 @@ func ListBranches(ctx *context.APIContext) { | |||
} | |||
} | |||
ctx.SetLinkHeader(int(totalNumOfBranches), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", totalNumOfBranches)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetLinkHeader(totalNumOfBranches, listOptions.PageSize) | |||
ctx.SetTotalCountHeader(int64(totalNumOfBranches)) | |||
ctx.JSON(http.StatusOK, &apiBranches) | |||
} | |||
@@ -47,15 +47,24 @@ func ListCollaborators(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/UserList" | |||
count, err := ctx.Repo.Repository.CountCollaborators() | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
collaborators, err := ctx.Repo.Repository.GetCollaborators(utils.GetListOptions(ctx)) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "ListCollaborators", err) | |||
return | |||
} | |||
users := make([]*api.User, len(collaborators)) | |||
for i, collaborator := range collaborators { | |||
users[i] = convert.ToUser(collaborator.User, ctx.User) | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, users) | |||
} | |||
@@ -200,16 +200,16 @@ func GetAllCommits(ctx *context.APIContext) { | |||
} | |||
} | |||
ctx.SetLinkHeader(int(commitsCountTotal), listOptions.PageSize) | |||
ctx.SetTotalCountHeader(commitsCountTotal) | |||
// kept for backwards compatibility | |||
ctx.Header().Set("X-Page", strconv.Itoa(listOptions.Page)) | |||
ctx.Header().Set("X-PerPage", strconv.Itoa(listOptions.PageSize)) | |||
ctx.Header().Set("X-Total", strconv.FormatInt(commitsCountTotal, 10)) | |||
ctx.Header().Set("X-PageCount", strconv.Itoa(pageCount)) | |||
ctx.Header().Set("X-HasMore", strconv.FormatBool(listOptions.Page < pageCount)) | |||
ctx.SetLinkHeader(int(commitsCountTotal), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", commitsCountTotal)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, X-PerPage, X-Total, X-PageCount, X-HasMore, Link") | |||
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-Total", "X-PageCount", "X-HasMore") | |||
ctx.JSON(http.StatusOK, &apiCommits) | |||
} |
@@ -62,6 +62,8 @@ func ListForks(ctx *context.APIContext) { | |||
} | |||
apiForks[i] = convert.ToRepo(fork, access) | |||
} | |||
ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumForks)) | |||
ctx.JSON(http.StatusOK, apiForks) | |||
} | |||
@@ -48,9 +48,20 @@ func ListHooks(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/HookList" | |||
hooks, err := models.GetWebhooksByRepoID(ctx.Repo.Repository.ID, utils.GetListOptions(ctx)) | |||
opts := &models.ListWebhookOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepoID: ctx.Repo.Repository.ID, | |||
} | |||
count, err := models.CountWebhooksByOpts(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetWebhooksByRepoID", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
hooks, err := models.ListWebhooksByOpts(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
@@ -58,6 +69,8 @@ func ListHooks(ctx *context.APIContext) { | |||
for i := range hooks { | |||
apiHooks[i] = convert.ToHook(ctx.Repo.RepoLink, hooks[i]) | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, &apiHooks) | |||
} | |||
@@ -232,8 +232,7 @@ func SearchIssues(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(filteredCount), setting.UI.IssuePagingNum) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", filteredCount)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(filteredCount) | |||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) | |||
} | |||
@@ -442,8 +441,7 @@ func ListIssues(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(filteredCount), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", filteredCount)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(filteredCount) | |||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) | |||
} | |||
@@ -68,17 +68,25 @@ func ListIssueComments(ctx *context.APIContext) { | |||
} | |||
issue.Repo = ctx.Repo.Repository | |||
comments, err := models.FindComments(models.FindCommentsOptions{ | |||
opts := &models.FindCommentsOptions{ | |||
IssueID: issue.ID, | |||
Since: since, | |||
Before: before, | |||
Type: models.CommentTypeComment, | |||
}) | |||
} | |||
comments, err := models.FindComments(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "FindComments", err) | |||
return | |||
} | |||
totalCount, err := models.CountComments(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
if err := models.CommentList(comments).LoadPosters(); err != nil { | |||
ctx.Error(http.StatusInternalServerError, "LoadPosters", err) | |||
return | |||
@@ -89,6 +97,8 @@ func ListIssueComments(ctx *context.APIContext) { | |||
comment.Issue = issue | |||
apiComments[i] = convert.ToComment(comments[i]) | |||
} | |||
ctx.SetTotalCountHeader(totalCount) | |||
ctx.JSON(http.StatusOK, &apiComments) | |||
} | |||
@@ -138,18 +148,26 @@ func ListRepoIssueComments(ctx *context.APIContext) { | |||
return | |||
} | |||
comments, err := models.FindComments(models.FindCommentsOptions{ | |||
opts := &models.FindCommentsOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepoID: ctx.Repo.Repository.ID, | |||
Type: models.CommentTypeComment, | |||
Since: since, | |||
Before: before, | |||
}) | |||
} | |||
comments, err := models.FindComments(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "FindComments", err) | |||
return | |||
} | |||
totalCount, err := models.CountComments(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
if err = models.CommentList(comments).LoadPosters(); err != nil { | |||
ctx.Error(http.StatusInternalServerError, "LoadPosters", err) | |||
return | |||
@@ -171,6 +189,8 @@ func ListRepoIssueComments(ctx *context.APIContext) { | |||
for i := range comments { | |||
apiComments[i] = convert.ToComment(comments[i]) | |||
} | |||
ctx.SetTotalCountHeader(totalCount) | |||
ctx.JSON(http.StatusOK, &apiComments) | |||
} | |||
@@ -225,11 +225,18 @@ func GetStopwatches(ctx *context.APIContext) { | |||
return | |||
} | |||
count, err := models.CountUserStopwatches(ctx.User.ID) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
apiSWs, err := convert.ToStopWatches(sws) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "APIFormat", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, apiSWs) | |||
} |
@@ -83,7 +83,7 @@ func ListTrackedTimes(ctx *context.APIContext) { | |||
return | |||
} | |||
opts := models.FindTrackedTimesOptions{ | |||
opts := &models.FindTrackedTimesOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepositoryID: ctx.Repo.Repository.ID, | |||
IssueID: issue.ID, | |||
@@ -119,6 +119,12 @@ func ListTrackedTimes(ctx *context.APIContext) { | |||
} | |||
} | |||
count, err := models.CountTrackedTimes(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
trackedTimes, err := models.GetTrackedTimes(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetTrackedTimes", err) | |||
@@ -128,6 +134,8 @@ func ListTrackedTimes(ctx *context.APIContext) { | |||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) | |||
} | |||
@@ -423,7 +431,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { | |||
return | |||
} | |||
opts := models.FindTrackedTimesOptions{ | |||
opts := &models.FindTrackedTimesOptions{ | |||
UserID: user.ID, | |||
RepositoryID: ctx.Repo.Repository.ID, | |||
} | |||
@@ -493,7 +501,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { | |||
return | |||
} | |||
opts := models.FindTrackedTimesOptions{ | |||
opts := &models.FindTrackedTimesOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepositoryID: ctx.Repo.Repository.ID, | |||
} | |||
@@ -530,6 +538,12 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { | |||
} | |||
} | |||
count, err := models.CountTrackedTimes(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
trackedTimes, err := models.GetTrackedTimes(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetTrackedTimes", err) | |||
@@ -539,6 +553,8 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { | |||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) | |||
} | |||
@@ -573,7 +589,7 @@ func ListMyTrackedTimes(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/TrackedTimeList" | |||
opts := models.FindTrackedTimesOptions{ | |||
opts := &models.FindTrackedTimesOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
UserID: ctx.User.ID, | |||
} | |||
@@ -584,6 +600,12 @@ func ListMyTrackedTimes(ctx *context.APIContext) { | |||
return | |||
} | |||
count, err := models.CountTrackedTimes(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
trackedTimes, err := models.GetTrackedTimes(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetTrackedTimesByUser", err) | |||
@@ -595,5 +617,6 @@ func ListMyTrackedTimes(ctx *context.APIContext) { | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(trackedTimes)) | |||
} |
@@ -75,26 +75,29 @@ func ListDeployKeys(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/DeployKeyList" | |||
var keys []*models.DeployKey | |||
var err error | |||
opts := &models.ListDeployKeysOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepoID: ctx.Repo.Repository.ID, | |||
KeyID: ctx.FormInt64("key_id"), | |||
Fingerprint: ctx.FormString("fingerprint"), | |||
} | |||
fingerprint := ctx.FormString("fingerprint") | |||
keyID := ctx.FormInt64("key_id") | |||
if fingerprint != "" || keyID != 0 { | |||
keys, err = models.SearchDeployKeys(ctx.Repo.Repository.ID, keyID, fingerprint) | |||
} else { | |||
keys, err = models.ListDeployKeys(ctx.Repo.Repository.ID, utils.GetListOptions(ctx)) | |||
keys, err := models.ListDeployKeys(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
count, err := models.CountDeployKeys(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "ListDeployKeys", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name) | |||
apiKeys := make([]*api.DeployKey, len(keys)) | |||
for i := range keys { | |||
if err = keys[i].GetContent(); err != nil { | |||
if err := keys[i].GetContent(); err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetContent", err) | |||
return | |||
} | |||
@@ -104,6 +107,7 @@ func ListDeployKeys(ctx *context.APIContext) { | |||
} | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, &apiKeys) | |||
} | |||
@@ -55,6 +55,13 @@ func ListLabels(ctx *context.APIContext) { | |||
return | |||
} | |||
count, err := models.CountLabelsByRepoID(ctx.Repo.Repository.ID) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToLabelList(labels)) | |||
} | |||
@@ -57,7 +57,7 @@ func ListMilestones(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/MilestoneList" | |||
milestones, err := models.GetMilestones(models.GetMilestonesOption{ | |||
milestones, total, err := models.GetMilestones(models.GetMilestonesOption{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepoID: ctx.Repo.Repository.ID, | |||
State: api.StateType(ctx.FormString("state")), | |||
@@ -72,6 +72,8 @@ func ListMilestones(ctx *context.APIContext) { | |||
for i := range milestones { | |||
apiMilestones[i] = convert.ToAPIMilestone(milestones[i]) | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, &apiMilestones) | |||
} | |||
@@ -119,8 +119,7 @@ func ListPullRequests(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, &apiPrs) | |||
} | |||
@@ -1232,13 +1231,14 @@ func GetPullRequestCommits(ctx *context.APIContext) { | |||
apiCommits = append(apiCommits, apiCommit) | |||
} | |||
ctx.SetLinkHeader(int(totalNumberOfCommits), listOptions.PageSize) | |||
ctx.SetLinkHeader(totalNumberOfCommits, listOptions.PageSize) | |||
ctx.SetTotalCountHeader(int64(totalNumberOfCommits)) | |||
ctx.Header().Set("X-Page", strconv.Itoa(listOptions.Page)) | |||
ctx.Header().Set("X-PerPage", strconv.Itoa(listOptions.PageSize)) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", totalNumberOfCommits)) | |||
ctx.Header().Set("X-PageCount", strconv.Itoa(totalNumberOfPages)) | |||
ctx.Header().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, X-PerPage, X-Total, X-PageCount, X-HasMore, Link") | |||
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore") | |||
ctx.JSON(http.StatusOK, &apiCommits) | |||
} |
@@ -78,14 +78,21 @@ func ListPullReviews(ctx *context.APIContext) { | |||
return | |||
} | |||
allReviews, err := models.FindReviews(models.FindReviewOptions{ | |||
opts := models.FindReviewOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
Type: models.ReviewTypeUnknown, | |||
IssueID: pr.IssueID, | |||
}) | |||
} | |||
allReviews, err := models.FindReviews(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
count, err := models.CountReviews(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "FindReviews", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
@@ -95,6 +102,7 @@ func ListPullReviews(ctx *context.APIContext) { | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, &apiReviews) | |||
} | |||
@@ -5,7 +5,6 @@ | |||
package repo | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
@@ -142,8 +141,7 @@ func ListReleases(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(filteredCount), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprint(filteredCount)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(filteredCount) | |||
ctx.JSON(http.StatusOK, rels) | |||
} | |||
@@ -230,8 +230,7 @@ func Search(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(count), opts.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", count)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, api.SearchResults{ | |||
OK: true, | |||
Data: results, |
@@ -52,5 +52,7 @@ func ListStargazers(ctx *context.APIContext) { | |||
for i, stargazer := range stargazers { | |||
users[i] = convert.ToUser(stargazer, ctx.User) | |||
} | |||
ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumStars)) | |||
ctx.JSON(http.StatusOK, users) | |||
} |
@@ -204,8 +204,7 @@ func getCommitStatuses(ctx *context.APIContext, sha string) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, apiStatuses) | |||
} | |||
@@ -267,5 +266,6 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) { | |||
combiStatus := convert.ToCombinedStatus(statuses, convert.ToRepo(repo, ctx.Repo.AccessMode)) | |||
// TODO: ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, combiStatus) | |||
} |
@@ -52,5 +52,7 @@ func ListSubscribers(ctx *context.APIContext) { | |||
for i, subscriber := range subscribers { | |||
users[i] = convert.ToUser(subscriber, ctx.User) | |||
} | |||
ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumWatches)) | |||
ctx.JSON(http.StatusOK, users) | |||
} |
@@ -50,7 +50,7 @@ func ListTags(ctx *context.APIContext) { | |||
listOpts := utils.GetListOptions(ctx) | |||
tags, err := ctx.Repo.GitRepo.GetTagInfos(listOpts.Page, listOpts.PageSize) | |||
tags, total, err := ctx.Repo.GitRepo.GetTagInfos(listOpts.Page, listOpts.PageSize) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetTags", err) | |||
return | |||
@@ -61,6 +61,7 @@ func ListTags(ctx *context.APIContext) { | |||
apiTags[i] = convert.ToTag(ctx.Repo.Repository, tags[i]) | |||
} | |||
ctx.SetTotalCountHeader(int64(total)) | |||
ctx.JSON(http.StatusOK, &apiTags) | |||
} | |||
@@ -47,12 +47,13 @@ func ListTopics(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/TopicNames" | |||
topics, err := models.FindTopics(&models.FindTopicOptions{ | |||
opts := &models.FindTopicOptions{ | |||
ListOptions: utils.GetListOptions(ctx), | |||
RepoID: ctx.Repo.Repository.ID, | |||
}) | |||
} | |||
topics, total, err := models.FindTopics(opts) | |||
if err != nil { | |||
log.Error("ListTopics failed: %v", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
@@ -61,6 +62,8 @@ func ListTopics(ctx *context.APIContext) { | |||
for i, topic := range topics { | |||
topicNames[i] = topic.Name | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"topics": topicNames, | |||
}) | |||
@@ -164,15 +167,15 @@ func AddTopic(ctx *context.APIContext) { | |||
} | |||
// Prevent adding more topics than allowed to repo | |||
topics, err := models.FindTopics(&models.FindTopicOptions{ | |||
count, err := models.CountTopics(&models.FindTopicOptions{ | |||
RepoID: ctx.Repo.Repository.ID, | |||
}) | |||
if err != nil { | |||
log.Error("AddTopic failed: %v", err) | |||
log.Error("CountTopics failed: %v", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
if len(topics) >= 25 { | |||
if count >= 25 { | |||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{ | |||
"message": "Exceeding maximum allowed topics per repo.", | |||
}) | |||
@@ -269,21 +272,13 @@ func TopicSearch(ctx *context.APIContext) { | |||
// "403": | |||
// "$ref": "#/responses/forbidden" | |||
if ctx.User == nil { | |||
ctx.Error(http.StatusForbidden, "UserIsNil", "Only owners could change the topics.") | |||
return | |||
opts := &models.FindTopicOptions{ | |||
Keyword: ctx.FormString("q"), | |||
ListOptions: utils.GetListOptions(ctx), | |||
} | |||
kw := ctx.FormString("q") | |||
listOptions := utils.GetListOptions(ctx) | |||
topics, err := models.FindTopics(&models.FindTopicOptions{ | |||
Keyword: kw, | |||
ListOptions: listOptions, | |||
}) | |||
topics, total, err := models.FindTopics(opts) | |||
if err != nil { | |||
log.Error("SearchTopics failed: %v", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
@@ -292,6 +287,8 @@ func TopicSearch(ctx *context.APIContext) { | |||
for i, topic := range topics { | |||
topicResponses[i] = convert.ToTopicResponse(topic) | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"topics": topicResponses, | |||
}) |
@@ -44,9 +44,16 @@ func ListAccessTokens(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/AccessTokenList" | |||
tokens, err := models.ListAccessTokens(models.ListAccessTokensOptions{UserID: ctx.User.ID, ListOptions: utils.GetListOptions(ctx)}) | |||
opts := models.ListAccessTokensOptions{UserID: ctx.User.ID, ListOptions: utils.GetListOptions(ctx)} | |||
count, err := models.CountAccessTokens(opts) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
tokens, err := models.ListAccessTokens(opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "ListAccessTokens", err) | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
@@ -58,6 +65,8 @@ func ListAccessTokens(ctx *context.APIContext) { | |||
TokenLastEight: tokens[i].TokenLastEight, | |||
} | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, &apiTokens) | |||
} | |||
@@ -242,7 +251,7 @@ func ListOauth2Applications(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/OAuth2ApplicationList" | |||
apps, err := models.ListOAuth2Applications(ctx.User.ID, utils.GetListOptions(ctx)) | |||
apps, total, err := models.ListOAuth2Applications(ctx.User.ID, utils.GetListOptions(ctx)) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "ListOAuth2Applications", err) | |||
return | |||
@@ -253,6 +262,8 @@ func ListOauth2Applications(ctx *context.APIContext) { | |||
apiApps[i] = convert.ToOAuth2Application(apps[i]) | |||
apiApps[i].ClientSecret = "" // Hide secret on application list | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, &apiApps) | |||
} | |||
@@ -29,6 +29,8 @@ func listUserFollowers(ctx *context.APIContext, u *models.User) { | |||
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(int64(u.NumFollowers)) | |||
responseAPIUsers(ctx, users) | |||
} | |||
@@ -93,6 +95,8 @@ func listUserFollowing(ctx *context.APIContext, u *models.User) { | |||
ctx.Error(http.StatusInternalServerError, "GetFollowing", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(int64(u.NumFollowing)) | |||
responseAPIUsers(ctx, users) | |||
} | |||
@@ -28,6 +28,13 @@ func listGPGKeys(ctx *context.APIContext, uid int64, listOptions models.ListOpti | |||
apiKeys[i] = convert.ToGPGKey(keys[i]) | |||
} | |||
total, err := models.CountUserGPGKeys(uid) | |||
if err != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, &apiKeys) | |||
} | |||
@@ -47,6 +47,7 @@ func composePublicKeysAPILink() string { | |||
func listPublicKeys(ctx *context.APIContext, user *models.User) { | |||
var keys []*models.PublicKey | |||
var err error | |||
var count int | |||
fingerprint := ctx.FormString("fingerprint") | |||
username := ctx.Params("username") | |||
@@ -60,7 +61,15 @@ func listPublicKeys(ctx *context.APIContext, user *models.User) { | |||
// Unrestricted | |||
keys, err = models.SearchPublicKey(0, fingerprint) | |||
} | |||
count = len(keys) | |||
} else { | |||
total, err2 := models.CountPublicKeys(user.ID) | |||
if err2 != nil { | |||
ctx.InternalServerError(err) | |||
return | |||
} | |||
count = int(total) | |||
// Use ListPublicKeys | |||
keys, err = models.ListPublicKeys(user.ID, utils.GetListOptions(ctx)) | |||
} | |||
@@ -79,6 +88,7 @@ func listPublicKeys(ctx *context.APIContext, user *models.User) { | |||
} | |||
} | |||
ctx.SetTotalCountHeader(int64(count)) | |||
ctx.JSON(http.StatusOK, &apiKeys) | |||
} | |||
@@ -6,7 +6,6 @@ package user | |||
import ( | |||
"net/http" | |||
"strconv" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
@@ -43,8 +42,7 @@ func listUserRepos(ctx *context.APIContext, u *models.User, private bool) { | |||
} | |||
ctx.SetLinkHeader(int(count), opts.PageSize) | |||
ctx.Header().Set("X-Total-Count", strconv.FormatInt(count, 10)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, &apiRepos) | |||
} | |||
@@ -130,8 +128,7 @@ func ListMyRepos(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(count), opts.ListOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", strconv.FormatInt(count, 10)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, &results) | |||
} | |||
@@ -92,6 +92,8 @@ func GetMyStarredRepos(ctx *context.APIContext) { | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "getStarredRepos", err) | |||
} | |||
ctx.SetTotalCountHeader(int64(ctx.User.NumStars)) | |||
ctx.JSON(http.StatusOK, &repos) | |||
} | |||
@@ -6,7 +6,6 @@ | |||
package user | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
@@ -73,8 +72,7 @@ func Search(ctx *context.APIContext) { | |||
} | |||
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) | |||
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) | |||
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") | |||
ctx.SetTotalCountHeader(maxResults) | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"ok": true, |
@@ -14,23 +14,22 @@ import ( | |||
"code.gitea.io/gitea/routers/api/v1/utils" | |||
) | |||
// getWatchedRepos returns the repos that the user with the specified userID is | |||
// watching | |||
func getWatchedRepos(user *models.User, private bool, listOptions models.ListOptions) ([]*api.Repository, error) { | |||
watchedRepos, err := models.GetWatchedRepos(user.ID, private, listOptions) | |||
// getWatchedRepos returns the repos that the user with the specified userID is watching | |||
func getWatchedRepos(user *models.User, private bool, listOptions models.ListOptions) ([]*api.Repository, int64, error) { | |||
watchedRepos, total, err := models.GetWatchedRepos(user.ID, private, listOptions) | |||
if err != nil { | |||
return nil, err | |||
return nil, 0, err | |||
} | |||
repos := make([]*api.Repository, len(watchedRepos)) | |||
for i, watched := range watchedRepos { | |||
access, err := models.AccessLevel(user, watched) | |||
if err != nil { | |||
return nil, err | |||
return nil, 0, err | |||
} | |||
repos[i] = convert.ToRepo(watched, access) | |||
} | |||
return repos, nil | |||
return repos, total, nil | |||
} | |||
// GetWatchedRepos returns the repos that the user specified in ctx is watching | |||
@@ -60,10 +59,12 @@ func GetWatchedRepos(ctx *context.APIContext) { | |||
user := GetUserByParams(ctx) | |||
private := user.ID == ctx.User.ID | |||
repos, err := getWatchedRepos(user, private, utils.GetListOptions(ctx)) | |||
repos, total, err := getWatchedRepos(user, private, utils.GetListOptions(ctx)) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err) | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, &repos) | |||
} | |||
@@ -87,10 +88,12 @@ func GetMyWatchedRepos(ctx *context.APIContext) { | |||
// "200": | |||
// "$ref": "#/responses/RepositoryList" | |||
repos, err := getWatchedRepos(ctx.User, true, utils.GetListOptions(ctx)) | |||
repos, total, err := getWatchedRepos(ctx.User, true, utils.GetListOptions(ctx)) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err) | |||
} | |||
ctx.SetTotalCountHeader(total) | |||
ctx.JSON(http.StatusOK, &repos) | |||
} | |||
@@ -107,7 +107,7 @@ func Home(ctx *context.Context) { | |||
return | |||
} | |||
var opts = models.FindOrgMembersOpts{ | |||
var opts = &models.FindOrgMembersOpts{ | |||
OrgID: org.ID, | |||
PublicOnly: true, | |||
ListOptions: models.ListOptions{Page: 1, PageSize: 25}, | |||
@@ -122,7 +122,7 @@ func Home(ctx *context.Context) { | |||
opts.PublicOnly = !isMember && !ctx.User.IsAdmin | |||
} | |||
members, _, err := models.FindOrgMembers(&opts) | |||
members, _, err := models.FindOrgMembers(opts) | |||
if err != nil { | |||
ctx.ServerError("FindOrgMembers", err) | |||
return |
@@ -31,7 +31,7 @@ func Members(ctx *context.Context) { | |||
page = 1 | |||
} | |||
var opts = models.FindOrgMembersOpts{ | |||
var opts = &models.FindOrgMembersOpts{ | |||
OrgID: org.ID, | |||
PublicOnly: true, | |||
} | |||
@@ -54,7 +54,7 @@ func Members(ctx *context.Context) { | |||
pager := context.NewPagination(int(total), setting.UI.MembersPagingNum, page, 5) | |||
opts.ListOptions.Page = page | |||
opts.ListOptions.PageSize = setting.UI.MembersPagingNum | |||
members, membersIsPublic, err := models.FindOrgMembers(&opts) | |||
members, membersIsPublic, err := models.FindOrgMembers(opts) | |||
if err != nil { | |||
ctx.ServerError("GetMembers", err) | |||
return |
@@ -186,7 +186,7 @@ func Webhooks(ctx *context.Context) { | |||
ctx.Data["BaseLinkNew"] = ctx.Org.OrgLink + "/settings/hooks" | |||
ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc") | |||
ws, err := models.GetWebhooksByOrgID(ctx.Org.Organization.ID, models.ListOptions{}) | |||
ws, err := models.ListWebhooksByOpts(&models.ListWebhookOptions{OrgID: ctx.Org.Organization.ID}) | |||
if err != nil { | |||
ctx.ServerError("GetWebhooksByOrgId", err) | |||
return |
@@ -378,7 +378,7 @@ func Issues(ctx *context.Context) { | |||
var err error | |||
// Get milestones | |||
ctx.Data["Milestones"], err = models.GetMilestones(models.GetMilestonesOption{ | |||
ctx.Data["Milestones"], _, err = models.GetMilestones(models.GetMilestonesOption{ | |||
RepoID: ctx.Repo.Repository.ID, | |||
State: api.StateType(ctx.FormString("state")), | |||
}) | |||
@@ -395,7 +395,7 @@ func Issues(ctx *context.Context) { | |||
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository | |||
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repository) { | |||
var err error | |||
ctx.Data["OpenMilestones"], err = models.GetMilestones(models.GetMilestonesOption{ | |||
ctx.Data["OpenMilestones"], _, err = models.GetMilestones(models.GetMilestonesOption{ | |||
RepoID: repo.ID, | |||
State: api.StateOpen, | |||
}) | |||
@@ -403,7 +403,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repos | |||
ctx.ServerError("GetMilestones", err) | |||
return | |||
} | |||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(models.GetMilestonesOption{ | |||
ctx.Data["ClosedMilestones"], _, err = models.GetMilestones(models.GetMilestonesOption{ | |||
RepoID: repo.ID, | |||
State: api.StateClosed, | |||
}) | |||
@@ -1265,7 +1265,7 @@ func ViewIssue(ctx *context.Context) { | |||
} else { | |||
ctx.Data["CanUseTimetracker"] = false | |||
} | |||
if ctx.Data["WorkingUsers"], err = models.TotalTimes(models.FindTrackedTimesOptions{IssueID: issue.ID}); err != nil { | |||
if ctx.Data["WorkingUsers"], err = models.TotalTimes(&models.FindTrackedTimesOptions{IssueID: issue.ID}); err != nil { | |||
ctx.ServerError("TotalTimes", err) | |||
return | |||
} | |||
@@ -2584,8 +2584,8 @@ func handleTeamMentions(ctx *context.Context) { | |||
} | |||
if isAdmin { | |||
if err := ctx.Repo.Owner.GetTeams(&models.SearchTeamOptions{}); err != nil { | |||
ctx.ServerError("GetTeams", err) | |||
if err := ctx.Repo.Owner.LoadTeams(); err != nil { | |||
ctx.ServerError("LoadTeams", err) | |||
return | |||
} | |||
} else { |
@@ -53,17 +53,12 @@ func Milestones(ctx *context.Context) { | |||
page = 1 | |||
} | |||
var total int | |||
var state structs.StateType | |||
if !isShowClosed { | |||
total = int(stats.OpenCount) | |||
state = structs.StateOpen | |||
} else { | |||
total = int(stats.ClosedCount) | |||
state := structs.StateOpen | |||
if isShowClosed { | |||
state = structs.StateClosed | |||
} | |||
miles, err := models.GetMilestones(models.GetMilestonesOption{ | |||
miles, total, err := models.GetMilestones(models.GetMilestonesOption{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.IssuePagingNum, | |||
@@ -106,7 +101,7 @@ func Milestones(ctx *context.Context) { | |||
ctx.Data["Keyword"] = keyword | |||
ctx.Data["IsShowClosed"] = isShowClosed | |||
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5) | |||
pager := context.NewPagination(int(total), setting.UI.IssuePagingNum, page, 5) | |||
pager.AddParam(ctx, "state", "State") | |||
pager.AddParam(ctx, "q", "Keyword") | |||
ctx.Data["Page"] = pager |
@@ -1002,7 +1002,7 @@ func DeployKeys(ctx *context.Context) { | |||
ctx.Data["PageIsSettingsKeys"] = true | |||
ctx.Data["DisableSSH"] = setting.SSH.Disabled | |||
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID, models.ListOptions{}) | |||
keys, err := models.ListDeployKeys(&models.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID}) | |||
if err != nil { | |||
ctx.ServerError("ListDeployKeys", err) | |||
return | |||
@@ -1018,7 +1018,7 @@ func DeployKeysPost(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys") | |||
ctx.Data["PageIsSettingsKeys"] = true | |||
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID, models.ListOptions{}) | |||
keys, err := models.ListDeployKeys(&models.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID}) | |||
if err != nil { | |||
ctx.ServerError("ListDeployKeys", err) | |||
return |
@@ -674,7 +674,7 @@ func renderLanguageStats(ctx *context.Context) { | |||
} | |||
func renderRepoTopics(ctx *context.Context) { | |||
topics, err := models.FindTopics(&models.FindTopicOptions{ | |||
topics, _, err := models.FindTopics(&models.FindTopicOptions{ | |||
RepoID: ctx.Repo.Repository.ID, | |||
}) | |||
if err != nil { |
@@ -41,7 +41,7 @@ func Webhooks(ctx *context.Context) { | |||
ctx.Data["BaseLinkNew"] = ctx.Repo.RepoLink + "/settings/hooks" | |||
ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://docs.gitea.io/en-us/webhooks/") | |||
ws, err := models.GetWebhooksByRepoID(ctx.Repo.Repository.ID, models.ListOptions{}) | |||
ws, err := models.ListWebhooksByOpts(&models.ListWebhookOptions{RepoID: ctx.Repo.Repository.ID}) | |||
if err != nil { | |||
ctx.ServerError("GetWebhooksByRepoID", err) | |||
return |
@@ -132,7 +132,7 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models | |||
head := pr.GetGitRefName() | |||
if line > 0 { | |||
if reviewID != 0 { | |||
first, err := models.FindComments(models.FindCommentsOptions{ | |||
first, err := models.FindComments(&models.FindCommentsOptions{ | |||
ReviewID: reviewID, | |||
Line: line, | |||
TreePath: treePath, |
@@ -14,6 +14,8 @@ import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/sync" | |||
"code.gitea.io/gitea/modules/util" | |||
"github.com/gobwas/glob" | |||
) | |||
@@ -187,7 +189,10 @@ func PrepareWebhooks(repo *models.Repository, event models.HookEventType, p api. | |||
} | |||
func prepareWebhooks(repo *models.Repository, event models.HookEventType, p api.Payloader) error { | |||
ws, err := models.GetActiveWebhooksByRepoID(repo.ID) | |||
ws, err := models.ListWebhooksByOpts(&models.ListWebhookOptions{ | |||
RepoID: repo.ID, | |||
IsActive: util.OptionalBoolTrue, | |||
}) | |||
if err != nil { | |||
return fmt.Errorf("GetActiveWebhooksByRepoID: %v", err) | |||
} | |||
@@ -195,7 +200,10 @@ func prepareWebhooks(repo *models.Repository, event models.HookEventType, p api. | |||
// check if repo belongs to org and append additional webhooks | |||
if repo.MustOwner().IsOrganization() { | |||
// get hooks for org | |||
orgHooks, err := models.GetActiveWebhooksByOrgID(repo.OwnerID) | |||
orgHooks, err := models.ListWebhooksByOpts(&models.ListWebhookOptions{ | |||
OrgID: repo.OwnerID, | |||
IsActive: util.OptionalBoolTrue, | |||
}) | |||
if err != nil { | |||
return fmt.Errorf("GetActiveWebhooksByOrgID: %v", err) | |||
} |