From 7cd9881b155b129dc74d1184963925a5623b17de Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 30 Jan 2020 08:29:10 +0100 Subject: [PATCH 01/58] squash-rebase --- models/fixtures/issue_watch.yml | 8 +- models/issue_watch.go | 95 ++++++++++++++++++----- models/issue_watch_test.go | 4 +- models/migrations/migrations.go | 3 + models/migrations/v999.go | 43 ++++++++++ models/notification.go | 79 ++++++++++--------- models/repo_watch.go | 6 +- routers/api/v1/repo/issue_subscription.go | 7 +- routers/repo/issue.go | 5 +- routers/repo/issue_watch.go | 9 ++- 10 files changed, 188 insertions(+), 71 deletions(-) create mode 100644 models/migrations/v999.go diff --git a/models/fixtures/issue_watch.yml b/models/fixtures/issue_watch.yml index 4bc3ff1b8b987..5b0ad0d7e5deb 100644 --- a/models/fixtures/issue_watch.yml +++ b/models/fixtures/issue_watch.yml @@ -2,7 +2,7 @@ id: 1 user_id: 9 issue_id: 1 - is_watching: true + mode: 1 #IssueWatchModeNormal created_unix: 946684800 updated_unix: 946684800 @@ -10,7 +10,7 @@ id: 2 user_id: 2 issue_id: 2 - is_watching: false + mode: 2 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 @@ -18,7 +18,7 @@ id: 3 user_id: 2 issue_id: 7 - is_watching: true + mode: 1 #IssueWatchModeNormal created_unix: 946684800 updated_unix: 946684800 @@ -26,6 +26,6 @@ id: 4 user_id: 1 issue_id: 7 - is_watching: false + mode: 2 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 diff --git a/models/issue_watch.go b/models/issue_watch.go index 343ad16cde170..b61e292b19a29 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -5,15 +5,32 @@ package models import ( + "fmt" + + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" ) +// IssueWatchMode specifies what kind of watch the user has on a issue +type IssueWatchMode int8 + +const ( + // IssueWatchModeNone don't watch + IssueWatchModeNone IssueWatchMode = iota // 0 + // IssueWatchModeNormal watch issue (from other sources) + IssueWatchModeNormal // 1 + // IssueWatchModeDont explicit don't auto-watch + IssueWatchModeDont // 2 + // IssueWatchModeAuto watch issue (from AutoWatchOnChanges) + IssueWatchModeAuto // 3 +) + // 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"` - IsWatching bool `xorm:"NOT NULL"` + Mode IssueWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` } @@ -21,27 +38,31 @@ type IssueWatch struct { // IssueWatchList contains IssueWatch type IssueWatchList []*IssueWatch -// CreateOrUpdateIssueWatch set watching for a user and issue -func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error { - iw, exists, err := getIssueWatch(x, userID, issueID) +// CreateOrUpdateIssueWatchMode set IssueWatchMode for a user and issue +func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) error { + return createOrUpdateIssueWatchMode(x, userID, issueID, mode) +} + +func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWatchMode) error { + iw, exists, err := getIssueWatch(e, userID, issueID) if err != nil { return err } - if !exists { iw = &IssueWatch{ - UserID: userID, - IssueID: issueID, - IsWatching: isWatching, + UserID: userID, + IssueID: issueID, } + } + + iw.Mode = mode - if _, err := x.Insert(iw); err != nil { + if !exists { + if _, err = e.Insert(iw); err != nil { return err } } else { - iw.IsWatching = isWatching - - if _, err := x.ID(iw.ID).Cols("is_watching", "updated_unix").Update(iw); err != nil { + if _, err = e.ID(iw.ID).Cols("is_watching", "updated_unix", "mode").Update(iw); err != nil { return err } } @@ -60,6 +81,7 @@ func getIssueWatch(e Engine, userID, issueID int64) (iw *IssueWatch, exists bool exists, err = e. Where("user_id = ?", userID). And("issue_id = ?", issueID). + And("mode <> ?", IssueWatchModeNone). Get(iw) return } @@ -67,24 +89,39 @@ func getIssueWatch(e Engine, userID, issueID int64) (iw *IssueWatch, exists bool // GetIssueWatchersIDs returns IDs of subscribers to a given issue id // but avoids joining with `user` for performance reasons // User permissions must be verified elsewhere if required -func GetIssueWatchersIDs(issueID int64) ([]int64, error) { +func GetIssueWatchersIDs(issueID int64, modes ...IssueWatchMode) ([]int64, error) { + if len(modes) == 0 { + modes = []IssueWatchMode{IssueWatchModeNormal, IssueWatchModeAuto} + } + return getIssueWatchersIDs(x, issueID, modes...) +} +func getIssueWatchersIDs(e Engine, issueID int64, modes ...IssueWatchMode) ([]int64, error) { ids := make([]int64, 0, 64) - return ids, x.Table("issue_watch"). + if len(modes) == 0 { + return nil, fmt.Errorf("no IssueWatchMode set") + } + return ids, e.Table("issue_watch"). Where("issue_id=?", issueID). - And("is_watching = ?", true). + In("mode", modes). Select("user_id"). Find(&ids) } // GetIssueWatchers returns watchers/unwatchers of a given issue -func GetIssueWatchers(issueID int64, listOptions ListOptions) (IssueWatchList, error) { - return getIssueWatchers(x, issueID, listOptions) +func GetIssueWatchers(issueID int64, listOptions ListOptions, modes ...IssueWatchMode) (IssueWatchList, error) { + if len(modes) == 0 { + modes = []IssueWatchMode{IssueWatchModeNormal, IssueWatchModeAuto} + } + return getIssueWatchers(x, issueID, listOptions, modes...) } -func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions) (watches IssueWatchList, err error) { +func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions, modes ...IssueWatchMode) (watches IssueWatchList, err error) { + if len(modes) == 0 { + return nil, fmt.Errorf("no IssueWatchMode set") + } sess := e. Where("`issue_watch`.issue_id = ?", issueID). - And("`issue_watch`.is_watching = ?", true). + In("`issue_watch`.mode", modes). And("`user`.is_active = ?", true). And("`user`.prohibit_login = ?", false). Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id") @@ -98,7 +135,7 @@ func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions) (watches func removeIssueWatchersByRepoID(e Engine, userID int64, repoID int64) error { iw := &IssueWatch{ - IsWatching: false, + Mode: IssueWatchModeNone, } _, err := e. Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID). @@ -108,6 +145,22 @@ func removeIssueWatchersByRepoID(e Engine, userID int64, repoID int64) error { return err } +// IsWatching is true if user iw watching either repo or issue (backwards compatibility) +func (iw IssueWatch) IsWatching() bool { + issue, err := GetIssueByID(iw.IssueID) + if err != nil { + // fail silent since template expect only bool + log.Error("IssueWatch.IsWatching: GetIssueByID: ", err) + return false + } + // if repowatch is ture ... + if IsWatching(iw.UserID, issue.RepoID) && iw.Mode != IssueWatchModeDont { + return true + } + + return iw.Mode == IssueWatchModeNormal || iw.Mode == IssueWatchModeAuto +} + // LoadWatchUsers return watching users func (iwl IssueWatchList) LoadWatchUsers() (users UserList, err error) { return iwl.loadWatchUsers(x) @@ -120,7 +173,7 @@ func (iwl IssueWatchList) loadWatchUsers(e Engine) (users UserList, err error) { var userIDs = make([]int64, 0, len(iwl)) for _, iw := range iwl { - if iw.IsWatching { + if iw.Mode == IssueWatchModeNormal || iw.Mode == IssueWatchModeAuto { userIDs = append(userIDs, iw.UserID) } } diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index 762b1486c6461..ed163efe33fee 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestCreateOrUpdateIssueWatch(t *testing.T) { +/**func TestCreateOrUpdateIssueWatch(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, CreateOrUpdateIssueWatch(3, 1, true)) @@ -20,7 +20,7 @@ func TestCreateOrUpdateIssueWatch(t *testing.T) { assert.NoError(t, CreateOrUpdateIssueWatch(1, 1, false)) iw = AssertExistsAndLoadBean(t, &IssueWatch{UserID: 1, IssueID: 1}).(*IssueWatch) assert.False(t, iw.IsWatching) -} +}**/ func TestGetIssueWatch(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ce3f77ba4e26f..318470f2552e0 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -188,6 +188,9 @@ var migrations = []Migration{ NewMigration("Fix topic repository count", fixTopicRepositoryCount), // v127 -> v128 NewMigration("add repository code language statistics", addLanguageStats), + + // v999 has no number jet + NewMigration("Change from IsWatching to Modes at IssueWatch", addIssueWatchModes), } // Migrate database to current version diff --git a/models/migrations/v999.go b/models/migrations/v999.go new file mode 100644 index 0000000000000..04ff35f6f57be --- /dev/null +++ b/models/migrations/v999.go @@ -0,0 +1,43 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "fmt" + + "code.gitea.io/gitea/models" + + "xorm.io/xorm" +) + +func addIssueWatchModes(x *xorm.Engine) error { + type IssueWatch struct { + Mode models.IssueWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` + } + + if err := x.Sync2(new(IssueWatch)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + + if _, err := sess.Where("is_watching = ?", false).Cols("mode").Update(&models.IssueWatch{Mode: models.IssueWatchModeDont}); err != nil { + return err + } + if _, err := sess.Where("is_watching = ?", true).Cols("mode").Update(&models.IssueWatch{Mode: models.IssueWatchModeNormal}); err != nil { + return err + } + + // Drop column `is_watching` + if _, err := sess.Exec("ALTER TABLE issue_watch DROP is_watching"); err != nil { + return err + } + + return nil +} diff --git a/models/notification.go b/models/notification.go index e7217a6e04793..a1eca74d2b727 100644 --- a/models/notification.go +++ b/models/notification.go @@ -133,72 +133,77 @@ func CreateOrUpdateIssueNotifications(issueID, commentID int64, notificationAuth } func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notificationAuthorID int64) error { - issueWatches, err := getIssueWatchers(e, issueID, ListOptions{}) + // init + alreadyNotified := make(map[int64]struct{}, 50) + notifications, err := getNotificationsByIssueID(e, issueID) if err != nil { return err } - issue, err := getIssueByID(e, issueID) if err != nil { return err } - watches, err := getWatchers(e, issue.RepoID) - if err != nil { + // explicit unwatch on issue + if issueUnWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeDont); err != nil { return err + } else { + fmt.Println("DEBUG: issueUnWatches: ", issueUnWatches) + for _, id := range issueUnWatches { + alreadyNotified[id] = struct{}{} + } } - notifications, err := getNotificationsByIssueID(e, issueID) + issueWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeNormal, IssueWatchModeAuto) if err != nil { return err } - alreadyNotified := make(map[int64]struct{}, len(issueWatches)+len(watches)) - - notifyUser := func(userID int64) error { - // do not send notification for the own issuer/commenter - if userID == notificationAuthorID { - return nil - } - - if _, ok := alreadyNotified[userID]; ok { - return nil - } - alreadyNotified[userID] = struct{}{} - - if notificationExists(notifications, issue.ID, userID) { - return updateIssueNotification(e, userID, issue.ID, commentID, notificationAuthorID) - } - return createIssueNotification(e, userID, issue, commentID, notificationAuthorID) + repoWatches, err := getRepoWatchersIDs(e, issue.RepoID) + if err != nil { + return err } - for _, issueWatch := range issueWatches { - // ignore if user unwatched the issue - if !issueWatch.IsWatching { - alreadyNotified[issueWatch.UserID] = struct{}{} - continue - } + err = issue.loadRepo(e) + if err != nil { + return err + } - if err := notifyUser(issueWatch.UserID); err != nil { + // if Issue/Comment creator/updater is not subscribed ... auto subscribe to issue + if _, ok := alreadyNotified[notificationAuthorID]; !ok { + alreadyNotified[notificationAuthorID] = struct{}{} + if err = createOrUpdateIssueWatchMode(e, notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { return err } } - err = issue.loadRepo(e) - if err != nil { - return err - } + // ToDo get Mentioned Users!!! + fmt.Println("DEBUG: alreadyNotified: ", alreadyNotified) + fmt.Println("DEBUG: repoWatches: ", repoWatches) + fmt.Println("DEBUG: issueWatches: ", issueWatches) - for _, watch := range watches { + // notify + for _, userID := range append(repoWatches, issueWatches...) { issue.Repo.Units = nil - if issue.IsPull && !issue.Repo.checkUnitUser(e, watch.UserID, false, UnitTypePullRequests) { + if issue.IsPull && !issue.Repo.checkUnitUser(e, userID, false, UnitTypePullRequests) { + continue + } + if !issue.IsPull && !issue.Repo.checkUnitUser(e, userID, false, UnitTypeIssues) { continue } - if !issue.IsPull && !issue.Repo.checkUnitUser(e, watch.UserID, false, UnitTypeIssues) { + + if _, ok := alreadyNotified[userID]; ok { continue } + alreadyNotified[userID] = struct{}{} - if err := notifyUser(watch.UserID); err != nil { + if notificationExists(notifications, issue.ID, userID) { + if err = updateIssueNotification(e, userID, issue.ID, commentID, notificationAuthorID); err != nil { + return err + } + continue + } + if err = createIssueNotification(e, userID, issue, commentID, notificationAuthorID); err != nil { return err } } diff --git a/models/repo_watch.go b/models/repo_watch.go index a9d56eff03d3e..11cfa88918447 100644 --- a/models/repo_watch.go +++ b/models/repo_watch.go @@ -144,8 +144,12 @@ func GetWatchers(repoID int64) ([]*Watch, error) { // but avoids joining with `user` for performance reasons // User permissions must be verified elsewhere if required func GetRepoWatchersIDs(repoID int64) ([]int64, error) { + return getRepoWatchersIDs(x, repoID) +} + +func getRepoWatchersIDs(e Engine, repoID int64) ([]int64, error) { ids := make([]int64, 0, 64) - return ids, x.Table("watch"). + return ids, e.Table("watch"). Where("watch.repo_id=?", repoID). And("watch.mode<>?", RepoWatchModeDont). Select("user_id"). diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 274da966fda8a..3d8667013ad55 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -125,7 +125,12 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - if err := models.CreateOrUpdateIssueWatch(user.ID, issue.ID, watch); err != nil { + mode := models.IssueWatchModeNormal + if !watch { + mode = models.IssueWatchModeDont + } + + if err := models.CreateOrUpdateIssueWatchMode(user.ID, issue.ID, mode); err != nil { ctx.Error(http.StatusInternalServerError, "CreateOrUpdateIssueWatch", err) return } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index fdade2795d164..857642ad18b7d 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -702,9 +702,8 @@ func ViewIssue(ctx *context.Context) { } if !exists { iw = &models.IssueWatch{ - UserID: ctx.User.ID, - IssueID: issue.ID, - IsWatching: models.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID), + UserID: ctx.User.ID, + IssueID: issue.ID, } } } diff --git a/routers/repo/issue_watch.go b/routers/repo/issue_watch.go index 07671af13a145..c977a3aae7e59 100644 --- a/routers/repo/issue_watch.go +++ b/routers/repo/issue_watch.go @@ -48,8 +48,13 @@ func IssueWatch(ctx *context.Context) { return } - if err := models.CreateOrUpdateIssueWatch(ctx.User.ID, issue.ID, watch); err != nil { - ctx.ServerError("CreateOrUpdateIssueWatch", err) + mode := models.IssueWatchModeNormal + if !watch { + mode = models.IssueWatchModeDont + } + + if err := models.CreateOrUpdateIssueWatchMode(ctx.User.ID, issue.ID, mode); err != nil { + ctx.ServerError("CreateOrUpdateIssueWatchMode", err) return } From 39bfe5b5666d8f467f5101acb3e6b49415d7fd50 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 11:59:26 +0100 Subject: [PATCH 02/58] Dont Drop - Alter table column --- models/migrations/v999.go | 52 +++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 04ff35f6f57be..f8a7f6c7ee88a 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -8,17 +8,23 @@ import ( "fmt" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/timeutil" + "xorm.io/core" "xorm.io/xorm" ) func addIssueWatchModes(x *xorm.Engine) error { type IssueWatch struct { - Mode models.IssueWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` - } - - if err := x.Sync2(new(IssueWatch)); err != nil { - return fmt.Errorf("Sync2: %v", err) + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` + IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` + Mode models.IssueWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` + //since it it is not used anymore and has NOT NULL constrain + //it is altered to have a default value - we can drop it later ... + IsWatching bool `xorm:"NOT NULL DEFAULT 1"` } sess := x.NewSession() @@ -27,6 +33,23 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } + if x.Dialect().DBType() == core.SQLITE { + if _, err := sess.Exec("ALTER TABLE `issue_watch` RENAME TO `issue_watch_old`;"); err != nil { + return err + } + } + if err := x.Sync2(new(IssueWatch)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + if x.Dialect().DBType() == core.SQLITE { + if _, err := sess.Exec("INSERT INTO `issue_watch` SELECT * FROM `issue_watch_old`;"); err != nil { + return err + } + if err := sess.DropTable("issue_watch_old"); err != nil { + return err + } + } + if _, err := sess.Where("is_watching = ?", false).Cols("mode").Update(&models.IssueWatch{Mode: models.IssueWatchModeDont}); err != nil { return err } @@ -34,9 +57,22 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } - // Drop column `is_watching` - if _, err := sess.Exec("ALTER TABLE issue_watch DROP is_watching"); err != nil { - return err + //add default value as suggested in: https://www.w3schools.com/sql/sql_default.asp + //sqlite is done from L36-50 (you cant alter a column) + switch x.Dialect().DBType() { + case core.POSTGRES: + case core.MYSQL: + if _, err := sess.Exec("ALTER TABLE `issue_watch` ALTER `is_watching` SET DEFAULT 1;"); err != nil { + return err + } + case core.MSSQL: + if _, err := sess.Exec("ALTER TABLE `issue_watch` ADD CONSTRAINT df_is_watching DEFAULT 1 FOR `is_watching`;"); err != nil { + return err + } + case core.ORACLE: + if _, err := sess.Exec("ALTER TABLE issue_watch MODIFY is_watching DEFAULT 1;"); err != nil { + return err + } } return nil From 9e173645534335e69ad9e634d0c7cb7b6233b9b1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 12:28:33 +0100 Subject: [PATCH 03/58] remove is_watching from models completly --- models/issue_watch.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index b61e292b19a29..d32f38479d1e2 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -62,7 +62,7 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat return err } } else { - if _, err = e.ID(iw.ID).Cols("is_watching", "updated_unix", "mode").Update(iw); err != nil { + if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } } @@ -139,7 +139,7 @@ func removeIssueWatchersByRepoID(e Engine, userID int64, repoID int64) error { } _, err := e. Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID). - Cols("is_watching", "updated_unix"). + Cols("mode", "updated_unix"). Where("`issue_watch`.user_id = ?", userID). Update(iw) return err From 038bcefc8566f3cd683a15d7ddb5f658b1d2837a Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 12:31:40 +0100 Subject: [PATCH 04/58] nit --- models/issue_watch.go | 2 +- models/migrations/v999.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index d32f38479d1e2..b4d8851427787 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -30,7 +30,7 @@ type IssueWatch struct { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` - Mode IssueWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` + Mode IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` } diff --git a/models/migrations/v999.go b/models/migrations/v999.go index f8a7f6c7ee88a..bf725df956445 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -19,7 +19,7 @@ func addIssueWatchModes(x *xorm.Engine) error { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` - Mode models.IssueWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` + Mode models.IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` //since it it is not used anymore and has NOT NULL constrain From 94171ed4863c852279ff9746f9a4948c0354f4d6 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 12:37:41 +0100 Subject: [PATCH 05/58] delete if IssueWatchMode = None --- models/issue_watch.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index b4d8851427787..23dd92bd06503 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -48,22 +48,25 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat if err != nil { return err } - if !exists { + iw.Mode = mode + + if !exists && mode != IssueWatchModeNone { iw = &IssueWatch{ UserID: userID, IssueID: issueID, } - } - - iw.Mode = mode - - if !exists { if _, err = e.Insert(iw); err != nil { return err } } else { - if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { - return err + if mode != IssueWatchModeNone { + if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { + return err + } + } else { + if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Delete(iw); err != nil { + return err + } } } return nil From 5cd8c731a9831fadfad931e15e731c2c37afc2c1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 12:41:02 +0100 Subject: [PATCH 06/58] update comments --- models/issue_watch.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 23dd92bd06503..d13a0d53485f3 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -73,12 +73,10 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat } // GetIssueWatch returns all IssueWatch objects from db by user and issue -// the current Web-UI need iw object for watchers AND explicit non-watchers func GetIssueWatch(userID, issueID int64) (iw *IssueWatch, exists bool, err error) { return getIssueWatch(x, userID, issueID) } -// Return watcher AND explicit non-watcher if entry in db exist func getIssueWatch(e Engine, userID, issueID int64) (iw *IssueWatch, exists bool, err error) { iw = new(IssueWatch) exists, err = e. From c6b3ea1e426a442804fd26e98d2f834f618968e5 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 12:46:46 +0100 Subject: [PATCH 07/58] fix test --- models/issue_watch_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index ed163efe33fee..9da4c8b31d49a 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -10,17 +10,17 @@ import ( "github.com/stretchr/testify/assert" ) -/**func TestCreateOrUpdateIssueWatch(t *testing.T) { +func TestCreateOrUpdateIssueWatch(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - assert.NoError(t, CreateOrUpdateIssueWatch(3, 1, true)) + assert.NoError(t, CreateOrUpdateIssueWatchMode(3, 1, IssueWatchModeNormal)) iw := AssertExistsAndLoadBean(t, &IssueWatch{UserID: 3, IssueID: 1}).(*IssueWatch) - assert.True(t, iw.IsWatching) + assert.EqualValues(t, IssueWatchModeNormal, iw.Mode) - assert.NoError(t, CreateOrUpdateIssueWatch(1, 1, false)) + assert.NoError(t, CreateOrUpdateIssueWatchMode(1, 1, IssueWatchModeDont)) iw = AssertExistsAndLoadBean(t, &IssueWatch{UserID: 1, IssueID: 1}).(*IssueWatch) - assert.False(t, iw.IsWatching) -}**/ + assert.EqualValues(t, IssueWatchModeDont, iw.Mode) +} func TestGetIssueWatch(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) From d6a764bb46e27e07a8aea102f7102696365c5d87 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 12:52:51 +0100 Subject: [PATCH 08/58] format code ... --- models/notification.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/models/notification.go b/models/notification.go index a1eca74d2b727..dedd10912a6df 100644 --- a/models/notification.go +++ b/models/notification.go @@ -145,13 +145,13 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi } // explicit unwatch on issue - if issueUnWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeDont); err != nil { + issueUnWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeDont) + if err != nil { return err - } else { - fmt.Println("DEBUG: issueUnWatches: ", issueUnWatches) - for _, id := range issueUnWatches { - alreadyNotified[id] = struct{}{} - } + } + fmt.Println("DEBUG: issueUnWatches: ", issueUnWatches) + for _, id := range issueUnWatches { + alreadyNotified[id] = struct{}{} } issueWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeNormal, IssueWatchModeAuto) From 3aa7e090c744fa7eadf3b62a9f4aa1166cd381d8 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 13:10:33 +0100 Subject: [PATCH 09/58] fix & optimize Create/Update-IW --- models/issue_watch.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index d13a0d53485f3..d3c46555c52ef 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -40,7 +40,16 @@ type IssueWatchList []*IssueWatch // CreateOrUpdateIssueWatchMode set IssueWatchMode for a user and issue func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) error { - return createOrUpdateIssueWatchMode(x, userID, issueID, mode) + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + err := createOrUpdateIssueWatchMode(sess, userID, issueID, mode) + if err != nil { + return err + } + return sess.Commit() } func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWatchMode) error { @@ -48,23 +57,24 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat if err != nil { return err } - iw.Mode = mode if !exists && mode != IssueWatchModeNone { iw = &IssueWatch{ UserID: userID, IssueID: issueID, + Mode: mode, } if _, err = e.Insert(iw); err != nil { return err } } else { if mode != IssueWatchModeNone { + iw.Mode = mode if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } } else { - if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Delete(iw); err != nil { + if _, err = e.ID(iw.ID).Delete(iw); err != nil { return err } } From 89e2e6af7e4af8f72dceb8fc67ec5edfca51e289 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 13:14:34 +0100 Subject: [PATCH 10/58] tests ... --- models/issue_watch_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index 9da4c8b31d49a..e3c287f715a5c 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -32,7 +32,7 @@ func TestGetIssueWatch(t *testing.T) { iw, exists, err := GetIssueWatch(2, 2) assert.True(t, exists) assert.NoError(t, err) - assert.EqualValues(t, false, iw.IsWatching) + assert.False(t, iw.IsWatching()) _, exists, err = GetIssueWatch(3, 1) assert.False(t, exists) From 9c316f684d29e99c76c398e80f42a97f063852e3 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 13:39:10 +0100 Subject: [PATCH 11/58] fix lint --- models/issue_watch.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index d3c46555c52ef..db95b3baf5350 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -73,11 +73,11 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } - } else { - if _, err = e.ID(iw.ID).Delete(iw); err != nil { - return err - } } + if _, err = e.ID(iw.ID).Delete(iw); err != nil { + return err + } + } return nil } From 483a212cf5086a5065f1f6f85c6247c1922dd47c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 13:47:20 +0100 Subject: [PATCH 12/58] extend Test --- models/issue_watch_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index e3c287f715a5c..153edbded948f 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -6,6 +6,7 @@ package models import ( "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -17,6 +18,18 @@ func TestCreateOrUpdateIssueWatch(t *testing.T) { iw := AssertExistsAndLoadBean(t, &IssueWatch{UserID: 3, IssueID: 1}).(*IssueWatch) assert.EqualValues(t, IssueWatchModeNormal, iw.Mode) + assert.NoError(t, CreateOrUpdateIssueWatchMode(3, 1, IssueWatchModeNone)) + AssertNotExistsBean(t, &IssueWatch{UserID: 3, IssueID: 1}) + + assert.NoError(t, CreateOrUpdateIssueWatchMode(3, 1, IssueWatchModeAuto)) + iw = AssertExistsAndLoadBean(t, &IssueWatch{UserID: 3, IssueID: 1}).(*IssueWatch) + assert.EqualValues(t, IssueWatchModeAuto, iw.Mode) + + assert.NoError(t, CreateOrUpdateIssueWatchMode(1, 1, IssueWatchModeAuto)) + iw = AssertExistsAndLoadBean(t, &IssueWatch{UserID: 1, IssueID: 1}).(*IssueWatch) + assert.EqualValues(t, IssueWatchModeAuto, iw.Mode) + + time.Sleep(1 * time.Second) assert.NoError(t, CreateOrUpdateIssueWatchMode(1, 1, IssueWatchModeDont)) iw = AssertExistsAndLoadBean(t, &IssueWatch{UserID: 1, IssueID: 1}).(*IssueWatch) assert.EqualValues(t, IssueWatchModeDont, iw.Mode) From e4a48cd98978dc0bb0beae7302ff59e3b69014d8 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 14:11:21 +0100 Subject: [PATCH 13/58] fix mssql migration --- models/issue_watch.go | 1 - models/migrations/v999.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index db95b3baf5350..5a3dfd15bb835 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -77,7 +77,6 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat if _, err = e.ID(iw.ID).Delete(iw); err != nil { return err } - } return nil } diff --git a/models/migrations/v999.go b/models/migrations/v999.go index bf725df956445..67b7f908f2efa 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -66,7 +66,7 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } case core.MSSQL: - if _, err := sess.Exec("ALTER TABLE `issue_watch` ADD CONSTRAINT df_is_watching DEFAULT 1 FOR `is_watching`;"); err != nil { + if _, err := sess.Exec("ALTER TABLE `issue_watch` ALTER COLUMN `is_watching` DEFAULT 1;"); err != nil { return err } case core.ORACLE: From afa745a48186d13521a7a685ba2a75d7192f03f1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 14:43:15 +0100 Subject: [PATCH 14/58] NULL as default --- models/migrations/v999.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 67b7f908f2efa..ff923260f047f 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -24,7 +24,7 @@ func addIssueWatchModes(x *xorm.Engine) error { UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` //since it it is not used anymore and has NOT NULL constrain //it is altered to have a default value - we can drop it later ... - IsWatching bool `xorm:"NOT NULL DEFAULT 1"` + IsWatching bool `xorm:"DEFAULT NULL"` } sess := x.NewSession() @@ -62,15 +62,15 @@ func addIssueWatchModes(x *xorm.Engine) error { switch x.Dialect().DBType() { case core.POSTGRES: case core.MYSQL: - if _, err := sess.Exec("ALTER TABLE `issue_watch` ALTER `is_watching` SET DEFAULT 1;"); err != nil { + if _, err := sess.Exec("ALTER TABLE `issue_watch` MODIFY `is_watching` tinyint(1) NULL;"); err != nil { return err } case core.MSSQL: - if _, err := sess.Exec("ALTER TABLE `issue_watch` ALTER COLUMN `is_watching` DEFAULT 1;"); err != nil { + if _, err := sess.Exec("ALTER TABLE `issue_watch` ALTER COLUMN `is_watching` NULL;"); err != nil { return err } case core.ORACLE: - if _, err := sess.Exec("ALTER TABLE issue_watch MODIFY is_watching DEFAULT 1;"); err != nil { + if _, err := sess.Exec("ALTER TABLE issue_watch MODIFY is_watching NULL;"); err != nil { return err } } From bd44ba44e9e09812c9745139f4a07af51dea9403 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 17:14:12 +0100 Subject: [PATCH 15/58] rework api stuff --- models/issue_watch.go | 20 +++++++------------- routers/api/v1/repo/issue_subscription.go | 10 ++++++++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 5a3dfd15bb835..69cd55c72db5b 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -117,7 +117,7 @@ func getIssueWatchersIDs(e Engine, issueID int64, modes ...IssueWatchMode) ([]in Find(&ids) } -// GetIssueWatchers returns watchers/unwatchers of a given issue +// GetIssueWatchers returns IssueWatch entry's based on modes of a given issue func GetIssueWatchers(issueID int64, listOptions ListOptions, modes ...IssueWatchMode) (IssueWatchList, error) { if len(modes) == 0 { modes = []IssueWatchMode{IssueWatchModeNormal, IssueWatchModeAuto} @@ -163,7 +163,7 @@ func (iw IssueWatch) IsWatching() bool { log.Error("IssueWatch.IsWatching: GetIssueByID: ", err) return false } - // if repowatch is ture ... + // if RepoWatch is true ... if IsWatching(iw.UserID, issue.RepoID) && iw.Mode != IssueWatchModeDont { return true } @@ -171,25 +171,19 @@ func (iw IssueWatch) IsWatching() bool { return iw.Mode == IssueWatchModeNormal || iw.Mode == IssueWatchModeAuto } -// LoadWatchUsers return watching users -func (iwl IssueWatchList) LoadWatchUsers() (users UserList, err error) { - return iwl.loadWatchUsers(x) +// GetWatchUsers return watching users based on an issue watch list +func (iwl IssueWatchList) GetWatchUsers() (users UserList, err error) { + return iwl.getWatchUsers(x) } -func (iwl IssueWatchList) loadWatchUsers(e Engine) (users UserList, err error) { +func (iwl IssueWatchList) getWatchUsers(e Engine) (users UserList, err error) { if len(iwl) == 0 { return []*User{}, nil } var userIDs = make([]int64, 0, len(iwl)) for _, iw := range iwl { - if iw.Mode == IssueWatchModeNormal || iw.Mode == IssueWatchModeAuto { - userIDs = append(userIDs, iw.UserID) - } - } - - if len(userIDs) == 0 { - return []*User{}, nil + userIDs = append(userIDs, iw.UserID) } err = e.In("id", userIDs).Find(&users) diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 3d8667013ad55..bb6295ed66b23 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -125,6 +125,12 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } + // get Repowatch + // if repowatch true + unwatch -> set explisitNOWatch + // if repowatch true + watch -> set explisitwatch + // if no repowatch + watch -> set explisit watch + // if no repowatch + unwatch -> is watch already set? Y: delete watch else do nothing + mode := models.IssueWatchModeNormal if !watch { mode = models.IssueWatchModeDont @@ -189,13 +195,13 @@ func GetIssueSubscribers(ctx *context.APIContext) { return } - iwl, err := models.GetIssueWatchers(issue.ID, utils.GetListOptions(ctx)) + iwl, err := models.GetIssueWatchers(issue.ID, utils.GetListOptions(ctx), models.IssueWatchModeNormal, models.IssueWatchModeAuto) if err != nil { ctx.Error(http.StatusInternalServerError, "GetIssueWatchers", err) return } - users, err := iwl.LoadWatchUsers() + users, err := iwl.GetWatchUsers() if err != nil { ctx.Error(http.StatusInternalServerError, "LoadWatchUsers", err) return From 840f0118fa8250f21928992c32a7f6052e28dd67 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 17:36:55 +0100 Subject: [PATCH 16/58] extend SET/UNSET issue subscritpion via API --- routers/api/v1/repo/issue_subscription.go | 37 +++++++++++++++++++---- templates/swagger/v1_json.tmpl | 3 ++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index bb6295ed66b23..53b15bc755346 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -86,6 +86,8 @@ func DelIssueSubscription(ctx *context.APIContext) { // type: string // required: true // responses: + // "200": + // "$ref": "#/responses/empty" // "201": // "$ref": "#/responses/empty" // "304": @@ -125,15 +127,38 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - // get Repowatch - // if repowatch true + unwatch -> set explisitNOWatch - // if repowatch true + watch -> set explisitwatch - // if no repowatch + watch -> set explisit watch - // if no repowatch + unwatch -> is watch already set? Y: delete watch else do nothing + // if watch + RepoWatch -> return OK + // if watch + no RepoWatch -> set IssueWatchModeNormal + // if unwatch + RepoWatch -> set IssueWatchModeDont + // if unwatch + no RepoWatch -> IssueWatch entry exist? + // yes -> delete + // no -> return OK + + repoWatch := models.IsWatching(user.ID, ctx.Repo.Repository.ID) mode := models.IssueWatchModeNormal if !watch { - mode = models.IssueWatchModeDont + if repoWatch { + mode = models.IssueWatchModeDont + } else { + _, exist, err := models.GetIssueWatch(user.ID, issue.ID) + if err != nil { + ctx.InternalServerError(err) + return + } + if !exist { + ctx.Status(http.StatusOK) + return + } + mode = models.IssueWatchModeNone + } + } else { + if repoWatch { + ctx.Status(http.StatusOK) + return + } else { + mode = models.IssueWatchModeNormal + } } if err := models.CreateOrUpdateIssueWatchMode(user.ID, issue.ID, mode); err != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index b52145a0a9b6f..6342ba7d1d7c5 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4805,6 +4805,9 @@ } ], "responses": { + "200": { + "$ref": "#/responses/empty" + }, "201": { "$ref": "#/responses/empty" }, From f4f8aef0f7caeffd62b28c08d7c99ecc64e53d91 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 18:17:51 +0100 Subject: [PATCH 17/58] fix lint --- models/migrations/v999.go | 1 - routers/api/v1/repo/issue_subscription.go | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index ff923260f047f..b48cadcb3e0b9 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -57,7 +57,6 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } - //add default value as suggested in: https://www.w3schools.com/sql/sql_default.asp //sqlite is done from L36-50 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 53b15bc755346..9636302d6d8c9 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -156,9 +156,8 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { if repoWatch { ctx.Status(http.StatusOK) return - } else { - mode = models.IssueWatchModeNormal } + mode = models.IssueWatchModeNormal } if err := models.CreateOrUpdateIssueWatchMode(user.ID, issue.ID, mode); err != nil { From 48d30f1e5f007c6150b36bed94d3c59abb2cddde Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 18:22:50 +0100 Subject: [PATCH 18/58] new trick --- models/migrations/v999.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index b48cadcb3e0b9..9f43c2c847a18 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -38,10 +38,15 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } } + if x.Dialect().DBType() == core.MSSQL { + if _, err := sess.Exec("sp_rename `issue_watch` `issue_watch_old`;"); err != nil { + return err + } + } if err := x.Sync2(new(IssueWatch)); err != nil { return fmt.Errorf("Sync2: %v", err) } - if x.Dialect().DBType() == core.SQLITE { + if x.Dialect().DBType() == core.SQLITE || x.Dialect().DBType() == core.MSSQL{ if _, err := sess.Exec("INSERT INTO `issue_watch` SELECT * FROM `issue_watch_old`;"); err != nil { return err } @@ -60,18 +65,11 @@ func addIssueWatchModes(x *xorm.Engine) error { //sqlite is done from L36-50 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: + case core.ORACLE: case core.MYSQL: if _, err := sess.Exec("ALTER TABLE `issue_watch` MODIFY `is_watching` tinyint(1) NULL;"); err != nil { return err } - case core.MSSQL: - if _, err := sess.Exec("ALTER TABLE `issue_watch` ALTER COLUMN `is_watching` NULL;"); err != nil { - return err - } - case core.ORACLE: - if _, err := sess.Exec("ALTER TABLE issue_watch MODIFY is_watching NULL;"); err != nil { - return err - } } return nil From 26acd3db3cccf08ad1fa08d260a4e2705ccdeca0 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 12 Feb 2020 18:26:04 +0100 Subject: [PATCH 19/58] remove debug msg --- models/migrations/v999.go | 2 +- models/notification.go | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 9f43c2c847a18..1f6b5c28bd545 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -46,7 +46,7 @@ func addIssueWatchModes(x *xorm.Engine) error { if err := x.Sync2(new(IssueWatch)); err != nil { return fmt.Errorf("Sync2: %v", err) } - if x.Dialect().DBType() == core.SQLITE || x.Dialect().DBType() == core.MSSQL{ + if x.Dialect().DBType() == core.SQLITE || x.Dialect().DBType() == core.MSSQL { if _, err := sess.Exec("INSERT INTO `issue_watch` SELECT * FROM `issue_watch_old`;"); err != nil { return err } diff --git a/models/notification.go b/models/notification.go index dedd10912a6df..d9734b23ce274 100644 --- a/models/notification.go +++ b/models/notification.go @@ -149,7 +149,6 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi if err != nil { return err } - fmt.Println("DEBUG: issueUnWatches: ", issueUnWatches) for _, id := range issueUnWatches { alreadyNotified[id] = struct{}{} } @@ -177,11 +176,6 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi } } - // ToDo get Mentioned Users!!! - fmt.Println("DEBUG: alreadyNotified: ", alreadyNotified) - fmt.Println("DEBUG: repoWatches: ", repoWatches) - fmt.Println("DEBUG: issueWatches: ", issueWatches) - // notify for _, userID := range append(repoWatches, issueWatches...) { issue.Repo.Units = nil From 757b29b77b5b7a00c31b0e352b8894a602099118 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 13 Feb 2020 00:04:30 +0100 Subject: [PATCH 20/58] make migration great again --- models/migrations/v999.go | 51 +++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 1f6b5c28bd545..2696607079b8b 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -24,36 +24,39 @@ func addIssueWatchModes(x *xorm.Engine) error { UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` //since it it is not used anymore and has NOT NULL constrain //it is altered to have a default value - we can drop it later ... - IsWatching bool `xorm:"DEFAULT NULL"` - } - - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return err + IsWatching bool } if x.Dialect().DBType() == core.SQLITE { - if _, err := sess.Exec("ALTER TABLE `issue_watch` RENAME TO `issue_watch_old`;"); err != nil { + _, _ = x.Exec("DROP TABLE `issue_watch_old`;") + _, _ = x.Exec("DROP INDEX `UQE_issue_watch_watch`;") + + if _, err := x.Exec("ALTER TABLE `issue_watch` RENAME TO `issue_watch_old`;"); err != nil { return err } - } - if x.Dialect().DBType() == core.MSSQL { - if _, err := sess.Exec("sp_rename `issue_watch` `issue_watch_old`;"); err != nil { - return err + + if err := x.Sync2(new(IssueWatch)); err != nil { + _, _ = x.Exec("ALTER TABLE `issue_watch_old` RENAME TO `issue_watch`;") + return fmt.Errorf("Sync2: %v", err) } - } - if err := x.Sync2(new(IssueWatch)); err != nil { - return fmt.Errorf("Sync2: %v", err) - } - if x.Dialect().DBType() == core.SQLITE || x.Dialect().DBType() == core.MSSQL { - if _, err := sess.Exec("INSERT INTO `issue_watch` SELECT * FROM `issue_watch_old`;"); err != nil { + + if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,is_watching,created_unix,updated_unix) SELECT user_id,issue_id,is_watching,created_unix,updated_unix FROM `issue_watch_old`;"); err != nil { return err } - if err := sess.DropTable("issue_watch_old"); err != nil { + if _, err := x.Exec("DROP TABLE `issue_watch_old`;"); err != nil { return err } } + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + if x.Dialect().DBType() != core.SQLITE { + if err := sess.Sync2(new(IssueWatch)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + } if _, err := sess.Where("is_watching = ?", false).Cols("mode").Update(&models.IssueWatch{Mode: models.IssueWatchModeDont}); err != nil { return err @@ -65,12 +68,18 @@ func addIssueWatchModes(x *xorm.Engine) error { //sqlite is done from L36-50 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: - case core.ORACLE: + if _, err := sess.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching DROP NOT NULL;"); err != nil { + return err + } + case core.MSSQL: + if _, err := sess.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching bit NULL;"); err != nil { + return err + } case core.MYSQL: if _, err := sess.Exec("ALTER TABLE `issue_watch` MODIFY `is_watching` tinyint(1) NULL;"); err != nil { return err } } - return nil + return sess.Commit() } From a162f26821c5bd3f1460121344ba65fc3394d906 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 13 Feb 2020 18:32:06 +0100 Subject: [PATCH 21/58] add TEST --- integrations/issue_test.go | 32 ++++++++++++++++++++++++++++++++ models/migrations/v999.go | 4 ++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 1454d75885019..6363ffb136563 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + repo_service "code.gitea.io/gitea/services/repository" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -57,6 +58,37 @@ func TestNoLoginViewIssues(t *testing.T) { MakeRequest(t, req, http.StatusOK) } +func TestIssueAutoSubscription(t *testing.T) { + defer prepareTestEnv(t)() + + user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User) + otherUser := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) + session := loginUser(t, user.Name) + + // create repo + repo, err := repo_service.CreateRepository(otherUser, otherUser, models.CreateRepoOptions{ + Name: "TESTIssueAutoSubscriptionRepo", + License: "MIT", + Readme: "Default", + IsPrivate: false, + AutoInit: true, + }) + assert.NoError(t, err) + + //make sure repo is not subscribed + models.AssertNotExistsBean(t, &models.Watch{UserID: user.ID, RepoID: repo.ID}) + models.AssertNotExistsBean(t, &models.IssueWatch{UserID: user.ID, Mode: models.IssueWatchModeAuto}) + + //create new issue + testNewIssue(t, session, repo.OwnerName, repo.Name, "some title text", "some body text") + newIssue, err := models.GetIssueByIndex(repo.ID, 1) + assert.NoError(t, err) + + models.AssertNotExistsBean(t, &models.Watch{UserID: user.ID, RepoID: repo.ID}) + issueWatch := models.AssertExistsAndLoadBean(t, &models.IssueWatch{UserID: user.ID, IssueID: newIssue.ID}).(*models.IssueWatch) + assert.Equal(t, models.IssueWatchModeAuto, issueWatch.Mode) +} + func TestViewIssuesSortByType(t *testing.T) { defer prepareTestEnv(t)() diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 2696607079b8b..c4fad175ed1f0 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -23,7 +23,7 @@ func addIssueWatchModes(x *xorm.Engine) error { CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` //since it it is not used anymore and has NOT NULL constrain - //it is altered to have a default value - we can drop it later ... + //it is altered to allow NULL - we can drop it later ... IsWatching bool } @@ -65,7 +65,7 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } - //sqlite is done from L36-50 (you cant alter a column) + //sqlite is done from L36-49 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: if _, err := sess.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching DROP NOT NULL;"); err != nil { From d8d2e8320c67a84d3f4799d580394882e5082c1d Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 13 Feb 2020 22:20:25 +0100 Subject: [PATCH 22/58] optimize! --- models/notification.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/models/notification.go b/models/notification.go index d9734b23ce274..6d1989b58d100 100644 --- a/models/notification.go +++ b/models/notification.go @@ -134,7 +134,7 @@ func CreateOrUpdateIssueNotifications(issueID, commentID int64, notificationAuth func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notificationAuthorID int64) error { // init - alreadyNotified := make(map[int64]struct{}, 50) + toNotify := make(map[int64]struct{}, 50) notifications, err := getNotificationsByIssueID(e, issueID) if err != nil { return err @@ -144,24 +144,30 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi return err } - // explicit unwatch on issue - issueUnWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeDont) + issueWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeNormal, IssueWatchModeAuto) if err != nil { return err } - for _, id := range issueUnWatches { - alreadyNotified[id] = struct{}{} + for _, id := range issueWatches { + toNotify[id] = struct{}{} } - issueWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeNormal, IssueWatchModeAuto) + repoWatches, err := getRepoWatchersIDs(e, issue.RepoID) if err != nil { return err } + for _, id := range repoWatches { + toNotify[id] = struct{}{} + } - repoWatches, err := getRepoWatchersIDs(e, issue.RepoID) + // explicit unwatch on issue + issueUnWatches, err := getIssueWatchersIDs(e, issueID, IssueWatchModeDont) if err != nil { return err } + for _, id := range issueUnWatches { + delete(toNotify, id) + } err = issue.loadRepo(e) if err != nil { @@ -169,15 +175,14 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi } // if Issue/Comment creator/updater is not subscribed ... auto subscribe to issue - if _, ok := alreadyNotified[notificationAuthorID]; !ok { - alreadyNotified[notificationAuthorID] = struct{}{} + if _, ok := toNotify[notificationAuthorID]; !ok { if err = createOrUpdateIssueWatchMode(e, notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { return err } } // notify - for _, userID := range append(repoWatches, issueWatches...) { + for userID := range toNotify { issue.Repo.Units = nil if issue.IsPull && !issue.Repo.checkUnitUser(e, userID, false, UnitTypePullRequests) { continue @@ -186,11 +191,6 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi continue } - if _, ok := alreadyNotified[userID]; ok { - continue - } - alreadyNotified[userID] = struct{}{} - if notificationExists(notifications, issue.ID, userID) { if err = updateIssueNotification(e, userID, issue.ID, commentID, notificationAuthorID); err != nil { return err From c8070d82137571a47cf858fa43de8805b86f96fa Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 13 Feb 2020 22:21:49 +0100 Subject: [PATCH 23/58] update SWAGGER --- templates/swagger/v1_json.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 6342ba7d1d7c5..decef865db928 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4805,9 +4805,6 @@ } ], "responses": { - "200": { - "$ref": "#/responses/empty" - }, "201": { "$ref": "#/responses/empty" }, @@ -5035,6 +5032,9 @@ } ], "responses": { + "200": { + "$ref": "#/responses/empty" + }, "201": { "$ref": "#/responses/empty" }, From ad12dd9f6ddf06bb25df7a3b17cb91613f818837 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 16 Feb 2020 20:12:59 +0100 Subject: [PATCH 24/58] dont use IssueWatchModeNone --- models/fixtures/issue_watch.yml | 8 ++-- models/issue_watch.go | 48 +++++++++++++---------- models/issue_watch_test.go | 2 +- routers/api/v1/repo/issue_subscription.go | 9 ++++- templates/swagger/v1_json.tmpl | 3 ++ 5 files changed, 43 insertions(+), 27 deletions(-) diff --git a/models/fixtures/issue_watch.yml b/models/fixtures/issue_watch.yml index 5b0ad0d7e5deb..34b92a8463ea5 100644 --- a/models/fixtures/issue_watch.yml +++ b/models/fixtures/issue_watch.yml @@ -2,7 +2,7 @@ id: 1 user_id: 9 issue_id: 1 - mode: 1 #IssueWatchModeNormal + mode: 0 #IssueWatchModeNormal created_unix: 946684800 updated_unix: 946684800 @@ -10,7 +10,7 @@ id: 2 user_id: 2 issue_id: 2 - mode: 2 #IssueWatchModeDont + mode: 1 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 @@ -18,7 +18,7 @@ id: 3 user_id: 2 issue_id: 7 - mode: 1 #IssueWatchModeNormal + mode: 0 #IssueWatchModeNormal created_unix: 946684800 updated_unix: 946684800 @@ -26,6 +26,6 @@ id: 4 user_id: 1 issue_id: 7 - mode: 2 #IssueWatchModeDont + mode: 1 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 diff --git a/models/issue_watch.go b/models/issue_watch.go index 69cd55c72db5b..ddd2caeeb3196 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -15,14 +15,12 @@ import ( type IssueWatchMode int8 const ( - // IssueWatchModeNone don't watch - IssueWatchModeNone IssueWatchMode = iota // 0 - // IssueWatchModeNormal watch issue (from other sources) - IssueWatchModeNormal // 1 - // IssueWatchModeDont explicit don't auto-watch - IssueWatchModeDont // 2 - // IssueWatchModeAuto watch issue (from AutoWatchOnChanges) - IssueWatchModeAuto // 3 + // IssueWatchModeNormal watch issue + IssueWatchModeNormal IssueWatchMode = iota // 0 + // IssueWatchModeDont explicit don't watch + IssueWatchModeDont // 1 + // IssueWatchModeAuto watch issue (from AutoWatchOnIssueChanges) + IssueWatchModeAuto // 2 ) // IssueWatch is connection request for receiving issue notification. @@ -58,7 +56,7 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat return err } - if !exists && mode != IssueWatchModeNone { + if !exists { iw = &IssueWatch{ UserID: userID, IssueID: issueID, @@ -68,19 +66,31 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat return err } } else { - if mode != IssueWatchModeNone { - iw.Mode = mode - if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { - return err - } - } - if _, err = e.ID(iw.ID).Delete(iw); err != nil { + iw.Mode = mode + if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } } return nil } +//DeleteIssueWatch delete an IssueWatch entry of an user to an given issue if exist +func DeleteIssueWatch(userID, issueID int64) error { + return deleteIssueWatch(x, userID, issueID) +} + +func deleteIssueWatch(e Engine, userID, issueID int64) error { + iw, exists, err := getIssueWatch(e, userID, issueID) + if err != nil { + return err + } + if exists { + _, err = e.ID(iw.ID).Delete(iw) + return err + } + return nil +} + // GetIssueWatch returns all IssueWatch objects from db by user and issue func GetIssueWatch(userID, issueID int64) (iw *IssueWatch, exists bool, err error) { return getIssueWatch(x, userID, issueID) @@ -91,7 +101,6 @@ func getIssueWatch(e Engine, userID, issueID int64) (iw *IssueWatch, exists bool exists, err = e. Where("user_id = ?", userID). And("issue_id = ?", issueID). - And("mode <> ?", IssueWatchModeNone). Get(iw) return } @@ -144,14 +153,11 @@ func getIssueWatchers(e Engine, issueID int64, listOptions ListOptions, modes .. } func removeIssueWatchersByRepoID(e Engine, userID int64, repoID int64) error { - iw := &IssueWatch{ - Mode: IssueWatchModeNone, - } _, err := e. Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID). Cols("mode", "updated_unix"). Where("`issue_watch`.user_id = ?", userID). - Update(iw) + Delete(new(IssueWatch)) return err } diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index 153edbded948f..a613311db21cd 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -18,7 +18,7 @@ func TestCreateOrUpdateIssueWatch(t *testing.T) { iw := AssertExistsAndLoadBean(t, &IssueWatch{UserID: 3, IssueID: 1}).(*IssueWatch) assert.EqualValues(t, IssueWatchModeNormal, iw.Mode) - assert.NoError(t, CreateOrUpdateIssueWatchMode(3, 1, IssueWatchModeNone)) + assert.NoError(t, DeleteIssueWatch(3, 1)) AssertNotExistsBean(t, &IssueWatch{UserID: 3, IssueID: 1}) assert.NoError(t, CreateOrUpdateIssueWatchMode(3, 1, IssueWatchModeAuto)) diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 9636302d6d8c9..128ca26722dc6 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -90,6 +90,8 @@ func DelIssueSubscription(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "201": // "$ref": "#/responses/empty" + // "204": + // "$ref": "#/responses/empty" // "304": // description: User can only subscribe itself if he is no admin // "404": @@ -150,7 +152,12 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { ctx.Status(http.StatusOK) return } - mode = models.IssueWatchModeNone + if err = models.DeleteIssueWatch(user.ID, issue.ID); err != nil { + ctx.Error(http.StatusInternalServerError, "DeleteIssueWatch", err) + return + } + ctx.Status(http.StatusNoContent) + return } } else { if repoWatch { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index decef865db928..4cc571a291713 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -5038,6 +5038,9 @@ "201": { "$ref": "#/responses/empty" }, + "204": { + "$ref": "#/responses/empty" + }, "304": { "description": "User can only subscribe itself if he is no admin" }, From 760a38922a76a753949141edb2b88ab0cc3231c4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 16 Feb 2020 21:00:32 +0100 Subject: [PATCH 25/58] Apply suggestions from code review Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> --- models/issue_watch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index ddd2caeeb3196..12d922803f410 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -166,7 +166,7 @@ func (iw IssueWatch) IsWatching() bool { issue, err := GetIssueByID(iw.IssueID) if err != nil { // fail silent since template expect only bool - log.Error("IssueWatch.IsWatching: GetIssueByID: ", err) + log.Warn("IssueWatch.IsWatching: GetIssueByID: ", err) return false } // if RepoWatch is true ... From 9b578b4a165c02193b374d3f50514b378f669cdb Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 16 Feb 2020 22:32:40 +0100 Subject: [PATCH 26/58] new migration func --- models/migrations/v999.go | 58 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index c4fad175ed1f0..8dfc30e89089f 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -22,36 +22,20 @@ func addIssueWatchModes(x *xorm.Engine) error { Mode models.IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` - //since it it is not used anymore and has NOT NULL constrain - //it is altered to allow NULL - we can drop it later ... - IsWatching bool } - if x.Dialect().DBType() == core.SQLITE { - _, _ = x.Exec("DROP TABLE `issue_watch_old`;") - _, _ = x.Exec("DROP INDEX `UQE_issue_watch_watch`;") - - if _, err := x.Exec("ALTER TABLE `issue_watch` RENAME TO `issue_watch_old`;"); err != nil { - return err - } - - if err := x.Sync2(new(IssueWatch)); err != nil { - _, _ = x.Exec("ALTER TABLE `issue_watch_old` RENAME TO `issue_watch`;") - return fmt.Errorf("Sync2: %v", err) - } - - if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,is_watching,created_unix,updated_unix) SELECT user_id,issue_id,is_watching,created_unix,updated_unix FROM `issue_watch_old`;"); err != nil { - return err - } - if _, err := x.Exec("DROP TABLE `issue_watch_old`;"); err != nil { - return err - } - } sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err } + + if x.Dialect().DBType() == core.SQLITE { + if _, err := x.Exec("ALTER TABLE issue_watch ADD mode INTEGER DEFAULT 1 NOT NULL;"); err != nil { + return err + } + } + if x.Dialect().DBType() != core.SQLITE { if err := sess.Sync2(new(IssueWatch)); err != nil { return fmt.Errorf("Sync2: %v", err) @@ -68,16 +52,34 @@ func addIssueWatchModes(x *xorm.Engine) error { //sqlite is done from L36-49 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: - if _, err := sess.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching DROP NOT NULL;"); err != nil { + case core.MYSQL: + if _, err := sess.Exec("ALTER TABLE issue_watch DROP COLUMN IF EXISTS is_watching;"); err != nil { return err } case core.MSSQL: - if _, err := sess.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching bit NULL;"); err != nil { + if _, err := sess.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { return err } - case core.MYSQL: - if _, err := sess.Exec("ALTER TABLE `issue_watch` MODIFY `is_watching` tinyint(1) NULL;"); err != nil { - return err + case core.SQLITE: + if x.Dialect().DBType() == core.SQLITE { + if _, err := x.Exec("CREATE TABLE temp.issue_watch_old AS SELECT * FROM issue_watch;"); err != nil { + return err + } + if _, err := x.Exec("DROP TABLE issue_watch;"); err != nil { + return err + } + + if err := x.Sync2(new(IssueWatch)); err != nil { + _, _ = x.Exec("ALTER TABLE `temp.issue_watch_old` RENAME TO `issue_watch`;") + return fmt.Errorf("Sync2: %v", err) + } + + if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,is_watching,created_unix,updated_unix) SELECT user_id,issue_id,is_watching,created_unix,updated_unix FROM `issue_watch_old`;"); err != nil { + return err + } + if _, err := x.Exec("DROP TABLE `temp.issue_watch_old`;"); err != nil { + return err + } } } From 370467c1a6f06aa40b7e38e84be21b02f066b282 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 17 Feb 2020 01:56:32 +0100 Subject: [PATCH 27/58] remove IF EXISTS --- models/migrations/v999.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 8dfc30e89089f..d58cfcebe50d7 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -53,9 +53,6 @@ func addIssueWatchModes(x *xorm.Engine) error { switch x.Dialect().DBType() { case core.POSTGRES: case core.MYSQL: - if _, err := sess.Exec("ALTER TABLE issue_watch DROP COLUMN IF EXISTS is_watching;"); err != nil { - return err - } case core.MSSQL: if _, err := sess.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { return err From 0669704e0de20cef403bf425505afd656c03cdc3 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 17 Feb 2020 23:09:40 +0100 Subject: [PATCH 28/58] start IssueWatchMode with 1 & remove DEFAULT=1 --- models/fixtures/issue_watch.yml | 8 ++++---- models/issue_watch.go | 8 ++++---- models/migrations/v999.go | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/models/fixtures/issue_watch.yml b/models/fixtures/issue_watch.yml index 34b92a8463ea5..5b0ad0d7e5deb 100644 --- a/models/fixtures/issue_watch.yml +++ b/models/fixtures/issue_watch.yml @@ -2,7 +2,7 @@ id: 1 user_id: 9 issue_id: 1 - mode: 0 #IssueWatchModeNormal + mode: 1 #IssueWatchModeNormal created_unix: 946684800 updated_unix: 946684800 @@ -10,7 +10,7 @@ id: 2 user_id: 2 issue_id: 2 - mode: 1 #IssueWatchModeDont + mode: 2 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 @@ -18,7 +18,7 @@ id: 3 user_id: 2 issue_id: 7 - mode: 0 #IssueWatchModeNormal + mode: 1 #IssueWatchModeNormal created_unix: 946684800 updated_unix: 946684800 @@ -26,6 +26,6 @@ id: 4 user_id: 1 issue_id: 7 - mode: 1 #IssueWatchModeDont + mode: 2 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 diff --git a/models/issue_watch.go b/models/issue_watch.go index 12d922803f410..a6586d6cdd02a 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -16,11 +16,11 @@ type IssueWatchMode int8 const ( // IssueWatchModeNormal watch issue - IssueWatchModeNormal IssueWatchMode = iota // 0 + IssueWatchModeNormal IssueWatchMode = iota + 1 // 1 // IssueWatchModeDont explicit don't watch - IssueWatchModeDont // 1 + IssueWatchModeDont // 2 // IssueWatchModeAuto watch issue (from AutoWatchOnIssueChanges) - IssueWatchModeAuto // 2 + IssueWatchModeAuto // 3 ) // IssueWatch is connection request for receiving issue notification. @@ -28,7 +28,7 @@ type IssueWatch struct { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` - Mode IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` + Mode IssueWatchMode `xorm:"NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` } diff --git a/models/migrations/v999.go b/models/migrations/v999.go index d58cfcebe50d7..281460fa79e5d 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -19,7 +19,7 @@ func addIssueWatchModes(x *xorm.Engine) error { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` - Mode models.IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` + Mode models.IssueWatchMode `xorm:"NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` } @@ -31,7 +31,7 @@ func addIssueWatchModes(x *xorm.Engine) error { } if x.Dialect().DBType() == core.SQLITE { - if _, err := x.Exec("ALTER TABLE issue_watch ADD mode INTEGER DEFAULT 1 NOT NULL;"); err != nil { + if _, err := x.Exec("ALTER TABLE issue_watch ADD mode INTEGER NOT NULL;"); err != nil { return err } } From 38c297a01d422792f86838da90cb4b7976a75669 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 18 Feb 2020 15:33:33 +0100 Subject: [PATCH 29/58] add testcase to fixtures --- integrations/issue_test.go | 1 - models/fixtures/issue_watch.yml | 8 ++++++++ models/issue_watch_test.go | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 6363ffb136563..717e08838ca1d 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -77,7 +77,6 @@ func TestIssueAutoSubscription(t *testing.T) { //make sure repo is not subscribed models.AssertNotExistsBean(t, &models.Watch{UserID: user.ID, RepoID: repo.ID}) - models.AssertNotExistsBean(t, &models.IssueWatch{UserID: user.ID, Mode: models.IssueWatchModeAuto}) //create new issue testNewIssue(t, session, repo.OwnerName, repo.Name, "some title text", "some body text") diff --git a/models/fixtures/issue_watch.yml b/models/fixtures/issue_watch.yml index 5b0ad0d7e5deb..ef00975d6fdb9 100644 --- a/models/fixtures/issue_watch.yml +++ b/models/fixtures/issue_watch.yml @@ -29,3 +29,11 @@ mode: 2 #IssueWatchModeDont created_unix: 946684800 updated_unix: 946684800 + +- + id: 5 + user_id: 1 + issue_id: 8 + mode: 3 #IssueWatchModeAuto + created_unix: 946684800 + updated_unix: 946684800 diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index a613311db21cd..a02dff988986f 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -50,6 +50,12 @@ func TestGetIssueWatch(t *testing.T) { _, exists, err = GetIssueWatch(3, 1) assert.False(t, exists) assert.NoError(t, err) + + assert.False(t, IsWatching(1, 10)) + iw, exists, err = GetIssueWatch(1, 8) + assert.True(t, exists) + assert.NoError(t, err) + assert.True(t, iw.IsWatching()) } func TestGetIssueWatchers(t *testing.T) { From 9482024b1d873de2249dd97788c619596d6ad1f3 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 18 Feb 2020 22:20:19 +0100 Subject: [PATCH 30/58] no race --- models/issue_watch.go | 37 +++++++++++-------------------------- models/notification.go | 2 +- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index a6586d6cdd02a..712b5bd2699a2 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -38,39 +38,24 @@ type IssueWatchList []*IssueWatch // CreateOrUpdateIssueWatchMode set IssueWatchMode for a user and issue func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) error { - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return err - } - err := createOrUpdateIssueWatchMode(sess, userID, issueID, mode) + iw, exist, err := getIssueWatch(x, userID, issueID) if err != nil { return err } - return sess.Commit() + if !exist { + if _, err := x.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode) SELECT %d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, userID, issueID)); err != nil { + return err + } + return nil + } + iw.Mode = mode + return updateIssueWatchMode(x, iw) } -func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWatchMode) error { - iw, exists, err := getIssueWatch(e, userID, issueID) - if err != nil { +func updateIssueWatchMode(e Engine, iw *IssueWatch) error { + if _, err := e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } - - if !exists { - iw = &IssueWatch{ - UserID: userID, - IssueID: issueID, - Mode: mode, - } - if _, err = e.Insert(iw); err != nil { - return err - } - } else { - iw.Mode = mode - if _, err = e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { - return err - } - } return nil } diff --git a/models/notification.go b/models/notification.go index 6d1989b58d100..6a6986611e9db 100644 --- a/models/notification.go +++ b/models/notification.go @@ -176,7 +176,7 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi // if Issue/Comment creator/updater is not subscribed ... auto subscribe to issue if _, ok := toNotify[notificationAuthorID]; !ok { - if err = createOrUpdateIssueWatchMode(e, notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { + if err = CreateOrUpdateIssueWatchMode(notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { return err } } From 51171c2346561654066ac26ef9d49a432682d0b9 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 18 Feb 2020 22:55:49 +0100 Subject: [PATCH 31/58] fix sqlite --- models/issue_watch.go | 6 +++--- models/migrations/v999.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 712b5bd2699a2..1a8a409aa46e6 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -28,7 +28,7 @@ type IssueWatch struct { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` - Mode IssueWatchMode `xorm:"NOT NULL"` + Mode IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` } @@ -49,10 +49,10 @@ func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) er return nil } iw.Mode = mode - return updateIssueWatchMode(x, iw) + return updateIssueWatch(x, iw) } -func updateIssueWatchMode(e Engine, iw *IssueWatch) error { +func updateIssueWatch(e Engine, iw *IssueWatch) error { if _, err := e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 281460fa79e5d..68614c98290fa 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -19,7 +19,7 @@ func addIssueWatchModes(x *xorm.Engine) error { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"UNIQUE(watch) NOT NULL"` IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` - Mode models.IssueWatchMode `xorm:"NOT NULL"` + Mode models.IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` } @@ -31,7 +31,7 @@ func addIssueWatchModes(x *xorm.Engine) error { } if x.Dialect().DBType() == core.SQLITE { - if _, err := x.Exec("ALTER TABLE issue_watch ADD mode INTEGER NOT NULL;"); err != nil { + if _, err := x.Exec("ALTER TABLE issue_watch ADD mode INTEGER NOT NULL DEFAULT 1;"); err != nil { return err } } From 893ad5c258ce65e6a3444d1b7ce7a85780ebc739 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 18 Feb 2020 23:11:54 +0100 Subject: [PATCH 32/58] Alter table outside a session --- models/migrations/v999.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 68614c98290fa..b7f558780e82e 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -49,12 +49,16 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } + if err := sess.Commit(); err != nil { + return err + } + //sqlite is done from L36-49 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: case core.MYSQL: case core.MSSQL: - if _, err := sess.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { + if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { return err } case core.SQLITE: @@ -79,6 +83,5 @@ func addIssueWatchModes(x *xorm.Engine) error { } } } - - return sess.Commit() + return nil } From 2b31fc64c93babe09550c10e3fb4608c6e69a9d2 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 18 Feb 2020 23:27:50 +0100 Subject: [PATCH 33/58] fix SQLite migration --- models/migrations/v999.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index b7f558780e82e..e39c00b6981fa 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -75,7 +75,7 @@ func addIssueWatchModes(x *xorm.Engine) error { return fmt.Errorf("Sync2: %v", err) } - if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,is_watching,created_unix,updated_unix) SELECT user_id,issue_id,is_watching,created_unix,updated_unix FROM `issue_watch_old`;"); err != nil { + if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM `issue_watch_old`;"); err != nil { return err } if _, err := x.Exec("DROP TABLE `temp.issue_watch_old`;"); err != nil { From 0c7826ab05ab6b15f3b65f4c6821af0409900c16 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 18 Feb 2020 23:38:36 +0100 Subject: [PATCH 34/58] fix CreateOrUpdateIssueWatchMode --- models/issue_watch.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 1a8a409aa46e6..d4d60457e1b86 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -6,6 +6,7 @@ package models import ( "fmt" + "time" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" @@ -43,7 +44,7 @@ func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) er return err } if !exist { - if _, err := x.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode) SELECT %d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, userID, issueID)); err != nil { + if _, err := x.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix) SELECT %d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), userID, issueID)); err != nil { return err } return nil From f3b0059cbf4899671e70b08e599f10e81bd7dda6 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 00:01:55 +0100 Subject: [PATCH 35/58] fix --- models/issue_watch.go | 2 +- models/migrations/v999.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index d4d60457e1b86..2da1f82f63654 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -44,7 +44,7 @@ func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) er return err } if !exist { - if _, err := x.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix) SELECT %d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), userID, issueID)); err != nil { + if _, err := x.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix,updated_unix) SELECT %d,%d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), time.Now().Unix(), userID, issueID)); err != nil { return err } return nil diff --git a/models/migrations/v999.go b/models/migrations/v999.go index e39c00b6981fa..2d1252c11188e 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -75,7 +75,7 @@ func addIssueWatchModes(x *xorm.Engine) error { return fmt.Errorf("Sync2: %v", err) } - if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM `issue_watch_old`;"); err != nil { + if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM `temp.issue_watch_old`;"); err != nil { return err } if _, err := x.Exec("DROP TABLE `temp.issue_watch_old`;"); err != nil { From 1f78c8028b3c4f4c94f3a95ae6bcbee05c208f67 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 00:57:09 +0100 Subject: [PATCH 36/58] now it should work --- models/migrations/v999.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 2d1252c11188e..61fcb8d3d01ff 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -71,11 +71,11 @@ func addIssueWatchModes(x *xorm.Engine) error { } if err := x.Sync2(new(IssueWatch)); err != nil { - _, _ = x.Exec("ALTER TABLE `temp.issue_watch_old` RENAME TO `issue_watch`;") + _, _ = x.Exec("CREATE TABLE issue_watch AS SELECT * FROM temp.issue_watch_old;") return fmt.Errorf("Sync2: %v", err) } - if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM `temp.issue_watch_old`;"); err != nil { + if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM temp.issue_watch_old;"); err != nil { return err } if _, err := x.Exec("DROP TABLE `temp.issue_watch_old`;"); err != nil { From aedbad51e32fac480392f1a8217517d4a132961f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 01:28:39 +0100 Subject: [PATCH 37/58] Update models/migrations/v999.go --- models/migrations/v999.go | 1 - 1 file changed, 1 deletion(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 61fcb8d3d01ff..a6f12a27db819 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -53,7 +53,6 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } - //sqlite is done from L36-49 (you cant alter a column) switch x.Dialect().DBType() { case core.POSTGRES: case core.MYSQL: From 7a0c75b198dd64740bcb4bb075e1983984b60ab9 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 01:41:14 +0100 Subject: [PATCH 38/58] test async --- models/notification.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/models/notification.go b/models/notification.go index 6a6986611e9db..a8c7beef49d02 100644 --- a/models/notification.go +++ b/models/notification.go @@ -176,9 +176,11 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi // if Issue/Comment creator/updater is not subscribed ... auto subscribe to issue if _, ok := toNotify[notificationAuthorID]; !ok { - if err = CreateOrUpdateIssueWatchMode(notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { - return err - } + go func() { + if err := CreateOrUpdateIssueWatchMode(notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { + log.Error(err.Error()) + } + }() } // notify From 41862796335a371fdd66a0e3a1e3c80cc4eb6911 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 01:54:20 +0100 Subject: [PATCH 39/58] test Sync2 on sqlite again --- models/migrations/v999.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index a6f12a27db819..f82f63a48c77e 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -30,16 +30,8 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } - if x.Dialect().DBType() == core.SQLITE { - if _, err := x.Exec("ALTER TABLE issue_watch ADD mode INTEGER NOT NULL DEFAULT 1;"); err != nil { - return err - } - } - - if x.Dialect().DBType() != core.SQLITE { - if err := sess.Sync2(new(IssueWatch)); err != nil { - return fmt.Errorf("Sync2: %v", err) - } + if err := sess.Sync2(new(IssueWatch)); err != nil { + return fmt.Errorf("Sync2: %v", err) } if _, err := sess.Where("is_watching = ?", false).Cols("mode").Update(&models.IssueWatch{Mode: models.IssueWatchModeDont}); err != nil { From 9bc4d33e06ceeab2c320e8f099621564e46c4c51 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 02:32:59 +0100 Subject: [PATCH 40/58] sqlite dont like the dot --- models/migrations/v999.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index f82f63a48c77e..40c72dd834815 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -22,6 +22,8 @@ func addIssueWatchModes(x *xorm.Engine) error { Mode models.IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` + //for convert query's make sure column exist + IsWatching bool } sess := x.NewSession() @@ -54,7 +56,7 @@ func addIssueWatchModes(x *xorm.Engine) error { } case core.SQLITE: if x.Dialect().DBType() == core.SQLITE { - if _, err := x.Exec("CREATE TABLE temp.issue_watch_old AS SELECT * FROM issue_watch;"); err != nil { + if _, err := x.Exec("CREATE TABLE issue_watch_old AS SELECT * FROM issue_watch;"); err != nil { return err } if _, err := x.Exec("DROP TABLE issue_watch;"); err != nil { @@ -62,14 +64,14 @@ func addIssueWatchModes(x *xorm.Engine) error { } if err := x.Sync2(new(IssueWatch)); err != nil { - _, _ = x.Exec("CREATE TABLE issue_watch AS SELECT * FROM temp.issue_watch_old;") + _, _ = x.Exec("CREATE TABLE issue_watch AS SELECT * FROM issue_watch_old;") return fmt.Errorf("Sync2: %v", err) } - if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM temp.issue_watch_old;"); err != nil { + if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM issue_watch_old;"); err != nil { return err } - if _, err := x.Exec("DROP TABLE `temp.issue_watch_old`;"); err != nil { + if _, err := x.Exec("DROP TABLE `issue_watch_old`;"); err != nil { return err } } From f354e61085e2b3683f131121870f14f2556b2801 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 03:16:44 +0100 Subject: [PATCH 41/58] test --- models/migrations/v999.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 40c72dd834815..463373c908ad7 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -51,7 +51,7 @@ func addIssueWatchModes(x *xorm.Engine) error { case core.POSTGRES: case core.MYSQL: case core.MSSQL: - if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { + if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN IF EXISTS is_watching;"); err != nil { return err } case core.SQLITE: From 4195f432de36704cfcc74445b1d5f1218cd576a1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 04:15:02 +0100 Subject: [PATCH 42/58] wait until async task finished --- integrations/issue_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 717e08838ca1d..6ff5d7ef775ba 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -83,6 +83,8 @@ func TestIssueAutoSubscription(t *testing.T) { newIssue, err := models.GetIssueByIndex(repo.ID, 1) assert.NoError(t, err) + time.Sleep(1 * time.Second) + models.AssertNotExistsBean(t, &models.Watch{UserID: user.ID, RepoID: repo.ID}) issueWatch := models.AssertExistsAndLoadBean(t, &models.IssueWatch{UserID: user.ID, IssueID: newIssue.ID}).(*models.IssueWatch) assert.Equal(t, models.IssueWatchModeAuto, issueWatch.Mode) From 547b5f99880091c94cb3347d19e5beb6900477c4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 04:28:54 +0100 Subject: [PATCH 43/58] mssql dont understand IfExist for AlterTable --- models/migrations/v999.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 463373c908ad7..4af25d34be05e 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -50,10 +50,13 @@ func addIssueWatchModes(x *xorm.Engine) error { switch x.Dialect().DBType() { case core.POSTGRES: case core.MYSQL: - case core.MSSQL: if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN IF EXISTS is_watching;"); err != nil { return err } + case core.MSSQL: + if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { + return err + } case core.SQLITE: if x.Dialect().DBType() == core.SQLITE { if _, err := x.Exec("CREATE TABLE issue_watch_old AS SELECT * FROM issue_watch;"); err != nil { From 220cdfec4a2d0a9932aaf10de97fa9c891d06224 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 04:58:36 +0100 Subject: [PATCH 44/58] postgress fix --- models/migrations/v999.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 4af25d34be05e..bf58a4a523255 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -48,7 +48,6 @@ func addIssueWatchModes(x *xorm.Engine) error { } switch x.Dialect().DBType() { - case core.POSTGRES: case core.MYSQL: if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN IF EXISTS is_watching;"); err != nil { return err @@ -57,6 +56,14 @@ func addIssueWatchModes(x *xorm.Engine) error { if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { return err } + case core.POSTGRES: + if _, err := x.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching DROP NOT NULL;"); err != nil { + return err + + } + if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { + return err + } case core.SQLITE: if x.Dialect().DBType() == core.SQLITE { if _, err := x.Exec("CREATE TABLE issue_watch_old AS SELECT * FROM issue_watch;"); err != nil { From 8ab3f7930134a01568697c03f17d1736eef9ef40 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 05:28:24 +0100 Subject: [PATCH 45/58] update README of integrations --- integrations/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/integrations/README.md b/integrations/README.md index 6ffd76815c265..fccce2ec65f14 100644 --- a/integrations/README.md +++ b/integrations/README.md @@ -19,7 +19,7 @@ drone exec --local --build-event "pull_request" ``` ## Run sqlite integrations tests -Start tests +Start tests ``` make test-sqlite ``` @@ -27,7 +27,8 @@ make test-sqlite ## Run mysql integrations tests Setup a mysql database inside docker ``` -docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:5.7 #(just ctrl-c to stop db and clean the container) +docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(just ctrl-c to stop db and clean the container) +docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --rm --name elasticsearch elasticsearch:7.6.0 #(in a secound terminal, just ctrl-c to stop db and clean the container) ``` Start tests based on the database container ``` @@ -37,7 +38,7 @@ TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root T ## Run pgsql integrations tests Setup a pgsql database inside docker ``` -docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:9.5 #(just ctrl-c to stop db and clean the container) +docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container) ``` Start tests based on the database container ``` @@ -47,7 +48,7 @@ TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgr ## Run mssql integrations tests Setup a mssql database inside docker ``` -docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container) +docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container) ``` Start tests based on the database container ``` @@ -68,4 +69,4 @@ For other databases(replace MSSQL to MYSQL, MYSQL8, PGSQL): ``` TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-mssql#GPG -``` \ No newline at end of file +``` From f2e9a75d0d00dab0deb945f3912b0aa5c281a95e Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 05:42:54 +0100 Subject: [PATCH 46/58] new atempt --- models/migrations/v999.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index bf58a4a523255..2cad3e655b19b 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -49,10 +49,16 @@ func addIssueWatchModes(x *xorm.Engine) error { switch x.Dialect().DBType() { case core.MYSQL: - if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN IF EXISTS is_watching;"); err != nil { + if _, err := x.Exec("ALTER TABLE `issue_watch` MODIFY `is_watching` tinyint(1) NULL;"); err != nil { + return err + } + if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { return err } case core.MSSQL: + if _, err := x.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching bit NULL;"); err != nil { + return err + } if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { return err } From 96abc117ea947d6b53e95aaed75833c711df351f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 05:54:24 +0100 Subject: [PATCH 47/58] easy solution --- models/migrations/v999.go | 50 ++------------------------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 2cad3e655b19b..5efb36345562c 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -10,7 +10,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/timeutil" - "xorm.io/core" "xorm.io/xorm" ) @@ -43,54 +42,9 @@ func addIssueWatchModes(x *xorm.Engine) error { return err } - if err := sess.Commit(); err != nil { + if err := dropTableColumns(sess, "issue_watch", "is_watching"); err != nil { return err } - switch x.Dialect().DBType() { - case core.MYSQL: - if _, err := x.Exec("ALTER TABLE `issue_watch` MODIFY `is_watching` tinyint(1) NULL;"); err != nil { - return err - } - if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { - return err - } - case core.MSSQL: - if _, err := x.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching bit NULL;"); err != nil { - return err - } - if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { - return err - } - case core.POSTGRES: - if _, err := x.Exec("ALTER TABLE issue_watch ALTER COLUMN is_watching DROP NOT NULL;"); err != nil { - return err - - } - if _, err := x.Exec("ALTER TABLE issue_watch DROP COLUMN is_watching;"); err != nil { - return err - } - case core.SQLITE: - if x.Dialect().DBType() == core.SQLITE { - if _, err := x.Exec("CREATE TABLE issue_watch_old AS SELECT * FROM issue_watch;"); err != nil { - return err - } - if _, err := x.Exec("DROP TABLE issue_watch;"); err != nil { - return err - } - - if err := x.Sync2(new(IssueWatch)); err != nil { - _, _ = x.Exec("CREATE TABLE issue_watch AS SELECT * FROM issue_watch_old;") - return fmt.Errorf("Sync2: %v", err) - } - - if _, err := x.Exec("INSERT INTO `issue_watch` (user_id,issue_id,mode,created_unix,updated_unix) SELECT user_id,issue_id,mode,created_unix,updated_unix FROM issue_watch_old;"); err != nil { - return err - } - if _, err := x.Exec("DROP TABLE `issue_watch_old`;"); err != nil { - return err - } - } - } - return nil + return sess.Commit() } From c3efb3dd0cb815ed0ecb771be8e04f089384b0f2 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 06:03:12 +0100 Subject: [PATCH 48/58] some tweeks --- models/issue_watch.go | 1 + models/migrations/v999.go | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 2da1f82f63654..7744fb8a4d78e 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -54,6 +54,7 @@ func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) er } func updateIssueWatch(e Engine, iw *IssueWatch) error { + iw.UpdatedUnix = timeutil.TimeStampNow() if _, err := e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err } diff --git a/models/migrations/v999.go b/models/migrations/v999.go index 5efb36345562c..3c91347e9b7da 100644 --- a/models/migrations/v999.go +++ b/models/migrations/v999.go @@ -21,8 +21,6 @@ func addIssueWatchModes(x *xorm.Engine) error { Mode models.IssueWatchMode `xorm:"NOT NULL DEFAULT 1"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"` - //for convert query's make sure column exist - IsWatching bool } sess := x.NewSession() From 413fa6d966645ad3b99ba6106a6c68aacf411c87 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 13:25:14 +0100 Subject: [PATCH 49/58] do it within a session --- models/issue_watch.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 7744fb8a4d78e..533a88467d098 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -39,18 +39,23 @@ type IssueWatchList []*IssueWatch // CreateOrUpdateIssueWatchMode set IssueWatchMode for a user and issue func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) error { - iw, exist, err := getIssueWatch(x, userID, issueID) - if err != nil { + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + if _, err := sess.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix,updated_unix) SELECT %d,%d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), time.Now().Unix(), userID, issueID)); err != nil { return err } - if !exist { - if _, err := x.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix,updated_unix) SELECT %d,%d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), time.Now().Unix(), userID, issueID)); err != nil { - return err - } - return nil + iw, exist, err := getIssueWatch(sess, userID, issueID) + if err != nil && !exist { + return err } iw.Mode = mode - return updateIssueWatch(x, iw) + if err := updateIssueWatch(sess, iw); err != nil { + return err + } + return sess.Commit() } func updateIssueWatch(e Engine, iw *IssueWatch) error { From a069ab33696735aa2f100a99e7157a6f9ea6897f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 13:28:07 +0100 Subject: [PATCH 50/58] finalize --- models/migrations/migrations.go | 3 +-- models/migrations/{v999.go => v128.go} | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename models/migrations/{v999.go => v128.go} (100%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 318470f2552e0..573332f76616e 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -188,8 +188,7 @@ var migrations = []Migration{ NewMigration("Fix topic repository count", fixTopicRepositoryCount), // v127 -> v128 NewMigration("add repository code language statistics", addLanguageStats), - - // v999 has no number jet + // v128 -> v129 NewMigration("Change from IsWatching to Modes at IssueWatch", addIssueWatchModes), } diff --git a/models/migrations/v999.go b/models/migrations/v128.go similarity index 100% rename from models/migrations/v999.go rename to models/migrations/v128.go From c5d2cf958e756b64d5e37777d5c4fdafe1a3ef4e Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 14:56:19 +0100 Subject: [PATCH 51/58] no async --- models/issue_watch.go | 18 +++++++++--------- models/notification.go | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 533a88467d098..3803e75bcd5c4 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -44,21 +44,21 @@ func CreateOrUpdateIssueWatchMode(userID, issueID int64, mode IssueWatchMode) er if err := sess.Begin(); err != nil { return err } - if _, err := sess.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix,updated_unix) SELECT %d,%d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), time.Now().Unix(), userID, issueID)); err != nil { + if err := createOrUpdateIssueWatchMode(sess, userID, issueID, mode); err != nil { return err } - iw, exist, err := getIssueWatch(sess, userID, issueID) - if err != nil && !exist { + return sess.Commit() +} + +func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWatchMode) error { + if _, err := e.Exec(fmt.Sprintf("INSERT INTO issue_watch(user_id,issue_id,mode,created_unix,updated_unix) SELECT %d,%d,%d,%d,%d WHERE NOT EXISTS(SELECT 1 FROM issue_watch WHERE user_id = %d AND issue_id = %d);", userID, issueID, mode, time.Now().Unix(), time.Now().Unix(), userID, issueID)); err != nil { return err } - iw.Mode = mode - if err := updateIssueWatch(sess, iw); err != nil { + iw, exist, err := getIssueWatch(e, userID, issueID) + if err != nil && !exist { return err } - return sess.Commit() -} - -func updateIssueWatch(e Engine, iw *IssueWatch) error { + iw.Mode = mode iw.UpdatedUnix = timeutil.TimeStampNow() if _, err := e.ID(iw.ID).Cols("updated_unix", "mode").Update(iw); err != nil { return err diff --git a/models/notification.go b/models/notification.go index a8c7beef49d02..6186462713af6 100644 --- a/models/notification.go +++ b/models/notification.go @@ -176,11 +176,11 @@ func createOrUpdateIssueNotifications(e Engine, issueID, commentID int64, notifi // if Issue/Comment creator/updater is not subscribed ... auto subscribe to issue if _, ok := toNotify[notificationAuthorID]; !ok { - go func() { - if err := CreateOrUpdateIssueWatchMode(notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { - log.Error(err.Error()) - } - }() + + if err := createOrUpdateIssueWatchMode(e, notificationAuthorID, issueID, IssueWatchModeAuto); err != nil { + return err + } + } // notify From 060e28b7ff38131467db5be1547fe9074bcc7b34 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 15:02:58 +0100 Subject: [PATCH 52/58] no async anymore --- integrations/issue_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 6ff5d7ef775ba..717e08838ca1d 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -83,8 +83,6 @@ func TestIssueAutoSubscription(t *testing.T) { newIssue, err := models.GetIssueByIndex(repo.ID, 1) assert.NoError(t, err) - time.Sleep(1 * time.Second) - models.AssertNotExistsBean(t, &models.Watch{UserID: user.ID, RepoID: repo.ID}) issueWatch := models.AssertExistsAndLoadBean(t, &models.IssueWatch{UserID: user.ID, IssueID: newIssue.ID}).(*models.IssueWatch) assert.Equal(t, models.IssueWatchModeAuto, issueWatch.Mode) From d28af72068868d534ab4eba3538f1885ef947e3e Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 15:31:00 +0100 Subject: [PATCH 53/58] simple delete --- models/issue_watch.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 3803e75bcd5c4..3b43a033bb9fa 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -72,15 +72,8 @@ func DeleteIssueWatch(userID, issueID int64) error { } func deleteIssueWatch(e Engine, userID, issueID int64) error { - iw, exists, err := getIssueWatch(e, userID, issueID) - if err != nil { - return err - } - if exists { - _, err = e.ID(iw.ID).Delete(iw) - return err - } - return nil + _, err := e.Where("user_id = ?", userID).And("issue_id = ?", issueID).Delete(iw) + return err } // GetIssueWatch returns all IssueWatch objects from db by user and issue From a90815618566766d0d287c530a5c6a3728a385ac Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 15:33:09 +0100 Subject: [PATCH 54/58] Revert "remove sleep 1 sec" This reverts commit 060e28b7ff38131467db5be1547fe9074bcc7b34. --- integrations/issue_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 717e08838ca1d..6ff5d7ef775ba 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -83,6 +83,8 @@ func TestIssueAutoSubscription(t *testing.T) { newIssue, err := models.GetIssueByIndex(repo.ID, 1) assert.NoError(t, err) + time.Sleep(1 * time.Second) + models.AssertNotExistsBean(t, &models.Watch{UserID: user.ID, RepoID: repo.ID}) issueWatch := models.AssertExistsAndLoadBean(t, &models.IssueWatch{UserID: user.ID, IssueID: newIssue.ID}).(*models.IssueWatch) assert.Equal(t, models.IssueWatchModeAuto, issueWatch.Mode) From 6483396729f4ccfe78daea42fd7e257fb249c9d2 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 19 Feb 2020 15:47:15 +0100 Subject: [PATCH 55/58] fix deleteIssueWatch --- models/issue_watch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 3b43a033bb9fa..0cce18f70ded7 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -72,7 +72,7 @@ func DeleteIssueWatch(userID, issueID int64) error { } func deleteIssueWatch(e Engine, userID, issueID int64) error { - _, err := e.Where("user_id = ?", userID).And("issue_id = ?", issueID).Delete(iw) + _, err := e.Where("user_id = ?", userID).And("issue_id = ?", issueID).Delete(new(IssueWatch)) return err } From 9f7148c98dae7efaccf3ac062dbd3b791454838f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 21 Feb 2020 14:29:33 +0100 Subject: [PATCH 56/58] seperate docs update --- integrations/README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/integrations/README.md b/integrations/README.md index fccce2ec65f14..6ffd76815c265 100644 --- a/integrations/README.md +++ b/integrations/README.md @@ -19,7 +19,7 @@ drone exec --local --build-event "pull_request" ``` ## Run sqlite integrations tests -Start tests +Start tests ``` make test-sqlite ``` @@ -27,8 +27,7 @@ make test-sqlite ## Run mysql integrations tests Setup a mysql database inside docker ``` -docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(just ctrl-c to stop db and clean the container) -docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --rm --name elasticsearch elasticsearch:7.6.0 #(in a secound terminal, just ctrl-c to stop db and clean the container) +docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:5.7 #(just ctrl-c to stop db and clean the container) ``` Start tests based on the database container ``` @@ -38,7 +37,7 @@ TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root T ## Run pgsql integrations tests Setup a pgsql database inside docker ``` -docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container) +docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:9.5 #(just ctrl-c to stop db and clean the container) ``` Start tests based on the database container ``` @@ -48,7 +47,7 @@ TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgr ## Run mssql integrations tests Setup a mssql database inside docker ``` -docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container) +docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container) ``` Start tests based on the database container ``` @@ -69,4 +68,4 @@ For other databases(replace MSSQL to MYSQL, MYSQL8, PGSQL): ``` TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-mssql#GPG -``` +``` \ No newline at end of file From f6c9883d827ca1d77b96bd88fb09747cc6989b5c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 23 Feb 2020 01:12:53 +0100 Subject: [PATCH 57/58] do not extend api --- routers/api/v1/repo/issue_subscription.go | 39 +---------------------- templates/swagger/v1_json.tmpl | 6 ---- 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 128ca26722dc6..a67d9eac6835f 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -86,12 +86,8 @@ func DelIssueSubscription(ctx *context.APIContext) { // type: string // required: true // responses: - // "200": - // "$ref": "#/responses/empty" // "201": // "$ref": "#/responses/empty" - // "204": - // "$ref": "#/responses/empty" // "304": // description: User can only subscribe itself if he is no admin // "404": @@ -129,42 +125,9 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - // if watch + RepoWatch -> return OK - // if watch + no RepoWatch -> set IssueWatchModeNormal - // if unwatch + RepoWatch -> set IssueWatchModeDont - // if unwatch + no RepoWatch -> IssueWatch entry exist? - // yes -> delete - // no -> return OK - - repoWatch := models.IsWatching(user.ID, ctx.Repo.Repository.ID) - mode := models.IssueWatchModeNormal if !watch { - if repoWatch { - mode = models.IssueWatchModeDont - } else { - _, exist, err := models.GetIssueWatch(user.ID, issue.ID) - if err != nil { - ctx.InternalServerError(err) - return - } - if !exist { - ctx.Status(http.StatusOK) - return - } - if err = models.DeleteIssueWatch(user.ID, issue.ID); err != nil { - ctx.Error(http.StatusInternalServerError, "DeleteIssueWatch", err) - return - } - ctx.Status(http.StatusNoContent) - return - } - } else { - if repoWatch { - ctx.Status(http.StatusOK) - return - } - mode = models.IssueWatchModeNormal + mode = models.IssueWatchModeDont } if err := models.CreateOrUpdateIssueWatchMode(user.ID, issue.ID, mode); err != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 4cc571a291713..b52145a0a9b6f 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -5032,15 +5032,9 @@ } ], "responses": { - "200": { - "$ref": "#/responses/empty" - }, "201": { "$ref": "#/responses/empty" }, - "204": { - "$ref": "#/responses/empty" - }, "304": { "description": "User can only subscribe itself if he is no admin" }, From e3e1bbd2f2563c56504aa9c53822f74737b9c367 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 23 Feb 2020 01:14:31 +0100 Subject: [PATCH 58/58] remove unused --- models/issue_watch.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/models/issue_watch.go b/models/issue_watch.go index 0cce18f70ded7..317dcac521900 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -66,16 +66,6 @@ func createOrUpdateIssueWatchMode(e Engine, userID, issueID int64, mode IssueWat return nil } -//DeleteIssueWatch delete an IssueWatch entry of an user to an given issue if exist -func DeleteIssueWatch(userID, issueID int64) error { - return deleteIssueWatch(x, userID, issueID) -} - -func deleteIssueWatch(e Engine, userID, issueID int64) error { - _, err := e.Where("user_id = ?", userID).And("issue_id = ?", issueID).Delete(new(IssueWatch)) - return err -} - // GetIssueWatch returns all IssueWatch objects from db by user and issue func GetIssueWatch(userID, issueID int64) (iw *IssueWatch, exists bool, err error) { return getIssueWatch(x, userID, issueID)