mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Make URL scheme unambiguous (#2408)
* Make URL scheme unambiguous Redirect old routes to new routes * Fix redirects to new URL scheme, and update template * Fix branches/_new endpoints, and update integration test
This commit is contained in:
		@@ -111,7 +111,7 @@ func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePa
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusFound)
 | 
						resp = session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Verify the change
 | 
						// Verify the change
 | 
				
			||||||
	req = NewRequest(t, "GET", path.Join(user, repo, "raw", branch, filePath))
 | 
						req = NewRequest(t, "GET", path.Join(user, repo, "raw/branch", branch, filePath))
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	assert.EqualValues(t, newContent, string(resp.Body))
 | 
						assert.EqualValues(t, newContent, string(resp.Body))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,7 +142,7 @@ func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, bra
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusFound)
 | 
						resp = session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Verify the change
 | 
						// Verify the change
 | 
				
			||||||
	req = NewRequest(t, "GET", path.Join(user, repo, "raw", targetBranch, filePath))
 | 
						req = NewRequest(t, "GET", path.Join(user, repo, "raw/branch", targetBranch, filePath))
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	assert.EqualValues(t, newContent, string(resp.Body))
 | 
						assert.EqualValues(t, newContent, string(resp.Body))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	api "code.gitea.io/sdk/gitea"
 | 
						api "code.gitea.io/sdk/gitea"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestLinksNoLogin(t *testing.T) {
 | 
					func TestLinksNoLogin(t *testing.T) {
 | 
				
			||||||
@@ -38,6 +40,20 @@ func TestLinksNoLogin(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRedirectsNoLogin(t *testing.T) {
 | 
				
			||||||
 | 
						prepareTestEnv(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var redirects = map[string]string{
 | 
				
			||||||
 | 
							"/user2/repo1/commits/master": "/user2/repo1/commits/branch/master",
 | 
				
			||||||
 | 
							"/user2/repo1/src/master":     "/user2/repo1/src/branch/master",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for link, redirectLink := range redirects {
 | 
				
			||||||
 | 
							req := NewRequest(t, "GET", link)
 | 
				
			||||||
 | 
							resp := MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
							assert.EqualValues(t, redirectLink, RedirectURL(t, resp))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testLinksAsUser(userName string, t *testing.T) {
 | 
					func testLinksAsUser(userName string, t *testing.T) {
 | 
				
			||||||
	var links = []string{
 | 
						var links = []string{
 | 
				
			||||||
		"/explore/repos",
 | 
							"/explore/repos",
 | 
				
			||||||
@@ -99,7 +115,7 @@ func testLinksAsUser(userName string, t *testing.T) {
 | 
				
			|||||||
		"",
 | 
							"",
 | 
				
			||||||
		"/issues",
 | 
							"/issues",
 | 
				
			||||||
		"/pulls",
 | 
							"/pulls",
 | 
				
			||||||
		"/commits/master",
 | 
							"/commits/branch/master",
 | 
				
			||||||
		"/graph",
 | 
							"/graph",
 | 
				
			||||||
		"/settings",
 | 
							"/settings",
 | 
				
			||||||
		"/settings/collaboration",
 | 
							"/settings/collaboration",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,14 +14,14 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testCreateBranch(t *testing.T, session *TestSession, user, repo, oldRefName, newBranchName string, expectedStatus int) string {
 | 
					func testCreateBranch(t *testing.T, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string {
 | 
				
			||||||
	var csrf string
 | 
						var csrf string
 | 
				
			||||||
	if expectedStatus == http.StatusNotFound {
 | 
						if expectedStatus == http.StatusNotFound {
 | 
				
			||||||
		csrf = GetCSRF(t, session, path.Join(user, repo, "src/master"))
 | 
							csrf = GetCSRF(t, session, path.Join(user, repo, "src/branch/master"))
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		csrf = GetCSRF(t, session, path.Join(user, repo, "src", oldRefName))
 | 
							csrf = GetCSRF(t, session, path.Join(user, repo, "src", oldRefSubURL))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefName), map[string]string{
 | 
						req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{
 | 
				
			||||||
		"_csrf":           csrf,
 | 
							"_csrf":           csrf,
 | 
				
			||||||
		"new_branch_name": newBranchName,
 | 
							"new_branch_name": newBranchName,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -34,68 +34,68 @@ func testCreateBranch(t *testing.T, session *TestSession, user, repo, oldRefName
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestCreateBranch(t *testing.T) {
 | 
					func TestCreateBranch(t *testing.T) {
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		OldBranchOrCommit string
 | 
							OldRefSubURL   string
 | 
				
			||||||
		NewBranch      string
 | 
							NewBranch      string
 | 
				
			||||||
		CreateRelease  string
 | 
							CreateRelease  string
 | 
				
			||||||
		FlashMessage   string
 | 
							FlashMessage   string
 | 
				
			||||||
		ExpectedStatus int
 | 
							ExpectedStatus int
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      "feature/test1",
 | 
								NewBranch:      "feature/test1",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "repo.branch.create_success", "feature/test1"),
 | 
								FlashMessage:   i18n.Tr("en", "repo.branch.create_success", "feature/test1"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      "",
 | 
								NewBranch:      "",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.require_error"),
 | 
								FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.require_error"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      "feature=test1",
 | 
								NewBranch:      "feature=test1",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.git_ref_name_error"),
 | 
								FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.git_ref_name_error"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      strings.Repeat("b", 101),
 | 
								NewBranch:      strings.Repeat("b", 101),
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.max_size_error", "100"),
 | 
								FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.max_size_error", "100"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      "master",
 | 
								NewBranch:      "master",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "repo.branch.branch_already_exists", "master"),
 | 
								FlashMessage:   i18n.Tr("en", "repo.branch.branch_already_exists", "master"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      "master/test",
 | 
								NewBranch:      "master/test",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "repo.branch.branch_name_conflict", "master/test", "master"),
 | 
								FlashMessage:   i18n.Tr("en", "repo.branch.branch_name_conflict", "master/test", "master"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "acd1d892867872cb47f3993468605b8aa59aa2e0",
 | 
								OldRefSubURL:   "commit/acd1d892867872cb47f3993468605b8aa59aa2e0",
 | 
				
			||||||
			NewBranch:      "feature/test2",
 | 
								NewBranch:      "feature/test2",
 | 
				
			||||||
			ExpectedStatus: http.StatusNotFound,
 | 
								ExpectedStatus: http.StatusNotFound,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
								OldRefSubURL:   "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
			NewBranch:      "feature/test3",
 | 
								NewBranch:      "feature/test3",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "repo.branch.create_success", "feature/test3"),
 | 
								FlashMessage:   i18n.Tr("en", "repo.branch.create_success", "feature/test3"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "master",
 | 
								OldRefSubURL:   "branch/master",
 | 
				
			||||||
			NewBranch:      "v1.0.0",
 | 
								NewBranch:      "v1.0.0",
 | 
				
			||||||
			CreateRelease:  "v1.0.0",
 | 
								CreateRelease:  "v1.0.0",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
			FlashMessage:   i18n.Tr("en", "repo.branch.tag_collision", "v1.0.0"),
 | 
								FlashMessage:   i18n.Tr("en", "repo.branch.tag_collision", "v1.0.0"),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			OldBranchOrCommit: "v1.0.0",
 | 
								OldRefSubURL:   "tag/v1.0.0",
 | 
				
			||||||
			NewBranch:      "feature/test4",
 | 
								NewBranch:      "feature/test4",
 | 
				
			||||||
			CreateRelease:  "v1.0.0",
 | 
								CreateRelease:  "v1.0.0",
 | 
				
			||||||
			ExpectedStatus: http.StatusFound,
 | 
								ExpectedStatus: http.StatusFound,
 | 
				
			||||||
@@ -108,7 +108,7 @@ func TestCreateBranch(t *testing.T) {
 | 
				
			|||||||
		if test.CreateRelease != "" {
 | 
							if test.CreateRelease != "" {
 | 
				
			||||||
			createNewRelease(t, session, "/user2/repo1", test.CreateRelease, test.CreateRelease, false, false)
 | 
								createNewRelease(t, session, "/user2/repo1", test.CreateRelease, test.CreateRelease, false, false)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		redirectURL := testCreateBranch(t, session, "user2", "repo1", test.OldBranchOrCommit, test.NewBranch, test.ExpectedStatus)
 | 
							redirectURL := testCreateBranch(t, session, "user2", "repo1", test.OldRefSubURL, test.NewBranch, test.ExpectedStatus)
 | 
				
			||||||
		if test.ExpectedStatus == http.StatusFound {
 | 
							if test.ExpectedStatus == http.StatusFound {
 | 
				
			||||||
			req := NewRequest(t, "GET", redirectURL)
 | 
								req := NewRequest(t, "GET", redirectURL)
 | 
				
			||||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
@@ -124,7 +124,7 @@ func TestCreateBranch(t *testing.T) {
 | 
				
			|||||||
func TestCreateBranchInvalidCSRF(t *testing.T) {
 | 
					func TestCreateBranchInvalidCSRF(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						prepareTestEnv(t)
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", "user2/repo1/branches/_new/master", map[string]string{
 | 
						req := NewRequestWithValues(t, "POST", "user2/repo1/branches/_new/branch/master", map[string]string{
 | 
				
			||||||
		"_csrf":           "fake_csrf",
 | 
							"_csrf":           "fake_csrf",
 | 
				
			||||||
		"new_branch_name": "test",
 | 
							"new_branch_name": "test",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ func TestRepoCommits(t *testing.T) {
 | 
				
			|||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Request repository commits page
 | 
						// Request repository commits page
 | 
				
			||||||
	req := NewRequest(t, "GET", "/user2/repo1/commits/master")
 | 
						req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	doc := NewHTMLParser(t, resp.Body)
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
@@ -35,7 +35,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
				
			|||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Request repository commits page
 | 
						// Request repository commits page
 | 
				
			||||||
	req := NewRequest(t, "GET", "/user2/repo1/commits/master")
 | 
						req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	doc := NewHTMLParser(t, resp.Body)
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
@@ -56,7 +56,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusCreated)
 | 
						resp = session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req = NewRequest(t, "GET", "/user2/repo1/commits/master")
 | 
						req = NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	doc = NewHTMLParser(t, resp.Body)
 | 
						doc = NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,12 +80,22 @@ func SlackLinkFormatter(url string, text string) string {
 | 
				
			|||||||
	return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
 | 
						return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
					// SlackLinkToRef slack-formatter link to a repo ref
 | 
				
			||||||
	// created tag/branch
 | 
					func SlackLinkToRef(repoURL, ref string) string {
 | 
				
			||||||
	refName := git.RefEndName(p.Ref)
 | 
						refName := git.RefEndName(ref)
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case strings.HasPrefix(ref, git.BranchPrefix):
 | 
				
			||||||
 | 
							return SlackLinkFormatter(repoURL+"/src/branch/"+refName, refName)
 | 
				
			||||||
 | 
						case strings.HasPrefix(ref, git.TagPrefix):
 | 
				
			||||||
 | 
							return SlackLinkFormatter(repoURL+"/src/tag/"+refName, refName)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return SlackLinkFormatter(repoURL+"/src/commit/"+refName, refName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
				
			||||||
	repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
 | 
						repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
 | 
				
			||||||
	refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
 | 
						refLink := SlackLinkToRef(p.Repo.HTMLURL, p.Ref)
 | 
				
			||||||
	text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
 | 
						text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &SlackPayload{
 | 
						return &SlackPayload{
 | 
				
			||||||
@@ -99,7 +109,6 @@ func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayloa
 | 
				
			|||||||
func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
					func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
				
			||||||
	// n new commits
 | 
						// n new commits
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		branchName   = git.RefEndName(p.Ref)
 | 
					 | 
				
			||||||
		commitDesc   string
 | 
							commitDesc   string
 | 
				
			||||||
		commitString string
 | 
							commitString string
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
@@ -116,7 +125,7 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
 | 
						repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
 | 
				
			||||||
	branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
 | 
						branchLink := SlackLinkToRef(p.Repo.HTMLURL, p.Ref)
 | 
				
			||||||
	text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName)
 | 
						text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var attachmentText string
 | 
						var attachmentText string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/git"
 | 
						"code.gitea.io/git"
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/cache"
 | 
						"code.gitea.io/gitea/modules/cache"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
						"github.com/Unknwon/com"
 | 
				
			||||||
@@ -117,6 +118,20 @@ func (r *Repository) GetCommitsCount() (int64, error) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BranchNameSubURL sub-URL for the BranchName field
 | 
				
			||||||
 | 
					func (r *Repository) BranchNameSubURL() string {
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case r.IsViewBranch:
 | 
				
			||||||
 | 
							return "branch/" + r.BranchName
 | 
				
			||||||
 | 
						case r.IsViewTag:
 | 
				
			||||||
 | 
							return "tag/" + r.BranchName
 | 
				
			||||||
 | 
						case r.IsViewCommit:
 | 
				
			||||||
 | 
							return "commit/" + r.BranchName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						log.Error(4, "Unknown view type for repo: %v", r)
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetEditorconfig returns the .editorconfig definition if found in the
 | 
					// GetEditorconfig returns the .editorconfig definition if found in the
 | 
				
			||||||
// HEAD of the default repo branch.
 | 
					// HEAD of the default repo branch.
 | 
				
			||||||
func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
 | 
					func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
 | 
				
			||||||
@@ -444,8 +459,81 @@ func RepoAssignment() macaron.Handler {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RepoRef handles repository reference name including those contain `/`.
 | 
					// RepoRefType type of repo reference
 | 
				
			||||||
 | 
					type RepoRefType int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// RepoRefLegacy unknown type, make educated guess and redirect.
 | 
				
			||||||
 | 
						// for backward compatibility with previous URL scheme
 | 
				
			||||||
 | 
						RepoRefLegacy RepoRefType = iota
 | 
				
			||||||
 | 
						// RepoRefBranch branch
 | 
				
			||||||
 | 
						RepoRefBranch
 | 
				
			||||||
 | 
						// RepoRefTag tag
 | 
				
			||||||
 | 
						RepoRefTag
 | 
				
			||||||
 | 
						// RepoRefCommit commit
 | 
				
			||||||
 | 
						RepoRefCommit
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RepoRef handles repository reference names when the ref name is not
 | 
				
			||||||
 | 
					// explicitly given
 | 
				
			||||||
func RepoRef() macaron.Handler {
 | 
					func RepoRef() macaron.Handler {
 | 
				
			||||||
 | 
						// since no ref name is explicitly specified, ok to just use branch
 | 
				
			||||||
 | 
						return RepoRefByType(RepoRefBranch)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getRefNameFromPath(ctx *Context, path string, isExist func(string) bool) string {
 | 
				
			||||||
 | 
						refName := ""
 | 
				
			||||||
 | 
						parts := strings.Split(path, "/")
 | 
				
			||||||
 | 
						for i, part := range parts {
 | 
				
			||||||
 | 
							refName = strings.TrimPrefix(refName+"/"+part, "/")
 | 
				
			||||||
 | 
							if isExist(refName) {
 | 
				
			||||||
 | 
								ctx.Repo.TreePath = strings.Join(parts[i+1:], "/")
 | 
				
			||||||
 | 
								return refName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getRefName(ctx *Context, pathType RepoRefType) string {
 | 
				
			||||||
 | 
						path := ctx.Params("*")
 | 
				
			||||||
 | 
						switch pathType {
 | 
				
			||||||
 | 
						case RepoRefLegacy:
 | 
				
			||||||
 | 
							if refName := getRefName(ctx, RepoRefBranch); len(refName) > 0 {
 | 
				
			||||||
 | 
								return refName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if refName := getRefName(ctx, RepoRefTag); len(refName) > 0 {
 | 
				
			||||||
 | 
								return refName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return getRefName(ctx, RepoRefCommit)
 | 
				
			||||||
 | 
						case RepoRefBranch:
 | 
				
			||||||
 | 
							return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsBranchExist)
 | 
				
			||||||
 | 
						case RepoRefTag:
 | 
				
			||||||
 | 
							return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
 | 
				
			||||||
 | 
						case RepoRefCommit:
 | 
				
			||||||
 | 
							parts := strings.Split(path, "/")
 | 
				
			||||||
 | 
							if len(parts) > 0 && len(parts[0]) == 40 {
 | 
				
			||||||
 | 
								ctx.Repo.TreePath = strings.Join(parts[1:], "/")
 | 
				
			||||||
 | 
								return parts[0]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							log.Error(4, "Unrecognized path type: %v", path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// URL to redirect to for deprecated URL scheme
 | 
				
			||||||
 | 
					func repoRefRedirect(ctx *Context) string {
 | 
				
			||||||
 | 
						urlPath := ctx.Req.URL.String()
 | 
				
			||||||
 | 
						idx := strings.LastIndex(urlPath, ctx.Params("*"))
 | 
				
			||||||
 | 
						if idx < 0 {
 | 
				
			||||||
 | 
							idx = len(urlPath)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return path.Join(urlPath[:idx], ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RepoRefByType handles repository reference name for a specific type
 | 
				
			||||||
 | 
					// of repository reference
 | 
				
			||||||
 | 
					func RepoRefByType(refType RepoRefType) macaron.Handler {
 | 
				
			||||||
	return func(ctx *Context) {
 | 
						return func(ctx *Context) {
 | 
				
			||||||
		// Empty repository does not have reference information.
 | 
							// Empty repository does not have reference information.
 | 
				
			||||||
		if ctx.Repo.Repository.IsBare {
 | 
							if ctx.Repo.Repository.IsBare {
 | 
				
			||||||
@@ -470,6 +558,7 @@ func RepoRef() macaron.Handler {
 | 
				
			|||||||
		// Get default branch.
 | 
							// Get default branch.
 | 
				
			||||||
		if len(ctx.Params("*")) == 0 {
 | 
							if len(ctx.Params("*")) == 0 {
 | 
				
			||||||
			refName = ctx.Repo.Repository.DefaultBranch
 | 
								refName = ctx.Repo.Repository.DefaultBranch
 | 
				
			||||||
 | 
								ctx.Repo.BranchName = refName
 | 
				
			||||||
			if !ctx.Repo.GitRepo.IsBranchExist(refName) {
 | 
								if !ctx.Repo.GitRepo.IsBranchExist(refName) {
 | 
				
			||||||
				brs, err := ctx.Repo.GitRepo.GetBranches()
 | 
									brs, err := ctx.Repo.GitRepo.GetBranches()
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
@@ -492,25 +581,8 @@ func RepoRef() macaron.Handler {
 | 
				
			|||||||
			ctx.Repo.IsViewBranch = true
 | 
								ctx.Repo.IsViewBranch = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			hasMatched := false
 | 
								refName = getRefName(ctx, refType)
 | 
				
			||||||
			parts := strings.Split(ctx.Params("*"), "/")
 | 
								ctx.Repo.BranchName = refName
 | 
				
			||||||
			for i, part := range parts {
 | 
					 | 
				
			||||||
				refName = strings.TrimPrefix(refName+"/"+part, "/")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if ctx.Repo.GitRepo.IsBranchExist(refName) ||
 | 
					 | 
				
			||||||
					ctx.Repo.GitRepo.IsTagExist(refName) {
 | 
					 | 
				
			||||||
					if i < len(parts)-1 {
 | 
					 | 
				
			||||||
						ctx.Repo.TreePath = strings.Join(parts[i+1:], "/")
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					hasMatched = true
 | 
					 | 
				
			||||||
					break
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if !hasMatched && len(parts[0]) == 40 {
 | 
					 | 
				
			||||||
				refName = parts[0]
 | 
					 | 
				
			||||||
				ctx.Repo.TreePath = strings.Join(parts[1:], "/")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if ctx.Repo.GitRepo.IsBranchExist(refName) {
 | 
								if ctx.Repo.GitRepo.IsBranchExist(refName) {
 | 
				
			||||||
				ctx.Repo.IsViewBranch = true
 | 
									ctx.Repo.IsViewBranch = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -542,10 +614,16 @@ func RepoRef() macaron.Handler {
 | 
				
			|||||||
				ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
 | 
									ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if refType == RepoRefLegacy {
 | 
				
			||||||
 | 
									// redirect from old URL scheme to new URL scheme
 | 
				
			||||||
 | 
									ctx.Redirect(repoRefRedirect(ctx))
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx.Repo.BranchName = refName
 | 
					 | 
				
			||||||
		ctx.Data["BranchName"] = ctx.Repo.BranchName
 | 
							ctx.Data["BranchName"] = ctx.Repo.BranchName
 | 
				
			||||||
 | 
							ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
		ctx.Data["CommitID"] = ctx.Repo.CommitID
 | 
							ctx.Data["CommitID"] = ctx.Repo.CommitID
 | 
				
			||||||
		ctx.Data["TreePath"] = ctx.Repo.TreePath
 | 
							ctx.Data["TreePath"] = ctx.Repo.TreePath
 | 
				
			||||||
		ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
 | 
							ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -391,7 +391,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
					Post(reqToken(), bind(api.CreateForkOption{}), repo.CreateFork)
 | 
										Post(reqToken(), bind(api.CreateForkOption{}), repo.CreateFork)
 | 
				
			||||||
				m.Group("/branches", func() {
 | 
									m.Group("/branches", func() {
 | 
				
			||||||
					m.Get("", repo.ListBranches)
 | 
										m.Get("", repo.ListBranches)
 | 
				
			||||||
					m.Get("/*", context.RepoRef(), repo.GetBranch)
 | 
										m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch)
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
				m.Group("/keys", func() {
 | 
									m.Group("/keys", func() {
 | 
				
			||||||
					m.Combo("").Get(repo.ListDeployKeys).
 | 
										m.Combo("").Get(repo.ListDeployKeys).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -202,7 +202,7 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if ctx.HasError() {
 | 
						if ctx.HasError() {
 | 
				
			||||||
		ctx.Flash.Error(ctx.GetErrMsg())
 | 
							ctx.Flash.Error(ctx.GetErrMsg())
 | 
				
			||||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName)
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -216,19 +216,19 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
 | 
				
			|||||||
		if models.IsErrTagAlreadyExists(err) {
 | 
							if models.IsErrTagAlreadyExists(err) {
 | 
				
			||||||
			e := err.(models.ErrTagAlreadyExists)
 | 
								e := err.(models.ErrTagAlreadyExists)
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName))
 | 
								ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName))
 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName)
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if models.IsErrBranchAlreadyExists(err) {
 | 
							if models.IsErrBranchAlreadyExists(err) {
 | 
				
			||||||
			e := err.(models.ErrBranchAlreadyExists)
 | 
								e := err.(models.ErrBranchAlreadyExists)
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", e.BranchName))
 | 
								ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", e.BranchName))
 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName)
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if models.IsErrBranchNameConflict(err) {
 | 
							if models.IsErrBranchNameConflict(err) {
 | 
				
			||||||
			e := err.(models.ErrBranchNameConflict)
 | 
								e := err.(models.ErrBranchNameConflict)
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("repo.branch.branch_name_conflict", form.NewBranchName, e.BranchName))
 | 
								ctx.Flash.Error(ctx.Tr("repo.branch.branch_name_conflict", form.NewBranchName, e.BranchName))
 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName)
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -237,5 +237,5 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Flash.Success(ctx.Tr("repo.branch.create_success", form.NewBranchName))
 | 
						ctx.Flash.Success(ctx.Tr("repo.branch.create_success", form.NewBranchName))
 | 
				
			||||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + form.NewBranchName)
 | 
						ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + form.NewBranchName)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,7 +120,7 @@ func SearchCommits(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	keyword := strings.Trim(ctx.Query("q"), " ")
 | 
						keyword := strings.Trim(ctx.Query("q"), " ")
 | 
				
			||||||
	if len(keyword) == 0 {
 | 
						if len(keyword) == 0 {
 | 
				
			||||||
		ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchName)
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	all := ctx.QueryBool("all")
 | 
						all := ctx.QueryBool("all")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,7 +113,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["TreeNames"] = treeNames
 | 
						ctx.Data["TreeNames"] = treeNames
 | 
				
			||||||
	ctx.Data["TreePaths"] = treePaths
 | 
						ctx.Data["TreePaths"] = treePaths
 | 
				
			||||||
	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
 | 
						ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
	ctx.Data["commit_summary"] = ""
 | 
						ctx.Data["commit_summary"] = ""
 | 
				
			||||||
	ctx.Data["commit_message"] = ""
 | 
						ctx.Data["commit_message"] = ""
 | 
				
			||||||
	if canCommit {
 | 
						if canCommit {
 | 
				
			||||||
@@ -164,7 +164,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
				
			|||||||
	ctx.Data["TreePath"] = form.TreePath
 | 
						ctx.Data["TreePath"] = form.TreePath
 | 
				
			||||||
	ctx.Data["TreeNames"] = treeNames
 | 
						ctx.Data["TreeNames"] = treeNames
 | 
				
			||||||
	ctx.Data["TreePaths"] = treePaths
 | 
						ctx.Data["TreePaths"] = treePaths
 | 
				
			||||||
	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + branchName
 | 
						ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + branchName
 | 
				
			||||||
	ctx.Data["FileContent"] = form.Content
 | 
						ctx.Data["FileContent"] = form.Content
 | 
				
			||||||
	ctx.Data["commit_summary"] = form.CommitSummary
 | 
						ctx.Data["commit_summary"] = form.CommitSummary
 | 
				
			||||||
	ctx.Data["commit_message"] = form.CommitMessage
 | 
						ctx.Data["commit_message"] = form.CommitMessage
 | 
				
			||||||
@@ -304,7 +304,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(form.TreePath))
 | 
						ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + branchName + "/" + strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(form.TreePath))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EditFilePost response for editing file
 | 
					// EditFilePost response for editing file
 | 
				
			||||||
@@ -348,7 +348,7 @@ func DiffPreviewPost(ctx *context.Context, form auth.EditPreviewDiffForm) {
 | 
				
			|||||||
// DeleteFile render delete file page
 | 
					// DeleteFile render delete file page
 | 
				
			||||||
func DeleteFile(ctx *context.Context) {
 | 
					func DeleteFile(ctx *context.Context) {
 | 
				
			||||||
	ctx.Data["PageIsDelete"] = true
 | 
						ctx.Data["PageIsDelete"] = true
 | 
				
			||||||
	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
 | 
						ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
	ctx.Data["TreePath"] = ctx.Repo.TreePath
 | 
						ctx.Data["TreePath"] = ctx.Repo.TreePath
 | 
				
			||||||
	canCommit := renderCommitRights(ctx)
 | 
						canCommit := renderCommitRights(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -367,7 +367,7 @@ func DeleteFile(ctx *context.Context) {
 | 
				
			|||||||
// DeleteFilePost response for deleting file
 | 
					// DeleteFilePost response for deleting file
 | 
				
			||||||
func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
					func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
				
			||||||
	ctx.Data["PageIsDelete"] = true
 | 
						ctx.Data["PageIsDelete"] = true
 | 
				
			||||||
	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
 | 
						ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
	ctx.Data["TreePath"] = ctx.Repo.TreePath
 | 
						ctx.Data["TreePath"] = ctx.Repo.TreePath
 | 
				
			||||||
	canCommit := renderCommitRights(ctx)
 | 
						canCommit := renderCommitRights(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -422,7 +422,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
 | 
						ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
 | 
				
			||||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName)
 | 
						ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + branchName)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func renderUploadSettings(ctx *context.Context) {
 | 
					func renderUploadSettings(ctx *context.Context) {
 | 
				
			||||||
@@ -446,7 +446,7 @@ func UploadFile(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["TreeNames"] = treeNames
 | 
						ctx.Data["TreeNames"] = treeNames
 | 
				
			||||||
	ctx.Data["TreePaths"] = treePaths
 | 
						ctx.Data["TreePaths"] = treePaths
 | 
				
			||||||
	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
 | 
						ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
	ctx.Data["commit_summary"] = ""
 | 
						ctx.Data["commit_summary"] = ""
 | 
				
			||||||
	ctx.Data["commit_message"] = ""
 | 
						ctx.Data["commit_message"] = ""
 | 
				
			||||||
	if canCommit {
 | 
						if canCommit {
 | 
				
			||||||
@@ -482,7 +482,7 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
 | 
				
			|||||||
	ctx.Data["TreePath"] = form.TreePath
 | 
						ctx.Data["TreePath"] = form.TreePath
 | 
				
			||||||
	ctx.Data["TreeNames"] = treeNames
 | 
						ctx.Data["TreeNames"] = treeNames
 | 
				
			||||||
	ctx.Data["TreePaths"] = treePaths
 | 
						ctx.Data["TreePaths"] = treePaths
 | 
				
			||||||
	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + branchName
 | 
						ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + branchName
 | 
				
			||||||
	ctx.Data["commit_summary"] = form.CommitSummary
 | 
						ctx.Data["commit_summary"] = form.CommitSummary
 | 
				
			||||||
	ctx.Data["commit_message"] = form.CommitMessage
 | 
						ctx.Data["commit_message"] = form.CommitMessage
 | 
				
			||||||
	ctx.Data["commit_choice"] = form.CommitChoice
 | 
						ctx.Data["commit_choice"] = form.CommitChoice
 | 
				
			||||||
@@ -551,7 +551,7 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + form.TreePath)
 | 
						ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + branchName + "/" + form.TreePath)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UploadFileToServer upload file to server file dir not git
 | 
					// UploadFileToServer upload file to server file dir not git
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,21 @@ func MustBeNotBare(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MustBeEditable check that repo can be edited
 | 
				
			||||||
 | 
					func MustBeEditable(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
 | 
				
			||||||
 | 
							ctx.Handle(404, "", nil)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MustBeAbleToUpload check that repo can be uploaded to
 | 
				
			||||||
 | 
					func MustBeAbleToUpload(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !setting.Repository.Upload.Enabled {
 | 
				
			||||||
 | 
							ctx.Handle(404, "", nil)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkContextUser(ctx *context.Context, uid int64) *models.User {
 | 
					func checkContextUser(ctx *context.Context, uid int64) *models.User {
 | 
				
			||||||
	orgs, err := models.GetOwnedOrgsByUserIDDesc(ctx.User.ID, "updated_unix")
 | 
						orgs, err := models.GetOwnedOrgsByUserIDDesc(ctx.User.ID, "updated_unix")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -297,9 +297,9 @@ func renderCode(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = title
 | 
						ctx.Data["Title"] = title
 | 
				
			||||||
	ctx.Data["RequireHighlightJS"] = true
 | 
						ctx.Data["RequireHighlightJS"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
 | 
						branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
	treeLink := branchLink
 | 
						treeLink := branchLink
 | 
				
			||||||
	rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchName
 | 
						rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(ctx.Repo.TreePath) > 0 {
 | 
						if len(ctx.Repo.TreePath) > 0 {
 | 
				
			||||||
		treeLink += "/" + ctx.Repo.TreePath
 | 
							treeLink += "/" + ctx.Repo.TreePath
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -521,6 +521,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
			Get(repo.CompareAndPullRequest).
 | 
								Get(repo.CompareAndPullRequest).
 | 
				
			||||||
			Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
 | 
								Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m.Group("", func() {
 | 
				
			||||||
			m.Group("", func() {
 | 
								m.Group("", func() {
 | 
				
			||||||
				m.Combo("/_edit/*").Get(repo.EditFile).
 | 
									m.Combo("/_edit/*").Get(repo.EditFile).
 | 
				
			||||||
					Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost)
 | 
										Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost)
 | 
				
			||||||
@@ -529,27 +530,22 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
				m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
 | 
									m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
 | 
				
			||||||
				m.Combo("/_delete/*").Get(repo.DeleteFile).
 | 
									m.Combo("/_delete/*").Get(repo.DeleteFile).
 | 
				
			||||||
					Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
 | 
										Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
 | 
				
			||||||
 | 
									m.Combo("/_upload/*", repo.MustBeAbleToUpload).
 | 
				
			||||||
			m.Group("", func() {
 | 
										Get(repo.UploadFile).
 | 
				
			||||||
				m.Combo("/_upload/*").Get(repo.UploadFile).
 | 
					 | 
				
			||||||
					Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
 | 
										Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
 | 
				
			||||||
 | 
								}, context.RepoRefByType(context.RepoRefBranch), repo.MustBeEditable)
 | 
				
			||||||
 | 
								m.Group("", func() {
 | 
				
			||||||
				m.Post("/upload-file", repo.UploadFileToServer)
 | 
									m.Post("/upload-file", repo.UploadFileToServer)
 | 
				
			||||||
				m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
 | 
									m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
 | 
				
			||||||
			}, func(ctx *context.Context) {
 | 
								}, context.RepoRef(), repo.MustBeEditable, repo.MustBeAbleToUpload)
 | 
				
			||||||
				if !setting.Repository.Upload.Enabled {
 | 
							}, repo.MustBeNotBare, reqRepoWriter)
 | 
				
			||||||
					ctx.Handle(404, "", nil)
 | 
					 | 
				
			||||||
					return
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef(), func(ctx *context.Context) {
 | 
					 | 
				
			||||||
			if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
 | 
					 | 
				
			||||||
				ctx.Handle(404, "", nil)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m.Group("/branches", func() {
 | 
							m.Group("/branches", func() {
 | 
				
			||||||
			m.Post("/_new/*", context.RepoRef(), bindIgnErr(auth.NewBranchForm{}), repo.CreateBranch)
 | 
								m.Group("/_new/", func() {
 | 
				
			||||||
 | 
									m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch)
 | 
				
			||||||
 | 
									m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch)
 | 
				
			||||||
 | 
									m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch)
 | 
				
			||||||
 | 
								}, bindIgnErr(auth.NewBranchForm{}))
 | 
				
			||||||
			m.Post("/delete", repo.DeleteBranchPost)
 | 
								m.Post("/delete", repo.DeleteBranchPost)
 | 
				
			||||||
			m.Post("/restore", repo.RestoreBranchPost)
 | 
								m.Post("/restore", repo.RestoreBranchPost)
 | 
				
			||||||
		}, reqRepoWriter, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
 | 
							}, reqRepoWriter, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
 | 
				
			||||||
@@ -629,15 +625,36 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
			m.Post("/cleanup", context.RepoRef(), repo.CleanUpPullRequest)
 | 
								m.Post("/cleanup", context.RepoRef(), repo.CleanUpPullRequest)
 | 
				
			||||||
		}, repo.MustAllowPulls)
 | 
							}, repo.MustAllowPulls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m.Group("/raw", func() {
 | 
				
			||||||
 | 
								m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownload)
 | 
				
			||||||
 | 
								m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownload)
 | 
				
			||||||
 | 
								m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownload)
 | 
				
			||||||
 | 
								// "/*" route is deprecated, and kept for backward compatibility
 | 
				
			||||||
 | 
								m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
 | 
				
			||||||
 | 
							}, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m.Group("/commits", func() {
 | 
				
			||||||
 | 
								m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
 | 
				
			||||||
 | 
								m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits)
 | 
				
			||||||
 | 
								m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits)
 | 
				
			||||||
 | 
								// "/*" route is deprecated, and kept for backward compatibility
 | 
				
			||||||
 | 
								m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.RefCommits)
 | 
				
			||||||
 | 
							}, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m.Group("", func() {
 | 
							m.Group("", func() {
 | 
				
			||||||
			m.Get("/raw/*", repo.SingleDownload)
 | 
					 | 
				
			||||||
			m.Get("/commits/*", repo.RefCommits)
 | 
					 | 
				
			||||||
			m.Get("/graph", repo.Graph)
 | 
								m.Get("/graph", repo.Graph)
 | 
				
			||||||
			m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
 | 
								m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
 | 
				
			||||||
		}, repo.MustBeNotBare, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
 | 
							}, repo.MustBeNotBare, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m.Group("/src", func() {
 | 
				
			||||||
 | 
								m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
 | 
				
			||||||
 | 
								m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home)
 | 
				
			||||||
 | 
								m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.Home)
 | 
				
			||||||
 | 
								// "/*" route is deprecated, and kept for backward compatibility
 | 
				
			||||||
 | 
								m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home)
 | 
				
			||||||
 | 
							}, repo.SetEditorconfigIfExists)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m.Group("", func() {
 | 
							m.Group("", func() {
 | 
				
			||||||
			m.Get("/src/*", repo.SetEditorconfigIfExists, repo.Home)
 | 
					 | 
				
			||||||
			m.Get("/forks", repo.Forks)
 | 
								m.Get("/forks", repo.Forks)
 | 
				
			||||||
		}, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
 | 
							}, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
 | 
				
			||||||
		m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)",
 | 
							m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,10 +10,10 @@
 | 
				
			|||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<div class="data" style="display: none" data-mode="{{if .IsViewTag}}tags{{else}}branches{{end}}">
 | 
							<div class="data" style="display: none" data-mode="{{if .IsViewTag}}tags{{else}}branches{{end}}">
 | 
				
			||||||
			{{range .Branches}}
 | 
								{{range .Branches}}
 | 
				
			||||||
				<div class="item branch {{if eq $.BranchName .}}selected{{end}}" data-url="{{$.RepoLink}}/{{if $.PageIsCommits}}commits{{else}}src{{end}}/{{EscapePound .}}{{if $.TreePath}}/{{EscapePound $.TreePath}}{{end}}">{{.}}</div>
 | 
									<div class="item branch {{if eq $.BranchName .}}selected{{end}}" data-url="{{$.RepoLink}}/{{if $.PageIsCommits}}commits{{else}}src{{end}}/branch/{{EscapePound .}}{{if $.TreePath}}/{{EscapePound $.TreePath}}{{end}}">{{.}}</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
			{{range .Tags}}
 | 
								{{range .Tags}}
 | 
				
			||||||
				<div class="item tag {{if eq $.BranchName .}}selected{{end}}" data-url="{{$.RepoLink}}/{{if $.PageIsCommits}}commits{{else}}src{{end}}/{{EscapePound .}}{{if $.TreePath}}/{{EscapePound $.TreePath}}{{end}}">{{.}}</div>
 | 
									<div class="item tag {{if eq $.BranchName .}}selected{{end}}" data-url="{{$.RepoLink}}/{{if $.PageIsCommits}}commits{{else}}src{{end}}/tag/{{EscapePound .}}{{if $.TreePath}}/{{EscapePound $.TreePath}}{{end}}">{{.}}</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<div class="menu transition" :class="{visible: menuVisible}" v-if="menuVisible" v-cloak>
 | 
							<div class="menu transition" :class="{visible: menuVisible}" v-if="menuVisible" v-cloak>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
	{{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}} {{if .Branch}}({{.Branch}}){{end}}
 | 
						{{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}} {{if .Branch}}({{.Branch}}){{end}}
 | 
				
			||||||
	{{if .PageIsCommits}}
 | 
						{{if .PageIsCommits}}
 | 
				
			||||||
		<div class="ui right">
 | 
							<div class="ui right">
 | 
				
			||||||
			<form action="{{.RepoLink}}/commits/{{.BranchName}}/search">
 | 
								<form action="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/search">
 | 
				
			||||||
				<div class="ui tiny search input">
 | 
									<div class="ui tiny search input">
 | 
				
			||||||
					<input name="q" placeholder="{{.i18n.Tr "repo.commits.search"}}" value="{{.Keyword}}" autofocus>
 | 
										<input name="q" placeholder="{{.i18n.Tr "repo.commits.search"}}" value="{{.Keyword}}" autofocus>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
@@ -75,17 +75,17 @@
 | 
				
			|||||||
	{{if gt .TotalPages 1}}
 | 
						{{if gt .TotalPages 1}}
 | 
				
			||||||
		<div class="center page buttons">
 | 
							<div class="center page buttons">
 | 
				
			||||||
			<div class="ui borderless pagination menu">
 | 
								<div class="ui borderless pagination menu">
 | 
				
			||||||
				<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.RepoLink}}/commits/{{$.BranchName}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Previous}}"{{end}}>
 | 
									<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.RepoLink}}/commits/{{$.BranchNameSubURL}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Previous}}"{{end}}>
 | 
				
			||||||
					<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
 | 
										<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				{{range .Pages}}
 | 
									{{range .Pages}}
 | 
				
			||||||
					{{if eq .Num -1}}
 | 
										{{if eq .Num -1}}
 | 
				
			||||||
						<a class="disabled item">...</a>
 | 
											<a class="disabled item">...</a>
 | 
				
			||||||
					{{else}}
 | 
										{{else}}
 | 
				
			||||||
						<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.RepoLink}}/commits/{{$.BranchName}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Num}}"{{end}}>{{.Num}}</a>
 | 
											<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.RepoLink}}/commits/{{$.BranchNameSubURL}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Num}}"{{end}}>{{.Num}}</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
				<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.RepoLink}}/commits/{{$.BranchName}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Next}}"{{end}}>
 | 
									<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.RepoLink}}/commits/{{$.BranchNameSubURL}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Next}}"{{end}}>
 | 
				
			||||||
					{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i>
 | 
										{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i>
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@
 | 
				
			|||||||
				<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
 | 
									<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
 | 
				
			||||||
					<a class="active item" data-tab="write"><i class="octicon octicon-code"></i> {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a>
 | 
										<a class="active item" data-tab="write"><i class="octicon octicon-code"></i> {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a>
 | 
				
			||||||
					{{if not .IsNewFile}}
 | 
										{{if not .IsNewFile}}
 | 
				
			||||||
					<a class="item" data-tab="preview" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}/src/{{.BranchName}}" data-preview-file-modes="{{.PreviewableFileModes}}"><i class="octicon octicon-eye"></i> {{.i18n.Tr "repo.release.preview"}}</a>
 | 
										<a class="item" data-tab="preview" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}"><i class="octicon octicon-eye"></i> {{.i18n.Tr "repo.release.preview"}}</a>
 | 
				
			||||||
					<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName}}/{{.TreePath}}" data-context="{{.BranchLink}}"><i class="octicon octicon-diff"></i> {{.i18n.Tr "repo.editor.preview_changes"}}</a>
 | 
										<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName}}/{{.TreePath}}" data-context="{{.BranchLink}}"><i class="octicon octicon-diff"></i> {{.i18n.Tr "repo.editor.preview_changes"}}</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@
 | 
				
			|||||||
			{{template "repo/branch_dropdown" .}}
 | 
								{{template "repo/branch_dropdown" .}}
 | 
				
			||||||
			{{ $n := len .TreeNames}}
 | 
								{{ $n := len .TreeNames}}
 | 
				
			||||||
			{{ $l := Subtract $n 1}}
 | 
								{{ $l := Subtract $n 1}}
 | 
				
			||||||
			<div class="fitted item"><span class="ui breadcrumb repo-path"><a class="section" href="{{.RepoLink}}/src/{{EscapePound .BranchName}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section">{{EllipsisString $v 30}}</span>{{else}}{{ $p := index $.Paths $i}}<span class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span></div>
 | 
								<div class="fitted item"><span class="ui breadcrumb repo-path"><a class="section" href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section">{{EllipsisString $v 30}}</span>{{else}}{{ $p := index $.Paths $i}}<span class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span></div>
 | 
				
			||||||
			<div class="right fitted item">
 | 
								<div class="right fitted item">
 | 
				
			||||||
				{{if .Repository.CanEnableEditor}}
 | 
									{{if .Repository.CanEnableEditor}}
 | 
				
			||||||
					<div id="file-buttons" class="ui tiny blue buttons">
 | 
										<div id="file-buttons" class="ui tiny blue buttons">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -172,7 +172,7 @@
 | 
				
			|||||||
					<a class="title has-emoji" href="{{$.Link}}/{{.Index}}">{{.Title}}</a>
 | 
										<a class="title has-emoji" href="{{$.Link}}/{{.Index}}">{{.Title}}</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					{{if .Ref}}
 | 
										{{if .Ref}}
 | 
				
			||||||
						<a class="ui label" href="{{$.RepoLink}}/src/{{.Ref}}">{{.Ref}}</a>
 | 
											<a class="ui label" href="{{$.RepoLink}}/src/commit/{{.Ref}}">{{.Ref}}</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					{{range .Labels}}
 | 
										{{range .Labels}}
 | 
				
			||||||
						<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}">{{.Name | Sanitize}}</a>
 | 
											<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}">{{.Name | Sanitize}}</a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,26 +28,26 @@
 | 
				
			|||||||
								<span class="ui green label">{{$.i18n.Tr "repo.release.stable"}}</span>
 | 
													<span class="ui green label">{{$.i18n.Tr "repo.release.stable"}}</span>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
							<span class="tag text blue">
 | 
												<span class="tag text blue">
 | 
				
			||||||
								<a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="tag icon"></i> {{.TagName}}</a>
 | 
													<a href="{{$.RepoLink}}/src/tag/{{.TagName}}" rel="nofollow"><i class="tag icon"></i> {{.TagName}}</a>
 | 
				
			||||||
							</span>
 | 
												</span>
 | 
				
			||||||
							<span class="commit">
 | 
												<span class="commit">
 | 
				
			||||||
								<a href="{{$.RepoLink}}/src/{{.Sha1}}" rel="nofollow"><i class="code icon"></i> {{ShortSha .Sha1}}</a>
 | 
													<a href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow"><i class="code icon"></i> {{ShortSha .Sha1}}</a>
 | 
				
			||||||
							</span>
 | 
												</span>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					<div class="ui twelve wide column detail">
 | 
										<div class="ui twelve wide column detail">
 | 
				
			||||||
						{{if .IsTag}}
 | 
											{{if .IsTag}}
 | 
				
			||||||
							<h4>
 | 
												<h4>
 | 
				
			||||||
								<a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="tag icon"></i> {{.TagName}}</a>
 | 
													<a href="{{$.RepoLink}}/src/tag/{{.TagName}}" rel="nofollow"><i class="tag icon"></i> {{.TagName}}</a>
 | 
				
			||||||
							</h4>
 | 
												</h4>
 | 
				
			||||||
							<div class="download">
 | 
												<div class="download">
 | 
				
			||||||
								<a href="{{$.RepoLink}}/src/{{.Sha1}}" rel="nofollow"><i class="code icon"></i> {{ShortSha .Sha1}}</a>
 | 
													<a href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow"><i class="code icon"></i> {{ShortSha .Sha1}}</a>
 | 
				
			||||||
								<a href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="octicon octicon-file-zip"></i> ZIP</a>
 | 
													<a href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="octicon octicon-file-zip"></i> ZIP</a>
 | 
				
			||||||
								<a href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="octicon octicon-file-zip"></i> TAR.GZ</a>
 | 
													<a href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="octicon octicon-file-zip"></i> TAR.GZ</a>
 | 
				
			||||||
							</div>
 | 
												</div>
 | 
				
			||||||
						{{else}}
 | 
											{{else}}
 | 
				
			||||||
							<h3>
 | 
												<h3>
 | 
				
			||||||
								<a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a>
 | 
													<a href="{{$.RepoLink}}/src/tag/{{.TagName}}">{{.Title}}</a>
 | 
				
			||||||
								{{if $.IsRepositoryWriter}}<small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small>{{end}}
 | 
													{{if $.IsRepositoryWriter}}<small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small>{{end}}
 | 
				
			||||||
							</h3>
 | 
												</h3>
 | 
				
			||||||
							<p class="text grey">
 | 
												<p class="text grey">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,9 +15,9 @@
 | 
				
			|||||||
			<div class="ui right file-actions">
 | 
								<div class="ui right file-actions">
 | 
				
			||||||
				<div class="ui buttons">
 | 
									<div class="ui buttons">
 | 
				
			||||||
					{{if not .IsViewCommit}}
 | 
										{{if not .IsViewCommit}}
 | 
				
			||||||
						<a class="ui button" href="{{.RepoLink}}/src/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a>
 | 
											<a class="ui button" href="{{.RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					<a class="ui button" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_history"}}</a>
 | 
										<a class="ui button" href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_history"}}</a>
 | 
				
			||||||
					<a class="ui button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a>
 | 
										<a class="ui button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
				{{if .Repository.CanEnableEditor}}
 | 
									{{if .Repository.CanEnableEditor}}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user