summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author6543 <6543@obermui.de>2020-11-23 21:49:36 +0100
committerGitHub <noreply@github.com>2020-11-23 20:49:36 +0000
commitf88a2eae9777e0be612647bc17227c1ca13616ba (patch)
tree78aad7908e3fa61e674610cb24c7f4d1b8ad9bc2
parent78204a7a71eedbc099aff51abd88cb16f60d50a8 (diff)
downloadgitea-f88a2eae9777e0be612647bc17227c1ca13616ba.tar.gz
gitea-f88a2eae9777e0be612647bc17227c1ca13616ba.zip
[API] Add more filters to issues search (#13514)
* Add time filter for issue search * Add limit option for paggination * Add Filter for: Created by User, Assigned to User, Mentioning User * update swagger * Add Tests for limit, before & since
-rw-r--r--integrations/api_issue_test.go29
-rw-r--r--models/issue.go9
-rw-r--r--routers/api/v1/repo/issue.go61
-rw-r--r--templates/swagger/v1_json.tmpl40
4 files changed, 130 insertions, 9 deletions
diff --git a/integrations/api_issue_test.go b/integrations/api_issue_test.go
index 9311d50c5c..81e5c44873 100644
--- a/integrations/api_issue_test.go
+++ b/integrations/api_issue_test.go
@@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"testing"
+ "time"
"code.gitea.io/gitea/models"
api "code.gitea.io/gitea/modules/structs"
@@ -152,17 +153,27 @@ func TestAPISearchIssues(t *testing.T) {
resp := session.MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
-
assert.Len(t, apiIssues, 10)
- query := url.Values{}
- query.Add("token", token)
+ query := url.Values{"token": {token}}
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
+ since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
+ before := time.Unix(999307200, 0).Format(time.RFC3339)
+ query.Add("since", since)
+ query.Add("before", before)
+ link.RawQuery = query.Encode()
+ req = NewRequest(t, "GET", link.String())
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ DecodeJSON(t, resp, &apiIssues)
+ assert.Len(t, apiIssues, 8)
+ query.Del("since")
+ query.Del("before")
+
query.Add("state", "closed")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
@@ -175,14 +186,22 @@ func TestAPISearchIssues(t *testing.T) {
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
+ assert.EqualValues(t, "12", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 10) //there are more but 10 is page item limit
- query.Add("page", "2")
+ query.Add("limit", "20")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 2)
+ assert.Len(t, apiIssues, 12)
+
+ query = url.Values{"assigned": {"true"}, "state": {"all"}}
+ link.RawQuery = query.Encode()
+ req = NewRequest(t, "GET", link.String())
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ DecodeJSON(t, resp, &apiIssues)
+ assert.Len(t, apiIssues, 1)
}
func TestAPISearchIssuesWithLabels(t *testing.T) {
diff --git a/models/issue.go b/models/issue.go
index ee75623f53..8c135faa8d 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -1100,6 +1100,8 @@ type IssuesOptions struct {
ExcludedLabelNames []string
SortType string
IssueIDs []int64
+ UpdatedAfterUnix int64
+ UpdatedBeforeUnix int64
// prioritize issues from this repo
PriorityRepoID int64
}
@@ -1178,6 +1180,13 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
sess.In("issue.milestone_id", opts.MilestoneIDs)
}
+ if opts.UpdatedAfterUnix != 0 {
+ sess.And(builder.Gte{"issue.updated_unix": opts.UpdatedAfterUnix})
+ }
+ if opts.UpdatedBeforeUnix != 0 {
+ sess.And(builder.Lte{"issue.updated_unix": opts.UpdatedBeforeUnix})
+ }
+
if opts.ProjectID > 0 {
sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id").
And("project_issue.project_id=?", opts.ProjectID)
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 0dbf2741ad..c58e0bb6ce 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -55,14 +55,48 @@ func SearchIssues(ctx *context.APIContext) {
// in: query
// description: filter by type (issues / pulls) if set
// type: string
+ // - name: since
+ // in: query
+ // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
+ // type: string
+ // format: date-time
+ // required: false
+ // - name: before
+ // in: query
+ // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format
+ // type: string
+ // format: date-time
+ // required: false
+ // - name: assigned
+ // in: query
+ // description: filter (issues / pulls) assigned to you, default is false
+ // type: boolean
+ // - name: created
+ // in: query
+ // description: filter (issues / pulls) created by you, default is false
+ // type: boolean
+ // - name: mentioned
+ // in: query
+ // description: filter (issues / pulls) mentioning you, default is false
+ // type: boolean
// - name: page
// in: query
- // description: page number of requested issues
+ // description: page number of results to return (1-based)
+ // type: integer
+ // - name: limit
+ // in: query
+ // description: page size of results
// type: integer
// responses:
// "200":
// "$ref": "#/responses/IssueList"
+ before, since, err := utils.GetQueryBeforeSince(ctx)
+ if err != nil {
+ ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
+ return
+ }
+
var isClosed util.OptionalBool
switch ctx.Query("state") {
case "closed":
@@ -119,7 +153,6 @@ func SearchIssues(ctx *context.APIContext) {
}
var issueIDs []int64
var labelIDs []int64
- var err error
if len(keyword) > 0 && len(repoIDs) > 0 {
if issueIDs, err = issue_indexer.SearchIssuesByKeyword(repoIDs, keyword); err != nil {
ctx.Error(http.StatusInternalServerError, "SearchIssuesByKeyword", err)
@@ -143,13 +176,22 @@ func SearchIssues(ctx *context.APIContext) {
includedLabelNames = strings.Split(labels, ",")
}
+ // this api is also used in UI,
+ // so the default limit is set to fit UI needs
+ limit := ctx.QueryInt("limit")
+ if limit == 0 {
+ limit = setting.UI.IssuePagingNum
+ } else if limit > setting.API.MaxResponseItems {
+ limit = setting.API.MaxResponseItems
+ }
+
// Only fetch the issues if we either don't have a keyword or the search returned issues
// This would otherwise return all issues if no issues were found by the search.
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
issuesOpt := &models.IssuesOptions{
ListOptions: models.ListOptions{
Page: ctx.QueryInt("page"),
- PageSize: setting.UI.IssuePagingNum,
+ PageSize: limit,
},
RepoIDs: repoIDs,
IsClosed: isClosed,
@@ -158,6 +200,19 @@ func SearchIssues(ctx *context.APIContext) {
SortType: "priorityrepo",
PriorityRepoID: ctx.QueryInt64("priority_repo_id"),
IsPull: isPull,
+ UpdatedBeforeUnix: before,
+ UpdatedAfterUnix: since,
+ }
+
+ // Filter for: Created by User, Assigned to User, Mentioning User
+ if ctx.QueryBool("created") {
+ issuesOpt.PosterID = ctx.User.ID
+ }
+ if ctx.QueryBool("assigned") {
+ issuesOpt.AssigneeID = ctx.User.ID
+ }
+ if ctx.QueryBool("mentioned") {
+ issuesOpt.MentionedID = ctx.User.ID
}
if issues, err = models.Issues(issuesOpt); err != nil {
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 9d775da7d6..8bcfc43d73 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -1880,10 +1880,48 @@
"in": "query"
},
{
+ "type": "string",
+ "format": "date-time",
+ "description": "Only show notifications updated after the given time. This is a timestamp in RFC 3339 format",
+ "name": "since",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "format": "date-time",
+ "description": "Only show notifications updated before the given time. This is a timestamp in RFC 3339 format",
+ "name": "before",
+ "in": "query"
+ },
+ {
+ "type": "boolean",
+ "description": "filter (issues / pulls) assigned to you, default is false",
+ "name": "assigned",
+ "in": "query"
+ },
+ {
+ "type": "boolean",
+ "description": "filter (issues / pulls) created by you, default is false",
+ "name": "created",
+ "in": "query"
+ },
+ {
+ "type": "boolean",
+ "description": "filter (issues / pulls) mentioning you, default is false",
+ "name": "mentioned",
+ "in": "query"
+ },
+ {
"type": "integer",
- "description": "page number of requested issues",
+ "description": "page number of results to return (1-based)",
"name": "page",
"in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "page size of results",
+ "name": "limit",
+ "in": "query"
}
],
"responses": {