From 5da7adc70fdbd0cb14ceac877dacc60f2f3b6cca Mon Sep 17 00:00:00 2001 From: fnetx Date: Thu, 24 Feb 2022 14:07:51 +0100 Subject: [PATCH 01/17] Allow removing issues via API Signed-off-by: fnetx --- models/issue.go | 124 +++++++++++++++++++++++++++++++++ routers/api/v1/api.go | 3 +- routers/api/v1/repo/issue.go | 65 +++++++++++++++++ services/issue/issue.go | 11 +++ templates/swagger/v1_json.tmpl | 44 ++++++++++++ 5 files changed, 246 insertions(+), 1 deletion(-) diff --git a/models/issue.go b/models/issue.go index 91d4df32d1cd8..c95dd3db9b9d9 100644 --- a/models/issue.go +++ b/models/issue.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" + admin_model "code.gitea.io/gitea/models/admin" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/perm" @@ -24,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -356,6 +358,83 @@ func (issue *Issue) GetIsRead(userID int64) error { return nil } +func (issue *Issue) AfterDelete() { + e := db.GetEngine(db.DefaultContext) + // Delete content histories + if _, err := e.In("issue_id", issue.ID). + Delete(&issues.ContentHistory{}); err != nil { + log.Info("Could not delete content history for issue %d: %s", issue.ID, err) + } + + // Delete comments and attachments + if _, err := e.In("issue_id", issue.ID). + Delete(&Comment{}); err != nil { + log.Info("Could not delete comments for issue %d: %s", issue.ID, err) + } + + // Dependencies for issues in this repository + if _, err := e.In("issue_id", issue.ID). + Delete(&IssueDependency{}); err != nil { + log.Info("Could not delete internal issue dependencies for issue %d: %s", issue.ID, err) + } + + // Delete dependencies for issues in other repositories + if _, err := e.In("dependency_id", issue.ID). + Delete(&IssueDependency{}); err != nil { + log.Info("Could not delete external issue dependencies for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&IssueUser{}); err != nil { + log.Info("Could not delete IssueUser for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&Reaction{}); err != nil { + log.Info("Could not delete Reaction for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&IssueWatch{}); err != nil { + log.Info("Could not delete IssueWatch for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&Stopwatch{}); err != nil { + log.Info("Could not delete StopWatch for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&TrackedTime{}); err != nil { + log.Info("Could not delete TrackedTime for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&ProjectIssue{}); err != nil { + log.Info("Could not delete ProjektIssue for issue %d: %s", issue.ID, err) + } + + if _, err := e.In("dependent_issue_id", issue.ID). + Delete(&Comment{}); err != nil { + log.Info("Could not delete dependend issue for issue %d: %s", issue.ID, err) + } + + var attachments []*repo_model.Attachment + if err := e.In("issue_id", issue.ID). + Find(&attachments); err != nil { + log.Info("Could not find attachments for issue %d: %s", issue.ID, err) + } + + for i := range attachments { + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachments[i].RelativePath()) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&repo_model.Attachment{}); err != nil { + log.Info("Could not delete attachment for issue %d: %s", issue.ID, err) + } +} + // APIURL returns the absolute APIURL to this issue. func (issue *Issue) APIURL() string { if issue.Repo == nil { @@ -1990,6 +2069,51 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us return committer.Commit() } +// DeleteIssue deletes the issue +func DeleteIssue(issue *Issue) error { + ctx, committer, err := db.TxContext() + if err != nil { + return err + } + defer committer.Close() + + if err := deleteIssue(db.GetEngine(ctx), issue); err != nil { + return err + } + + return committer.Commit() +} + +func deleteIssue(e db.Engine, issue *Issue) error { + if _, err := e.Delete(&Issue{ + ID: issue.ID, + }); err != nil { + return err + } + + if issue.IsPull { + if _, err := e.Exec("UPDATE `repository` SET num_pulls = num_pulls - 1 WHERE id = ?", issue.RepoID); err != nil { + return err + } + if issue.IsClosed { + if _, err := e.Exec("UPDATE `repository` SET num_closed_pulls = num_closed_pulls -1 WHERE id = ?", issue.RepoID); err != nil { + return err + } + } + } else { + if _, err := e.Exec("UPDATE `repository` SET num_issues = num_issues - 1 WHERE id = ?", issue.RepoID); err != nil { + return err + } + if issue.IsClosed { + if _, err := e.Exec("UPDATE `repository` SET num_closed_issues = num_closed_issues -1 WHERE id = ?", issue.RepoID); err != nil { + return err + } + } + } + + return nil +} + // DependencyInfo represents high level information about an issue which is a dependency of another issue. type DependencyInfo struct { Issue `xorm:"extends"` diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 6d8ab8ce98fd9..54458ceead4de 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -835,7 +835,8 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route { }) m.Group("/{index}", func() { m.Combo("").Get(repo.GetIssue). - Patch(reqToken(), bind(api.EditIssueOption{}), repo.EditIssue) + Patch(reqToken(), bind(api.EditIssueOption{}), repo.EditIssue). + Delete(reqToken(), repo.DeleteIssue) m.Group("/comments", func() { m.Combo("").Get(repo.ListIssueComments). Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index e2afa724989f3..2db4f128b08a4 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -834,6 +835,70 @@ func EditIssue(ctx *context.APIContext) { ctx.JSON(http.StatusCreated, convert.ToAPIIssue(issue)) } +func DeleteIssue(ctx *context.APIContext) { + // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index} issue issueDelete + // --- + // summary: Delete an issue + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of issue to delete + // type: integer + // format: int64 + // required: true + // responses: + // "204": + // "$ref": "#/responses/empty" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + + deleteIssue(ctx) +} + +func deleteIssue(ctx *context.APIContext) { + if !ctx.IsSigned || !ctx.Repo.IsAdmin() { + ctx.Status(http.StatusForbidden) + return + } + + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Params(":username"), ctx.Params(":reponame")) + if err != nil { + if repo_model.IsErrRepoNotExist(err) { + ctx.NotFound(err) + } else { + ctx.Error(http.StatusInternalServerError, "GetRepoByOwnerAndName", err) + } + } + issue, err := models.GetIssueByIndex(repo.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrIssueNotExist(err) { + ctx.NotFound(err) + } else { + ctx.Error(http.StatusInternalServerError, "GetIssueByID", err) + } + return + } + + if err = issue_service.DeleteIssue(ctx.User, issue); err != nil { + ctx.Error(http.StatusInternalServerError, "DeleteIssueByID", err) + return + } + + ctx.Status(http.StatusNoContent) +} + // UpdateIssueDeadline updates an issue deadline func UpdateIssueDeadline(ctx *context.APIContext) { // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/deadline issue issueEditIssueDeadline diff --git a/services/issue/issue.go b/services/issue/issue.go index 8b6262c571387..47434cf1804dd 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -125,6 +125,17 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees return } +// DeleteIssue deletes an issue +func DeleteIssue(doer *user_model.User, issue *models.Issue) error { + if err := models.DeleteIssue(issue); err != nil { + return err + } + + // notification.NotifyDeleteIssue(doer, issue) + + return nil +} + // AddAssigneeIfNotAssigned adds an assignee only if he isn't already assigned to the issue. // Also checks for access of assigned user func AddAssigneeIfNotAssigned(issue *models.Issue, doer *user_model.User, assigneeID int64) (err error) { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0b0b83ebbc16f..d0214329ce957 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4923,6 +4923,50 @@ } } }, + "/repos/{owner}/{repo}/issues/{id}": { + "delete": { + "tags": [ + "issue" + ], + "summary": "Delete an issue", + "operationId": "issueDelete", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "id of issue to delete", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "$ref": "#/responses/empty" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/issues/{index}": { "get": { "produces": [ From 166002b2b80eeb0bbc292b622c8612bd9baf4fe4 Mon Sep 17 00:00:00 2001 From: fnetx Date: Thu, 24 Feb 2022 17:15:54 +0100 Subject: [PATCH 02/17] Fixup: Swagger Signed-off-by: fnetx --- templates/swagger/v1_json.tmpl | 44 ++++++++++++++++------------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index d0214329ce957..69abe24020978 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4923,13 +4923,16 @@ } } }, - "/repos/{owner}/{repo}/issues/{id}": { - "delete": { + "/repos/{owner}/{repo}/issues/{index}": { + "get": { + "produces": [ + "application/json" + ], "tags": [ "issue" ], - "summary": "Delete an issue", - "operationId": "issueDelete", + "summary": "Get an issue", + "operationId": "issueGetIssue", "parameters": [ { "type": "string", @@ -4948,35 +4951,27 @@ { "type": "integer", "format": "int64", - "description": "id of issue to delete", - "name": "id", + "description": "index of the issue to get", + "name": "index", "in": "path", "required": true } ], "responses": { - "204": { - "$ref": "#/responses/empty" - }, - "403": { - "$ref": "#/responses/forbidden" + "200": { + "$ref": "#/responses/Issue" }, "404": { "$ref": "#/responses/notFound" } } - } - }, - "/repos/{owner}/{repo}/issues/{index}": { - "get": { - "produces": [ - "application/json" - ], + }, + "delete": { "tags": [ "issue" ], - "summary": "Get an issue", - "operationId": "issueGetIssue", + "summary": "Delete an issue", + "operationId": "issueDelete", "parameters": [ { "type": "string", @@ -4995,15 +4990,18 @@ { "type": "integer", "format": "int64", - "description": "index of the issue to get", + "description": "index of issue to delete", "name": "index", "in": "path", "required": true } ], "responses": { - "200": { - "$ref": "#/responses/Issue" + "204": { + "$ref": "#/responses/empty" + }, + "403": { + "$ref": "#/responses/forbidden" }, "404": { "$ref": "#/responses/notFound" From 34dabcd7718b79148c1e0cece94108842a581fd6 Mon Sep 17 00:00:00 2001 From: fnetx Date: Thu, 24 Feb 2022 18:10:57 +0100 Subject: [PATCH 03/17] Cleanup references in other issues --- models/issue.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/models/issue.go b/models/issue.go index c95dd3db9b9d9..2c3a944761981 100644 --- a/models/issue.go +++ b/models/issue.go @@ -372,6 +372,12 @@ func (issue *Issue) AfterDelete() { log.Info("Could not delete comments for issue %d: %s", issue.ID, err) } + // References to this issue in other issues + if _, err := e.In("ref_issue_id", issue.ID). + Delete(&Comment{}); err != nil { + log.Info("Could not delete referring comments for issue %d: %s", issue.ID, err) + } + // Dependencies for issues in this repository if _, err := e.In("issue_id", issue.ID). Delete(&IssueDependency{}); err != nil { From d66325e5e4008cbe10a2f63595570a5f339cd48d Mon Sep 17 00:00:00 2001 From: fnetx Date: Fri, 25 Feb 2022 12:49:14 +0100 Subject: [PATCH 04/17] Simple test case for most important failures Leftover attachments and issues that can't be closed would probably be the most important issues. Everything else should be cleaned up by consistency checks in case it really fails. --- models/issue_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/models/issue_test.go b/models/issue_test.go index 9344d385a7c75..7cc0aa61b0da9 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -397,6 +397,58 @@ func TestIssue_InsertIssue(t *testing.T) { assert.NoError(t, err) } +func TestIssue_DeleteIssue(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + issueIDs, err := GetIssueIDsByRepoID(1) + assert.NoError(t, err) + assert.EqualValues(t, 5, len(issueIDs)) + + issue := &Issue{ + RepoID: 1, + ID: issueIDs[2], + } + + err = DeleteIssue(issue) + assert.NoError(t, err) + issueIDs, err = GetIssueIDsByRepoID(1) + assert.NoError(t, err) + assert.EqualValues(t, 4, len(issueIDs)) + + // check attachment removal + attachments, err := repo_model.GetAttachmentsByIssueID(4) + assert.NoError(t, err) + issue, err = GetIssueByID(4) + assert.NoError(t, err) + err = DeleteIssue(issue) + assert.NoError(t, err) + assert.EqualValues(t, 2, len(attachments)) + for i := range attachments { + attachment, err := repo_model.GetAttachmentByUUID(attachments[i].UUID) + assert.Error(t, err) + assert.True(t, repo_model.IsErrAttachmentNotExist(err)) + assert.Nil(t, attachment) + } + + // check issue dependencies + user, err := user_model.GetUserByID(1) + assert.NoError(t, err) + issue1, err := GetIssueByID(1) + assert.NoError(t, err) + issue2, err := GetIssueByID(2) + assert.NoError(t, err) + err = CreateIssueDependency(user, issue1, issue2) + assert.NoError(t, err) + left, err := IssueNoDependenciesLeft(issue1) + assert.NoError(t, err) + assert.False(t, left) + err = DeleteIssue(&Issue{ID: 2}) + assert.NoError(t, err) + left, err = IssueNoDependenciesLeft(issue1) + assert.NoError(t, err) + assert.True(t, left) +} + func TestIssue_ResolveMentions(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) From fe4812e615486100a57bc525c3fabb373bccf164 Mon Sep 17 00:00:00 2001 From: fnetx Date: Fri, 25 Feb 2022 13:22:55 +0100 Subject: [PATCH 05/17] remove more leftover data --- models/issue.go | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/models/issue.go b/models/issue.go index 2c3a944761981..0743ed8d486ee 100644 --- a/models/issue.go +++ b/models/issue.go @@ -372,6 +372,12 @@ func (issue *Issue) AfterDelete() { log.Info("Could not delete comments for issue %d: %s", issue.ID, err) } + // Delete label assignment + if _, err := e.In("issue_id", issue.ID). + Delete(&IssueLabel{}); err != nil { + log.Info("Could not delete issue labels for issue %d: %s", issue.ID, err) + } + // References to this issue in other issues if _, err := e.In("ref_issue_id", issue.ID). Delete(&Comment{}); err != nil { @@ -390,41 +396,54 @@ func (issue *Issue) AfterDelete() { log.Info("Could not delete external issue dependencies for issue %d: %s", issue.ID, err) } + // delete from dependent issues + if _, err := e.In("dependent_issue_id", issue.ID). + Delete(&Comment{}); err != nil { + log.Info("Could not delete dependend issue for issue %d: %s", issue.ID, err) + } + + // delete issue assignment + if _, err := e.In("issue_id", issue.ID). + Delete(&IssueAssignees{}); err != nil { + log.Info("Could not delete issue assignees for issue %d: %s", issue.ID, err) + } + + // delete issue user state if _, err := e.In("issue_id", issue.ID). Delete(&IssueUser{}); err != nil { log.Info("Could not delete IssueUser for issue %d: %s", issue.ID, err) } + // delete reactions if _, err := e.In("issue_id", issue.ID). Delete(&Reaction{}); err != nil { log.Info("Could not delete Reaction for issue %d: %s", issue.ID, err) } + // delete user watches if _, err := e.In("issue_id", issue.ID). Delete(&IssueWatch{}); err != nil { log.Info("Could not delete IssueWatch for issue %d: %s", issue.ID, err) } + // delete stopwatches if _, err := e.In("issue_id", issue.ID). Delete(&Stopwatch{}); err != nil { log.Info("Could not delete StopWatch for issue %d: %s", issue.ID, err) } + // delete tracked time if _, err := e.In("issue_id", issue.ID). Delete(&TrackedTime{}); err != nil { log.Info("Could not delete TrackedTime for issue %d: %s", issue.ID, err) } + // delete from projects if _, err := e.In("issue_id", issue.ID). Delete(&ProjectIssue{}); err != nil { log.Info("Could not delete ProjektIssue for issue %d: %s", issue.ID, err) } - if _, err := e.In("dependent_issue_id", issue.ID). - Delete(&Comment{}); err != nil { - log.Info("Could not delete dependend issue for issue %d: %s", issue.ID, err) - } - var attachments []*repo_model.Attachment if err := e.In("issue_id", issue.ID). Find(&attachments); err != nil { From eb56b2595a0d9671460b3dc599a01b93143fcdcd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 26 Feb 2022 20:09:13 +0800 Subject: [PATCH 06/17] Improve delete issue --- models/issue.go | 166 +++++++++----------------- models/issue_comment.go | 4 +- modules/notification/base/notifier.go | 2 + modules/notification/base/null.go | 5 + modules/notification/notification.go | 8 ++ routers/api/v1/repo/issue.go | 13 +- services/issue/issue.go | 16 ++- 7 files changed, 91 insertions(+), 123 deletions(-) diff --git a/models/issue.go b/models/issue.go index 0743ed8d486ee..0b6131db07de5 100644 --- a/models/issue.go +++ b/models/issue.go @@ -358,108 +358,6 @@ func (issue *Issue) GetIsRead(userID int64) error { return nil } -func (issue *Issue) AfterDelete() { - e := db.GetEngine(db.DefaultContext) - // Delete content histories - if _, err := e.In("issue_id", issue.ID). - Delete(&issues.ContentHistory{}); err != nil { - log.Info("Could not delete content history for issue %d: %s", issue.ID, err) - } - - // Delete comments and attachments - if _, err := e.In("issue_id", issue.ID). - Delete(&Comment{}); err != nil { - log.Info("Could not delete comments for issue %d: %s", issue.ID, err) - } - - // Delete label assignment - if _, err := e.In("issue_id", issue.ID). - Delete(&IssueLabel{}); err != nil { - log.Info("Could not delete issue labels for issue %d: %s", issue.ID, err) - } - - // References to this issue in other issues - if _, err := e.In("ref_issue_id", issue.ID). - Delete(&Comment{}); err != nil { - log.Info("Could not delete referring comments for issue %d: %s", issue.ID, err) - } - - // Dependencies for issues in this repository - if _, err := e.In("issue_id", issue.ID). - Delete(&IssueDependency{}); err != nil { - log.Info("Could not delete internal issue dependencies for issue %d: %s", issue.ID, err) - } - - // Delete dependencies for issues in other repositories - if _, err := e.In("dependency_id", issue.ID). - Delete(&IssueDependency{}); err != nil { - log.Info("Could not delete external issue dependencies for issue %d: %s", issue.ID, err) - } - - // delete from dependent issues - if _, err := e.In("dependent_issue_id", issue.ID). - Delete(&Comment{}); err != nil { - log.Info("Could not delete dependend issue for issue %d: %s", issue.ID, err) - } - - // delete issue assignment - if _, err := e.In("issue_id", issue.ID). - Delete(&IssueAssignees{}); err != nil { - log.Info("Could not delete issue assignees for issue %d: %s", issue.ID, err) - } - - // delete issue user state - if _, err := e.In("issue_id", issue.ID). - Delete(&IssueUser{}); err != nil { - log.Info("Could not delete IssueUser for issue %d: %s", issue.ID, err) - } - - // delete reactions - if _, err := e.In("issue_id", issue.ID). - Delete(&Reaction{}); err != nil { - log.Info("Could not delete Reaction for issue %d: %s", issue.ID, err) - } - - // delete user watches - if _, err := e.In("issue_id", issue.ID). - Delete(&IssueWatch{}); err != nil { - log.Info("Could not delete IssueWatch for issue %d: %s", issue.ID, err) - } - - // delete stopwatches - if _, err := e.In("issue_id", issue.ID). - Delete(&Stopwatch{}); err != nil { - log.Info("Could not delete StopWatch for issue %d: %s", issue.ID, err) - } - - // delete tracked time - if _, err := e.In("issue_id", issue.ID). - Delete(&TrackedTime{}); err != nil { - log.Info("Could not delete TrackedTime for issue %d: %s", issue.ID, err) - } - - // delete from projects - if _, err := e.In("issue_id", issue.ID). - Delete(&ProjectIssue{}); err != nil { - log.Info("Could not delete ProjektIssue for issue %d: %s", issue.ID, err) - } - - var attachments []*repo_model.Attachment - if err := e.In("issue_id", issue.ID). - Find(&attachments); err != nil { - log.Info("Could not find attachments for issue %d: %s", issue.ID, err) - } - - for i := range attachments { - admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachments[i].RelativePath()) - } - - if _, err := e.In("issue_id", issue.ID). - Delete(&repo_model.Attachment{}); err != nil { - log.Info("Could not delete attachment for issue %d: %s", issue.ID, err) - } -} - // APIURL returns the absolute APIURL to this issue. func (issue *Issue) APIURL() string { if issue.Repo == nil { @@ -2102,17 +2000,25 @@ func DeleteIssue(issue *Issue) error { } defer committer.Close() - if err := deleteIssue(db.GetEngine(ctx), issue); err != nil { + if err := deleteIssue(ctx, issue); err != nil { return err } return committer.Commit() } -func deleteIssue(e db.Engine, issue *Issue) error { - if _, err := e.Delete(&Issue{ - ID: issue.ID, - }); err != nil { +func deleteIn(e db.Engine, issueID int64, beans ...interface{}) error { + for _, bean := range beans { + if _, err := e.In("issue_id", issueID).Delete(bean); err != nil { + return err + } + } + return nil +} + +func deleteIssue(ctx context.Context, issue *Issue) error { + e := db.GetEngine(ctx) + if _, err := e.ID(issue.ID).NoAutoCondition().Delete(issue); err != nil { return err } @@ -2136,6 +2042,52 @@ func deleteIssue(e db.Engine, issue *Issue) error { } } + if err := deleteIn(e, issue.ID, + &issues.ContentHistory{}, + &Comment{}, + &IssueLabel{}, + &IssueDependency{}, + &IssueAssignees{}, + &IssueUser{}, + &Reaction{}, + &IssueWatch{}, + &Stopwatch{}, + &TrackedTime{}, + &ProjectIssue{}, + ); err != nil { + return err + } + + // References to this issue in other issues + if _, err := e.In("ref_issue_id", issue.ID).Delete(&Comment{}); err != nil { + return err + } + + // Delete dependencies for issues in other repositories + if _, err := e.In("dependency_id", issue.ID).Delete(&IssueDependency{}); err != nil { + return err + } + + // delete from dependent issues + if _, err := e.In("dependent_issue_id", issue.ID).Delete(&Comment{}); err != nil { + return err + } + + var attachments []*repo_model.Attachment + if err := e.In("issue_id", issue.ID). + Find(&attachments); err != nil { + log.Info("Could not find attachments for issue %d: %s", issue.ID, err) + } + + for i := range attachments { + admin_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", attachments[i].RelativePath()) + } + + if _, err := e.In("issue_id", issue.ID). + Delete(&repo_model.Attachment{}); err != nil { + return err + } + return nil } diff --git a/models/issue_comment.go b/models/issue_comment.go index 31bd041ca759d..0af45e80e8b3a 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1152,9 +1152,7 @@ func DeleteComment(comment *Comment) error { } func deleteComment(e db.Engine, comment *Comment) error { - if _, err := e.Delete(&Comment{ - ID: comment.ID, - }); err != nil { + if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil { return err } diff --git a/modules/notification/base/notifier.go b/modules/notification/base/notifier.go index 7f5caa3bcc273..9a7156c7ad139 100644 --- a/modules/notification/base/notifier.go +++ b/modules/notification/base/notifier.go @@ -8,6 +8,7 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/repository" ) @@ -22,6 +23,7 @@ type Notifier interface { NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) NotifyIssueChangeStatus(*user_model.User, *models.Issue, *models.Comment, bool) + NotifyDeleteIssue(*user_model.User, *git.Repository, *models.Issue) NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) diff --git a/modules/notification/base/null.go b/modules/notification/base/null.go index bd52b843a7c36..f5a3aab3043aa 100644 --- a/modules/notification/base/null.go +++ b/modules/notification/base/null.go @@ -8,6 +8,7 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/repository" ) @@ -33,6 +34,10 @@ func (*NullNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_model. func (*NullNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) { } +// NotifyDeleteIssue notify when some issue deleted +func (*NullNotifier) NotifyDeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.Issue) { +} + // NotifyNewPullRequest places a place holder function func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) { } diff --git a/modules/notification/notification.go b/modules/notification/notification.go index e8d5d07b344c8..3d5a4674fb8f0 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -8,6 +8,7 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/notification/action" "code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/notification/indexer" @@ -60,6 +61,13 @@ func NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionC } } +// NotifyDeleteIssue notify when some issue deleted +func NotifyDeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.Issue) { + for _, notifier := range notifiers { + notifier.NotifyDeleteIssue(doer, gitRepo, issue) + } +} + // NotifyMergePullRequest notifies merge pull request to notifiers func NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) { for _, notifier := range notifiers { diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 2db4f128b08a4..49e66d9ff58b0 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -14,7 +14,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -873,15 +872,7 @@ func deleteIssue(ctx *context.APIContext) { return } - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Params(":username"), ctx.Params(":reponame")) - if err != nil { - if repo_model.IsErrRepoNotExist(err) { - ctx.NotFound(err) - } else { - ctx.Error(http.StatusInternalServerError, "GetRepoByOwnerAndName", err) - } - } - issue, err := models.GetIssueByIndex(repo.ID, ctx.ParamsInt64(":index")) + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { ctx.NotFound(err) @@ -891,7 +882,7 @@ func deleteIssue(ctx *context.APIContext) { return } - if err = issue_service.DeleteIssue(ctx.User, issue); err != nil { + if err = issue_service.DeleteIssue(ctx.User, ctx.Repo.GitRepo, issue); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteIssueByID", err) return } diff --git a/services/issue/issue.go b/services/issue/issue.go index 47434cf1804dd..5972aefa9b4c8 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -5,6 +5,8 @@ package issue import ( + "fmt" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" @@ -126,12 +128,22 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees } // DeleteIssue deletes an issue -func DeleteIssue(doer *user_model.User, issue *models.Issue) error { +func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.Issue) error { if err := models.DeleteIssue(issue); err != nil { return err } - // notification.NotifyDeleteIssue(doer, issue) + // delete pull request related git data + if issue.IsPull { + if err := issue.LoadPullRequest(); err != nil { + return err + } + if err := gitRepo.RemoveReference(fmt.Sprintf(git.PullPrefix+"%d", issue.PullRequest.Index)); err != nil { + return err + } + } + + notification.NotifyDeleteIssue(doer, gitRepo, issue) return nil } From 636e78cf15f664b9ece798149e35d166553beeab Mon Sep 17 00:00:00 2001 From: fnetx Date: Mon, 28 Feb 2022 12:47:40 +0100 Subject: [PATCH 07/17] Further deduplication and change deleteInIssue function name --- models/issue.go | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/models/issue.go b/models/issue.go index 0b6131db07de5..c276321cf4090 100644 --- a/models/issue.go +++ b/models/issue.go @@ -2007,7 +2007,7 @@ func DeleteIssue(issue *Issue) error { return committer.Commit() } -func deleteIn(e db.Engine, issueID int64, beans ...interface{}) error { +func deleteInIssue(e db.Engine, issueID int64, beans ...interface{}) error { for _, bean := range beans { if _, err := e.In("issue_id", issueID).Delete(bean); err != nil { return err @@ -2042,7 +2042,19 @@ func deleteIssue(ctx context.Context, issue *Issue) error { } } - if err := deleteIn(e, issue.ID, + // find attachments related to this issue and remove them + var attachments []*repo_model.Attachment + if err := e.In("issue_id", issue.ID). + Find(&attachments); err != nil { + log.Info("Could not find attachments for issue %d: %s", issue.ID, err) + } + + for i := range attachments { + admin_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", attachments[i].RelativePath()) + } + + // delete all database data still assigned to this issue + if err := deleteInIssue(e, issue.ID, &issues.ContentHistory{}, &Comment{}, &IssueLabel{}, @@ -2054,6 +2066,7 @@ func deleteIssue(ctx context.Context, issue *Issue) error { &Stopwatch{}, &TrackedTime{}, &ProjectIssue{}, + &repo_model.Attachment{}, ); err != nil { return err } @@ -2073,21 +2086,6 @@ func deleteIssue(ctx context.Context, issue *Issue) error { return err } - var attachments []*repo_model.Attachment - if err := e.In("issue_id", issue.ID). - Find(&attachments); err != nil { - log.Info("Could not find attachments for issue %d: %s", issue.ID, err) - } - - for i := range attachments { - admin_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", attachments[i].RelativePath()) - } - - if _, err := e.In("issue_id", issue.ID). - Delete(&repo_model.Attachment{}); err != nil { - return err - } - return nil } From cc4fd81ebfde1f84a5d14ab688910f928635eda1 Mon Sep 17 00:00:00 2001 From: fnetx Date: Mon, 28 Feb 2022 15:18:21 +0100 Subject: [PATCH 08/17] Remove in-issue actions from database --- models/issue.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/models/issue.go b/models/issue.go index c276321cf4090..7fd22f1dcd74c 100644 --- a/models/issue.go +++ b/models/issue.go @@ -2042,11 +2042,23 @@ func deleteIssue(ctx context.Context, issue *Issue) error { } } + // delete actions assigned to this issue + var comments []*Comment + if err := e.In("issue_id", issue.ID). + Find(&comments); err != nil { + return err + } + for i := range comments { + if _, err := e.Where("comment_id = ?", comments[i].ID).Cols("is_deleted").Delete(&Action{}); err != nil { + return err + } + } + // find attachments related to this issue and remove them var attachments []*repo_model.Attachment if err := e.In("issue_id", issue.ID). Find(&attachments); err != nil { - log.Info("Could not find attachments for issue %d: %s", issue.ID, err) + return err } for i := range attachments { From 117547b55a759555ba2a75b2b71f9724fbafe864 Mon Sep 17 00:00:00 2001 From: "Otto Richter (fnetX)" Date: Mon, 28 Feb 2022 15:38:06 +0100 Subject: [PATCH 09/17] reqAdmin() for DeleteIssue route Co-authored-by: Gusted --- routers/api/v1/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 54458ceead4de..d4891daef0f76 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -836,7 +836,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route { m.Group("/{index}", func() { m.Combo("").Get(repo.GetIssue). Patch(reqToken(), bind(api.EditIssueOption{}), repo.EditIssue). - Delete(reqToken(), repo.DeleteIssue) + Delete(reqToken(), reqAdmin(), repo.DeleteIssue) m.Group("/comments", func() { m.Combo("").Get(repo.ListIssueComments). Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment) From 879e4f9c8175a416e6b8278a23bff50793ef186b Mon Sep 17 00:00:00 2001 From: "Otto Richter (fnetX)" Date: Mon, 28 Feb 2022 15:39:17 +0100 Subject: [PATCH 10/17] Update routers/api/v1/repo/issue.go Co-authored-by: Gusted --- routers/api/v1/repo/issue.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 49e66d9ff58b0..b2284c05dbef9 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -867,11 +867,6 @@ func DeleteIssue(ctx *context.APIContext) { } func deleteIssue(ctx *context.APIContext) { - if !ctx.IsSigned || !ctx.Repo.IsAdmin() { - ctx.Status(http.StatusForbidden) - return - } - issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { From 7e5e474ff6a034fdf1074ab4787583f94719f8b5 Mon Sep 17 00:00:00 2001 From: fnetx Date: Mon, 28 Feb 2022 16:23:07 +0100 Subject: [PATCH 11/17] Clean up createIssue / createPullRequest actions --- models/issue.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/models/issue.go b/models/issue.go index 7fd22f1dcd74c..33fe4226285ea 100644 --- a/models/issue.go +++ b/models/issue.go @@ -2044,15 +2044,19 @@ func deleteIssue(ctx context.Context, issue *Issue) error { // delete actions assigned to this issue var comments []*Comment - if err := e.In("issue_id", issue.ID). + if err := e.In("issue_id", issue.ID).Cols("id"). Find(&comments); err != nil { return err } for i := range comments { - if _, err := e.Where("comment_id = ?", comments[i].ID).Cols("is_deleted").Delete(&Action{}); err != nil { + if _, err := e.Where("comment_id = ?", comments[i].ID).Delete(&Action{}); err != nil { return err } } + if _, err := e.Table("action").Where("repo_id = ?", issue.RepoID).In("op_type", ActionCreateIssue, ActionCreatePullRequest). + Where("content LIKE ?", strconv.FormatInt(issue.ID, 10)+"|%").Delete(&Action{}); err != nil { + return err + } // find attachments related to this issue and remove them var attachments []*repo_model.Attachment From d19f0575c2228076eec79401d0841be117865208 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 28 Feb 2022 20:38:36 +0100 Subject: [PATCH 12/17] code format nits --- routers/api/v1/repo/issue.go | 5 ----- services/issue/issue.go | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index b2284c05dbef9..9e550c4c4759e 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -862,11 +862,6 @@ func DeleteIssue(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - - deleteIssue(ctx) -} - -func deleteIssue(ctx *context.APIContext) { issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { diff --git a/services/issue/issue.go b/services/issue/issue.go index 5972aefa9b4c8..5e5c49c594f96 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -138,7 +138,7 @@ func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.I if err := issue.LoadPullRequest(); err != nil { return err } - if err := gitRepo.RemoveReference(fmt.Sprintf(git.PullPrefix+"%d", issue.PullRequest.Index)); err != nil { + if err := gitRepo.RemoveReference(fmt.Sprintf("%s%d", git.PullPrefix, issue.PullRequest.Index)); err != nil { return err } } From df8ad3ff3f759d4e2e0ca2e20520779d2b80c113 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 1 Mar 2022 00:05:50 +0100 Subject: [PATCH 13/17] no gitRepo --- modules/nosql/manager_leveldb.go | 1 + modules/notification/base/notifier.go | 3 +-- modules/notification/base/null.go | 3 +-- modules/notification/notification.go | 5 ++--- services/issue/issue.go | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/modules/nosql/manager_leveldb.go b/modules/nosql/manager_leveldb.go index 97f917af78c5c..de4ef14d7dcf4 100644 --- a/modules/nosql/manager_leveldb.go +++ b/modules/nosql/manager_leveldb.go @@ -11,6 +11,7 @@ import ( "strings" "code.gitea.io/gitea/modules/log" + "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" "github.com/syndtr/goleveldb/leveldb/opt" diff --git a/modules/notification/base/notifier.go b/modules/notification/base/notifier.go index 9a7156c7ad139..817474116936d 100644 --- a/modules/notification/base/notifier.go +++ b/modules/notification/base/notifier.go @@ -8,7 +8,6 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/repository" ) @@ -23,7 +22,7 @@ type Notifier interface { NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) NotifyIssueChangeStatus(*user_model.User, *models.Issue, *models.Comment, bool) - NotifyDeleteIssue(*user_model.User, *git.Repository, *models.Issue) + NotifyDeleteIssue(*user_model.User, *models.Issue) NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) diff --git a/modules/notification/base/null.go b/modules/notification/base/null.go index f5a3aab3043aa..2bfcaafda966a 100644 --- a/modules/notification/base/null.go +++ b/modules/notification/base/null.go @@ -8,7 +8,6 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/repository" ) @@ -35,7 +34,7 @@ func (*NullNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *model } // NotifyDeleteIssue notify when some issue deleted -func (*NullNotifier) NotifyDeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.Issue) { +func (*NullNotifier) NotifyDeleteIssue(doer *user_model.User, issue *models.Issue) { } // NotifyNewPullRequest places a place holder function diff --git a/modules/notification/notification.go b/modules/notification/notification.go index 3d5a4674fb8f0..a31e3810e2854 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -8,7 +8,6 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/notification/action" "code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/notification/indexer" @@ -62,9 +61,9 @@ func NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionC } // NotifyDeleteIssue notify when some issue deleted -func NotifyDeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.Issue) { +func NotifyDeleteIssue(doer *user_model.User, issue *models.Issue) { for _, notifier := range notifiers { - notifier.NotifyDeleteIssue(doer, gitRepo, issue) + notifier.NotifyDeleteIssue(doer, issue) } } diff --git a/services/issue/issue.go b/services/issue/issue.go index 5e5c49c594f96..09bd66f2855f8 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -143,7 +143,7 @@ func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.I } } - notification.NotifyDeleteIssue(doer, gitRepo, issue) + notification.NotifyDeleteIssue(doer, issue) return nil } From e4d0163debd07965c86c5140093cd144fccb2d1e Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 1 Mar 2022 00:10:59 +0100 Subject: [PATCH 14/17] load first delete after --- services/issue/issue.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/issue/issue.go b/services/issue/issue.go index 09bd66f2855f8..6e5e4bfd373fb 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -129,15 +129,21 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees // DeleteIssue deletes an issue func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *models.Issue) error { + // load issue before deleting it + if err := issue.LoadAttributes(); err != nil { + return err + } + if err := issue.LoadPullRequest(); err != nil { + return err + } + + // delete entries in database if err := models.DeleteIssue(issue); err != nil { return err } // delete pull request related git data if issue.IsPull { - if err := issue.LoadPullRequest(); err != nil { - return err - } if err := gitRepo.RemoveReference(fmt.Sprintf("%s%d", git.PullPrefix, issue.PullRequest.Index)); err != nil { return err } From 5853e994edee5b0e2c6590aa0f7b529ef810fe13 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 1 Mar 2022 00:14:35 +0100 Subject: [PATCH 15/17] rm pullrequest entry too --- models/issue.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/issue.go b/models/issue.go index 33fe4226285ea..a749facb14b8d 100644 --- a/models/issue.go +++ b/models/issue.go @@ -2083,6 +2083,7 @@ func deleteIssue(ctx context.Context, issue *Issue) error { &TrackedTime{}, &ProjectIssue{}, &repo_model.Attachment{}, + &PullRequest{}, ); err != nil { return err } From fd814736fbfaeb72bb0abb4111812fccc6dfbe7b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 1 Mar 2022 00:21:34 +0100 Subject: [PATCH 16/17] use .Decr --- models/issue.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/models/issue.go b/models/issue.go index a749facb14b8d..3552bfb59fb8e 100644 --- a/models/issue.go +++ b/models/issue.go @@ -2023,20 +2023,20 @@ func deleteIssue(ctx context.Context, issue *Issue) error { } if issue.IsPull { - if _, err := e.Exec("UPDATE `repository` SET num_pulls = num_pulls - 1 WHERE id = ?", issue.RepoID); err != nil { + if _, err := e.ID(issue.RepoID).Decr("num_pulls").Update(new(repo_model.Repository)); err != nil { return err } if issue.IsClosed { - if _, err := e.Exec("UPDATE `repository` SET num_closed_pulls = num_closed_pulls -1 WHERE id = ?", issue.RepoID); err != nil { + if _, err := e.ID(issue.RepoID).Decr("num_closed_pulls").Update(new(repo_model.Repository)); err != nil { return err } } } else { - if _, err := e.Exec("UPDATE `repository` SET num_issues = num_issues - 1 WHERE id = ?", issue.RepoID); err != nil { + if _, err := e.ID(issue.RepoID).Decr("num_issues").Update(new(repo_model.Repository)); err != nil { return err } if issue.IsClosed { - if _, err := e.Exec("UPDATE `repository` SET num_closed_issues = num_closed_issues -1 WHERE id = ?", issue.RepoID); err != nil { + if _, err := e.ID(issue.RepoID).Decr("num_closed_issues").Update(new(repo_model.Repository)); err != nil { return err } } @@ -2060,8 +2060,7 @@ func deleteIssue(ctx context.Context, issue *Issue) error { // find attachments related to this issue and remove them var attachments []*repo_model.Attachment - if err := e.In("issue_id", issue.ID). - Find(&attachments); err != nil { + if err := e.In("issue_id", issue.ID).Find(&attachments); err != nil { return err } From 6e4407a1908448f0b2b87d439c7ddbdec5c3ecff Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 1 Mar 2022 00:56:35 +0100 Subject: [PATCH 17/17] int64 slice --- models/issue.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/models/issue.go b/models/issue.go index 3552bfb59fb8e..625374faaf4ed 100644 --- a/models/issue.go +++ b/models/issue.go @@ -2043,13 +2043,12 @@ func deleteIssue(ctx context.Context, issue *Issue) error { } // delete actions assigned to this issue - var comments []*Comment - if err := e.In("issue_id", issue.ID).Cols("id"). - Find(&comments); err != nil { + var comments []int64 + if err := e.Table(new(Comment)).In("issue_id", issue.ID).Cols("id").Find(&comments); err != nil { return err } for i := range comments { - if _, err := e.Where("comment_id = ?", comments[i].ID).Delete(&Action{}); err != nil { + if _, err := e.Where("comment_id = ?", comments[i]).Delete(&Action{}); err != nil { return err } }