Skip to content
New issue

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

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

Already on GitHub? # to your account

Add review requested filter on pull request overview #13701

Merged
merged 14 commits into from
Jan 17, 2021
Merged
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
159 changes: 97 additions & 62 deletions models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,7 @@ type IssuesOptions struct {
AssigneeID int64
PosterID int64
MentionedID int64
ReviewRequestedID int64
MilestoneIDs []int64
ProjectID int64
ProjectBoardID int64
Expand Down Expand Up @@ -1151,8 +1152,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
}

if len(opts.RepoIDs) > 0 {
// In case repository IDs are provided but actually no repository has issue.
sess.In("issue.repo_id", opts.RepoIDs)
applyReposCondition(sess, opts.RepoIDs)
}

switch opts.IsClosed {
Expand All @@ -1163,18 +1163,19 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
}

if opts.AssigneeID > 0 {
sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.AssigneeID)
applyAssigneeCondition(sess, opts.AssigneeID)
}

if opts.PosterID > 0 {
sess.And("issue.poster_id=?", opts.PosterID)
applyPosterCondition(sess, opts.PosterID)
}

if opts.MentionedID > 0 {
sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", opts.MentionedID)
applyMentionedCondition(sess, opts.MentionedID)
}

if opts.ReviewRequestedID > 0 {
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
}

if len(opts.MilestoneIDs) > 0 {
Expand Down Expand Up @@ -1232,6 +1233,33 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
}
}

func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
return sess.In("issue.repo_id", repoIDs)
}

func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) *xorm.Session {
return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", assigneeID)
}

func applyPosterCondition(sess *xorm.Session, posterID int64) *xorm.Session {
return sess.And("issue.poster_id=?", posterID)
}

func applyMentionedCondition(sess *xorm.Session, mentionedID int64) *xorm.Session {
return sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", mentionedID)
}

func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) *xorm.Session {
return sess.Join("INNER", []string{"review", "r"}, "issue.id = r.issue_id").
And("r.type = ?", ReviewTypeRequest).
And("r.reviewer_id = ? and r.id in (select max(id) from review where issue_id = r.issue_id and reviewer_id = r.reviewer_id and type in (?, ?, ?))"+
" or r.reviewer_team_id in (select team_id from team_user where uid = ?)",
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
}

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

// Filter modes.
Expand All @@ -1372,6 +1401,7 @@ const (
FilterModeAssign
FilterModeCreate
FilterModeMention
FilterModeReviewRequested
)

func parseCountResult(results []map[string][]byte) int64 {
Expand All @@ -1387,14 +1417,15 @@ func parseCountResult(results []map[string][]byte) int64 {

// IssueStatsOptions contains parameters accepted by GetIssueStats.
type IssueStatsOptions struct {
RepoID int64
Labels string
MilestoneID int64
AssigneeID int64
MentionedID int64
PosterID int64
IsPull util.OptionalBool
IssueIDs []int64
RepoID int64
Labels string
MilestoneID int64
AssigneeID int64
MentionedID int64
PosterID int64
ReviewRequestedID int64
IsPull util.OptionalBool
IssueIDs []int64
}

// GetIssueStats returns issue statistic information by given conditions.
Expand Down Expand Up @@ -1423,6 +1454,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
accum.AssignCount += stats.AssignCount
accum.CreateCount += stats.CreateCount
accum.OpenCount += stats.MentionCount
accum.ReviewRequestedCount += stats.ReviewRequestedCount
i = chunk
}
return accum, nil
Expand Down Expand Up @@ -1460,18 +1492,19 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
}

if opts.AssigneeID > 0 {
sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.AssigneeID)
applyAssigneeCondition(sess, opts.AssigneeID)
}

if opts.PosterID > 0 {
sess.And("issue.poster_id = ?", opts.PosterID)
applyPosterCondition(sess, opts.PosterID)
}

if opts.MentionedID > 0 {
sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.uid = ?", opts.MentionedID).
And("issue_user.is_mentioned = ?", true)
applyMentionedCondition(sess, opts.MentionedID)
}

if opts.ReviewRequestedID > 0 {
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
}

