[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
This commit is contained in:
		
							parent
							
								
									78204a7a71
								
							
						
					
					
						commit
						f88a2eae97
					
				| @ -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) { | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -1879,11 +1879,49 @@ | ||||
|             "name": "type", | ||||
|             "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": { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user