diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index 7edcb3aa6f..3078882258 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "runtime/pprof" + "strings" "sync/atomic" "time" @@ -280,6 +281,33 @@ const ( SortByDeadlineAsc = internal.SortByDeadlineAsc ) +// ParseSortBy parses the `sortBy` string and returns the associated `SortBy` +// value, if one exists. Otherwise return `defaultSortBy`. +func ParseSortBy(sortBy string, defaultSortBy internal.SortBy) internal.SortBy { + switch strings.ToLower(sortBy) { + case "relevance": + return SortByScore + case "latest": + return SortByCreatedDesc + case "oldest": + return SortByCreatedAsc + case "recentupdate": + return SortByUpdatedDesc + case "leastupdate": + return SortByUpdatedAsc + case "mostcomment": + return SortByCommentsDesc + case "leastcomment": + return SortByCommentsAsc + case "nearduedate": + return SortByDeadlineAsc + case "farduedate": + return SortByDeadlineDesc + default: + return defaultSortBy + } +} + // SearchIssues search issues by options. func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, error) { indexer := *globalIndexer.Load() diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 6221681875..57fc4b2f17 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -397,6 +397,12 @@ func ListIssues(ctx *context.APIContext) { // in: query // description: page size of results // type: integer + // - name: sort + // in: query + // description: Type of sort + // type: string + // enum: [relevance, latest, oldest, recentupdate, leastupdate, mostcomment, leastcomment, nearduedate, farduedate] + // default: latest // responses: // "200": // "$ref": "#/responses/IssueList" @@ -510,7 +516,7 @@ func ListIssues(ctx *context.APIContext) { RepoIDs: []int64{ctx.Repo.Repository.ID}, IsPull: isPull, IsClosed: isClosed, - SortBy: issue_indexer.SortByCreatedDesc, + SortBy: issue_indexer.ParseSortBy(ctx.FormString("sort"), issue_indexer.SortByCreatedDesc), } if since != 0 { searchOpt.UpdatedAfterUnix = optional.Some(since) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 1399442676..248e457197 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -8628,6 +8628,24 @@ "description": "page size of results", "name": "limit", "in": "query" + }, + { + "enum": [ + "relevance", + "latest", + "oldest", + "recentupdate", + "leastupdate", + "mostcomment", + "leastcomment", + "nearduedate", + "farduedate" + ], + "type": "string", + "default": "latest", + "description": "Type of sort", + "name": "sort", + "in": "query" } ], "responses": { diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go index 4051f95ed9..2d3fd80c06 100644 --- a/tests/integration/api_issue_test.go +++ b/tests/integration/api_issue_test.go @@ -74,6 +74,50 @@ func TestAPIListIssues(t *testing.T) { if assert.Len(t, apiIssues, 1) { assert.EqualValues(t, 1, apiIssues[0].ID) } + + t.Run("Sort", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + link.RawQuery = url.Values{"token": {token}, "sort": {"oldest"}}.Encode() + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + if assert.Len(t, apiIssues, 4) { + assert.EqualValues(t, 1, apiIssues[0].ID) + assert.EqualValues(t, 2, apiIssues[1].ID) + assert.EqualValues(t, 3, apiIssues[2].ID) + assert.EqualValues(t, 11, apiIssues[3].ID) + } + + link.RawQuery = url.Values{"token": {token}, "sort": {"newest"}}.Encode() + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + if assert.Len(t, apiIssues, 4) { + assert.EqualValues(t, 11, apiIssues[0].ID) + assert.EqualValues(t, 3, apiIssues[1].ID) + assert.EqualValues(t, 2, apiIssues[2].ID) + assert.EqualValues(t, 1, apiIssues[3].ID) + } + + link.RawQuery = url.Values{"token": {token}, "sort": {"recentupdate"}}.Encode() + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + if assert.Len(t, apiIssues, 4) { + assert.EqualValues(t, 11, apiIssues[0].ID) + assert.EqualValues(t, 1, apiIssues[1].ID) + assert.EqualValues(t, 2, apiIssues[2].ID) + assert.EqualValues(t, 3, apiIssues[3].ID) + } + + link.RawQuery = url.Values{"token": {token}, "sort": {"leastupdate"}}.Encode() + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + if assert.Len(t, apiIssues, 4) { + assert.EqualValues(t, 3, apiIssues[0].ID) + assert.EqualValues(t, 2, apiIssues[1].ID) + assert.EqualValues(t, 1, apiIssues[2].ID) + assert.EqualValues(t, 11, apiIssues[3].ID) + } + }) } func TestAPIListIssuesPublicOnly(t *testing.T) {