diff --git a/cmd/doctor.go b/cmd/doctor.go index 5ba0451110..3c271f131f 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -606,6 +606,22 @@ func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) { } } + // find IssueLabels without existing label + count, err = models.CountOrphanedIssueLabels() + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + if err = models.DeleteOrphanedIssueLabels(); err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d issue_labels without existing label deleted", count)) + } else { + results = append(results, fmt.Sprintf("%d issue_labels without existing label", count)) + } + } + //find issues without existing repository count, err = models.CountOrphanedIssues() if err != nil { diff --git a/models/consistency.go b/models/consistency.go index 0c62d4dc24..3a5c4cae50 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -224,6 +224,24 @@ func DeleteOrphanedLabels() error { return nil } +// CountOrphanedIssueLabels return count of IssueLabels witch have no label behind anymore +func CountOrphanedIssueLabels() (int64, error) { + return x.Table("issue_label"). + Join("LEFT", "label", "issue_label.label_id = label.id"). + Where(builder.IsNull{"label.id"}).Count() +} + +// DeleteOrphanedIssueLabels delete IssueLabels witch have no label behind anymore +func DeleteOrphanedIssueLabels() error { + + _, err := x.In("id", builder.Select("issue_label.id").From("issue_label"). + Join("LEFT", "label", "issue_label.label_id = label.id"). + Where(builder.IsNull{"label.id"})). + Delete(IssueLabel{}) + + return err +} + // CountOrphanedIssues count issues without a repo func CountOrphanedIssues() (int64, error) { return x.Table("issue"). diff --git a/models/issue_label.go b/models/issue_label.go index 54b286fe7e..6d519aa8cd 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -764,3 +764,15 @@ func DeleteIssueLabel(issue *Issue, label *Label, doer *User) (err error) { return sess.Commit() } + +func deleteLabelsByRepoID(sess Engine, repoID int64) error { + deleteCond := builder.Select("id").From("label").Where(builder.Eq{"label.repo_id": repoID}) + + if _, err := sess.In("label_id", deleteCond). + Delete(&IssueLabel{}); err != nil { + return err + } + + _, err := sess.Delete(&Label{RepoID: repoID}) + return err +} diff --git a/models/repo.go b/models/repo.go index 8c6d8b9ee3..6d6f61597b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1729,6 +1729,10 @@ func DeleteRepository(doer *User, uid, repoID int64) error { return fmt.Errorf("deleteBeans: %v", err) } + if err := deleteLabelsByRepoID(sess, repoID); err != nil { + return err + } + // Delete Issues and related objects var attachmentPaths []string if attachmentPaths, err = deleteIssuesByRepoID(sess, repoID); err != nil {