Skip to content

Commit bbee652

Browse files
kerwin612lunny
andauthored
Prevent duplicate form submissions when creating forks (#34714)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
1 parent 637070e commit bbee652

File tree

3 files changed

+17
-15
lines changed

3 files changed

+17
-15
lines changed

routers/web/repo/fork.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -151,20 +151,20 @@ func ForkPost(ctx *context.Context) {
151151
ctx.Data["ContextUser"] = ctxUser
152152

153153
if ctx.HasError() {
154-
ctx.HTML(http.StatusOK, tplFork)
154+
ctx.JSONError(ctx.GetErrMsg())
155155
return
156156
}
157157

158158
var err error
159159
traverseParentRepo := forkRepo
160160
for {
161161
if !repository.CanUserForkBetweenOwners(ctxUser.ID, traverseParentRepo.OwnerID) {
162-
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
162+
ctx.JSONError(ctx.Tr("repo.settings.new_owner_has_same_repo"))
163163
return
164164
}
165165
repo := repo_model.GetForkedRepo(ctx, ctxUser.ID, traverseParentRepo.ID)
166166
if repo != nil {
167-
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
167+
ctx.JSONRedirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
168168
return
169169
}
170170
if !traverseParentRepo.IsFork {
@@ -201,32 +201,32 @@ func ForkPost(ctx *context.Context) {
201201
case repo_model.IsErrReachLimitOfRepo(err):
202202
maxCreationLimit := ctxUser.MaxCreationLimit()
203203
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
204-
ctx.RenderWithErr(msg, tplFork, &form)
204+
ctx.JSONError(msg)
205205
case repo_model.IsErrRepoAlreadyExist(err):
206-
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
206+
ctx.JSONError(ctx.Tr("repo.settings.new_owner_has_same_repo"))
207207
case repo_model.IsErrRepoFilesAlreadyExist(err):
208208
switch {
209209
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
210-
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tplFork, form)
210+
ctx.JSONError(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"))
211211
case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
212-
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tplFork, form)
212+
ctx.JSONError(ctx.Tr("form.repository_files_already_exist.adopt"))
213213
case setting.Repository.AllowDeleteOfUnadoptedRepositories:
214-
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tplFork, form)
214+
ctx.JSONError(ctx.Tr("form.repository_files_already_exist.delete"))
215215
default:
216-
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tplFork, form)
216+
ctx.JSONError(ctx.Tr("form.repository_files_already_exist"))
217217
}
218218
case db.IsErrNameReserved(err):
219-
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplFork, &form)
219+
ctx.JSONError(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name))
220220
case db.IsErrNamePatternNotAllowed(err):
221-
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplFork, &form)
221+
ctx.JSONError(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern))
222222
case errors.Is(err, user_model.ErrBlockedUser):
223-
ctx.RenderWithErr(ctx.Tr("repo.fork.blocked_user"), tplFork, form)
223+
ctx.JSONError(ctx.Tr("repo.fork.blocked_user"))
224224
default:
225225
ctx.ServerError("ForkPost", err)
226226
}
227227
return
228228
}
229229

230230
log.Trace("Repository forked[%d]: %s/%s", forkRepo.ID, ctxUser.Name, repo.Name)
231-
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
231+
ctx.JSONRedirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
232232
}

templates/repo/pulls/fork.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</h3>
77
<div class="ui attached segment">
88
{{template "base/alert" .}}
9-
<form class="ui form left-right-form" action="{{.Link}}" method="post">
9+
<form class="ui form form-fetch-action left-right-form" action="{{.Link}}" method="post">
1010
{{.CsrfTokenHtml}}
1111
<div class="inline required field {{if .Err_Owner}}error{{end}}">
1212
<label>{{ctx.Locale.Tr "repo.owner"}}</label>

tests/integration/repo_fork_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"code.gitea.io/gitea/models/unittest"
1616
user_model "code.gitea.io/gitea/models/user"
1717
"code.gitea.io/gitea/modules/structs"
18+
"code.gitea.io/gitea/modules/test"
1819
org_service "code.gitea.io/gitea/services/org"
1920
"code.gitea.io/gitea/tests"
2021

@@ -51,7 +52,8 @@ func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkO
5152
"repo_name": forkRepoName,
5253
"fork_single_branch": forkBranch,
5354
})
54-
session.MakeRequest(t, req, http.StatusSeeOther)
55+
resp = session.MakeRequest(t, req, http.StatusOK)
56+
assert.Equal(t, fmt.Sprintf("/%s/%s", forkOwnerName, forkRepoName), test.RedirectURL(resp))
5557

5658
// Step4: check the existence of the forked repo
5759
req = NewRequestf(t, "GET", "/%s/%s", forkOwnerName, forkRepoName)

0 commit comments

Comments
 (0)