Skip to content

Add filter option for subscribed issues #17053

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,7 @@ type IssuesOptions struct {
PosterID int64
MentionedID int64
ReviewRequestedID int64
SubscribedID int64
MilestoneIDs []int64
ProjectID int64
ProjectBoardID int64
Expand Down Expand Up @@ -1225,6 +1226,10 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
}

if opts.SubscribedID > 0 {
applySubscribedCondition(sess, opts.SubscribedID)
}

if len(opts.MilestoneIDs) > 0 {
sess.In("issue.milestone_id", opts.MilestoneIDs)
}
Expand Down Expand Up @@ -1315,6 +1320,13 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64)
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
}

func applySubscribedCondition(sess *xorm.Session, subscribedID int64) *xorm.Session {
return sess.And("(issue.id IN (SELECT issue_id FROM issue_watch WHERE (is_watching = ?) AND user_id = ?)) "+
"OR ((issue.id IN ((SELECT issue_id FROM comment WHERE poster_id = ?))) AND (NOT issue.id IN (SELECT issue_id FROM issue_watch WHERE user_id = ? AND (is_watching = ?)))) "+
"OR ((issue.id IN (SELECT id FROM issue WHERE poster_id = ?)) AND (NOT issue.id IN (SELECT issue_id FROM issue_watch WHERE user_id = ? AND (is_watching = ?))))",
true, subscribedID, subscribedID, subscribedID, false, subscribedID, subscribedID, false)
}

// CountIssuesByRepo map from repoID to number of issues matching the options
func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
sess := db.NewSession(db.DefaultContext)
Expand Down Expand Up @@ -1453,6 +1465,7 @@ type IssueStats struct {
CreateCount int64
MentionCount int64
ReviewRequestedCount int64
SubscribedCount int64
}

// Filter modes.
Expand All @@ -1462,6 +1475,7 @@ const (
FilterModeCreate
FilterModeMention
FilterModeReviewRequested
FilterModeSubscribed
)

func parseCountResult(results []map[string][]byte) int64 {
Expand All @@ -1484,6 +1498,7 @@ type IssueStatsOptions struct {
MentionedID int64
PosterID int64
ReviewRequestedID int64
SubscribedID int64
IsPull util.OptionalBool
IssueIDs []int64
}
Expand Down Expand Up @@ -1573,6 +1588,10 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
}

if opts.SubscribedID > 0 {
applySubscribedCondition(sess, opts.SubscribedID)
}

switch opts.IsPull {
case util.OptionalBoolTrue:
sess.And("issue.is_pull=?", true)
Expand Down Expand Up @@ -1702,6 +1721,19 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
if err != nil {
return nil, err
}
case FilterModeSubscribed:
stats.OpenCount, err = applySubscribedCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", false).
Count(new(Issue))
if err != nil {
return nil, err
}
stats.ClosedCount, err = applySubscribedCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", true).
Count(new(Issue))
if err != nil {
return nil, err
}
}

cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
Expand Down Expand Up @@ -1730,6 +1762,11 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
return nil, err
}

stats.SubscribedCount, err = applySubscribedCondition(sess(cond), opts.UserID).Count(new(Issue))
if err != nil {
return nil, err
}

return stats, nil
}

