summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--integrations/api_issue_test.go32
-rw-r--r--models/fixtures/issue_user.yml2
-rw-r--r--routers/api/v1/repo/issue.go83
-rw-r--r--templates/swagger/v1_json.tmpl32
4 files changed, 134 insertions, 15 deletions
diff --git a/integrations/api_issue_test.go b/integrations/api_issue_test.go
index 109135b634..604e6d6381 100644
--- a/integrations/api_issue_test.go
+++ b/integrations/api_issue_test.go
@@ -25,9 +25,10 @@ func TestAPIListIssues(t *testing.T) {
session := loginUser(t, owner.Name)
token := getTokenForLoggedInUser(t, session)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all&token=%s",
- owner.Name, repo.Name, token)
- resp := session.MakeRequest(t, req, http.StatusOK)
+ link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner.Name, repo.Name))
+
+ link.RawQuery = url.Values{"token": {token}, "state": {"all"}}.Encode()
+ resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, models.GetCount(t, &models.Issue{RepoID: repo.ID}))
@@ -36,15 +37,34 @@ func TestAPIListIssues(t *testing.T) {
}
// test milestone filter
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all&type=all&milestones=ignore,milestone1,3,4&token=%s",
- owner.Name, repo.Name, token)
- resp = session.MakeRequest(t, req, http.StatusOK)
+ link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "type": {"all"}, "milestones": {"ignore,milestone1,3,4"}}.Encode()
+ resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
if assert.Len(t, apiIssues, 2) {
assert.EqualValues(t, 3, apiIssues[0].Milestone.ID)
assert.EqualValues(t, 1, apiIssues[1].Milestone.ID)
}
+ link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "created_by": {"user2"}}.Encode()
+ resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
+ DecodeJSON(t, resp, &apiIssues)
+ if assert.Len(t, apiIssues, 1) {
+ assert.EqualValues(t, 5, apiIssues[0].ID)
+ }
+
+ link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "assigned_by": {"user1"}}.Encode()
+ resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
+ DecodeJSON(t, resp, &apiIssues)
+ if assert.Len(t, apiIssues, 1) {
+ assert.EqualValues(t, 1, apiIssues[0].ID)
+ }
+
+ link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "mentioned_by": {"user4"}}.Encode()
+ resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
+ DecodeJSON(t, resp, &apiIssues)
+ if assert.Len(t, apiIssues, 1) {
+ assert.EqualValues(t, 1, apiIssues[0].ID)
+ }
}
func TestAPICreateIssue(t *testing.T) {
diff --git a/models/fixtures/issue_user.yml b/models/fixtures/issue_user.yml
index 8039b1e40f..64824316ea 100644
--- a/models/fixtures/issue_user.yml
+++ b/models/fixtures/issue_user.yml
@@ -17,4 +17,4 @@
uid: 4
issue_id: 1
is_read: false
- is_mentioned: false
+ is_mentioned: true
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 6b46dc0fef..5932765ab8 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -266,6 +266,30 @@ func ListIssues(ctx *context.APIContext) {
// in: query
// description: comma separated list of milestone names or ids. It uses names and fall back to ids. Fetch only issues that have any of this milestones. Non existent milestones are discarded
// 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: created_by
+ // in: query
+ // description: filter (issues / pulls) created to
+ // type: string
+ // - name: assigned_by
+ // in: query
+ // description: filter (issues / pulls) assigned to
+ // type: string
+ // - name: mentioned_by
+ // in: query
+ // description: filter (issues / pulls) mentioning to
+ // type: string
// - name: page
// in: query
// description: page number of results to return (1-based)
@@ -277,6 +301,11 @@ func ListIssues(ctx *context.APIContext) {
// 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") {
@@ -297,7 +326,6 @@ func ListIssues(ctx *context.APIContext) {
}
var issueIDs []int64
var labelIDs []int64
- var err error
if len(keyword) > 0 {
issueIDs, err = issue_indexer.SearchIssuesByKeyword([]int64{ctx.Repo.Repository.ID}, keyword)
if err != nil {
@@ -356,17 +384,36 @@ func ListIssues(ctx *context.APIContext) {
isPull = util.OptionalBoolNone
}
+ // FIXME: we should be more efficient here
+ createdByID := getUserIDForFilter(ctx, "created_by")
+ if ctx.Written() {
+ return
+ }
+ assignedByID := getUserIDForFilter(ctx, "assigned_by")
+ if ctx.Written() {
+ return
+ }
+ mentionedByID := getUserIDForFilter(ctx, "mentioned_by")
+ if ctx.Written() {
+ return
+ }
+
// 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: listOptions,
- RepoIDs: []int64{ctx.Repo.Repository.ID},
- IsClosed: isClosed,
- IssueIDs: issueIDs,
- LabelIDs: labelIDs,
- MilestoneIDs: mileIDs,
- IsPull: isPull,
+ ListOptions: listOptions,
+ RepoIDs: []int64{ctx.Repo.Repository.ID},
+ IsClosed: isClosed,
+ IssueIDs: issueIDs,
+ LabelIDs: labelIDs,
+ MilestoneIDs: mileIDs,
+ IsPull: isPull,
+ UpdatedBeforeUnix: before,
+ UpdatedAfterUnix: since,
+ PosterID: createdByID,
+ AssigneeID: assignedByID,
+ MentionedID: mentionedByID,
}
if issues, err = models.Issues(issuesOpt); err != nil {
@@ -389,6 +436,26 @@ func ListIssues(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues))
}
+func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 {
+ userName := ctx.Query(queryName)
+ if len(userName) == 0 {
+ return 0
+ }
+
+ user, err := models.GetUserByName(userName)
+ if models.IsErrUserNotExist(err) {
+ ctx.NotFound(err)
+ return 0
+ }
+
+ if err != nil {
+ ctx.InternalServerError(err)
+ return 0
+ }
+
+ return user.ID
+}
+
// GetIssue get an issue of a repository
func GetIssue(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/{index} issue issueGetIssue
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 8ad9ae5a43..8ea5edb6fc 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -4235,6 +4235,38 @@
"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": "string",
+ "description": "filter (issues / pulls) created to",
+ "name": "created_by",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "filter (issues / pulls) assigned to",
+ "name": "assigned_by",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "filter (issues / pulls) mentioning to",
+ "name": "mentioned_by",
+ "in": "query"
+ },
+ {
"type": "integer",
"description": "page number of results to return (1-based)",
"name": "page",