Skip to content

Commit f29e486

Browse files
committed
Move fork to edit logic to a separate file
1 parent 4da881b commit f29e486

File tree

4 files changed

+263
-240
lines changed

4 files changed

+263
-240
lines changed

routers/web/repo/editor.go

Lines changed: 14 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,13 @@ import (
1111
"strings"
1212

1313
git_model "code.gitea.io/gitea/models/git"
14-
access_model "code.gitea.io/gitea/models/perm/access"
1514
repo_model "code.gitea.io/gitea/models/repo"
1615
"code.gitea.io/gitea/models/unit"
1716
"code.gitea.io/gitea/modules/charset"
1817
"code.gitea.io/gitea/modules/git"
19-
"code.gitea.io/gitea/modules/gitrepo"
2018
"code.gitea.io/gitea/modules/json"
2119
"code.gitea.io/gitea/modules/log"
2220
"code.gitea.io/gitea/modules/markup"
23-
repo_module "code.gitea.io/gitea/modules/repository"
2421
"code.gitea.io/gitea/modules/setting"
2522
"code.gitea.io/gitea/modules/templates"
2623
"code.gitea.io/gitea/modules/typesniffer"
@@ -30,7 +27,6 @@ import (
3027
"code.gitea.io/gitea/services/context"
3128
"code.gitea.io/gitea/services/context/upload"
3229
"code.gitea.io/gitea/services/forms"
33-
repo_service "code.gitea.io/gitea/services/repository"
3430
files_service "code.gitea.io/gitea/services/repository/files"
3531
)
3632

@@ -39,7 +35,6 @@ const (
3935
tplEditDiffPreview templates.TplName = "repo/editor/diff_preview"
4036
tplDeleteFile templates.TplName = "repo/editor/delete"
4137
tplUploadFile templates.TplName = "repo/editor/upload"
42-
tplForkFile templates.TplName = "repo/editor/fork"
4338

4439
frmCommitChoiceDirect string = "direct"
4540
frmCommitChoiceNewBranch string = "commit-to-new-branch"
@@ -117,201 +112,6 @@ func getParentTreeFields(treePath string) (treeNames, treePaths []string) {
117112
return treeNames, treePaths
118113
}
119114

120-
// getEditRepository returns the repository where the actual edits will be written to.
121-
// This may be a fork of the repository owned by the user. If no repository can be found
122-
// for editing, nil is returned along with a message explaining why editing is not possible.
123-
func getEditRepository(ctx *context.Context) (*repo_model.Repository, any) {
124-
if context.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.BranchName) {
125-
return ctx.Repo.Repository, nil
126-
}
127-
128-
// If we can't write to the branch, try find a user fork to create a branch in instead
129-
userRepo, err := repo_model.GetUserFork(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID)
130-
if err != nil {
131-
log.Error("GetUserFork: %v", err)
132-
return nil, nil
133-
}
134-
if userRepo == nil {
135-
return nil, nil
136-
}
137-
138-
// Load repository information
139-
if err := userRepo.LoadOwner(ctx); err != nil {
140-
log.Error("LoadOwner: %v", err)
141-
return nil, ctx.Tr("repo.editor.fork_internal_error", userRepo.FullName())
142-
}
143-
if err := userRepo.GetBaseRepo(ctx); err != nil || userRepo.BaseRepo == nil {
144-
if err != nil {
145-
log.Error("GetBaseRepo: %v", err)
146-
} else {
147-
log.Error("GetBaseRepo: Expected a base repo for user fork", err)
148-
}
149-
return nil, ctx.Tr("repo.editor.fork_internal_error", userRepo.FullName())
150-
}
151-
152-
// Check code unit, archiving and permissions.
153-
if !userRepo.UnitEnabled(ctx, unit.TypeCode) {
154-
return nil, ctx.Tr("repo.editor.fork_code_disabled", userRepo.FullName())
155-
}
156-
if userRepo.IsArchived {
157-
return nil, ctx.Tr("repo.editor.fork_is_archived", userRepo.FullName())
158-
}
159-
permission, err := access_model.GetUserRepoPermission(ctx, userRepo, ctx.Doer)
160-
if err != nil {
161-
log.Error("access_model.GetUserRepoPermission: %v", err)
162-
return nil, ctx.Tr("repo.editor.fork_internal_error", userRepo.FullName())
163-
}
164-
if !permission.CanWrite(unit.TypeCode) {
165-
return nil, ctx.Tr("repo.editor.fork_no_permission", userRepo.FullName())
166-
}
167-
168-
ctx.Data["ForkRepo"] = userRepo
169-
return userRepo, nil
170-
}
171-
172-
// GetEditRepository returns the repository where the edits will be written to.
173-
// If no repository is editable, redirects to a page to create a fork.
174-
func GetEditRepositoryOrFork(ctx *context.Context, editOperation string) *repo_model.Repository {
175-
editRepo, notEditableMessage := getEditRepository(ctx)
176-
if editRepo != nil {
177-
return editRepo
178-
}
179-
180-
// No editable repository, suggest to create a fork
181-
forkToEditFileCommon(ctx, editOperation, ctx.Repo.TreePath, notEditableMessage)
182-
ctx.HTML(http.StatusOK, tplForkFile)
183-
return nil
184-
}
185-
186-
// GetEditRepository returns the repository where the edits will be written to.
187-
// If no repository is editable, display an error.
188-
func GetEditRepositoryOrError(ctx *context.Context, tpl templates.TplName, form any) *repo_model.Repository {
189-
editRepo, _ := getEditRepository(ctx)
190-
if editRepo == nil {
191-
// No editable repo, maybe the fork was deleted in the meantime
192-
ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_find_editable_repo"), tpl, form)
193-
return nil
194-
}
195-
return editRepo
196-
}
197-
198-
// CheckPushEditBranch chesk if pushing to the branch in the edit repository is possible,
199-
// and if not renders an error and returns false.
200-
func CheckCanPushEditBranch(ctx *context.Context, editRepo *repo_model.Repository, branchName string, tpl templates.TplName, form any) bool {
201-
// When pushing to a fork or another branch on the same repository, it should not exist yet
202-
if ctx.Repo.Repository != editRepo || ctx.Repo.BranchName != branchName {
203-
if exist, err := git_model.IsBranchExist(ctx, editRepo.ID, branchName); err == nil && exist {
204-
ctx.Data["Err_NewBranchName"] = true
205-
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), tpl, form)
206-
return false
207-
}
208-
}
209-
210-
// Check for protected branch
211-
canCommitToBranch, err := context.CanCommitToBranch(ctx, ctx.Doer, editRepo, branchName)
212-
if err != nil {
213-
log.Error("CanCommitToBranch: %v", err)
214-
}
215-
if !canCommitToBranch.CanCommitToBranch {
216-
ctx.Data["Err_NewBranchName"] = true
217-
ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tpl, form)
218-
return false
219-
}
220-
221-
return true
222-
}
223-
224-
// PushEditBranchOrError pushes the branch that editing will be applied on top of
225-
// to the user fork, if needed. On failure, it displays and returns an error. The
226-
// branch name to be used for editing is returned.
227-
func PushEditBranchOrError(ctx *context.Context, editRepo *repo_model.Repository, branchName string, tpl templates.TplName, form any) (string, error) {
228-
if editRepo == ctx.Repo.Repository {
229-
return ctx.Repo.BranchName, nil
230-
}
231-
232-
// If editing a user fork, first push the branch to that repository
233-
baseRepo := ctx.Repo.Repository
234-
baseBranchName := ctx.Repo.BranchName
235-
236-
log.Trace("pushBranchToUserRepo: pushing branch to user repo for editing: %s:%s %s:%s", baseRepo.FullName(), baseBranchName, editRepo.FullName(), branchName)
237-
238-
if err := git.Push(ctx, baseRepo.RepoPath(), git.PushOptions{
239-
Remote: editRepo.RepoPath(),
240-
Branch: baseBranchName + ":" + branchName,
241-
Env: repo_module.PushingEnvironment(ctx.Doer, editRepo),
242-
}); err != nil {
243-
ctx.RenderWithErr(ctx.Tr("repo.editor.fork_failed_to_push_branch", branchName), tpl, form)
244-
return "", nil
245-
}
246-
247-
return branchName, nil
248-
}
249-
250-
// UpdateEditRepositoryIsEmpty updates the the edit repository to mark it as no longer empty
251-
func UpdateEditRepositoryIsEmpty(ctx *context.Context, editRepo *repo_model.Repository) {
252-
if !editRepo.IsEmpty {
253-
return
254-
}
255-
256-
editGitRepo, err := gitrepo.OpenRepository(git.DefaultContext, editRepo)
257-
if err != nil {
258-
log.Error("gitrepo.OpenRepository: %v", err)
259-
return
260-
}
261-
if editGitRepo == nil {
262-
return
263-
}
264-
265-
if isEmpty, err := editGitRepo.IsEmpty(); err == nil && !isEmpty {
266-
_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: editRepo.ID, IsEmpty: false}, "is_empty")
267-
}
268-
editGitRepo.Close()
269-
}
270-
271-
func forkToEditFileCommon(ctx *context.Context, editOperation, treePath string, notEditableMessage any) {
272-
// Check if the filename (and additional path) is specified in the querystring
273-
// (filename is a misnomer, but kept for compatibility with GitHub)
274-
filePath, _ := path.Split(ctx.Req.URL.Query().Get("filename"))
275-
filePath = strings.Trim(filePath, "/")
276-
treeNames, treePaths := getParentTreeFields(path.Join(ctx.Repo.TreePath, filePath))
277-
278-
ctx.Data["EditOperation"] = editOperation
279-
ctx.Data["TreePath"] = treePath
280-
ctx.Data["TreeNames"] = treeNames
281-
ctx.Data["TreePaths"] = treePaths
282-
ctx.Data["CanForkRepo"] = notEditableMessage == nil
283-
ctx.Data["NotEditableMessage"] = notEditableMessage
284-
}
285-
286-
func ForkToEditFilePost(ctx *context.Context) {
287-
form := web.GetForm(ctx).(*forms.ForkToEditRepoFileForm)
288-
289-
editRepo, notEditableMessage := getEditRepository(ctx)
290-
291-
ctx.Data["PageHasPosted"] = true
292-
293-
// Fork repository, if it doesn't already exist
294-
if editRepo == nil && notEditableMessage == nil {
295-
_, err := ForkRepository(ctx, ctx.Doer, repo_service.ForkRepoOptions{
296-
BaseRepo: ctx.Repo.Repository,
297-
Name: GetUniqueRepositoryName(ctx, ctx.Repo.Repository.Name),
298-
Description: ctx.Repo.Repository.Description,
299-
SingleBranch: ctx.Repo.BranchName,
300-
}, tplForkFile, form)
301-
if err != nil {
302-
forkToEditFileCommon(ctx, form.EditOperation, form.TreePath, notEditableMessage)
303-
ctx.HTML(http.StatusOK, tplForkFile)
304-
return
305-
}
306-
}
307-
308-
// Redirect back to editing page
309-
ctx.Redirect(path.Join(ctx.Repo.RepoLink, form.EditOperation, util.PathEscapeSegments(ctx.Repo.BranchName), util.PathEscapeSegments(form.TreePath)))
310-
}
311-
312-
// editFileCommon setup common context, and return repository that will be edited.
313-
// If no repository can be found for editing, nil is returned along with a message
314-
// explaining why editing is not possible.
315115
func editFileCommon(ctx *context.Context, isNewFile bool) {
316116
ctx.Data["PageIsEdit"] = true
317117
ctx.Data["IsNewFile"] = isNewFile
@@ -323,7 +123,7 @@ func editFileCommon(ctx *context.Context, isNewFile bool) {
323123
}
324124

325125
func editFile(ctx *context.Context, isNewFile bool) {
326-
editRepo := GetEditRepositoryOrFork(ctx, util.Iif(isNewFile, "_new", "_edit"))
126+
editRepo := getEditRepositoryOrFork(ctx, util.Iif(isNewFile, "_new", "_edit"))
327127
if editRepo == nil {
328128
return
329129
}
@@ -464,15 +264,15 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
464264
return
465265
}
466266

467-
editRepo := GetEditRepositoryOrError(ctx, tplEditFile, &form)
267+
editRepo := getEditRepositoryOrError(ctx, tplEditFile, &form)
468268
if editRepo == nil {
469269
return
470270
}
471271

472272
renderCommitRights(ctx, editRepo)
473273

474274
// Cannot commit to an existing branch if user doesn't have rights
475-
if !CheckCanPushEditBranch(ctx, editRepo, branchName, tplEditFile, &form) {
275+
if !canPushToEditRepository(ctx, editRepo, branchName, tplEditFile, &form) {
476276
return
477277
}
478278

@@ -503,7 +303,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
503303
operation = "create"
504304
}
505305

506-
editBranchName, err := PushEditBranchOrError(ctx, editRepo, branchName, tplEditFile, &form)
306+
editBranchName, err := pushToEditRepositoryOrError(ctx, editRepo, branchName, tplEditFile, &form)
507307
if err != nil {
508308
return
509309
}
@@ -602,7 +402,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
602402
}
603403
}
604404