switch opts.IsPull {
Expand Down Expand Up @@ -1539,90 +1572,94 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {

switch opts.FilterMode {
case FilterModeAll:
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
And(builder.In("issue.repo_id", opts.UserRepoIDs)).
stats.OpenCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
And("issue.is_closed = ?", false).
Count(new(Issue))
if err != nil {
return nil, err
}
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
And(builder.In("issue.repo_id", opts.UserRepoIDs)).
stats.ClosedCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).
And("issue.is_closed = ?", true).
Count(new(Issue))
if err != nil {
return nil, err
}
case FilterModeAssign:
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.UserID).
stats.OpenCount, err = applyAssigneeCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", false).
Count(new(Issue))
if err != nil {
return nil, err
}
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.UserID).
stats.ClosedCount, err = applyAssigneeCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", true).
Count(new(Issue))
if err != nil {
return nil, err
}
case FilterModeCreate:
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
And("issue.poster_id = ?", opts.UserID).
stats.OpenCount, err = applyPosterCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", false).
Count(new(Issue))
if err != nil {
return nil, err
}
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
And("issue.poster_id = ?", opts.UserID).
stats.ClosedCount, err = applyPosterCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", true).
Count(new(Issue))
if err != nil {
return nil, err
}
case FilterModeMention:
stats.OpenCount, err = sess(cond).And("issue.is_closed = ?", false).
Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", opts.UserID).
stats.OpenCount, err = applyMentionedCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", false).
Count(new(Issue))
if err != nil {
return nil, err
}
stats.ClosedCount, err = sess(cond).And("issue.is_closed = ?", true).
Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", opts.UserID).
stats.ClosedCount, err = applyMentionedCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", true).
Count(new(Issue))
if err != nil {
return nil, err
}
case FilterModeReviewRequested:
stats.OpenCount, err = applyReviewRequestedCondition(sess(cond), opts.UserID).
And("issue.is_closed = ?", false).
Count(new(Issue))
if err != nil {
return nil, err
}
stats.ClosedCount, err = applyReviewRequestedCondition(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})
stats.AssignCount, err = sess(cond).
Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.UserID).
Count(new(Issue))
stats.AssignCount, err = applyAssigneeCondition(sess(cond), opts.UserID).Count(new(Issue))
if err != nil {
return nil, err
}

stats.CreateCount, err = sess(cond).
And("poster_id = ?", opts.UserID).
Count(new(Issue))
stats.CreateCount, err = applyPosterCondition(sess(cond), opts.UserID).Count(new(Issue))
if err != nil {
return nil, err
}

stats.MentionCount, err = sess(cond).
Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", opts.UserID).
Count(new(Issue))
stats.MentionCount, err = applyMentionedCondition(sess(cond), opts.UserID).Count(new(Issue))
if err != nil {
return nil, err
}

stats.YourRepositoriesCount, err = sess(cond).
And(builder.In("issue.repo_id", opts.UserRepoIDs)).
Count(new(Issue))
stats.YourRepositoriesCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).Count(new(Issue))
if err != nil {
return nil, err
}

stats.ReviewRequestedCount, err = applyReviewRequestedCondition(sess(cond), opts.UserID).Count(new(Issue))
if err != nil {
return nil, err
}
Expand All @@ -1646,13 +1683,11 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen

switch filterMode {
case FilterModeAssign:
openCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", uid)
closedCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", uid)
applyAssigneeCondition(openCountSession, uid)
applyAssigneeCondition(closedCountSession, uid)
case FilterModeCreate:
openCountSession.And("poster_id = ?", uid)
closedCountSession.And("poster_id = ?", uid)
applyPosterCondition(openCountSession, uid)
applyPosterCondition(closedCountSession, uid)
}

openResult, _ := openCountSession.Count(new(Issue))
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 @@ -1030,6 +1030,7 @@ issues.filter_type.all_issues = All issues
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_sort = Sort
issues.filter_sort.latest = Newest
issues.filter_sort.oldest = Oldest
Expand Down
9 changes: 8 additions & 1 deletion routers/api/v1/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func SearchIssues(ctx *context.APIContext) {
// in: query
// description: filter (issues / pulls) mentioning you, default is false
// type: boolean
// - name: review_requested
// in: query
// description: filter pulls requesting your review, default is false
// type: boolean
// - name: page
// in: query
// description: page number of results to return (1-based)
Expand Down Expand Up @@ -204,7 +208,7 @@ func SearchIssues(ctx *context.APIContext) {
UpdatedAfterUnix: since,
}

// Filter for: Created by User, Assigned to User, Mentioning User
// Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
if ctx.QueryBool("created") {
issuesOpt.PosterID = ctx.User.ID
}
Expand All @@ -214,6 +218,9 @@ func SearchIssues(ctx *context.APIContext) {
if ctx.QueryBool("mentioned") {
issuesOpt.MentionedID = ctx.User.ID
}
if ctx.QueryBool("review_requested") {
issuesOpt.ReviewRequestedID = ctx.User.ID
}

if issues, err = models.Issues(issuesOpt); err != nil {
ctx.Error(http.StatusInternalServerError, "Issues", err)
Expand Down
Loading