Skip to content

Commit 2289580

Browse files
authored
[API] generalize list header (#16551)
* 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 func
1 parent ca13e1d commit 2289580

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+636
-328
lines changed

CONTRIBUTING.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ In general, HTTP methods are chosen as follows:
207207

208208
An endpoint which changes/edits an object expects all fields to be optional (except ones to identify the object, which are required).
209209

210+
### Endpoints returning lists should
211+
* support pagination (`page` & `limit` options in query)
212+
* set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
213+
210214

211215
## Developer Certificate of Origin (DCO)
212216

@@ -231,8 +235,8 @@ on, finishing, and issuing releases. The overall goal is to make a
231235
minor release every three or four months, which breaks down into two or three months of
232236
general development followed by one month of testing and polishing
233237
known as the release freeze. All the feature pull requests should be
234-
merged before feature freeze. And, during the frozen period, a corresponding
235-
release branch is open for fixes backported from main branch. Release candidates
238+
merged before feature freeze. And, during the frozen period, a corresponding
239+
release branch is open for fixes backported from main branch. Release candidates
236240
are made during this period for user testing to
237241
obtain a final version that is maintained in this branch. A release is
238242
maintained by issuing patch releases to only correct critical problems

integrations/api_issue_tracked_time_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestAPIGetTrackedTimes(t *testing.T) {
3030
resp := session.MakeRequest(t, req, http.StatusOK)
3131
var apiTimes api.TrackedTimeList
3232
DecodeJSON(t, resp, &apiTimes)
33-
expect, err := models.GetTrackedTimes(models.FindTrackedTimesOptions{IssueID: issue2.ID})
33+
expect, err := models.GetTrackedTimes(&models.FindTrackedTimesOptions{IssueID: issue2.ID})
3434
assert.NoError(t, err)
3535
assert.Len(t, apiTimes, 3)
3636

integrations/api_repo_topic_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package integrations
77
import (
88
"fmt"
99
"net/http"
10+
"net/url"
1011
"testing"
1112

1213
"code.gitea.io/gitea/models"
@@ -15,6 +16,38 @@ import (
1516
"github.com/stretchr/testify/assert"
1617
)
1718

19+
func TestAPITopicSearch(t *testing.T) {
20+
defer prepareTestEnv(t)()
21+
searchURL, _ := url.Parse("/api/v1/topics/search")
22+
var topics struct {
23+
TopicNames []*api.TopicResponse `json:"topics"`
24+
}
25+
26+
query := url.Values{"page": []string{"1"}, "limit": []string{"4"}}
27+
28+
searchURL.RawQuery = query.Encode()
29+
res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
30+
DecodeJSON(t, res, &topics)
31+
assert.Len(t, topics.TopicNames, 4)
32+
assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
33+
34+
query.Add("q", "topic")
35+
searchURL.RawQuery = query.Encode()
36+
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
37+
DecodeJSON(t, res, &topics)
38+
assert.Len(t, topics.TopicNames, 2)
39+
40+
query.Set("q", "database")
41+
searchURL.RawQuery = query.Encode()
42+
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
43+
DecodeJSON(t, res, &topics)
44+
if assert.Len(t, topics.TopicNames, 1) {
45+
assert.EqualValues(t, 2, topics.TopicNames[0].ID)
46+
assert.EqualValues(t, "database", topics.TopicNames[0].Name)
47+
assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount)
48+
}
49+
}
50+
1851
func TestAPIRepoTopic(t *testing.T) {
1952
defer prepareTestEnv(t)()
2053
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) // owner of repo2

models/access.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err
246246
return fmt.Errorf("refreshCollaboratorAccesses: %v", err)
247247
}
248248

249-
if err = repo.Owner.getTeams(e); err != nil {
249+
if err = repo.Owner.loadTeams(e); err != nil {
250250
return err
251251
}
252252

models/commit_status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func getLatestCommitStatus(e Engine, repoID int64, sha string, listOptions ListO
159159
if len(ids) == 0 {
160160
return statuses, nil
161161
}
162-
return statuses, x.In("id", ids).Find(&statuses)
162+
return statuses, e.In("id", ids).Find(&statuses)
163163
}
164164

165165
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts

models/gpg_key.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ func listGPGKeys(e Engine, uid int64, listOptions ListOptions) ([]*GPGKey, error
7171
return keys, sess.Find(&keys)
7272
}
7373

74+
// CountUserGPGKeys return number of gpg keys a user own
75+
func CountUserGPGKeys(userID int64) (int64, error) {
76+
return x.Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
77+
}
78+
7479
// GetGPGKeyByID returns public key by given ID.
7580
func GetGPGKeyByID(keyID int64) (*GPGKey, error) {
7681
key := new(GPGKey)

models/issue.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func init() {
8989

9090
func (issue *Issue) loadTotalTimes(e Engine) (err error) {
9191
opts := FindTrackedTimesOptions{IssueID: issue.ID}
92-
issue.TotalTrackedTime, err = opts.ToSession(e).SumInt(&TrackedTime{}, "time")
92+
issue.TotalTrackedTime, err = opts.toSession(e).SumInt(&TrackedTime{}, "time")
9393
if err != nil {
9494
return err
9595
}
@@ -214,7 +214,7 @@ func (issue *Issue) loadCommentsByType(e Engine, tp CommentType) (err error) {
214214
if issue.Comments != nil {
215215
return nil
216216
}
217-
issue.Comments, err = findComments(e, FindCommentsOptions{
217+
issue.Comments, err = findComments(e, &FindCommentsOptions{
218218
IssueID: issue.ID,
219219
Type: tp,
220220
})

models/issue_comment.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ func (opts *FindCommentsOptions) toConds() builder.Cond {
999999
return cond
10001000
}
10011001

1002-
func findComments(e Engine, opts FindCommentsOptions) ([]*Comment, error) {
1002+
func findComments(e Engine, opts *FindCommentsOptions) ([]*Comment, error) {
10031003
comments := make([]*Comment, 0, 10)
10041004
sess := e.Where(opts.toConds())
10051005
if opts.RepoID > 0 {
@@ -1019,10 +1019,19 @@ func findComments(e Engine, opts FindCommentsOptions) ([]*Comment, error) {
10191019
}
10201020

10211021
// FindComments returns all comments according options
1022-
func FindComments(opts FindCommentsOptions) ([]*Comment, error) {
1022+
func FindComments(opts *FindCommentsOptions) ([]*Comment, error) {
10231023
return findComments(x, opts)
10241024
}
10251025

1026+
// CountComments count all comments according options by ignoring pagination
1027+
func CountComments(opts *FindCommentsOptions) (int64, error) {
1028+
sess := x.Where(opts.toConds())
1029+
if opts.RepoID > 0 {
1030+
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
1031+
}
1032+
return sess.Count(&Comment{})
1033+
}
1034+
10261035
// UpdateComment updates information of comment.
10271036
func UpdateComment(c *Comment, doer *User) error {
10281037
sess := x.NewSession()

models/issue_label.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,11 @@ func GetLabelsByRepoID(repoID int64, sortType string, listOptions ListOptions) (
444444
return getLabelsByRepoID(x, repoID, sortType, listOptions)
445445
}
446446

447+
// CountLabelsByRepoID count number of all labels that belong to given repository by ID.
448+
func CountLabelsByRepoID(repoID int64) (int64, error) {
449+
return x.Where("repo_id = ?", repoID).Count(&Label{})
450+
}
451+
447452
// ________
448453
// \_____ \_______ ____
449454
// / | \_ __ \/ ___\
@@ -556,6 +561,11 @@ func GetLabelsByOrgID(orgID int64, sortType string, listOptions ListOptions) ([]
556561
return getLabelsByOrgID(x, orgID, sortType, listOptions)
557562
}
558563

564+
// CountLabelsByOrgID count all labels that belong to given organization by ID.
565+
func CountLabelsByOrgID(orgID int64) (int64, error) {
566+
return x.Where("org_id = ?", orgID).Count(&Label{})
567+
}
568+
559569
// .___
560570
// | | ______ ________ __ ____
561571
// | |/ ___// ___/ | \_/ __ \

models/issue_milestone.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -380,24 +380,33 @@ type GetMilestonesOption struct {
380380
SortType string
381381
}
382382

383-
// GetMilestones returns milestones filtered by GetMilestonesOption's
384-
func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) {
385-
sess := x.Where("repo_id = ?", opts.RepoID)
383+
func (opts GetMilestonesOption) toCond() builder.Cond {
384+
cond := builder.NewCond()
385+
if opts.RepoID != 0 {
386+
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
387+
}
386388

387389
switch opts.State {
388390
case api.StateClosed:
389-
sess = sess.And("is_closed = ?", true)
391+
cond = cond.And(builder.Eq{"is_closed": true})
390392
case api.StateAll:
391393
break
392394
// api.StateOpen:
393395
default:
394-
sess = sess.And("is_closed = ?", false)
396+
cond = cond.And(builder.Eq{"is_closed": false})
395397
}
396398

397399
if len(opts.Name) != 0 {
398-
sess = sess.And(builder.Like{"name", opts.Name})
400+
cond = cond.And(builder.Like{"name", opts.Name})
399401
}
400402

403+
return cond
404+
}
405+
406+
// GetMilestones returns milestones filtered by GetMilestonesOption's
407+
func GetMilestones(opts GetMilestonesOption) (MilestoneList, int64, error) {
408+
sess := x.Where(opts.toCond())
409+
401410
if opts.Page != 0 {
402411
sess = opts.setSessionPagination(sess)
403412
}
@@ -420,7 +429,8 @@ func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) {
420429
}
421430

422431
miles := make([]*Milestone, 0, opts.PageSize)
423-
return miles, sess.Find(&miles)
432+
total, err := sess.FindAndCount(&miles)
433+
return miles, total, err
424434
}
425435

426436
// SearchMilestones search milestones

0 commit comments

Comments
 (0)