From e397ee4b627ea28cce231f35d2880b55c0d448d2 Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Tue, 29 Aug 2023 22:46:29 +0800 Subject: [PATCH 01/15] fix --- models/issues/issue_watch.go | 33 ++++++++++++++++------- routers/api/v1/repo/issue_subscription.go | 7 +---- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 1efc0ea6871c4..8950c759b055e 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -97,20 +97,35 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i } // GetIssueWatchers returns watchers/unwatchers of a given issue -func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) (IssueWatchList, error) { - sess := db.GetEngine(ctx). - Where("`issue_watch`.issue_id = ?", issueID). - And("`issue_watch`.is_watching = ?", true). - And("`user`.is_active = ?", true). - And("`user`.prohibit_login = ?", false). - Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id") +func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) ([]int64, error) { + sess := db.GetEngine(ctx).SQL( + "select `user`.id "+ + "from issue_watch "+ + "inner join user on `user`.id = `issue_watch`.user_id "+ + "where `issue_watch`.issue_id = ? "+ + "and `issue_watch`.is_watching = true "+ + "and `user`.is_active = true "+ + "and `user`.prohibit_login = false "+ + " union "+ + "select `comment`.poster_id as id "+ + "from comment inner join user on `user`.id = `comment`.poster_id "+ + "where `comment`.issue_id = ? "+ + "and `comment`.type in (?,?,?) "+ + "and `user`.is_active = true "+ + "and `user`.prohibit_login = false "+ + "and NOT exists( "+ + "select 1 "+ + "from issue_watch "+ + "where `issue_watch`.issue_id = ? and `issue_watch`.is_watching = false)", + issueID, issueID, CommentTypeComment, CommentTypeCode, CommentTypeReview, issueID, + ) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) - watches := make([]*IssueWatch, 0, listOptions.PageSize) + watches := make([]int64, 0, listOptions.PageSize) return watches, sess.Find(&watches) } - watches := make([]*IssueWatch, 0, 8) + watches := make([]int64, 0, 8) return watches, sess.Find(&watches) } diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 5a05471264653..3308e98da80ea 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -262,17 +262,12 @@ func GetIssueSubscribers(ctx *context.APIContext) { return } - iwl, err := issues_model.GetIssueWatchers(ctx, issue.ID, utils.GetListOptions(ctx)) + userIDs, err := issues_model.GetIssueWatchers(ctx, issue.ID, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetIssueWatchers", err) return } - userIDs := make([]int64, 0, len(iwl)) - for _, iw := range iwl { - userIDs = append(userIDs, iw.UserID) - } - users, err := user_model.GetUsersByIDs(userIDs) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUsersByIDs", err) From 80e8cf09a982805c7922df95e00c87067044c25f Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Wed, 30 Aug 2023 11:06:21 +0800 Subject: [PATCH 02/15] fix sql --- models/issues/issue_watch.go | 41 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 8950c759b055e..29eda4caa29ef 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -5,6 +5,7 @@ package issues import ( "context" + "xorm.io/builder" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" @@ -98,27 +99,25 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i // GetIssueWatchers returns watchers/unwatchers of a given issue func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) ([]int64, error) { - sess := db.GetEngine(ctx).SQL( - "select `user`.id "+ - "from issue_watch "+ - "inner join user on `user`.id = `issue_watch`.user_id "+ - "where `issue_watch`.issue_id = ? "+ - "and `issue_watch`.is_watching = true "+ - "and `user`.is_active = true "+ - "and `user`.prohibit_login = false "+ - " union "+ - "select `comment`.poster_id as id "+ - "from comment inner join user on `user`.id = `comment`.poster_id "+ - "where `comment`.issue_id = ? "+ - "and `comment`.type in (?,?,?) "+ - "and `user`.is_active = true "+ - "and `user`.prohibit_login = false "+ - "and NOT exists( "+ - "select 1 "+ - "from issue_watch "+ - "where `issue_watch`.issue_id = ? and `issue_watch`.is_watching = false)", - issueID, issueID, CommentTypeComment, CommentTypeCode, CommentTypeReview, issueID, - ) + subscribeWatchers := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID}). + And(builder.Eq{"`issue_watch`.is_watching": true}) + + participantsWatchers := builder.Select("`comment`.poster_id"). + From("comment"). + Where(builder.Eq{"`comment`.issue_id": issueID}). + And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)). + And(builder.NotIn("`comment`.poster_id", + builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID}). + And(builder.Eq{"`issue_watch`.is_watching": false}))) + + sess := db.GetEngine(ctx).Select("id").Table("user"). + Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). + And(builder.Eq{"`user`.is_active": true}). + And(builder.Eq{"`user`.prohibit_login": false}) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) From 69f003ef3047398452adab12353caed54d93190e Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Wed, 30 Aug 2023 11:06:32 +0800 Subject: [PATCH 03/15] fix test --- models/issues/issue_watch_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/models/issues/issue_watch_test.go b/models/issues/issue_watch_test.go index 4f44487f567ad..86eb09d1e7c35 100644 --- a/models/issues/issue_watch_test.go +++ b/models/issues/issue_watch_test.go @@ -47,13 +47,17 @@ func TestGetIssueWatchers(t *testing.T) { iws, err := issues_model.GetIssueWatchers(db.DefaultContext, 1, db.ListOptions{}) assert.NoError(t, err) - // Watcher is inactive, thus 0 - assert.Len(t, iws, 0) + // user 9 watch it ,but user status is inactive, thus 0 + // user 5 participates and is not explicitly not watching , thus 1 + // total 1 + assert.Len(t, iws, 1) iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 2, db.ListOptions{}) assert.NoError(t, err) - // Watcher is explicit not watching - assert.Len(t, iws, 0) + // user 2 in Watcher is explicitly not watching, thus 0 + // user 1 participates and is not explicitly not watching , thus 1 + // total 1 + assert.Len(t, iws, 1) iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 5, db.ListOptions{}) assert.NoError(t, err) From 89a64568523eb25348f66ac84ff7dd91ea1570b1 Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Wed, 30 Aug 2023 11:06:51 +0800 Subject: [PATCH 04/15] adjust comment --- models/fixtures/comment.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/fixtures/comment.yml b/models/fixtures/comment.yml index bd64680c8c787..5cb02fb9f47e5 100644 --- a/models/fixtures/comment.yml +++ b/models/fixtures/comment.yml @@ -9,7 +9,7 @@ - id: 2 type: 0 # comment - poster_id: 3 # user not watching (see watch.yml) + poster_id: 3 # the user not explicitly not watching (see issue_watch.yml) issue_id: 1 # in repo_id 1 content: "good work!" created_unix: 946684811 @@ -17,7 +17,7 @@ - id: 3 type: 0 # comment - poster_id: 5 # user not watching (see watch.yml) + poster_id: 5 # the user not explicitly not watching (see issue_watch.yml) issue_id: 1 # in repo_id 1 content: "meh..." created_unix: 946684812 From ae1fb8049821dff7dffc0da478d78ca970cccd1c Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Wed, 30 Aug 2023 11:50:07 +0800 Subject: [PATCH 05/15] fix lint --- models/issues/issue_watch.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 29eda4caa29ef..f7b0a0014081e 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -5,12 +5,13 @@ package issues import ( "context" - "xorm.io/builder" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/builder" ) // IssueWatch is connection request for receiving issue notification. From e44e0c32f3130c4dcfac5dc97eea729d5385e084 Mon Sep 17 00:00:00 2001 From: CaiCandong <50507092+CaiCandong@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:10:05 +0800 Subject: [PATCH 06/15] Format Co-authored-by: yp05327 <576951401@qq.com> --- models/issues/issue_watch.go | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index f7b0a0014081e..9259e42f1f950 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -100,25 +100,20 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i // GetIssueWatchers returns watchers/unwatchers of a given issue func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) ([]int64, error) { - subscribeWatchers := builder.Select("`issue_watch`.user_id"). - From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID}). - And(builder.Eq{"`issue_watch`.is_watching": true}) - - participantsWatchers := builder.Select("`comment`.poster_id"). - From("comment"). - Where(builder.Eq{"`comment`.issue_id": issueID}). - And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)). - And(builder.NotIn("`comment`.poster_id", - builder.Select("`issue_watch`.user_id"). - From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID}). - And(builder.Eq{"`issue_watch`.is_watching": false}))) - - sess := db.GetEngine(ctx).Select("id").Table("user"). - Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). - And(builder.Eq{"`user`.is_active": true}). - And(builder.Eq{"`user`.prohibit_login": false}) + issueWatchers := builder.Select("`issue_watch`.user_id").From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID}) + + participantsWatchers := builder.Select("`comment`.poster_id").From("comment"). + Where(builder.And( + builder.Eq{"`comment`.issue_id": issueID}), + builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview), + builder.NotIn("`comment`.poster_id", issueWatchers.And(builder.Eq{"`issue_watch`.is_watching": false}), + ) + + sess := db.GetEngine(ctx).Select("`user`.id").Table("user"). + Where(builder.And( + builder.Or(builder.In("`user`.id", participantsWatchers), builder.In("`user`.id", issueWatchers.And(builder.Eq{"`issue_watch`.is_watching": true})))), + builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) From 6c69b9f4c9af97705462171686c704350e18f6db Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Wed, 30 Aug 2023 16:27:59 +0800 Subject: [PATCH 07/15] Revert "Format" This reverts commit e44e0c32f3130c4dcfac5dc97eea729d5385e084. --- models/issues/issue_watch.go | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 9259e42f1f950..f7b0a0014081e 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -100,20 +100,25 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i // GetIssueWatchers returns watchers/unwatchers of a given issue func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) ([]int64, error) { - issueWatchers := builder.Select("`issue_watch`.user_id").From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID}) - - participantsWatchers := builder.Select("`comment`.poster_id").From("comment"). - Where(builder.And( - builder.Eq{"`comment`.issue_id": issueID}), - builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview), - builder.NotIn("`comment`.poster_id", issueWatchers.And(builder.Eq{"`issue_watch`.is_watching": false}), - ) - - sess := db.GetEngine(ctx).Select("`user`.id").Table("user"). - Where(builder.And( - builder.Or(builder.In("`user`.id", participantsWatchers), builder.In("`user`.id", issueWatchers.And(builder.Eq{"`issue_watch`.is_watching": true})))), - builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) + subscribeWatchers := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID}). + And(builder.Eq{"`issue_watch`.is_watching": true}) + + participantsWatchers := builder.Select("`comment`.poster_id"). + From("comment"). + Where(builder.Eq{"`comment`.issue_id": issueID}). + And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)). + And(builder.NotIn("`comment`.poster_id", + builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID}). + And(builder.Eq{"`issue_watch`.is_watching": false}))) + + sess := db.GetEngine(ctx).Select("id").Table("user"). + Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). + And(builder.Eq{"`user`.is_active": true}). + And(builder.Eq{"`user`.prohibit_login": false}) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) From f3bf0b5d7c3df525ed4d5a140edb1cb91df1713b Mon Sep 17 00:00:00 2001 From: CaiCandong <50507092+CaiCandong@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:20:35 +0800 Subject: [PATCH 08/15] Apply suggestions from code review Co-authored-by: delvh --- models/issues/issue_watch.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index f7b0a0014081e..aedb33c3fcd5e 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -102,8 +102,7 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) ([]int64, error) { subscribeWatchers := builder.Select("`issue_watch`.user_id"). From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID}). - And(builder.Eq{"`issue_watch`.is_watching": true}) + Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": true}) participantsWatchers := builder.Select("`comment`.poster_id"). From("comment"). @@ -112,13 +111,11 @@ func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOpt And(builder.NotIn("`comment`.poster_id", builder.Select("`issue_watch`.user_id"). From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID}). - And(builder.Eq{"`issue_watch`.is_watching": false}))) + Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": false}))) sess := db.GetEngine(ctx).Select("id").Table("user"). Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). - And(builder.Eq{"`user`.is_active": true}). - And(builder.Eq{"`user`.prohibit_login": false}) + And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) From 5a15e0059f5e98d32142eff7b8f1b9c389933c1c Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Sun, 3 Sep 2023 17:40:10 +0800 Subject: [PATCH 09/15] Adjust index order of issue_watch table --- models/issues/issue_watch.go | 2 +- models/migrations/migrations.go | 2 ++ models/migrations/v1_21/v274.go | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 models/migrations/v1_21/v274.go diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index f7b0a0014081e..82d3429f7a4c6 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -17,8 +17,8 @@ import ( // IssueWatch is connection request for receiving issue notification. type IssueWatch struct { ID int64 `xorm:"pk autoincr"` - UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` + UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IsWatching bool `xorm:"NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 9f4acda23699a..263546ae78ee8 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -528,6 +528,8 @@ var migrations = []Migration{ NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable), // v273 -> v274 NewMigration("Add Action Schedule Table", v1_21.AddActionScheduleTable), + // v274 -> v275 + NewMigration("Adjust index order of issue_watch table ", v1_21.AdjustIssueWatchIndexOrder), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_21/v274.go b/models/migrations/v1_21/v274.go new file mode 100644 index 0000000000000..e73e828611a89 --- /dev/null +++ b/models/migrations/v1_21/v274.go @@ -0,0 +1,23 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" +) + +func AdjustIssueWatchIndexOrder(x *xorm.Engine) error { + type IssueWatch struct { + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` + IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` + IsWatching bool `xorm:"NOT NULL"` + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` + } + // Drop the old index :(user_id,issue_id) + // Then automatically created new index => (issue_id,user_id) + return x.DropIndexes(new(IssueWatch)) +} From 02e894fd46a2c2447c76f70761bebcb73ced47a2 Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Mon, 4 Sep 2023 14:48:49 +0800 Subject: [PATCH 10/15] Reduce unnecessary database queries & rename --- models/issues/issue_watch.go | 14 +++++++------- routers/api/v1/repo/issue_subscription.go | 9 ++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 654dcd1c8a607..6844c48edfa60 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -98,8 +98,8 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i Find(&ids) } -// GetIssueWatchers returns watchers/unwatchers of a given issue -func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) ([]int64, error) { +// GetIssueSubscribers returns subscribers of a given issue +func GetIssueSubscribers(ctx context.Context, issueID int64, listOptions db.ListOptions) (user_model.UserList, error) { subscribeWatchers := builder.Select("`issue_watch`.user_id"). From("issue_watch"). Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": true}) @@ -113,17 +113,17 @@ func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOpt From("issue_watch"). Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": false}))) - sess := db.GetEngine(ctx).Select("id").Table("user"). + sess := db.GetEngine(ctx).Table("user"). Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) - watches := make([]int64, 0, listOptions.PageSize) - return watches, sess.Find(&watches) + users := make(user_model.UserList, 0, listOptions.PageSize) + return users, sess.Find(&users) } - watches := make([]int64, 0, 8) - return watches, sess.Find(&watches) + users := make(user_model.UserList, 0, 8) + return users, sess.Find(&users) } // CountIssueWatchers count watchers/unwatchers of a given issue diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 3308e98da80ea..ea495775c4192 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -262,17 +262,12 @@ func GetIssueSubscribers(ctx *context.APIContext) { return } - userIDs, err := issues_model.GetIssueWatchers(ctx, issue.ID, utils.GetListOptions(ctx)) + users, err := issues_model.GetIssueSubscribers(ctx, issue.ID, utils.GetListOptions(ctx)) if err != nil { - ctx.Error(http.StatusInternalServerError, "GetIssueWatchers", err) + ctx.Error(http.StatusInternalServerError, "GetIssueSubscribers", err) return } - users, err := user_model.GetUsersByIDs(userIDs) - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetUsersByIDs", err) - return - } apiUsers := make([]*api.User, 0, len(users)) for _, v := range users { apiUsers = append(apiUsers, convert.ToUser(ctx, v, ctx.Doer)) From 4adb2e5e6512616841637f8966a57a9b2507c308 Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Mon, 4 Sep 2023 14:49:45 +0800 Subject: [PATCH 11/15] rename & fix count --- models/issues/issue_watch.go | 27 ++++++++++++++++------- routers/api/v1/repo/issue_subscription.go | 4 ++-- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 6844c48edfa60..3a52b3bc1cb30 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -126,14 +126,25 @@ func GetIssueSubscribers(ctx context.Context, issueID int64, listOptions db.List return users, sess.Find(&users) } -// CountIssueWatchers count watchers/unwatchers of a given issue -func CountIssueWatchers(ctx context.Context, issueID int64) (int64, error) { - return db.GetEngine(ctx). - Where("`issue_watch`.issue_id = ?", issueID). - And("`issue_watch`.is_watching = ?", true). - And("`user`.is_active = ?", true). - And("`user`.prohibit_login = ?", false). - Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id").Count(new(IssueWatch)) +// CountIssueSubscribers count watchers of a given issue +func CountIssueSubscribers(ctx context.Context, issueID int64) (int64, error) { + subscribeWatchers := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": true}) + + participantsWatchers := builder.Select("`comment`.poster_id"). + From("comment"). + Where(builder.Eq{"`comment`.issue_id": issueID}). + And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)). + And(builder.NotIn("`comment`.poster_id", + builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": false}))) + + sess := db.GetEngine(ctx).Table("user"). + Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). + And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) + return sess.Count(new(user_model.User)) } // RemoveIssueWatchersByRepoID remove issue watchers by repoID diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index ea495775c4192..a264be72516cd 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -273,9 +273,9 @@ func GetIssueSubscribers(ctx *context.APIContext) { apiUsers = append(apiUsers, convert.ToUser(ctx, v, ctx.Doer)) } - count, err := issues_model.CountIssueWatchers(ctx, issue.ID) + count, err := issues_model.CountIssueSubscribers(ctx, issue.ID) if err != nil { - ctx.Error(http.StatusInternalServerError, "CountIssueWatchers", err) + ctx.Error(http.StatusInternalServerError, "CountIssueSubscribers", err) return } From cec368f2cba56fde623760b714a042561e068c2e Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Mon, 4 Sep 2023 15:47:50 +0800 Subject: [PATCH 12/15] fix test --- models/issues/issue_watch_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/issues/issue_watch_test.go b/models/issues/issue_watch_test.go index 86eb09d1e7c35..25bba5baa0890 100644 --- a/models/issues/issue_watch_test.go +++ b/models/issues/issue_watch_test.go @@ -45,26 +45,26 @@ func TestGetIssueWatch(t *testing.T) { func TestGetIssueWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - iws, err := issues_model.GetIssueWatchers(db.DefaultContext, 1, db.ListOptions{}) + iws, err := issues_model.GetIssueSubscribers(db.DefaultContext, 1, db.ListOptions{}) assert.NoError(t, err) // user 9 watch it ,but user status is inactive, thus 0 // user 5 participates and is not explicitly not watching , thus 1 // total 1 assert.Len(t, iws, 1) - iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 2, db.ListOptions{}) + iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, 2, db.ListOptions{}) assert.NoError(t, err) // user 2 in Watcher is explicitly not watching, thus 0 // user 1 participates and is not explicitly not watching , thus 1 // total 1 assert.Len(t, iws, 1) - iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 5, db.ListOptions{}) + iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, 5, db.ListOptions{}) assert.NoError(t, err) // Issue has no Watchers assert.Len(t, iws, 0) - iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 7, db.ListOptions{}) + iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, 7, db.ListOptions{}) assert.NoError(t, err) // Issue has one watcher assert.Len(t, iws, 1) From 695b5c70ff7b7a39f2567e05eaf153c92fea023d Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Mon, 4 Sep 2023 17:51:32 +0800 Subject: [PATCH 13/15] fix --- models/issues/issue_subscriber.go | 98 +++++++++++++++++++++++ models/issues/issue_subscriber_test.go | 52 ++++++++++++ models/issues/issue_watch.go | 70 ---------------- models/issues/issue_watch_test.go | 28 ------- routers/api/v1/repo/issue_subscription.go | 12 +-- routers/web/repo/issue.go | 2 +- tests/integration/incoming_email_test.go | 4 +- 7 files changed, 159 insertions(+), 107 deletions(-) create mode 100644 models/issues/issue_subscriber.go create mode 100644 models/issues/issue_subscriber_test.go diff --git a/models/issues/issue_subscriber.go b/models/issues/issue_subscriber.go new file mode 100644 index 0000000000000..461f0bab89bc7 --- /dev/null +++ b/models/issues/issue_subscriber.go @@ -0,0 +1,98 @@ +package issues + +import ( + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "context" + "xorm.io/builder" +) + +// CheckIssueSubscriber check if a user is subscribing an issue +// it takes participants and repo watch into account +func CheckIssueSubscriber(user *user_model.User, issue *Issue) (bool, error) { + iw, exist, err := GetIssueWatch(db.DefaultContext, user.ID, issue.ID) + if err != nil { + return false, err + } + if exist { + return iw.IsWatching, nil + } + w, err := repo_model.GetWatch(db.DefaultContext, user.ID, issue.RepoID) + if err != nil { + return false, err + } + return repo_model.IsWatchMode(w.Mode) || IsUserParticipantsOfIssue(user, issue), nil +} + +// GetIssueSubscribers returns subscribers of a given issue +func GetIssueSubscribers(ctx context.Context, issue *Issue, listOptions db.ListOptions) (user_model.UserList, error) { + subscribeUserIds := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issue.ID, "`issue_watch`.is_watching": true}) + + unsubscribeUserIds := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issue.ID, "`issue_watch`.is_watching": false}) + + participantsUserIds := builder.Select("`comment`.poster_id"). + From("comment"). + Where(builder.Eq{"`comment`.issue_id": issue.ID}). + And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)) + + repoSubscribeUserIds := builder.Select("`watch`.user_id"). + From("watch"). + Where(builder.Eq{"`watch`.repo_id": issue.RepoID}). + And(builder.NotIn("`watch`.mode", repo_model.WatchModeDont, repo_model.WatchModeNone)) + + sess := db.GetEngine(ctx).Table("user"). + Where(builder.Or( + builder.In("id", subscribeUserIds), + builder.In("id", repoSubscribeUserIds), + builder.In("id", participantsUserIds), + builder.In("id", issue.PosterID), + ). + And(builder.NotIn("id", unsubscribeUserIds)). + And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false})) + + if listOptions.Page != 0 { + sess = db.SetSessionPagination(sess, &listOptions) + users := make(user_model.UserList, 0, listOptions.PageSize) + return users, sess.Find(&users) + } + users := make(user_model.UserList, 0, 8) + return users, sess.Find(&users) +} + +// CountIssueSubscribers count subscribers of a given issue +func CountIssueSubscribers(ctx context.Context, issue *Issue) (int64, error) { + subscribeUserIds := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issue.ID, "`issue_watch`.is_watching": true}) + + unsubscribeUserIds := builder.Select("`issue_watch`.user_id"). + From("issue_watch"). + Where(builder.Eq{"`issue_watch`.issue_id": issue.ID, "`issue_watch`.is_watching": false}) + + participantsUserIds := builder.Select("`comment`.poster_id"). + From("comment"). + Where(builder.Eq{"`comment`.issue_id": issue.ID}). + And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)) + + repoSubscribeUserIds := builder.Select("`watch`.user_id"). + From("watch"). + Where(builder.Eq{"`watch`.repo_id": issue.RepoID}). + And(builder.NotIn("`watch`.mode", repo_model.WatchModeDont, repo_model.WatchModeNone)) + + sess := db.GetEngine(ctx).Table("user"). + Where(builder.Or( + builder.In("id", subscribeUserIds), + builder.In("id", repoSubscribeUserIds), + builder.In("id", participantsUserIds), + builder.In("id", issue.PosterID), + ). + And(builder.NotIn("id", unsubscribeUserIds)). + And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false})) + + return sess.Count(new(user_model.User)) +} diff --git a/models/issues/issue_subscriber_test.go b/models/issues/issue_subscriber_test.go new file mode 100644 index 0000000000000..d774a69573f5f --- /dev/null +++ b/models/issues/issue_subscriber_test.go @@ -0,0 +1,52 @@ +package issues_test + +import ( + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/unittest" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestGetIssueWatchers(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + // 写个表格测试 + + issueList := issues_model.IssueList{ + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}), // repo 1 + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}), // repo 1 + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 5}), // repo 1 + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 7}), // repo 2 + } + + iws, err := issues_model.GetIssueSubscribers(db.DefaultContext, issueList[0], db.ListOptions{}) + assert.NoError(t, err) + // user 9 watch it ,but user status is inactive, thus 0 + // user 5 participates and is not explicitly not watching, thus 1 + // repo1 have 1,2,3 user watch it, thus 3 + // total 4 + assert.Len(t, iws, 4) + + iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, issueList[1], db.ListOptions{}) + assert.NoError(t, err) + // user[2] in Watcher is explicitly not watching, thus 0 + // user[1] participates and is not explicitly not watching, thus 1 + // repo1 have [1,2,3] user watch it, thus 2 + // total 3 + assert.Len(t, iws, 3) + + iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, issueList[2], db.ListOptions{}) + assert.NoError(t, err) + // Issue has no Watchers + // repo[1] have [1,2,3] user watch it, thus 3 + // poster 2 participate, thus 1 + // total 4 + assert.Len(t, iws, 4) + + iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, issueList[3], db.ListOptions{}) + assert.NoError(t, err) + // Issue has one watcher, user 0 + // repo1 have no user watch it, thus 0 + // poster 1 participate, thus 1 + assert.Len(t, iws, 1) +} diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 3a52b3bc1cb30..6a94078f34da3 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -7,11 +7,7 @@ import ( "context" "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" - - "xorm.io/builder" ) // IssueWatch is connection request for receiving issue notification. @@ -69,23 +65,6 @@ func GetIssueWatch(ctx context.Context, userID, issueID int64) (iw *IssueWatch, return iw, exists, err } -// CheckIssueWatch check if an user is watching an issue -// it takes participants and repo watch into account -func CheckIssueWatch(user *user_model.User, issue *Issue) (bool, error) { - iw, exist, err := GetIssueWatch(db.DefaultContext, user.ID, issue.ID) - if err != nil { - return false, err - } - if exist { - return iw.IsWatching, nil - } - w, err := repo_model.GetWatch(db.DefaultContext, user.ID, issue.RepoID) - if err != nil { - return false, err - } - return repo_model.IsWatchMode(w.Mode) || IsUserParticipantsOfIssue(user, issue), nil -} - // GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id // but avoids joining with `user` for performance reasons // User permissions must be verified elsewhere if required @@ -98,55 +77,6 @@ func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]i Find(&ids) } -// GetIssueSubscribers returns subscribers of a given issue -func GetIssueSubscribers(ctx context.Context, issueID int64, listOptions db.ListOptions) (user_model.UserList, error) { - subscribeWatchers := builder.Select("`issue_watch`.user_id"). - From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": true}) - - participantsWatchers := builder.Select("`comment`.poster_id"). - From("comment"). - Where(builder.Eq{"`comment`.issue_id": issueID}). - And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)). - And(builder.NotIn("`comment`.poster_id", - builder.Select("`issue_watch`.user_id"). - From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": false}))) - - sess := db.GetEngine(ctx).Table("user"). - Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). - And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) - - if listOptions.Page != 0 { - sess = db.SetSessionPagination(sess, &listOptions) - users := make(user_model.UserList, 0, listOptions.PageSize) - return users, sess.Find(&users) - } - users := make(user_model.UserList, 0, 8) - return users, sess.Find(&users) -} - -// CountIssueSubscribers count watchers of a given issue -func CountIssueSubscribers(ctx context.Context, issueID int64) (int64, error) { - subscribeWatchers := builder.Select("`issue_watch`.user_id"). - From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": true}) - - participantsWatchers := builder.Select("`comment`.poster_id"). - From("comment"). - Where(builder.Eq{"`comment`.issue_id": issueID}). - And(builder.In("`comment`.type", CommentTypeComment, CommentTypeCode, CommentTypeReview)). - And(builder.NotIn("`comment`.poster_id", - builder.Select("`issue_watch`.user_id"). - From("issue_watch"). - Where(builder.Eq{"`issue_watch`.issue_id": issueID, "`issue_watch`.is_watching": false}))) - - sess := db.GetEngine(ctx).Table("user"). - Where(builder.Or(builder.In("id", participantsWatchers), builder.In("id", subscribeWatchers))). - And(builder.Eq{"`user`.is_active": true, "`user`.prohibit_login": false}) - return sess.Count(new(user_model.User)) -} - // RemoveIssueWatchersByRepoID remove issue watchers by repoID func RemoveIssueWatchersByRepoID(ctx context.Context, userID, repoID int64) error { _, err := db.GetEngine(ctx). diff --git a/models/issues/issue_watch_test.go b/models/issues/issue_watch_test.go index 25bba5baa0890..ab8783675fdd6 100644 --- a/models/issues/issue_watch_test.go +++ b/models/issues/issue_watch_test.go @@ -41,31 +41,3 @@ func TestGetIssueWatch(t *testing.T) { assert.False(t, exists) assert.NoError(t, err) } - -func TestGetIssueWatchers(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - iws, err := issues_model.GetIssueSubscribers(db.DefaultContext, 1, db.ListOptions{}) - assert.NoError(t, err) - // user 9 watch it ,but user status is inactive, thus 0 - // user 5 participates and is not explicitly not watching , thus 1 - // total 1 - assert.Len(t, iws, 1) - - iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, 2, db.ListOptions{}) - assert.NoError(t, err) - // user 2 in Watcher is explicitly not watching, thus 0 - // user 1 participates and is not explicitly not watching , thus 1 - // total 1 - assert.Len(t, iws, 1) - - iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, 5, db.ListOptions{}) - assert.NoError(t, err) - // Issue has no Watchers - assert.Len(t, iws, 0) - - iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, 7, db.ListOptions{}) - assert.NoError(t, err) - // Issue has one watcher - assert.Len(t, iws, 1) -} diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index a264be72516cd..04d4a4aa4bc39 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -132,7 +132,7 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - current, err := issues_model.CheckIssueWatch(user, issue) + current, err := issues_model.CheckIssueSubscriber(user, issue) if err != nil { ctx.Error(http.StatusInternalServerError, "CheckIssueWatch", err) return @@ -196,14 +196,14 @@ func CheckIssueSubscription(ctx *context.APIContext) { return } - watching, err := issues_model.CheckIssueWatch(ctx.Doer, issue) + subscribed, err := issues_model.CheckIssueSubscriber(ctx.Doer, issue) if err != nil { ctx.InternalServerError(err) return } ctx.JSON(http.StatusOK, api.WatchInfo{ - Subscribed: watching, - Ignored: !watching, + Subscribed: subscribed, + Ignored: !subscribed, Reason: nil, CreatedAt: issue.CreatedUnix.AsTime(), URL: issue.APIURL() + "/subscriptions", @@ -262,7 +262,7 @@ func GetIssueSubscribers(ctx *context.APIContext) { return } - users, err := issues_model.GetIssueSubscribers(ctx, issue.ID, utils.GetListOptions(ctx)) + users, err := issues_model.GetIssueSubscribers(ctx, issue, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetIssueSubscribers", err) return @@ -273,7 +273,7 @@ func GetIssueSubscribers(ctx *context.APIContext) { apiUsers = append(apiUsers, convert.ToUser(ctx, v, ctx.Doer)) } - count, err := issues_model.CountIssueSubscribers(ctx, issue.ID) + count, err := issues_model.CountIssueSubscribers(ctx, issue) if err != nil { ctx.Error(http.StatusInternalServerError, "CountIssueSubscribers", err) return diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index f5e8f80ddfe2e..73c3e64735c35 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1408,7 +1408,7 @@ func ViewIssue(ctx *context.Context) { if ctx.Doer != nil { iw.UserID = ctx.Doer.ID iw.IssueID = issue.ID - iw.IsWatching, err = issues_model.CheckIssueWatch(ctx.Doer, issue) + iw.IsWatching, err = issues_model.CheckIssueSubscriber(ctx.Doer, issue) if err != nil { ctx.ServerError("CheckIssueWatch", err) return diff --git a/tests/integration/incoming_email_test.go b/tests/integration/incoming_email_test.go index b4478f57809fa..053d5b0885db9 100644 --- a/tests/integration/incoming_email_test.go +++ b/tests/integration/incoming_email_test.go @@ -154,7 +154,7 @@ func TestIncomingEmail(t *testing.T) { t.Run("Unsubscribe", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - watching, err := issues_model.CheckIssueWatch(user, issue) + watching, err := issues_model.CheckIssueSubscriber(user, issue) assert.NoError(t, err) assert.True(t, watching) @@ -169,7 +169,7 @@ func TestIncomingEmail(t *testing.T) { assert.NoError(t, handler.Handle(db.DefaultContext, content, user, payload)) - watching, err = issues_model.CheckIssueWatch(user, issue) + watching, err = issues_model.CheckIssueSubscriber(user, issue) assert.NoError(t, err) assert.False(t, watching) }) From a3b6a6e953f0af70b8073ab2ad924e8d78f948ea Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Mon, 4 Sep 2023 18:29:56 +0800 Subject: [PATCH 14/15] fix lint & add comments --- models/issues/issue_subscriber.go | 7 +++- models/issues/issue_subscriber_test.go | 50 +++++++++++++++++--------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/models/issues/issue_subscriber.go b/models/issues/issue_subscriber.go index 461f0bab89bc7..7c0f21622ed6c 100644 --- a/models/issues/issue_subscriber.go +++ b/models/issues/issue_subscriber.go @@ -1,10 +1,15 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + package issues import ( + "context" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "context" + "xorm.io/builder" ) diff --git a/models/issues/issue_subscriber_test.go b/models/issues/issue_subscriber_test.go index d774a69573f5f..c3263f674e989 100644 --- a/models/issues/issue_subscriber_test.go +++ b/models/issues/issue_subscriber_test.go @@ -1,16 +1,19 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + package issues_test import ( + "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" - "testing" ) func TestGetIssueWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - // 写个表格测试 issueList := issues_model.IssueList{ unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}), // repo 1 @@ -21,32 +24,45 @@ func TestGetIssueWatchers(t *testing.T) { iws, err := issues_model.GetIssueSubscribers(db.DefaultContext, issueList[0], db.ListOptions{}) assert.NoError(t, err) - // user 9 watch it ,but user status is inactive, thus 0 - // user 5 participates and is not explicitly not watching, thus 1 - // repo1 have 1,2,3 user watch it, thus 3 - // total 4 + // +isIssueWatching[] + // -noIssueWatching[] + // +participates[2,3,5] + // +poster[1] + // +repoWatch[1,4,9,11] + // -inactive[3,9] + // => [1,4,5,11] assert.Len(t, iws, 4) iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, issueList[1], db.ListOptions{}) assert.NoError(t, err) - // user[2] in Watcher is explicitly not watching, thus 0 - // user[1] participates and is not explicitly not watching, thus 1 - // repo1 have [1,2,3] user watch it, thus 2 - // total 3 + // +isIssueWatching[] + // -noIssueWatching[2] + // +participates[1] + // +poster[1] + // +repoWatch[1,4,9,11] + // -inactive[3,9] + // => [1,4,11] assert.Len(t, iws, 3) iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, issueList[2], db.ListOptions{}) assert.NoError(t, err) - // Issue has no Watchers - // repo[1] have [1,2,3] user watch it, thus 3 - // poster 2 participate, thus 1 - // total 4 + // +isIssueWatching[] + // -noIssueWatching[] + // +participates[] + // +poster[2] + // +repoWatch[1,4,9,11] + // -inactive[3,9] + // => [1,2,4,11] assert.Len(t, iws, 4) iws, err = issues_model.GetIssueSubscribers(db.DefaultContext, issueList[3], db.ListOptions{}) assert.NoError(t, err) - // Issue has one watcher, user 0 - // repo1 have no user watch it, thus 0 - // poster 1 participate, thus 1 + // +isIssueWatching[] + // -noIssueWatching[] + // +participates[] + // +poster[2] + // +repoWatch[] + // -inactive[3,9] + // => [2] assert.Len(t, iws, 1) } From 2bd395d3b7738cb18c1c74088515ea9e4359f78d Mon Sep 17 00:00:00 2001 From: caicandong <1290147055@qq.com> Date: Mon, 4 Sep 2023 20:35:26 +0800 Subject: [PATCH 15/15] fix lint --- models/issues/issue_subscriber_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/issues/issue_subscriber_test.go b/models/issues/issue_subscriber_test.go index c3263f674e989..712bf25dcf578 100644 --- a/models/issues/issue_subscriber_test.go +++ b/models/issues/issue_subscriber_test.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" + "github.com/stretchr/testify/assert" )