Changes
11 changed files (+299/-4)
-
-
@@ -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"
-
@@ -1990,6 +1992,118 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *usreturn 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(ctx, issue); err != nil { return err } return committer.Commit() } 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 } } 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 } if issue.IsPull { if _, err := e.ID(issue.RepoID).Decr("num_pulls").Update(new(repo_model.Repository)); err != nil { return err } if issue.IsClosed { if _, err := e.ID(issue.RepoID).Decr("num_closed_pulls").Update(new(repo_model.Repository)); err != nil { return err } } } else { if _, err := e.ID(issue.RepoID).Decr("num_issues").Update(new(repo_model.Repository)); err != nil { return err } if issue.IsClosed { if _, err := e.ID(issue.RepoID).Decr("num_closed_issues").Update(new(repo_model.Repository)); err != nil { return err } } } // delete actions assigned to this issue 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]).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 if err := e.In("issue_id", issue.ID).Find(&attachments); err != nil { return 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{}, &IssueDependency{}, &IssueAssignees{}, &IssueUser{}, &Reaction{}, &IssueWatch{}, &Stopwatch{}, &TrackedTime{}, &ProjectIssue{}, &repo_model.Attachment{}, &PullRequest{}, ); 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 } return nil } // DependencyInfo represents high level information about an issue which is a dependency of another issue. type DependencyInfo struct { Issue `xorm:"extends"`
-
-
-
@@ -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 }
-
-
-
@@ -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())
-
-
-
@@ -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"
-
-
-
@@ -22,6 +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, *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)
-
-
-
@@ -33,6 +33,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, issue *models.Issue) { } // NotifyNewPullRequest places a place holder function func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) { }
-
-
-
@@ -60,6 +60,13 @@ func NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionC} } // NotifyDeleteIssue notify when some issue deleted func NotifyDeleteIssue(doer *user_model.User, issue *models.Issue) { for _, notifier := range notifiers { notifier.NotifyDeleteIssue(doer, issue) } } // NotifyMergePullRequest notifies merge pull request to notifiers func NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) { for _, notifier := range notifiers {
-
-
-
@@ -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(), reqAdmin(), repo.DeleteIssue) m.Group("/comments", func() { m.Combo("").Get(repo.ListIssueComments). Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment)
-
-
-
@@ -834,6 +834,52 @@ 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" issue, err := models.GetIssueByIndex(ctx.Repo.Repository.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, ctx.Repo.GitRepo, 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
-
-
-
@@ -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"
-
@@ -125,6 +127,33 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssigneesreturn } // 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 := gitRepo.RemoveReference(fmt.Sprintf("%s%d", git.PullPrefix, issue.PullRequest.Index)); 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) {
-
-
-
@@ -4966,6 +4966,48 @@} } }, "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": "index of issue to delete", "name": "index", "in": "path", "required": true } ], "responses": { "204": { "$ref": "#/responses/empty" }, "403": { "$ref": "#/responses/forbidden" }, "404": { "$ref": "#/responses/notFound" } } }, "patch": { "consumes": [ "application/json"
-