Expand Down
6 changes: 6 additions & 0 deletions models/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ func TestGetUserIssueStats(t *testing.T) {
CreateCount: 1,
OpenCount: 0,
ClosedCount: 0,
SubscribedCount: 1,
},
},
{
Expand All @@ -220,6 +221,7 @@ func TestGetUserIssueStats(t *testing.T) {
CreateCount: 2,
OpenCount: 2,
ClosedCount: 0,
SubscribedCount: 2,
},
},
{
Expand All @@ -233,6 +235,7 @@ func TestGetUserIssueStats(t *testing.T) {
CreateCount: 2,
OpenCount: 2,
ClosedCount: 0,
SubscribedCount: 2,
},
},
{
Expand All @@ -248,6 +251,7 @@ func TestGetUserIssueStats(t *testing.T) {
CreateCount: 2,
OpenCount: 2,
ClosedCount: 2,
SubscribedCount: 2,
},
},
{
Expand All @@ -261,6 +265,7 @@ func TestGetUserIssueStats(t *testing.T) {
CreateCount: 2,
OpenCount: 0,
ClosedCount: 0,
SubscribedCount: 2,
},
},
{
Expand All @@ -275,6 +280,7 @@ func TestGetUserIssueStats(t *testing.T) {
CreateCount: 1,
OpenCount: 1,
ClosedCount: 0,
SubscribedCount: 1,
},
},
} {
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,7 @@ issues.filter_type.assigned_to_you = Assigned to you
issues.filter_type.created_by_you = Created by you
issues.filter_type.mentioning_you = Mentioning you
issues.filter_type.review_requested = Review requested
issues.filter_type.subscribed = Subscribed
issues.filter_sort = Sort
issues.filter_sort.latest = Newest
issues.filter_sort.oldest = Oldest
Expand Down
7 changes: 7 additions & 0 deletions routers/api/v1/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func SearchIssues(ctx *context.APIContext) {
// in: query
// description: filter (issues / pulls) mentioning you, default is false
// type: boolean
// - name: subscribed
// in: query
// description: filter (issues / pulls) subscribed by you, default is false
// type: boolean
// - name: review_requested
// in: query
// description: filter pulls requesting your review, default is false
Expand Down Expand Up @@ -255,6 +259,9 @@ func SearchIssues(ctx *context.APIContext) {
if ctx.FormBool("review_requested") {
issuesOpt.ReviewRequestedID = ctx.User.ID
}
if ctx.FormBool("subscribed") {
issuesOpt.SubscribedID = ctx.User.ID
}

if issues, err = models.Issues(issuesOpt); err != nil {
ctx.Error(http.StatusInternalServerError, "Issues", err)
Expand Down
7 changes: 6 additions & 1 deletion routers/web/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
var err error
viewType := ctx.FormString("type")
sortType := ctx.FormString("sort")
types := []string{"all", "your_repositories", "assigned", "created_by", "mentioned", "review_requested"}
types := []string{"all", "your_repositories", "assigned", "created_by", "mentioned", "review_requested", "subscribed"}
if !util.IsStringInSlice(viewType, types, true) {
viewType = "all"
}
Expand All @@ -122,6 +122,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
posterID int64
mentionedID int64
reviewRequestedID int64
subscribedID int64
forceEmpty bool
)

Expand All @@ -135,6 +136,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
assigneeID = ctx.User.ID
case "review_requested":
reviewRequestedID = ctx.User.ID
case "subscribed":
subscribedID = ctx.User.ID
}
}

Expand Down Expand Up @@ -178,6 +181,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
MentionedID: mentionedID,
PosterID: posterID,
ReviewRequestedID: reviewRequestedID,
SubscribedID: subscribedID,
IsPull: isPullOption,
IssueIDs: issueIDs,
})
Expand Down Expand Up @@ -225,6 +229,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
PosterID: posterID,
MentionedID: mentionedID,
ReviewRequestedID: reviewRequestedID,
SubscribedID: subscribedID,
MilestoneIDs: mileIDs,
ProjectID: projectID,
IsClosed: util.OptionalBoolOf(isShowClosed),
Expand Down
4 changes: 4 additions & 0 deletions routers/web/user/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
filterMode = models.FilterModeMention
case "review_requested":
filterMode = models.FilterModeReviewRequested
case "subscribed":
filterMode = models.FilterModeSubscribed
case "your_repositories": // filterMode already set to All
default:
viewType = "your_repositories"
Expand Down Expand Up @@ -450,6 +452,8 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
opts.MentionedID = ctx.User.ID
case models.FilterModeReviewRequested:
opts.ReviewRequestedID = ctx.User.ID
case models.FilterModeSubscribed:
opts.SubscribedID = ctx.User.ID
}

if ctxUser.IsOrganization() {
Expand Down
1 change: 1 addition & 0 deletions templates/repo/issue/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
<a class="{{if eq .ViewType "subscribed"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=subscribed&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.subscribed"}}</a>
{{if .PageIsPullList}}
<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.review_requested"}}</a>
{{end}}
Expand Down
6 changes: 6 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,12 @@
"name": "mentioned",
"in": "query"
},
{
"type": "boolean",
"description": "filter (issues / pulls) subscribed by you, default is false",
"name": "subscribed",
"in": "query"
},
{
"type": "boolean",
"description": "filter pulls requesting your review, default is false",
Expand Down
4 changes: 4 additions & 0 deletions templates/user/dashboard/issues.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}
<strong class="ui right">{{CountFmt .IssueStats.MentionCount}}</strong>
</a>
<a class="{{if eq .ViewType "subscribed"}}ui basic blue button{{end}} item" href="{{.Link}}?type=subscribed&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
{{.i18n.Tr "repo.issues.filter_type.subscribed"}}
<strong class="ui right">{{CountFmt .IssueStats.SubscribedCount}}</strong>
</a>
{{if .PageIsPulls}}
<a class="{{if eq .ViewType "review_requested"}}ui basic blue button{{end}} item" href="{{.Link}}?type=review_requested&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state={{.State}}">
{{.i18n.Tr "repo.issues.filter_type.review_requested"}}
Expand Down