loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(api): add sort parameter to list issues API (#7211)

- Add the `sort` parameter to the `/api/v1/{repo}/{owner}/issues` API endpoint. Default behavior is preserved.
- Resolves forgejo/forgejo#4173
- Add (non-exhaustive) integration testing.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7211
Reviewed-by: Otto <otto@codeberg.org>
Co-authored-by: Gusted <postmaster@gusted.xyz>
Co-committed-by: Gusted <postmaster@gusted.xyz>

authored by

Gusted
Gusted
and committed by
Earl Warren
7d6d4f94 a624b6a8

+97 -1
+28
modules/indexer/issues/indexer.go
··· 8 8 "fmt" 9 9 "os" 10 10 "runtime/pprof" 11 + "strings" 11 12 "sync/atomic" 12 13 "time" 13 14 ··· 279 280 SortByCommentsAsc = internal.SortByCommentsAsc 280 281 SortByDeadlineAsc = internal.SortByDeadlineAsc 281 282 ) 283 + 284 + // ParseSortBy parses the `sortBy` string and returns the associated `SortBy` 285 + // value, if one exists. Otherwise return `defaultSortBy`. 286 + func ParseSortBy(sortBy string, defaultSortBy internal.SortBy) internal.SortBy { 287 + switch strings.ToLower(sortBy) { 288 + case "relevance": 289 + return SortByScore 290 + case "latest": 291 + return SortByCreatedDesc 292 + case "oldest": 293 + return SortByCreatedAsc 294 + case "recentupdate": 295 + return SortByUpdatedDesc 296 + case "leastupdate": 297 + return SortByUpdatedAsc 298 + case "mostcomment": 299 + return SortByCommentsDesc 300 + case "leastcomment": 301 + return SortByCommentsAsc 302 + case "nearduedate": 303 + return SortByDeadlineAsc 304 + case "farduedate": 305 + return SortByDeadlineDesc 306 + default: 307 + return defaultSortBy 308 + } 309 + } 282 310 283 311 // SearchIssues search issues by options. 284 312 func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, error) {
+7 -1
routers/api/v1/repo/issue.go
··· 397 397 // in: query 398 398 // description: page size of results 399 399 // type: integer 400 + // - name: sort 401 + // in: query 402 + // description: Type of sort 403 + // type: string 404 + // enum: [relevance, latest, oldest, recentupdate, leastupdate, mostcomment, leastcomment, nearduedate, farduedate] 405 + // default: latest 400 406 // responses: 401 407 // "200": 402 408 // "$ref": "#/responses/IssueList" ··· 510 516 RepoIDs: []int64{ctx.Repo.Repository.ID}, 511 517 IsPull: isPull, 512 518 IsClosed: isClosed, 513 - SortBy: issue_indexer.SortByCreatedDesc, 519 + SortBy: issue_indexer.ParseSortBy(ctx.FormString("sort"), issue_indexer.SortByCreatedDesc), 514 520 } 515 521 if since != 0 { 516 522 searchOpt.UpdatedAfterUnix = optional.Some(since)
+18
templates/swagger/v1_json.tmpl
··· 8628 8628 "description": "page size of results", 8629 8629 "name": "limit", 8630 8630 "in": "query" 8631 + }, 8632 + { 8633 + "enum": [ 8634 + "relevance", 8635 + "latest", 8636 + "oldest", 8637 + "recentupdate", 8638 + "leastupdate", 8639 + "mostcomment", 8640 + "leastcomment", 8641 + "nearduedate", 8642 + "farduedate" 8643 + ], 8644 + "type": "string", 8645 + "default": "latest", 8646 + "description": "Type of sort", 8647 + "name": "sort", 8648 + "in": "query" 8631 8649 } 8632 8650 ], 8633 8651 "responses": {
+44
tests/integration/api_issue_test.go
··· 74 74 if assert.Len(t, apiIssues, 1) { 75 75 assert.EqualValues(t, 1, apiIssues[0].ID) 76 76 } 77 + 78 + t.Run("Sort", func(t *testing.T) { 79 + defer tests.PrintCurrentTest(t)() 80 + 81 + link.RawQuery = url.Values{"token": {token}, "sort": {"oldest"}}.Encode() 82 + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 83 + DecodeJSON(t, resp, &apiIssues) 84 + if assert.Len(t, apiIssues, 4) { 85 + assert.EqualValues(t, 1, apiIssues[0].ID) 86 + assert.EqualValues(t, 2, apiIssues[1].ID) 87 + assert.EqualValues(t, 3, apiIssues[2].ID) 88 + assert.EqualValues(t, 11, apiIssues[3].ID) 89 + } 90 + 91 + link.RawQuery = url.Values{"token": {token}, "sort": {"newest"}}.Encode() 92 + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 93 + DecodeJSON(t, resp, &apiIssues) 94 + if assert.Len(t, apiIssues, 4) { 95 + assert.EqualValues(t, 11, apiIssues[0].ID) 96 + assert.EqualValues(t, 3, apiIssues[1].ID) 97 + assert.EqualValues(t, 2, apiIssues[2].ID) 98 + assert.EqualValues(t, 1, apiIssues[3].ID) 99 + } 100 + 101 + link.RawQuery = url.Values{"token": {token}, "sort": {"recentupdate"}}.Encode() 102 + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 103 + DecodeJSON(t, resp, &apiIssues) 104 + if assert.Len(t, apiIssues, 4) { 105 + assert.EqualValues(t, 11, apiIssues[0].ID) 106 + assert.EqualValues(t, 1, apiIssues[1].ID) 107 + assert.EqualValues(t, 2, apiIssues[2].ID) 108 + assert.EqualValues(t, 3, apiIssues[3].ID) 109 + } 110 + 111 + link.RawQuery = url.Values{"token": {token}, "sort": {"leastupdate"}}.Encode() 112 + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 113 + DecodeJSON(t, resp, &apiIssues) 114 + if assert.Len(t, apiIssues, 4) { 115 + assert.EqualValues(t, 3, apiIssues[0].ID) 116 + assert.EqualValues(t, 2, apiIssues[1].ID) 117 + assert.EqualValues(t, 1, apiIssues[2].ID) 118 + assert.EqualValues(t, 11, apiIssues[3].ID) 119 + } 120 + }) 77 121 } 78 122 79 123 func TestAPIListIssuesPublicOnly(t *testing.T) {