summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/consistency.go58
-rw-r--r--models/migrations/migrations.go2
-rw-r--r--models/migrations/v176.go74
-rw-r--r--modules/doctor/dbconsistency.go39
4 files changed, 173 insertions, 0 deletions
diff --git a/models/consistency.go b/models/consistency.go
index 3a2208014d..bed94d9395 100644
--- a/models/consistency.go
+++ b/models/consistency.go
@@ -319,6 +319,64 @@ func FixCommentTypeLabelWithEmptyLabel() (int64, error) {
return x.Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment))
}
+// CountCommentTypeLabelWithOutsideLabels count label comments with outside label
+func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
+ return x.Where("comment.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND repository.owner_id != label.org_id))", CommentTypeLabel).
+ Table("comment").
+ Join("inner", "label", "label.id = comment.label_id").
+ Join("inner", "issue", "issue.id = comment.issue_id ").
+ Join("inner", "repository", "issue.repo_id = repository.id").
+ Count(new(Comment))
+}
+
+// FixCommentTypeLabelWithOutsideLabels count label comments with outside label
+func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
+ res, err := x.Exec(`DELETE FROM comment WHERE comment.id IN (
+ SELECT il_too.id FROM (
+ SELECT com.id
+ FROM comment AS com
+ INNER JOIN label ON com.label_id = label.id
+ INNER JOIN issue on issue.id = com.issue_id
+ WHERE
+ com.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repo.owner_id))
+ ) AS il_too)`, CommentTypeLabel)
+ if err != nil {
+ return 0, err
+ }
+
+ return res.RowsAffected()
+}
+
+// CountIssueLabelWithOutsideLabels count label comments with outside label
+func CountIssueLabelWithOutsideLabels() (int64, error) {
+ return x.Where(builder.Expr("issue.repo_id != label.repo_id OR (label.repo_id = 0 AND repository.owner_id != label.org_id)")).
+ Table("issue_label").
+ Join("inner", "label", "issue_label.id = label.id ").
+ Join("inner", "issue", "issue.id = issue_label.issue_id ").
+ Join("inner", "repository", "issue.repo_id = repository.id").
+ Count(new(IssueLabel))
+}
+
+// FixIssueLabelWithOutsideLabels fix label comments with outside label
+func FixIssueLabelWithOutsideLabels() (int64, error) {
+ res, err := x.Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
+ SELECT il_too.id FROM (
+ SELECT il_too_too.id
+ FROM issue_label AS il_too_too
+ INNER JOIN label ON il_too_too.id = label.id
+ INNER JOIN issue on issue.id = il_too_too.issue_id
+ INNER JOIN repository on repository.id = issue.repo_id
+ WHERE
+ issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
+ ) AS il_too )`)
+
+ if err != nil {
+ return 0, err
+ }
+
+ return res.RowsAffected()
+}
+
// CountBadSequences looks for broken sequences from recreate-table mistakes
func CountBadSequences() (int64, error) {
if !setting.Database.UsePostgreSQL {
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index f46d151b7b..3427b5dec1 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -298,6 +298,8 @@ var migrations = []Migration{
NewMigration("create repo transfer table", addRepoTransfer),
// v175 -> v176
NewMigration("Fix Postgres ID Sequences broken by recreate-table", fixPostgresIDSequences),
+ // v176 -> v177
+ NewMigration("Remove invalid labels from comments", removeInvalidLabels),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v176.go b/models/migrations/v176.go
new file mode 100644
index 0000000000..ff6587508d
--- /dev/null
+++ b/models/migrations/v176.go
@@ -0,0 +1,74 @@
+// Copyright 2021 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 (
+ "xorm.io/xorm"
+)
+
+func removeInvalidLabels(x *xorm.Engine) error {
+ type Comment struct {
+ ID int64 `xorm:"pk autoincr"`
+ Type int `xorm:"INDEX"`
+ IssueID int64 `xorm:"INDEX"`
+ LabelID int64
+ }
+
+ type Issue struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
+ Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
+ }
+
+ type Repository struct {
+ ID int64 `xorm:"pk autoincr"`
+ OwnerID int64 `xorm:"UNIQUE(s) index"`
+ LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
+ }
+
+ type Label struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX"`
+ OrgID int64 `xorm:"INDEX"`
+ }
+
+ type IssueLabel struct {
+ ID int64 `xorm:"pk autoincr"`
+ IssueID int64 `xorm:"UNIQUE(s)"`
+ LabelID int64 `xorm:"UNIQUE(s)"`
+ }
+
+ if err := x.Sync2(new(Comment), new(Issue), new(Repository), new(Label), new(IssueLabel)); err != nil {
+ return err
+ }
+
+ if _, err := x.Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
+ SELECT il_too.id FROM (
+ SELECT il_too_too.id
+ FROM issue_label AS il_too_too
+ INNER JOIN label ON il_too_too.id = label.id
+ INNER JOIN issue on issue.id = il_too_too.issue_id
+ INNER JOIN repository on repository.id = issue.repo_id
+ WHERE
+ issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
+ ) AS il_too )`); err != nil {
+ return err
+ }
+
+ if _, err := x.Exec(`DELETE FROM comment WHERE comment.id IN (
+ SELECT il_too.id FROM (
+ SELECT com.id
+ FROM comment AS com
+ INNER JOIN label ON com.label_id = label.id
+ INNER JOIN issue on issue.id = com.issue_id
+ INNER JOIN repository on repository.id = issue.repo_id
+ WHERE
+ com.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id))
+ ) AS il_too)`, 7); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go
index 1e3c7258e3..83d3dc5fe2 100644
--- a/modules/doctor/dbconsistency.go
+++ b/modules/doctor/dbconsistency.go
@@ -130,6 +130,45 @@ func checkDBConsistency(logger log.Logger, autofix bool) error {
logger.Warn("%d label comments with empty labels", count)
}
}
+
+ // find label comments with labels from outside the repository
+ count, err = models.CountCommentTypeLabelWithOutsideLabels()
+ if err != nil {
+ logger.Critical("Error: %v whilst counting label comments with outside labels", err)
+ return err
+ }
+ if count > 0 {
+ if autofix {
+ updatedCount, err := models.FixCommentTypeLabelWithOutsideLabels()
+ if err != nil {
+ logger.Critical("Error: %v whilst removing label comments with outside labels", err)
+ return err
+ }
+ log.Info("%d label comments with outside labels removed", updatedCount)
+ } else {
+ log.Warn("%d label comments with outside labels", count)
+ }
+ }
+
+ // find issue_label with labels from outside the repository
+ count, err = models.CountIssueLabelWithOutsideLabels()
+ if err != nil {
+ logger.Critical("Error: %v whilst counting issue_labels from outside the repository or organisation", err)
+ return err
+ }
+ if count > 0 {
+ if autofix {
+ updatedCount, err := models.FixIssueLabelWithOutsideLabels()
+ if err != nil {
+ logger.Critical("Error: %v whilst removing issue_labels from outside the repository or organisation", err)
+ return err
+ }
+ logger.Info("%d issue_labels from outside the repository or organisation removed", updatedCount)
+ } else {
+ logger.Warn("%d issue_labels from outside the repository or organisation", count)
+ }
+ }
+
// TODO: function to recalc all counters
if setting.Database.UsePostgreSQL {