From a7e905ba130d0ab7e3f2a337e1ff790b4891d1fd Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 14 Feb 2023 22:04:46 +0100 Subject: [PATCH] Add "Reviewed by you" filter for pull requests This includes pull requests that you approved, requested changes or commented on. Currently such pull requests are not visible in any of the filters on /pulls, while they may need further action like merging, or prodding the author or reviewers. Especially when working with a large team on a repository it's helpful to get a full overview of pull requests that may need your attention, without having to sift through the complete list. --- models/issues/issue.go | 58 ++++++++++++++++++++++ models/migrations/migrations.go | 2 + models/migrations/v1_19/v244.go | 16 ++++++ options/locale/locale_en-US.ini | 1 + routers/api/v1/repo/issue.go | 7 +++ routers/web/repo/issue.go | 10 +++- routers/web/user/home.go | 4 ++ templates/repo/issue/list.tmpl | 3 +- templates/repo/issue/milestone_issues.tmpl | 3 +- templates/swagger/v1_json.tmpl | 6 +++ templates/user/dashboard/issues.tmpl | 12 +++-- 11 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 models/migrations/v1_19/v244.go diff --git a/models/issues/issue.go b/models/issues/issue.go index e0dcf3d269ee..9a5f000a00ae 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1119,6 +1119,7 @@ type IssuesOptions struct { //nolint PosterID int64 MentionedID int64 ReviewRequestedID int64 + ReviewedID int64 SubscriberID int64 MilestoneIDs []int64 ProjectID int64 @@ -1233,6 +1234,10 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) { applyReviewRequestedCondition(sess, opts.ReviewRequestedID) } + if opts.ReviewedID > 0 { + applyReviewedCondition(sess, opts.ReviewedID) + } + if opts.SubscriberID > 0 { applySubscribedCondition(sess, opts.SubscriberID) } @@ -1403,6 +1408,33 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID) } +func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session { + // Query for pull requests where you are a reviewer or commenter, excluding + // any pull requests already returned by the the review requested filter. + notPoster := builder.Neq{"issue.poster_id": reviewedID} + reviewed := builder.In("issue.id", builder. + Select("issue_id"). + From("review"). + Where(builder.And( + builder.Neq{"type": ReviewTypeRequest}, + builder.Or( + builder.Eq{"reviewer_id": reviewedID}, + builder.In("reviewer_team_id", builder. + Select("team_id"). + From("team_user"). + Where(builder.Eq{"uid": reviewedID}), + ), + ), + )), + ) + comment := builder.In("issue.id", builder. + Select("issue_id"). + From("comment"). + Where(builder.Eq{"poster_id": reviewedID}), + ) + return sess.And(notPoster, reviewed, comment) +} + func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session { return sess.And( builder. @@ -1557,6 +1589,7 @@ type IssueStats struct { CreateCount int64 MentionCount int64 ReviewRequestedCount int64 + ReviewedCount int64 } // Filter modes. @@ -1566,6 +1599,7 @@ const ( FilterModeCreate FilterModeMention FilterModeReviewRequested + FilterModeReviewed FilterModeYourRepositories ) @@ -1579,6 +1613,7 @@ type IssueStatsOptions struct { MentionedID int64 PosterID int64 ReviewRequestedID int64 + ReviewedID int64 IsPull util.OptionalBool IssueIDs []int64 } @@ -1617,6 +1652,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { accum.CreateCount += stats.CreateCount accum.OpenCount += stats.MentionCount accum.ReviewRequestedCount += stats.ReviewRequestedCount + accum.ReviewedCount += stats.ReviewedCount i = chunk } return accum, nil @@ -1674,6 +1710,10 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, applyReviewRequestedCondition(sess, opts.ReviewRequestedID) } + if opts.ReviewedID > 0 { + applyReviewedCondition(sess, opts.ReviewedID) + } + switch opts.IsPull { case util.OptionalBoolTrue: sess.And("issue.is_pull=?", true) @@ -1814,6 +1854,19 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { if err != nil { return nil, err } + case FilterModeReviewed: + stats.OpenCount, err = applyReviewedCondition(sess(cond), opts.UserID). + And("issue.is_closed = ?", false). + Count(new(Issue)) + if err != nil { + return nil, err + } + stats.ClosedCount, err = applyReviewedCondition(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}) @@ -1842,6 +1895,11 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { return nil, err } + stats.ReviewedCount, err = applyReviewedCondition(sess(cond), opts.UserID).Count(new(Issue)) + if err != nil { + return nil, err + } + return stats, nil } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 73c44f008a6c..c7497becd113 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -459,6 +459,8 @@ var migrations = []Migration{ NewMigration("Add card_type column to project table", v1_19.AddCardTypeToProjectTable), // v242 -> v243 NewMigration("Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText), + // v243 -> v244 + NewMigration("Add exclusive label", v1_19.AddExclusiveLabel), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_19/v244.go b/models/migrations/v1_19/v244.go new file mode 100644 index 000000000000..55bbfafb2fa4 --- /dev/null +++ b/models/migrations/v1_19/v244.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_19 //nolint + +import ( + "xorm.io/xorm" +) + +func AddExclusiveLabel(x *xorm.Engine) error { + type Label struct { + Exclusive bool + } + + return x.Sync(new(Label)) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 8410fef81e26..3e5b84df1bf8 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1322,6 +1322,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.reviewed_by_you = Reviewed by you issues.filter_sort = Sort issues.filter_sort.latest = Newest issues.filter_sort.oldest = Oldest diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 458838b93562..06bf06b4e847 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -92,6 +92,10 @@ func SearchIssues(ctx *context.APIContext) { // in: query // description: filter pulls requesting your review, default is false // type: boolean + // - name: reviewed + // in: query + // description: filter pulls reviewed by you, default is false + // type: boolean // - name: owner // in: query // description: filter by owner @@ -266,6 +270,9 @@ func SearchIssues(ctx *context.APIContext) { if ctx.FormBool("review_requested") { issuesOpt.ReviewRequestedID = ctxUserID } + if ctx.FormBool("reviewed") { + issuesOpt.ReviewedID = ctxUserID + } if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "Issues", err) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 42dcfb382d8d..105db3dcbce1 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -138,7 +138,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", "reviewed_by"} if !util.SliceContainsString(types, viewType, true) { viewType = "all" } @@ -148,6 +148,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti posterID = ctx.FormInt64("poster") mentionedID int64 reviewRequestedID int64 + reviewedID int64 forceEmpty bool ) @@ -161,6 +162,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti assigneeID = ctx.Doer.ID case "review_requested": reviewRequestedID = ctx.Doer.ID + case "reviewed_by": + reviewedID = ctx.Doer.ID } } @@ -208,6 +211,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti MentionedID: mentionedID, PosterID: posterID, ReviewRequestedID: reviewRequestedID, + ReviewedID: reviewedID, IsPull: isPullOption, IssueIDs: issueIDs, }) @@ -255,6 +259,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti PosterID: posterID, MentionedID: mentionedID, ReviewRequestedID: reviewRequestedID, + ReviewedID: reviewedID, MilestoneIDs: mileIDs, ProjectID: projectID, IsClosed: util.OptionalBoolOf(isShowClosed), @@ -2409,6 +2414,9 @@ func SearchIssues(ctx *context.Context) { if ctx.FormBool("review_requested") { issuesOpt.ReviewRequestedID = ctxUserID } + if ctx.FormBool("reviewed") { + issuesOpt.ReviewedID = ctxUserID + } if issues, err = issues_model.Issues(ctx, issuesOpt); err != nil { ctx.Error(http.StatusInternalServerError, "Issues", err.Error()) diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 4f45c1d5c314..8292b8246b79 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -366,6 +366,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { filterMode = issues_model.FilterModeMention case "review_requested": filterMode = issues_model.FilterModeReviewRequested + case "reviewed_by": + filterMode = issues_model.FilterModeReviewed case "your_repositories": fallthrough default: @@ -434,6 +436,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { opts.MentionedID = ctx.Doer.ID case issues_model.FilterModeReviewRequested: opts.ReviewRequestedID = ctx.Doer.ID + case issues_model.FilterModeReviewed: + opts.ReviewedID = ctx.Doer.ID } // keyword holds the search term entered into the search field. diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 4b55e7bec84e..47e7999d6739 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -165,10 +165,11 @@ {{.locale.Tr "repo.issues.filter_type.all_issues"}} {{.locale.Tr "repo.issues.filter_type.assigned_to_you"}} {{.locale.Tr "repo.issues.filter_type.created_by_you"}} - {{.locale.Tr "repo.issues.filter_type.mentioning_you"}} {{if .PageIsPullList}} {{.locale.Tr "repo.issues.filter_type.review_requested"}} + {{.locale.Tr "repo.issues.filter_type.reviewed_by_you"}} {{end}} + {{.locale.Tr "repo.issues.filter_type.mentioning_you"}} {{end}} diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index 8d6a97a713a8..11c61e8b53a0 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -111,8 +111,9 @@ {{.locale.Tr "repo.issues.filter_type.all_issues"}} {{.locale.Tr "repo.issues.filter_type.assigned_to_you"}} {{.locale.Tr "repo.issues.filter_type.created_by_you"}} - {{.locale.Tr "repo.issues.filter_type.mentioning_you"}} {{.locale.Tr "repo.issues.filter_type.review_requested"}} + {{.locale.Tr "repo.issues.filter_type.reviewed_by_you"}} + {{.locale.Tr "repo.issues.filter_type.mentioning_you"}} {{end}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 00fc3b60c454..e9ae96f4e261 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2366,6 +2366,12 @@ "name": "review_requested", "in": "query" }, + { + "type": "boolean", + "description": "filter pulls reviewed by you, default is false", + "name": "reviewed", + "in": "query" + }, { "type": "string", "description": "filter by owner", diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 049b6a168145..29023d921a08 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -17,16 +17,20 @@ {{.locale.Tr "repo.issues.filter_type.created_by_you"}} {{CountFmt .IssueStats.CreateCount}} - - {{.locale.Tr "repo.issues.filter_type.mentioning_you"}} - {{CountFmt .IssueStats.MentionCount}} - {{if .PageIsPulls}} {{.locale.Tr "repo.issues.filter_type.review_requested"}} {{CountFmt .IssueStats.ReviewRequestedCount}} + + {{.locale.Tr "repo.issues.filter_type.reviewed_by_you"}} + {{CountFmt .IssueStats.ReviewedCount}} + {{end}} + + {{.locale.Tr "repo.issues.filter_type.mentioning_you"}} + {{CountFmt .IssueStats.MentionCount}} +
All