diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json index 90133f36ff..0641a32e68 100644 --- a/options/locale_next/locale_en-US.json +++ b/options/locale_next/locale_en-US.json @@ -63,6 +63,7 @@ "repo.issues.filter_modified.hint": "Filter by last modified date", "repo.issues.filter_sort.hint": "Sort by: created/comments/updated/deadline", "issues.updated": "updated %s", + "repo.pulls.auto_merge.no_permission": "You do not have permission to cancel this pull request's auto merge.", "repo.pulls.poster_manage_approval": "Manage approval", "repo.pulls.poster_requires_approval": "Some workflows are waiting to be reviewed.", "repo.pulls.poster_requires_approval.tooltip": "The author of this pull request is not trusted to run workflows triggered by a pull request created from a forked repository or with AGit. The workflows triggered by a `pull_request` event will not run until they are approved.", diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 778a1c17b1..5ae86c5925 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -14,6 +14,7 @@ import ( "forgejo.org/models" activities_model "forgejo.org/models/activities" + "forgejo.org/models/db" git_model "forgejo.org/models/git" issues_model "forgejo.org/models/issues" access_model "forgejo.org/models/perm/access" @@ -1373,33 +1374,18 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { return } - exist, autoMerge, err := pull_model.GetScheduledMergeByPullID(ctx, pull.ID) - if err != nil { - ctx.InternalServerError(err) - return - } - if !exist { - ctx.NotFound() - return - } - - if ctx.Doer.ID != autoMerge.DoerID { - allowed, err := access_model.IsUserRepoAdmin(ctx, ctx.Repo.Repository, ctx.Doer) - if err != nil { - ctx.InternalServerError(err) - return - } - if !allowed { + if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, pull, ctx.Repo.Permission); err != nil { + switch { + case errors.Is(err, util.ErrPermissionDenied): ctx.Error(http.StatusForbidden, "No permission to cancel", "user has no permission to cancel the scheduled auto merge") - return + case db.IsErrNotExist(err): + ctx.NotFound() + default: + ctx.InternalServerError(err) } + return } - - if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, pull); err != nil { - ctx.InternalServerError(err) - } else { - ctx.Status(http.StatusNoContent) - } + ctx.Status(http.StatusNoContent) } // GetPullRequestCommits gets all commits associated with a given PR diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 69710824a4..781a001fba 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1538,17 +1538,22 @@ func CancelAutoMergePullRequest(ctx *context.Context) { return } - if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, issue.PullRequest); err != nil { - if db.IsErrNotExist(err) { + if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, issue.PullRequest, ctx.Repo.Permission); err != nil { + switch { + case errors.Is(err, util.ErrPermissionDenied): + ctx.Flash.Error(ctx.Tr("repo.pulls.auto_merge.no_permission")) + ctx.Redirect(issue.HTMLURL()) + case db.IsErrNotExist(err): ctx.Flash.Error(ctx.Tr("repo.pulls.auto_merge_not_scheduled")) - ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index)) - return + ctx.Redirect(issue.HTMLURL()) + default: + ctx.ServerError("RemoveScheduledAutoMerge", err) } - ctx.ServerError("RemoveScheduledAutoMerge", err) return } + ctx.Flash.Success(ctx.Tr("repo.pulls.auto_merge_canceled_schedule")) - ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index)) + ctx.Redirect(issue.HTMLURL()) } func stopTimerIfAvailable(ctx *context.Context, user *user_model.User, issue *issues_model.Issue) error { diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index 0cdc113379..099d048927 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -20,6 +20,7 @@ import ( "forgejo.org/modules/log" "forgejo.org/modules/process" "forgejo.org/modules/queue" + "forgejo.org/modules/util" notify_service "forgejo.org/services/notify" pull_service "forgejo.org/services/pull" repo_service "forgejo.org/services/repository" @@ -67,7 +68,25 @@ func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_ } // RemoveScheduledAutoMerge cancels a previously scheduled pull request -func RemoveScheduledAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest) error { +func RemoveScheduledAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest, repoPerms access_model.Permission) error { + exist, autoMerge, err := pull_model.GetScheduledMergeByPullID(ctx, pull.ID) + if err != nil { + return err + } + if !exist { + return db.ErrNotExist{Resource: "auto_merge", ID: pull.ID} + } + + if doer.ID != autoMerge.DoerID { + allowed, err := pull_service.IsUserAllowedToMerge(ctx, pull, repoPerms, doer) + if err != nil { + return err + } + if !allowed { + return util.ErrPermissionDenied + } + } + return db.WithTx(ctx, func(ctx context.Context) error { if err := pull_model.DeleteScheduledAutoMerge(ctx, pull.ID); err != nil { return err