605-
UpdateEditRepositoryIsEmpty(ctx, editRepo)
405+
updateEditRepositoryIsEmpty(ctx, editRepo)
606406

607407
redirectForCommitChoice(ctx, editRepo, form.CommitChoice, branchName, form.TreePath)
608408
}
@@ -652,7 +452,7 @@ func DiffPreviewPost(ctx *context.Context) {
652452

653453
// DeleteFile render delete file page
654454
func DeleteFile(ctx *context.Context) {
655-
editRepo := GetEditRepositoryOrFork(ctx, "_delete")
455+
editRepo := getEditRepositoryOrFork(ctx, "_delete")
656456
if editRepo == nil {
657457
return
658458
}
@@ -704,15 +504,15 @@ func DeleteFilePost(ctx *context.Context) {
704504
return
705505
}
706506

707-
editRepo := GetEditRepositoryOrError(ctx, tplDeleteFile, &form)
507+
editRepo := getEditRepositoryOrError(ctx, tplDeleteFile, &form)
708508
if editRepo == nil {
709509
return
710510
}
711511

712512
renderCommitRights(ctx, editRepo)
713513

714514
// Cannot commit to an existing branch if user doesn't have rights
715-
if !CheckCanPushEditBranch(ctx, editRepo, branchName, tplDeleteFile, &form) {
515+
if !canPushToEditRepository(ctx, editRepo, branchName, tplDeleteFile, &form) {
716516
return
717517
}
718518

@@ -732,7 +532,7 @@ func DeleteFilePost(ctx *context.Context) {
732532
return
733533
}
734534

735-
editBranchName, err := PushEditBranchOrError(ctx, editRepo, branchName, tplDeleteFile, &form)
535+
editBranchName, err := pushToEditRepositoryOrError(ctx, editRepo, branchName, tplDeleteFile, &form)
736536
if err != nil {
737537
return
738538
}
@@ -834,7 +634,7 @@ func DeleteFilePost(ctx *context.Context) {
834634

835635
// UploadFile render upload file page
836636
func UploadFile(ctx *context.Context) {
837-
editRepo := GetEditRepositoryOrFork(ctx, "_upload")
637+
editRepo := getEditRepositoryOrFork(ctx, "_upload")
838638
if editRepo == nil {
839639
return
840640
}
@@ -903,14 +703,14 @@ func UploadFilePost(ctx *context.Context) {
903703
return
904704
}
905705

906-
editRepo := GetEditRepositoryOrError(ctx, tplUploadFile, &form)
706+
editRepo := getEditRepositoryOrError(ctx, tplUploadFile, &form)
907707
if editRepo == nil {
908708
return
909709
}
910710

911711
renderCommitRights(ctx, editRepo)
912712

913-
if !CheckCanPushEditBranch(ctx, editRepo, branchName, tplUploadFile, &form) {
713+
if !canPushToEditRepository(ctx, editRepo, branchName, tplUploadFile, &form) {
914714
return
915715
}
916716

@@ -957,7 +757,7 @@ func UploadFilePost(ctx *context.Context) {
957757
return
958758
}
959759

960-
editBranchName, err := PushEditBranchOrError(ctx, editRepo, branchName, tplUploadFile, &form)
760+
editBranchName, err := pushToEditRepositoryOrError(ctx, editRepo, branchName, tplUploadFile, &form)
961761
if err != nil {
962762
return
963763
}
@@ -1029,7 +829,7 @@ func UploadFilePost(ctx *context.Context) {
1029829
return
1030830
}
1031831

1032-
UpdateEditRepositoryIsEmpty(ctx, editRepo)
832+
updateEditRepositoryIsEmpty(ctx, editRepo)
1033833

1034834
redirectForCommitChoice(ctx, editRepo, form.CommitChoice, branchName, form.TreePath)
1035835
}
@@ -1122,23 +922,6 @@ func GetUniquePatchBranchName(ctx *context.Context, editRepo *repo_model.Reposit
1122922
return ""
1123923
}
1124924

1125-
// GetUniqueRepositoryName Gets a unique repository name for a user
1126-
// It will append a -<num> postfix if the name is already taken
1127-
func GetUniqueRepositoryName(ctx *context.Context, name string) string {
1128-
uniqueName := name
1129-
i := 1
1130-
1131-
for {
1132-
_, err := repo_model.GetRepositoryByName(ctx, ctx.Doer.ID, uniqueName)
1133-
if err != nil || repo_model.IsErrRepoNotExist(err) {
1134-
return uniqueName
1135-
}
1136-
1137-
uniqueName = fmt.Sprintf("%s-%d", name, i)
1138-
i++
1139-
}
1140-
}
1141-
1142925
// GetClosestParentWithFiles Recursively gets the path of parent in a tree that has files (used when file in a tree is
1143926
// deleted). Returns "" for the root if no parents other than the root have files. If the given treePath isn't a
1144927
// SubTree or it has no entries, we go up one dir and see if we can return the user to that listing.

0 commit comments

Comments
 (0)