From 9e0db1b6469079b18cfc4a416cdd6396d42f9816 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Mon, 23 Sep 2024 02:08:27 +0800
Subject: [PATCH] Fix rename branch permission bug (#32066)

The previous implementation requires admin permission to rename branches
which should be write permission.

Fix #31993
---
 routers/web/web.go                      | 3 +--
 templates/repo/branch/list.tmpl         | 2 +-
 tests/integration/rename_branch_test.go | 8 ++++----
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/routers/web/web.go b/routers/web/web.go
index f1e941a84e..5129bd4bda 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1071,8 +1071,6 @@ func registerRoutes(m *web.Router) {
 			m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost)
 		}, repo.MustBeNotEmpty)
 
-		m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.RenameBranchPost)
-
 		m.Group("/tags", func() {
 			m.Get("", repo_setting.ProtectedTags)
 			m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.NewProtectedTagPost)
@@ -1304,6 +1302,7 @@ func registerRoutes(m *web.Router) {
 			}, web.Bind(forms.NewBranchForm{}))
 			m.Post("/delete", repo.DeleteBranchPost)
 			m.Post("/restore", repo.RestoreBranchPost)
+			m.Post("/rename", web.Bind(forms.RenameBranchForm{}), repo_setting.RenameBranchPost)
 		}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
 
 		m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index 3c8e5846d7..f5d709bb16 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -240,7 +240,7 @@
 	<div class="header">
 		{{ctx.Locale.Tr "repo.settings.rename_branch"}}
 	</div>
-	<form class="ui form" action="{{$.Repository.Link}}/settings/rename_branch" method="post">
+	<form class="ui form" action="{{$.Repository.Link}}/branches/rename" method="post">
 		<div class="content">
 			{{.CsrfTokenHtml}}
 			<div class="field default-branch-warning">
diff --git a/tests/integration/rename_branch_test.go b/tests/integration/rename_branch_test.go
index 13f6cf204b..71bfb6b6cb 100644
--- a/tests/integration/rename_branch_test.go
+++ b/tests/integration/rename_branch_test.go
@@ -28,11 +28,11 @@ func testRenameBranch(t *testing.T, u *url.URL) {
 
 	// get branch setting page
 	session := loginUser(t, "user2")
-	req := NewRequest(t, "GET", "/user2/repo1/settings/branches")
+	req := NewRequest(t, "GET", "/user2/repo1/branches")
 	resp := session.MakeRequest(t, req, http.StatusOK)
 	htmlDoc := NewHTMLParser(t, resp.Body)
 
-	req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{
+	req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/rename", map[string]string{
 		"_csrf": htmlDoc.GetCSRF(),
 		"from":  "master",
 		"to":    "main",
@@ -76,7 +76,7 @@ func testRenameBranch(t *testing.T, u *url.URL) {
 	assert.Equal(t, "branch2", branch2.Name)
 
 	// rename branch2 to branch1
-	req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{
+	req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/rename", map[string]string{
 		"_csrf": htmlDoc.GetCSRF(),
 		"from":  "branch2",
 		"to":    "branch1",
@@ -103,7 +103,7 @@ func testRenameBranch(t *testing.T, u *url.URL) {
 	assert.True(t, branch1.IsDeleted) // virtual deletion
 
 	// rename branch2 to branch1 again
-	req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{
+	req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/rename", map[string]string{
 		"_csrf": htmlDoc.GetCSRF(),
 		"from":  "branch2",
 		"to":    "branch1",