From a7e905ba130d0ab7e3f2a337e1ff790b4891d1fd Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 14 Feb 2023 22:04:46 +0100 Subject: [PATCH 1/4] 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 e0dcf3d269ee0..9a5f000a00aec 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 73c44f008a6cc..c7497becd1130 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 0000000000000..55bbfafb2fa4a --- /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 8410fef81e26c..3e5b84df1bf8f 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 458838b935624..06bf06b4e8472 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 42dcfb382d8de..105db3dcbce1e 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 4f45c1d5c3149..8292b8246b79e 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 4b55e7bec84e6..47e7999d67392 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 8d6a97a713a8a..11c61e8b53a0b 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 00fc3b60c4548..e9ae96f4e2617 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 049b6a1681456..29023d921a086 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 From a0d5074d518dffcc85f653e6e40afdfcf787a39c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 18 Feb 2023 12:59:13 +0100 Subject: [PATCH 2/4] Remove accidentally included changes --- models/migrations/migrations.go | 2 -- models/migrations/v1_19/v244.go | 16 ---------------- 2 files changed, 18 deletions(-) delete mode 100644 models/migrations/v1_19/v244.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index c7497becd1130..73c44f008a6cc 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -459,8 +459,6 @@ 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 deleted file mode 100644 index 55bbfafb2fa4a..0000000000000 --- a/models/migrations/v1_19/v244.go +++ /dev/null @@ -1,16 +0,0 @@ -// 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)) -} From ca4361d3d53e2849eb22b6f19244e31fea5c3671 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 18 Feb 2023 15:16:35 +0100 Subject: [PATCH 3/4] Fix mistake in query --- models/issues/issue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issues/issue.go b/models/issues/issue.go index 9a5f000a00aec..71fb3828a6958 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1432,7 +1432,7 @@ func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session From("comment"). Where(builder.Eq{"poster_id": reviewedID}), ) - return sess.And(notPoster, reviewed, comment) + return sess.And(notPoster, builder.Or(reviewed, comment)) } func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session { From 2903ce4f43f6f70202b02e6cfd3fe9fb5417ecd9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 20 Feb 2023 09:13:06 +0100 Subject: [PATCH 4/4] Only include comments where some text was written, same logic as participants --- models/issues/issue.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/models/issues/issue.go b/models/issues/issue.go index 71fb3828a6958..e8a0c541b3a41 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1427,12 +1427,15 @@ func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session ), )), ) - comment := builder.In("issue.id", builder. + commented := builder.In("issue.id", builder. Select("issue_id"). From("comment"). - Where(builder.Eq{"poster_id": reviewedID}), + Where(builder.And( + builder.Eq{"poster_id": reviewedID}, + builder.In("type", CommentTypeComment, CommentTypeCode, CommentTypeReview), + )), ) - return sess.And(notPoster, builder.Or(reviewed, comment)) + return sess.And(notPoster, builder.Or(reviewed, commented)) } func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session {