diff options
author | qwerty287 <80460567+qwerty287@users.noreply.github.com> | 2022-04-28 17:45:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-28 17:45:33 +0200 |
commit | 8eb1cd9264af9493e0f57a4a4c0a1f764f7cefcf (patch) | |
tree | 46049742d086daa7683db502883a58e94370a583 /routers/web/repo | |
parent | 92dfbada3793fc2be23d38783d6842eac9825f58 (diff) | |
download | gitea-8eb1cd9264af9493e0f57a4a4c0a1f764f7cefcf.tar.gz gitea-8eb1cd9264af9493e0f57a4a4c0a1f764f7cefcf.zip |
Add "Allow edits from maintainer" feature (#18002)
Adds a feature [like GitHub has](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) (step 7).
If you create a new PR from a forked repo, you can select (and change later, but only if you are the PR creator/poster) the "Allow edits from maintainers" option.
Then users with write access to the base branch get more permissions on this branch:
* use the update pull request button
* push directly from the command line (`git push`)
* edit/delete/upload files via web UI
* use related API endpoints
You can't merge PRs to this branch with this enabled, you'll need "full" code write permissions.
This feature has a pretty big impact on the permission system. I might forgot changing some things or didn't find security vulnerabilities. In this case, please leave a review or comment on this PR.
Closes #17728
Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'routers/web/repo')
-rw-r--r-- | routers/web/repo/compare.go | 2 | ||||
-rw-r--r-- | routers/web/repo/issue.go | 15 | ||||
-rw-r--r-- | routers/web/repo/pull.go | 45 | ||||
-rw-r--r-- | routers/web/repo/view.go | 8 |
4 files changed, 52 insertions, 18 deletions
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 9f7bef43ef..7721507bae 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -398,6 +398,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { } ctx.Data["HeadRepo"] = ci.HeadRepo + ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository // Now we need to assert that the ctx.Doer has permission to read // the baseRepo's code and pulls @@ -436,6 +437,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { ctx.NotFound("ParseCompareInfo", nil) return nil } + ctx.Data["CanWriteToHeadRepo"] = permHead.CanWrite(unit.TypeCode) } // If we have a rootRepo and it's different from: diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 8e865e448f..a54ad3306b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1529,7 +1529,7 @@ func ViewIssue(ctx *context.Context) { if ctx.IsSigned { if err := pull.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) - } else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch { + } else if pull.HeadRepo != nil { perm, err := models.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) @@ -1537,12 +1537,15 @@ func ViewIssue(ctx *context.Context) { } if perm.CanWrite(unit.TypeCode) { // Check if branch is not protected - if protected, err := models.IsProtectedBranch(pull.HeadRepo.ID, pull.HeadBranch); err != nil { - log.Error("IsProtectedBranch: %v", err) - } else if !protected { - canDelete = true - ctx.Data["DeleteBranchLink"] = issue.Link() + "/cleanup" + if pull.HeadBranch != pull.HeadRepo.DefaultBranch { + if protected, err := models.IsProtectedBranch(pull.HeadRepo.ID, pull.HeadBranch); err != nil { + log.Error("IsProtectedBranch: %v", err) + } else if !protected { + canDelete = true + ctx.Data["DeleteBranchLink"] = issue.Link() + "/cleanup" + } } + ctx.Data["CanWriteToHeadRepo"] = true } } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index a03e16f39a..99faa54138 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1132,14 +1132,15 @@ func CompareAndPullRequestPost(ctx *context.Context) { Content: form.Content, } pullRequest := &models.PullRequest{ - HeadRepoID: ci.HeadRepo.ID, - BaseRepoID: repo.ID, - HeadBranch: ci.HeadBranch, - BaseBranch: ci.BaseBranch, - HeadRepo: ci.HeadRepo, - BaseRepo: repo, - MergeBase: ci.CompareInfo.MergeBase, - Type: models.PullRequestGitea, + HeadRepoID: ci.HeadRepo.ID, + BaseRepoID: repo.ID, + HeadBranch: ci.HeadBranch, + BaseBranch: ci.BaseBranch, + HeadRepo: ci.HeadRepo, + BaseRepo: repo, + MergeBase: ci.CompareInfo.MergeBase, + Type: models.PullRequestGitea, + AllowMaintainerEdit: form.AllowMaintainerEdit, } // FIXME: check error in the case two people send pull request at almost same time, give nice error prompt // instead of 500. @@ -1411,3 +1412,31 @@ func UpdatePullRequestTarget(ctx *context.Context) { "base_branch": pr.BaseBranch, }) } + +// SetAllowEdits allow edits from maintainers to PRs +func SetAllowEdits(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.UpdateAllowEditsForm) + + pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrPullRequestNotExist(err) { + ctx.NotFound("GetPullRequestByIndex", err) + } else { + ctx.ServerError("GetPullRequestByIndex", err) + } + return + } + + if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, form.AllowMaintainerEdit); err != nil { + if errors.Is(pull_service.ErrUserHasNoPermissionForAction, err) { + ctx.Error(http.StatusForbidden) + return + } + ctx.ServerError("SetAllowEdits", err) + return + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "allow_maintainer_edit": pr.AllowMaintainerEdit, + }) +} diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 168927d101..86fc36fad7 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -579,7 +579,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["LineEscapeStatus"] = statuses } if !isLFSFile { - if ctx.Repo.CanEnableEditor() { + if ctx.Repo.CanEnableEditor(ctx.Doer) { if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID { ctx.Data["CanEditFile"] = false ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.this_file_locked") @@ -589,7 +589,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } else if !ctx.Repo.IsViewBranch { ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch") - } else if !ctx.Repo.CanWrite(unit_model.TypeCode) { + } else if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.fork_before_edit") } } @@ -629,7 +629,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } - if ctx.Repo.CanEnableEditor() { + if ctx.Repo.CanEnableEditor(ctx.Doer) { if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID { ctx.Data["CanDeleteFile"] = false ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.this_file_locked") @@ -639,7 +639,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } else if !ctx.Repo.IsViewBranch { ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch") - } else if !ctx.Repo.CanWrite(unit_model.TypeCode) { + } else if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_have_write_access") } } |