diff --git a/models/issues/dependency_test.go b/models/issues/dependency_test.go index 6eed483cc9..67418039de 100644 --- a/models/issues/dependency_test.go +++ b/models/issues/dependency_test.go @@ -49,9 +49,13 @@ func TestCreateIssueDependency(t *testing.T) { assert.False(t, left) // Close #2 and check again - _, err = issues_model.ChangeIssueStatus(db.DefaultContext, issue2, user1, true) + _, err = issues_model.CloseIssue(db.DefaultContext, issue2, user1) assert.NoError(t, err) + issue2Closed, err := issues_model.GetIssueByID(db.DefaultContext, 2) + assert.NoError(t, err) + assert.True(t, issue2Closed.IsClosed) + left, err = issues_model.IssueNoDependenciesLeft(db.DefaultContext, issue1) assert.NoError(t, err) assert.True(t, left) @@ -59,4 +63,11 @@ func TestCreateIssueDependency(t *testing.T) { // Test removing the dependency err = issues_model.RemoveIssueDependency(db.DefaultContext, user1, issue1, issue2, issues_model.DependencyTypeBlockedBy) assert.NoError(t, err) + + _, err = issues_model.ReopenIssue(db.DefaultContext, issue2, user1) + assert.NoError(t, err) + + issue2Reopened, err := issues_model.GetIssueByID(db.DefaultContext, 2) + assert.NoError(t, err) + assert.False(t, issue2Reopened.IsClosed) } diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 5b929c9115..ceb4a4027e 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -119,8 +119,8 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use }) } -// ChangeIssueStatus changes issue status to open or closed. -func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed bool) (*Comment, error) { +// CloseIssue changes issue status to closed. +func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) { if err := issue.LoadRepo(ctx); err != nil { return nil, err } @@ -128,7 +128,45 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, return nil, err } - return changeIssueStatus(ctx, issue, doer, isClosed, false) + ctx, committer, err := db.TxContext(ctx) + if err != nil { + return nil, err + } + defer committer.Close() + + comment, err := changeIssueStatus(ctx, issue, doer, true, false) + if err != nil { + return nil, err + } + if err := committer.Commit(); err != nil { + return nil, err + } + return comment, nil +} + +// ReopenIssue changes issue status to open. +func ReopenIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) { + if err := issue.LoadRepo(ctx); err != nil { + return nil, err + } + if err := issue.LoadPoster(ctx); err != nil { + return nil, err + } + + ctx, committer, err := db.TxContext(ctx) + if err != nil { + return nil, err + } + defer committer.Close() + + comment, err := changeIssueStatus(ctx, issue, doer, false, false) + if err != nil { + return nil, err + } + if err := committer.Commit(); err != nil { + return nil, err + } + return comment, nil } // ChangeIssueTitle changes the title of this issue, as the given user. diff --git a/models/issues/issue_xref_test.go b/models/issues/issue_xref_test.go index f1b1bb2a6b..7f257330b7 100644 --- a/models/issues/issue_xref_test.go +++ b/models/issues/issue_xref_test.go @@ -98,7 +98,7 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { i1 := testCreateIssue(t, 1, 2, "title1", "content1", false) i2 := testCreateIssue(t, 1, 2, "title2", "content2", false) i3 := testCreateIssue(t, 1, 2, "title3", "content3", false) - _, err := issues_model.ChangeIssueStatus(db.DefaultContext, i3, d, true) + _, err := issues_model.CloseIssue(db.DefaultContext, i3, d) assert.NoError(t, err) pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index)) diff --git a/modules/markup/html_link.go b/modules/markup/html_link.go index 5fd38b63cd..fea82e50ab 100644 --- a/modules/markup/html_link.go +++ b/modules/markup/html_link.go @@ -9,6 +9,7 @@ import ( "strings" "code.gitea.io/gitea/modules/markup/common" + "code.gitea.io/gitea/modules/util" "golang.org/x/net/html" "golang.org/x/net/html/atom" @@ -171,6 +172,10 @@ func linkProcessor(ctx *RenderContext, node *html.Node) { } uri := node.Data[m[0]:m[1]] + remaining := node.Data[m[1]:] + if util.IsLikelySplitLeftPart(remaining) { + return + } replaceContent(node, m[0], m[1], createLink(ctx, uri, uri, "" /*link*/)) node = node.NextSibling.NextSibling } diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 54bd91f3b3..f14fe4075c 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -206,6 +206,16 @@ func TestRender_links(t *testing.T) { test( "ftps://gitea.com", `

ftps://gitea.com

`) + + t.Run("LinkSplit", func(t *testing.T) { + input, _ := util.SplitStringAtByteN("http://10.1.2.3", 12) + assert.Equal(t, "http://10…", input) + test(input, "

http://10…

") + + input, _ = util.SplitStringAtByteN("http://10.1.2.3", 13) + assert.Equal(t, "http://10.…", input) + test(input, "

http://10.…

") + }) } func TestRender_email(t *testing.T) { diff --git a/modules/packages/maven/metadata.go b/modules/packages/maven/metadata.go index 42aa250718..a61a62c086 100644 --- a/modules/packages/maven/metadata.go +++ b/modules/packages/maven/metadata.go @@ -7,6 +7,7 @@ import ( "encoding/xml" "io" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "golang.org/x/net/html/charset" @@ -31,18 +32,27 @@ type Dependency struct { } type pomStruct struct { - XMLName xml.Name `xml:"project"` - GroupID string `xml:"groupId"` - ArtifactID string `xml:"artifactId"` - Version string `xml:"version"` - Name string `xml:"name"` - Description string `xml:"description"` - URL string `xml:"url"` - Licenses []struct { + XMLName xml.Name `xml:"project"` + + Parent struct { + GroupID string `xml:"groupId"` + ArtifactID string `xml:"artifactId"` + Version string `xml:"version"` + } `xml:"parent"` + + GroupID string `xml:"groupId"` + ArtifactID string `xml:"artifactId"` + Version string `xml:"version"` + Name string `xml:"name"` + Description string `xml:"description"` + URL string `xml:"url"` + + Licenses []struct { Name string `xml:"name"` URL string `xml:"url"` Distribution string `xml:"distribution"` } `xml:"licenses>license"` + Dependencies []struct { GroupID string `xml:"groupId"` ArtifactID string `xml:"artifactId"` @@ -81,8 +91,16 @@ func ParsePackageMetaData(r io.Reader) (*Metadata, error) { }) } + pomGroupID := pom.GroupID + if pomGroupID == "" { + // the current module could inherit parent: https://maven.apache.org/pom.html#Inheritance + pomGroupID = pom.Parent.GroupID + } + if pomGroupID == "" { + return nil, util.ErrInvalidArgument + } return &Metadata{ - GroupID: pom.GroupID, + GroupID: pomGroupID, ArtifactID: pom.ArtifactID, Name: pom.Name, Description: pom.Description, diff --git a/modules/packages/maven/metadata_test.go b/modules/packages/maven/metadata_test.go index e675467730..2cff290808 100644 --- a/modules/packages/maven/metadata_test.go +++ b/modules/packages/maven/metadata_test.go @@ -7,7 +7,10 @@ import ( "strings" "testing" + "code.gitea.io/gitea/modules/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/text/encoding/charmap" ) @@ -86,4 +89,35 @@ func TestParsePackageMetaData(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, m) }) + + t.Run("ParentInherit", func(t *testing.T) { + pom := ` + + 4.0.0 + + com.mycompany.app + my-app + 1.0-SNAPSHOT + + submodule1 + +` + m, err := ParsePackageMetaData(strings.NewReader(pom)) + require.NoError(t, err) + require.NotNil(t, m) + + assert.Equal(t, "com.mycompany.app", m.GroupID) + assert.Equal(t, "submodule1", m.ArtifactID) + }) + + t.Run("ParentInherit", func(t *testing.T) { + pom := ` + + 4.0.0 + + +` + _, err := ParsePackageMetaData(strings.NewReader(pom)) + require.ErrorIs(t, err, util.ErrInvalidArgument) + }) } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index c93d199b1b..20da796b58 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -235,3 +235,9 @@ func checkOverlappedPath(name, path string) { } configuredPaths[path] = name } + +func PanicInDevOrTesting(msg string, a ...any) { + if !IsProd || IsInTesting { + panic(fmt.Sprintf(msg, a...)) + } +} diff --git a/modules/storage/azureblob.go b/modules/storage/azureblob.go index 96c2525b29..837afd0ba6 100644 --- a/modules/storage/azureblob.go +++ b/modules/storage/azureblob.go @@ -70,7 +70,7 @@ func (a *azureBlobObject) Seek(offset int64, whence int) (int64, error) { case io.SeekCurrent: offset += a.offset case io.SeekEnd: - offset = a.Size - offset + offset = a.Size + offset default: return 0, errors.New("Seek: invalid whence") } diff --git a/modules/storage/azureblob_test.go b/modules/storage/azureblob_test.go index 604870cb98..6905db5008 100644 --- a/modules/storage/azureblob_test.go +++ b/modules/storage/azureblob_test.go @@ -4,6 +4,8 @@ package storage import ( + "bytes" + "io" "os" "testing" @@ -54,3 +56,46 @@ func TestAzureBlobStoragePath(t *testing.T) { assert.Equal(t, "base/a", m.buildAzureBlobPath("/a")) assert.Equal(t, "base/a/b", m.buildAzureBlobPath("/a/b/")) } + +func Test_azureBlobObject(t *testing.T) { + if os.Getenv("CI") == "" { + t.Skip("azureBlobStorage not present outside of CI") + return + } + + s, err := NewStorage(setting.AzureBlobStorageType, &setting.Storage{ + AzureBlobConfig: setting.AzureBlobStorageConfig{ + // https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio-code#ip-style-url + Endpoint: "http://devstoreaccount1.azurite.local:10000", + // https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio-code#well-known-storage-account-and-key + AccountName: "devstoreaccount1", + AccountKey: "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==", + Container: "test", + }, + }) + assert.NoError(t, err) + + data := "Q2xTckt6Y1hDOWh0" + _, err = s.Save("test.txt", bytes.NewBufferString(data), int64(len(data))) + assert.NoError(t, err) + obj, err := s.Open("test.txt") + assert.NoError(t, err) + offset, err := obj.Seek(2, io.SeekStart) + assert.NoError(t, err) + assert.EqualValues(t, 2, offset) + buf1 := make([]byte, 3) + read, err := obj.Read(buf1) + assert.NoError(t, err) + assert.EqualValues(t, 3, read) + assert.Equal(t, data[2:5], string(buf1)) + offset, err = obj.Seek(-5, io.SeekEnd) + assert.NoError(t, err) + assert.EqualValues(t, len(data)-5, offset) + buf2 := make([]byte, 4) + read, err = obj.Read(buf2) + assert.NoError(t, err) + assert.EqualValues(t, 4, read) + assert.Equal(t, data[11:15], string(buf2)) + assert.NoError(t, obj.Close()) + assert.NoError(t, s.Delete("test.txt")) +} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 880769dc65..b673450f5a 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -331,7 +331,5 @@ func QueryBuild(a ...any) template.URL { } func panicIfDevOrTesting() { - if !setting.IsProd || setting.IsInTesting { - panic("legacy template functions are for backward compatibility only, do not use them in new code") - } + setting.PanicInDevOrTesting("legacy template functions are for backward compatibility only, do not use them in new code") } diff --git a/modules/util/string.go b/modules/util/string.go index cf50f591c6..19cf75b8b3 100644 --- a/modules/util/string.go +++ b/modules/util/string.go @@ -3,7 +3,10 @@ package util -import "unsafe" +import ( + "strings" + "unsafe" +) func isSnakeCaseUpper(c byte) bool { return 'A' <= c && c <= 'Z' @@ -95,3 +98,15 @@ func UnsafeBytesToString(b []byte) string { func UnsafeStringToBytes(s string) []byte { return unsafe.Slice(unsafe.StringData(s), len(s)) } + +// SplitTrimSpace splits the string at given separator and trims leading and trailing space +func SplitTrimSpace(input, sep string) []string { + input = strings.TrimSpace(input) + var stringList []string + for _, s := range strings.Split(input, sep) { + if s = strings.TrimSpace(s); s != "" { + stringList = append(stringList, s) + } + } + return stringList +} diff --git a/modules/util/string_test.go b/modules/util/string_test.go index 0a4a8bbcfb..ff67b5c7d4 100644 --- a/modules/util/string_test.go +++ b/modules/util/string_test.go @@ -45,3 +45,8 @@ func TestToSnakeCase(t *testing.T) { assert.Equal(t, expected, ToSnakeCase(input)) } } + +func TestSplitTrimSpace(t *testing.T) { + assert.Equal(t, []string{"a", "b", "c"}, SplitTrimSpace("a\nb\nc", "\n")) + assert.Equal(t, []string{"a", "b"}, SplitTrimSpace("\r\na\n\r\nb\n\n", "\n")) +} diff --git a/modules/util/truncate.go b/modules/util/truncate.go index f2edbdc673..9f932facc9 100644 --- a/modules/util/truncate.go +++ b/modules/util/truncate.go @@ -14,6 +14,10 @@ const ( asciiEllipsis = "..." ) +func IsLikelySplitLeftPart(s string) bool { + return strings.HasSuffix(s, utf8Ellipsis) || strings.HasSuffix(s, asciiEllipsis) +} + // SplitStringAtByteN splits a string at byte n accounting for rune boundaries. (Combining characters are not accounted for.) func SplitStringAtByteN(input string, n int) (left, right string) { if len(input) <= n { @@ -38,19 +42,3 @@ func SplitStringAtByteN(input string, n int) (left, right string) { return input[:end] + utf8Ellipsis, utf8Ellipsis + input[end:] } - -// SplitTrimSpace splits the string at given separator and trims leading and trailing space -func SplitTrimSpace(input, sep string) []string { - // Trim initial leading & trailing space - input = strings.TrimSpace(input) - // replace CRLF with LF - input = strings.ReplaceAll(input, "\r\n", "\n") - - var stringList []string - for _, s := range strings.Split(input, sep) { - // trim leading and trailing space - stringList = append(stringList, strings.TrimSpace(s)) - } - - return stringList -} diff --git a/modules/web/route.go b/modules/web/route.go index 533ac3eaf1..729ac46cdc 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -4,14 +4,18 @@ package web import ( + "fmt" "net/http" "net/url" "reflect" + "regexp" "strings" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/htmlutil" "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "gitea.com/go-chi/binding" @@ -181,6 +185,17 @@ func (r *Router) NotFound(h http.HandlerFunc) { r.chiRouter.NotFound(h) } +type pathProcessorParam struct { + name string + captureGroup int +} + +type PathProcessor struct { + methods container.Set[string] + re *regexp.Regexp + params []pathProcessorParam +} + func (r *Router) normalizeRequestPath(resp http.ResponseWriter, req *http.Request, next http.Handler) { normalized := false normalizedPath := req.URL.EscapedPath() @@ -238,6 +253,83 @@ func (r *Router) normalizeRequestPath(resp http.ResponseWriter, req *http.Reques next.ServeHTTP(resp, req) } +func (p *PathProcessor) ProcessRequestPath(chiCtx *chi.Context, path string) bool { + if !p.methods.Contains(chiCtx.RouteMethod) { + return false + } + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + pathMatches := p.re.FindStringSubmatchIndex(path) // Golang regexp match pairs [start, end, start, end, ...] + if pathMatches == nil { + return false + } + var paramMatches [][]int + for i := 2; i < len(pathMatches); { + paramMatches = append(paramMatches, []int{pathMatches[i], pathMatches[i+1]}) + pmIdx := len(paramMatches) - 1 + end := pathMatches[i+1] + i += 2 + for ; i < len(pathMatches); i += 2 { + if pathMatches[i] >= end { + break + } + paramMatches[pmIdx] = append(paramMatches[pmIdx], pathMatches[i], pathMatches[i+1]) + } + } + for i, pm := range paramMatches { + groupIdx := p.params[i].captureGroup * 2 + chiCtx.URLParams.Add(p.params[i].name, path[pm[groupIdx]:pm[groupIdx+1]]) + } + return true +} + +func NewPathProcessor(methods, pattern string) *PathProcessor { + p := &PathProcessor{methods: make(container.Set[string])} + for _, method := range strings.Split(methods, ",") { + p.methods.Add(strings.TrimSpace(method)) + } + re := []byte{'^'} + lastEnd := 0 + for lastEnd < len(pattern) { + start := strings.IndexByte(pattern[lastEnd:], '<') + if start == -1 { + re = append(re, pattern[lastEnd:]...) + break + } + end := strings.IndexByte(pattern[lastEnd+start:], '>') + if end == -1 { + panic(fmt.Sprintf("invalid pattern: %s", pattern)) + } + re = append(re, pattern[lastEnd:lastEnd+start]...) + partName, partExp, _ := strings.Cut(pattern[lastEnd+start+1:lastEnd+start+end], ":") + lastEnd += start + end + 1 + + // TODO: it could support to specify a "capture group" for the name, for example: "/" + // it is not used so no need to implement it now + param := pathProcessorParam{} + if partExp == "*" { + re = append(re, "(.*?)/?"...) + if lastEnd < len(pattern) { + if pattern[lastEnd] == '/' { + lastEnd++ + } + } + } else { + partExp = util.IfZero(partExp, "[^/]+") + re = append(re, '(') + re = append(re, partExp...) + re = append(re, ')') + } + param.name = partName + p.params = append(p.params, param) + } + re = append(re, '$') + reStr := string(re) + p.re = regexp.MustCompile(reStr) + return p +} + // Combo delegates requests to Combo func (r *Router) Combo(pattern string, h ...any) *Combo { return &Combo{r, pattern, h} diff --git a/modules/web/route_test.go b/modules/web/route_test.go index 6e4c309293..ca3134b546 100644 --- a/modules/web/route_test.go +++ b/modules/web/route_test.go @@ -7,177 +7,160 @@ import ( "bytes" "net/http" "net/http/httptest" - "strconv" + "strings" "testing" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/util" - chi "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" ) -func TestRoute1(t *testing.T) { - buff := bytes.NewBufferString("") - recorder := httptest.NewRecorder() - recorder.Body = buff - - r := NewRouter() - r.Get("/{username}/{reponame}/{type:issues|pulls}", func(resp http.ResponseWriter, req *http.Request) { - username := chi.URLParam(req, "username") - assert.EqualValues(t, "gitea", username) - reponame := chi.URLParam(req, "reponame") - assert.EqualValues(t, "gitea", reponame) - tp := chi.URLParam(req, "type") - assert.EqualValues(t, "issues", tp) - }) - - req, err := http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) +func chiURLParamsToMap(chiCtx *chi.Context) map[string]string { + pathParams := chiCtx.URLParams + m := make(map[string]string, len(pathParams.Keys)) + for i, key := range pathParams.Keys { + if key == "*" && pathParams.Values[i] == "" { + continue // chi router will add an empty "*" key if there is a "Mount" + } + m[key] = pathParams.Values[i] + } + return m } -func TestRoute2(t *testing.T) { +func TestPathProcessor(t *testing.T) { + testProcess := func(pattern, uri string, expectedPathParams map[string]string) { + chiCtx := chi.NewRouteContext() + chiCtx.RouteMethod = "GET" + p := NewPathProcessor("GET", pattern) + assert.True(t, p.ProcessRequestPath(chiCtx, uri), "use pattern %s to process uri %s", pattern, uri) + assert.Equal(t, expectedPathParams, chiURLParamsToMap(chiCtx), "use pattern %s to process uri %s", pattern, uri) + } + testProcess("//", "/a/b", map[string]string{"p1": "a", "p2": "b"}) + testProcess("/", "", map[string]string{"p1": ""}) // this is a special case, because chi router could use empty path + testProcess("/", "/", map[string]string{"p1": ""}) + testProcess("//", "/a", map[string]string{"p1": "", "p2": "a"}) + testProcess("//", "/a/b", map[string]string{"p1": "a", "p2": "b"}) + testProcess("//", "/a/b/c", map[string]string{"p1": "a/b", "p2": "c"}) +} + +func TestRouter(t *testing.T) { buff := bytes.NewBufferString("") recorder := httptest.NewRecorder() recorder.Body = buff - hit := -1 + type resultStruct struct { + method string + pathParams map[string]string + handlerMark string + } + var res resultStruct + + h := func(optMark ...string) func(resp http.ResponseWriter, req *http.Request) { + mark := util.OptionalArg(optMark, "") + return func(resp http.ResponseWriter, req *http.Request) { + res.method = req.Method + res.pathParams = chiURLParamsToMap(chi.RouteContext(req.Context())) + res.handlerMark = mark + } + } r := NewRouter() + r.Get("/{username}/{reponame}/{type:issues|pulls}", h("list-issues-a")) // this one will never be called r.Group("/{username}/{reponame}", func() { + r.Get("/{type:issues|pulls}", h("list-issues-b")) r.Group("", func() { - r.Get("/{type:issues|pulls}", func(resp http.ResponseWriter, req *http.Request) { - username := chi.URLParam(req, "username") - assert.EqualValues(t, "gitea", username) - reponame := chi.URLParam(req, "reponame") - assert.EqualValues(t, "gitea", reponame) - tp := chi.URLParam(req, "type") - assert.EqualValues(t, "issues", tp) - hit = 0 - }) - - r.Get("/{type:issues|pulls}/{index}", func(resp http.ResponseWriter, req *http.Request) { - username := chi.URLParam(req, "username") - assert.EqualValues(t, "gitea", username) - reponame := chi.URLParam(req, "reponame") - assert.EqualValues(t, "gitea", reponame) - tp := chi.URLParam(req, "type") - assert.EqualValues(t, "issues", tp) - index := chi.URLParam(req, "index") - assert.EqualValues(t, "1", index) - hit = 1 - }) + r.Get("/{type:issues|pulls}/{index}", h("view-issue")) }, func(resp http.ResponseWriter, req *http.Request) { - if stop, err := strconv.Atoi(req.FormValue("stop")); err == nil { - hit = stop + if stop := req.FormValue("stop"); stop != "" { + h(stop)(resp, req) resp.WriteHeader(http.StatusOK) } }) - r.Group("/issues/{index}", func() { - r.Get("/view", func(resp http.ResponseWriter, req *http.Request) { - username := chi.URLParam(req, "username") - assert.EqualValues(t, "gitea", username) - reponame := chi.URLParam(req, "reponame") - assert.EqualValues(t, "gitea", reponame) - index := chi.URLParam(req, "index") - assert.EqualValues(t, "1", index) - hit = 2 - }) + r.Post("/update", h("update-issue")) }) }) - req, err := http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 0, hit) - - req, err = http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues/1", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 1, hit) - - req, err = http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues/1?stop=100", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 100, hit) - - req, err = http.NewRequest("GET", "http://localhost:8000/gitea/gitea/issues/1/view", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 2, hit) -} - -func TestRoute3(t *testing.T) { - buff := bytes.NewBufferString("") - recorder := httptest.NewRecorder() - recorder.Body = buff - - hit := -1 - m := NewRouter() - r := NewRouter() r.Mount("/api/v1", m) - m.Group("/repos", func() { m.Group("/{username}/{reponame}", func() { - m.Group("/branch_protections", func() { - m.Get("", func(resp http.ResponseWriter, req *http.Request) { - hit = 0 - }) - m.Post("", func(resp http.ResponseWriter, req *http.Request) { - hit = 1 - }) + m.Group("/branches", func() { + m.Get("", h()) + m.Post("", h()) m.Group("/{name}", func() { - m.Get("", func(resp http.ResponseWriter, req *http.Request) { - hit = 2 - }) - m.Patch("", func(resp http.ResponseWriter, req *http.Request) { - hit = 3 - }) - m.Delete("", func(resp http.ResponseWriter, req *http.Request) { - hit = 4 - }) + m.Get("", h()) + m.Patch("", h()) + m.Delete("", h()) }) }) }) }) - req, err := http.NewRequest("GET", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 0, hit) + testRoute := func(methodPath string, expected resultStruct) { + t.Run(methodPath, func(t *testing.T) { + res = resultStruct{} + methodPathFields := strings.Fields(methodPath) + req, err := http.NewRequest(methodPathFields[0], methodPathFields[1], nil) + assert.NoError(t, err) + r.ServeHTTP(recorder, req) + assert.EqualValues(t, expected, res) + }) + } - req, err = http.NewRequest("POST", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code, http.StatusOK) - assert.EqualValues(t, 1, hit) + t.Run("Root Router", func(t *testing.T) { + testRoute("GET /the-user/the-repo/other", resultStruct{}) + testRoute("GET /the-user/the-repo/pulls", resultStruct{ + method: "GET", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "pulls"}, + handlerMark: "list-issues-b", + }) + testRoute("GET /the-user/the-repo/issues/123", resultStruct{ + method: "GET", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "issues", "index": "123"}, + handlerMark: "view-issue", + }) + testRoute("GET /the-user/the-repo/issues/123?stop=hijack", resultStruct{ + method: "GET", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "issues", "index": "123"}, + handlerMark: "hijack", + }) + testRoute("POST /the-user/the-repo/issues/123/update", resultStruct{ + method: "POST", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "index": "123"}, + handlerMark: "update-issue", + }) + }) - req, err = http.NewRequest("GET", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections/master", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 2, hit) + t.Run("Sub Router", func(t *testing.T) { + testRoute("GET /api/v1/repos/the-user/the-repo/branches", resultStruct{ + method: "GET", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo"}, + }) - req, err = http.NewRequest("PATCH", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections/master", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 3, hit) + testRoute("POST /api/v1/repos/the-user/the-repo/branches", resultStruct{ + method: "POST", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo"}, + }) - req, err = http.NewRequest("DELETE", "http://localhost:8000/api/v1/repos/gitea/gitea/branch_protections/master", nil) - assert.NoError(t, err) - r.ServeHTTP(recorder, req) - assert.EqualValues(t, http.StatusOK, recorder.Code) - assert.EqualValues(t, 4, hit) + testRoute("GET /api/v1/repos/the-user/the-repo/branches/master", resultStruct{ + method: "GET", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"}, + }) + + testRoute("PATCH /api/v1/repos/the-user/the-repo/branches/master", resultStruct{ + method: "PATCH", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"}, + }) + + testRoute("DELETE /api/v1/repos/the-user/the-repo/branches/master", resultStruct{ + method: "DELETE", + pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "name": "master"}, + }) + }) } func TestRouteNormalizePath(t *testing.T) { diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 13e7318c6f..bd317f3aa4 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -3719,6 +3719,7 @@ runners.status.active=Em funcionamento runners.status.offline=Desconectado runners.version=Versão runners.reset_registration_token=Repor código de registo +runners.reset_registration_token_confirm=Gostaria de invalidar o código vigente e gerar um novo? runners.reset_registration_token_success=O código de incrição do executor foi reposto com sucesso runs.all_workflows=Todas as sequências de trabalho diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 47ea7137b8..b50fbd638e 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -37,6 +37,8 @@ import ( "code.gitea.io/gitea/routers/api/packages/vagrant" "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/context" + + "github.com/go-chi/chi/v5" ) func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) { @@ -139,39 +141,33 @@ func CommonRoutes() *web.Router { r.Group("/arch", func() { r.Methods("HEAD,GET", "/repository.key", arch.GetRepositoryKey) - r.Methods("HEAD,GET,PUT,DELETE", "*", func(ctx *context.Context) { - path := strings.Trim(ctx.PathParam("*"), "/") + reqPutRepository := web.NewPathProcessor("PUT", "/") + reqGetRepoArchFile := web.NewPathProcessor("HEAD,GET", "///") + reqDeleteRepoNameVerArch := web.NewPathProcessor("DELETE", "////") - if ctx.Req.Method == "PUT" { + r.Any("*", func(ctx *context.Context) { + chiCtx := chi.RouteContext(ctx.Req.Context()) + path := ctx.PathParam("*") + + if reqPutRepository.ProcessRequestPath(chiCtx, path) { reqPackageAccess(perm.AccessModeWrite)(ctx) if ctx.Written() { return } - ctx.SetPathParam("repository", path) arch.UploadPackageFile(ctx) return } - pathFields := strings.Split(path, "/") - pathFieldsLen := len(pathFields) - - if (ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET") && pathFieldsLen >= 2 { - ctx.SetPathParam("repository", strings.Join(pathFields[:pathFieldsLen-2], "/")) - ctx.SetPathParam("architecture", pathFields[pathFieldsLen-2]) - ctx.SetPathParam("filename", pathFields[pathFieldsLen-1]) + if reqGetRepoArchFile.ProcessRequestPath(chiCtx, path) { arch.GetPackageOrRepositoryFile(ctx) return } - if ctx.Req.Method == "DELETE" && pathFieldsLen >= 3 { + if reqDeleteRepoNameVerArch.ProcessRequestPath(chiCtx, path) { reqPackageAccess(perm.AccessModeWrite)(ctx) if ctx.Written() { return } - ctx.SetPathParam("repository", strings.Join(pathFields[:pathFieldsLen-3], "/")) - ctx.SetPathParam("name", pathFields[pathFieldsLen-3]) - ctx.SetPathParam("version", pathFields[pathFieldsLen-2]) - ctx.SetPathParam("architecture", pathFields[pathFieldsLen-1]) arch.DeletePackageVersion(ctx) return } @@ -465,6 +461,8 @@ func CommonRoutes() *web.Router { r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage) }, reqPackageAccess(perm.AccessModeRead)) r.Group("/maven", func() { + // FIXME: this path design is not right. + // It should be `/.../{groupId}/{artifactId}/{version}`, but not `/.../{groupId}-{artifactId}/{version}` r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile) r.Get("/*", maven.DownloadPackageFile) r.Head("/*", maven.ProvidePackageFileHeader) diff --git a/routers/api/v1/admin/adopt.go b/routers/api/v1/admin/adopt.go index 613d123494..55ea8c6758 100644 --- a/routers/api/v1/admin/adopt.go +++ b/routers/api/v1/admin/adopt.go @@ -80,8 +80,8 @@ func AdoptRepository(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "403": // "$ref": "#/responses/forbidden" - ownerName := ctx.PathParam(":username") - repoName := ctx.PathParam(":reponame") + ownerName := ctx.PathParam("username") + repoName := ctx.PathParam("reponame") ctxUser, err := user_model.GetUserByName(ctx, ownerName) if err != nil { @@ -142,8 +142,8 @@ func DeleteUnadoptedRepository(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "403": // "$ref": "#/responses/forbidden" - ownerName := ctx.PathParam(":username") - repoName := ctx.PathParam(":reponame") + ownerName := ctx.PathParam("username") + repoName := ctx.PathParam("reponame") ctxUser, err := user_model.GetUserByName(ctx, ownerName) if err != nil { diff --git a/routers/api/v1/admin/cron.go b/routers/api/v1/admin/cron.go index fba9d33f25..962e007776 100644 --- a/routers/api/v1/admin/cron.go +++ b/routers/api/v1/admin/cron.go @@ -74,7 +74,7 @@ func PostCronTask(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - task := cron.GetTask(ctx.PathParam(":task")) + task := cron.GetTask(ctx.PathParam("task")) if task == nil { ctx.NotFound() return diff --git a/routers/api/v1/admin/email.go b/routers/api/v1/admin/email.go index 6fe418249b..3de94d6868 100644 --- a/routers/api/v1/admin/email.go +++ b/routers/api/v1/admin/email.go @@ -38,7 +38,7 @@ func GetAllEmails(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) emails, maxResults, err := user_model.SearchEmails(ctx, &user_model.SearchEmailOptions{ - Keyword: ctx.PathParam(":email"), + Keyword: ctx.PathParam("email"), ListOptions: listOptions, }) if err != nil { @@ -82,6 +82,6 @@ func SearchEmail(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - ctx.SetPathParam(":email", ctx.FormTrim("q")) + ctx.SetPathParam("email", ctx.FormTrim("q")) GetAllEmails(ctx) } diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go index db481fbf59..6b4689047b 100644 --- a/routers/api/v1/admin/hooks.go +++ b/routers/api/v1/admin/hooks.go @@ -73,7 +73,7 @@ func GetHook(ctx *context.APIContext) { // "200": // "$ref": "#/responses/Hook" - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") hook, err := webhook.GetSystemOrDefaultWebhook(ctx, hookID) if err != nil { if errors.Is(err, util.ErrNotExist) { @@ -142,7 +142,7 @@ func EditHook(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.EditHookOption) // TODO in body params - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") utils.EditSystemHook(ctx, form, hookID) } @@ -164,7 +164,7 @@ func DeleteHook(ctx *context.APIContext) { // "204": // "$ref": "#/responses/empty" - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") if err := webhook.DeleteDefaultSystemWebhook(ctx, hookID); err != nil { if errors.Is(err, util.ErrNotExist) { ctx.NotFound() diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 3f4a73dcad..21cb2f9ccd 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -375,7 +375,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := asymkey_service.DeletePublicKey(ctx, ctx.ContextUser, ctx.PathParamInt64(":id")); err != nil { + if err := asymkey_service.DeletePublicKey(ctx, ctx.ContextUser, ctx.PathParamInt64("id")); err != nil { if asymkey_model.IsErrKeyNotExist(err) { ctx.NotFound() } else if asymkey_model.IsErrKeyAccessDenied(err) { diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 96365e7c14..2f943d306c 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -596,12 +596,12 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) { var err error if assignOrg { - ctx.Org.Organization, err = organization.GetOrgByName(ctx, ctx.PathParam(":org")) + ctx.Org.Organization, err = organization.GetOrgByName(ctx, ctx.PathParam("org")) if err != nil { if organization.IsErrOrgNotExist(err) { - redirectUserID, err := user_model.LookupUserRedirect(ctx, ctx.PathParam(":org")) + redirectUserID, err := user_model.LookupUserRedirect(ctx, ctx.PathParam("org")) if err == nil { - context.RedirectToUser(ctx.Base, ctx.PathParam(":org"), redirectUserID) + context.RedirectToUser(ctx.Base, ctx.PathParam("org"), redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { ctx.NotFound("GetOrgByName", err) } else { @@ -616,7 +616,7 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) { } if assignTeam { - ctx.Org.Team, err = organization.GetTeamByID(ctx, ctx.PathParamInt64(":teamid")) + ctx.Org.Team, err = organization.GetTeamByID(ctx, ctx.PathParamInt64("teamid")) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/notify/threads.go b/routers/api/v1/notify/threads.go index 0761e684a3..58a38cfd18 100644 --- a/routers/api/v1/notify/threads.go +++ b/routers/api/v1/notify/threads.go @@ -101,7 +101,7 @@ func ReadThread(ctx *context.APIContext) { } func getThread(ctx *context.APIContext) *activities_model.Notification { - n, err := activities_model.GetNotificationByID(ctx, ctx.PathParamInt64(":id")) + n, err := activities_model.GetNotificationByID(ctx, ctx.PathParamInt64("id")) if err != nil { if db.IsErrNotExist(err) { ctx.Error(http.StatusNotFound, "GetNotificationByID", err) diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go index 24ee4ed642..2a9bd92e87 100644 --- a/routers/api/v1/org/label.go +++ b/routers/api/v1/org/label.go @@ -139,7 +139,7 @@ func GetLabel(ctx *context.APIContext) { label *issues_model.Label err error ) - strID := ctx.PathParam(":id") + strID := ctx.PathParam("id") if intID, err2 := strconv.ParseInt(strID, 10, 64); err2 != nil { label, err = issues_model.GetLabelInOrgByName(ctx, ctx.Org.Organization.ID, strID) } else { @@ -190,7 +190,7 @@ func EditLabel(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.EditLabelOption) - l, err := issues_model.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64(":id")) + l, err := issues_model.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrOrgLabelNotExist(err) { ctx.NotFound() @@ -249,7 +249,7 @@ func DeleteLabel(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := issues_model.DeleteLabel(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64(":id")); err != nil { + if err := issues_model.DeleteLabel(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64("id")); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteLabel", err) return } diff --git a/routers/api/v1/org/member.go b/routers/api/v1/org/member.go index 294d33014d..23c7da3d96 100644 --- a/routers/api/v1/org/member.go +++ b/routers/api/v1/org/member.go @@ -143,7 +143,7 @@ func IsMember(ctx *context.APIContext) { // "404": // description: user is not a member - userToCheck := user.GetUserByParams(ctx) + userToCheck := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -194,7 +194,7 @@ func IsPublicMember(ctx *context.APIContext) { // "404": // description: user is not a public member - userToCheck := user.GetUserByParams(ctx) + userToCheck := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -236,7 +236,7 @@ func PublicizeMember(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - userToPublicize := user.GetUserByParams(ctx) + userToPublicize := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -278,7 +278,7 @@ func ConcealMember(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - userToConceal := user.GetUserByParams(ctx) + userToConceal := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -318,7 +318,7 @@ func DeleteMember(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - member := user.GetUserByParams(ctx) + member := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 3fb653bcb6..d65f922434 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -131,7 +131,7 @@ func GetUserOrgsPermissions(ctx *context.APIContext) { // "$ref": "#/responses/notFound" var o *user_model.User - if o = user.GetUserByParamsName(ctx, ":org"); o == nil { + if o = user.GetUserByPathParam(ctx, "org"); o == nil { return } diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index 8164d2cfe9..7f44f6ed95 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -449,7 +449,7 @@ func GetTeamMember(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - u := user.GetUserByParams(ctx) + u := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -492,7 +492,7 @@ func AddTeamMember(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - u := user.GetUserByParams(ctx) + u := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -532,7 +532,7 @@ func RemoveTeamMember(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - u := user.GetUserByParams(ctx) + u := user.GetContextUserByPathParam(ctx) if ctx.Written() { return } @@ -645,7 +645,7 @@ func GetTeamRepo(ctx *context.APIContext) { // getRepositoryByParams get repository by a team's organization ID and repo name func getRepositoryByParams(ctx *context.APIContext) *repo_model.Repository { - repo, err := repo_model.GetRepositoryByName(ctx, ctx.Org.Team.OrgID, ctx.PathParam(":reponame")) + repo, err := repo_model.GetRepositoryByName(ctx, ctx.Org.Team.OrgID, ctx.PathParam("reponame")) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index f6df866efc..67dfda39a8 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -487,7 +487,7 @@ func GetBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" repo := ctx.Repo.Repository - bpName := ctx.PathParam(":name") + bpName := ctx.PathParam("name") bp, err := git_model.GetProtectedBranchRuleByName(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) @@ -805,7 +805,7 @@ func EditBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.EditBranchProtectionOption) repo := ctx.Repo.Repository - bpName := ctx.PathParam(":name") + bpName := ctx.PathParam("name") protectBranch, err := git_model.GetProtectedBranchRuleByName(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) @@ -1124,7 +1124,7 @@ func DeleteBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" repo := ctx.Repo.Repository - bpName := ctx.PathParam(":name") + bpName := ctx.PathParam("name") bp, err := git_model.GetProtectedBranchRuleByName(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 0bbf5a1ea4..da3ee54e69 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -103,7 +103,7 @@ func IsCollaborator(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - user, err := user_model.GetUserByName(ctx, ctx.PathParam(":collaborator")) + user, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -163,7 +163,7 @@ func AddOrUpdateCollaborator(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.AddCollaboratorOption) - collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam(":collaborator")) + collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -226,7 +226,7 @@ func DeleteCollaborator(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam(":collaborator")) + collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -274,12 +274,12 @@ func GetRepoPermissions(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - if !ctx.Doer.IsAdmin && ctx.Doer.LoginName != ctx.PathParam(":collaborator") && !ctx.IsUserRepoAdmin() { + if !ctx.Doer.IsAdmin && ctx.Doer.LoginName != ctx.PathParam("collaborator") && !ctx.IsUserRepoAdmin() { ctx.Error(http.StatusForbidden, "User", "Only admins can query all permissions, repo admins can query all repo permissions, collaborators can query only their own") return } - collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam(":collaborator")) + collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusNotFound, "GetUserByName", err) diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go index 788c75fab2..3b144d0c43 100644 --- a/routers/api/v1/repo/commits.go +++ b/routers/api/v1/repo/commits.go @@ -63,7 +63,7 @@ func GetSingleCommit(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - sha := ctx.PathParam(":sha") + sha := ctx.PathParam("sha") if !git.IsValidRefPattern(sha) { ctx.Error(http.StatusUnprocessableEntity, "no valid ref or sha", fmt.Sprintf("no valid ref or sha: %s", sha)) return @@ -312,8 +312,8 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) { // "$ref": "#/responses/string" // "404": // "$ref": "#/responses/notFound" - sha := ctx.PathParam(":sha") - diffType := git.RawDiffType(ctx.PathParam(":diffType")) + sha := ctx.PathParam("sha") + diffType := git.RawDiffType(ctx.PathParam("diffType")) if err := git.GetRawDiff(ctx.Repo.GitRepo, sha, diffType, ctx.Resp); err != nil { if git.IsErrNotExist(err) { diff --git a/routers/api/v1/repo/git_hook.go b/routers/api/v1/repo/git_hook.go index 0887a90096..9b66b69068 100644 --- a/routers/api/v1/repo/git_hook.go +++ b/routers/api/v1/repo/git_hook.go @@ -79,7 +79,7 @@ func GetGitHook(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - hookID := ctx.PathParam(":id") + hookID := ctx.PathParam("id") hook, err := ctx.Repo.GitRepo.GetHook(hookID) if err != nil { if err == git.ErrNotValidHook { @@ -126,7 +126,7 @@ func EditGitHook(ctx *context.APIContext) { // "$ref": "#/responses/notFound" form := web.GetForm(ctx).(*api.EditGitHookOption) - hookID := ctx.PathParam(":id") + hookID := ctx.PathParam("id") hook, err := ctx.Repo.GitRepo.GetHook(hookID) if err != nil { if err == git.ErrNotValidHook { @@ -175,7 +175,7 @@ func DeleteGitHook(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - hookID := ctx.PathParam(":id") + hookID := ctx.PathParam("id") hook, err := ctx.Repo.GitRepo.GetHook(hookID) if err != nil { if err == git.ErrNotValidHook { diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 9ef57da1b9..03143c8f99 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -109,7 +109,7 @@ func GetHook(ctx *context.APIContext) { // "$ref": "#/responses/notFound" repo := ctx.Repo - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") hook, err := utils.GetRepoHook(ctx, repo.Repository.ID, hookID) if err != nil { return @@ -168,7 +168,7 @@ func TestHook(ctx *context.APIContext) { ref = r } - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") hook, err := utils.GetRepoHook(ctx, ctx.Repo.Repository.ID, hookID) if err != nil { return @@ -263,7 +263,7 @@ func EditHook(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" form := web.GetForm(ctx).(*api.EditHookOption) - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") utils.EditRepoHook(ctx, form, hookID) } @@ -296,7 +296,7 @@ func DeleteHook(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - if err := webhook.DeleteWebhookByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")); err != nil { + if err := webhook.DeleteWebhookByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")); err != nil { if webhook.IsErrWebhookNotExist(err) { ctx.NotFound() } else { diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go index c2f3a972ef..c659a16f54 100644 --- a/routers/api/v1/repo/hook_test.go +++ b/routers/api/v1/repo/hook_test.go @@ -18,7 +18,7 @@ func TestTestHook(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockAPIContext(t, "user2/repo1/wiki/_pages") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index cbe709c030..86dbcee5f7 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -613,7 +613,7 @@ func GetIssue(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -733,7 +733,7 @@ func CreateIssue(ctx *context.APIContext) { } if form.Closed { - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", true); err != nil { + if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil { if issues_model.IsErrDependenciesLeft(err) { ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") return @@ -793,7 +793,7 @@ func EditIssue(ctx *context.APIContext) { // "$ref": "#/responses/error" form := web.GetForm(ctx).(*api.EditIssueOption) - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -912,27 +912,11 @@ func EditIssue(ctx *context.APIContext) { } } - var isClosed bool - switch state := api.StateType(*form.State); state { - case api.StateOpen: - isClosed = false - case api.StateClosed: - isClosed = true - default: - ctx.Error(http.StatusPreconditionFailed, "UnknownIssueStateError", fmt.Sprintf("unknown state: %s", state)) + state := api.StateType(*form.State) + closeOrReopenIssue(ctx, issue, state) + if ctx.Written() { return } - - if issue.IsClosed != isClosed { - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil { - if issues_model.IsErrDependenciesLeft(err) { - ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") - return - } - ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) - return - } - } } // Refetch from database to assign some automatic values @@ -976,7 +960,7 @@ func DeleteIssue(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound(err) @@ -1032,7 +1016,7 @@ func UpdateIssueDeadline(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" form := web.GetForm(ctx).(*api.EditDeadlineOption) - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -1055,3 +1039,26 @@ func UpdateIssueDeadline(ctx *context.APIContext) { ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: deadlineUnix.AsTimePtr()}) } + +func closeOrReopenIssue(ctx *context.APIContext, issue *issues_model.Issue, state api.StateType) { + if state != api.StateOpen && state != api.StateClosed { + ctx.Error(http.StatusPreconditionFailed, "UnknownIssueStateError", fmt.Sprintf("unknown state: %s", state)) + return + } + + if state == api.StateClosed && !issue.IsClosed { + if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil { + if issues_model.IsErrDependenciesLeft(err) { + ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue or pull request because it still has open dependencies") + return + } + ctx.Error(http.StatusInternalServerError, "CloseIssue", err) + return + } + } else if state == api.StateOpen && issue.IsClosed { + if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil { + ctx.Error(http.StatusInternalServerError, "ReopenIssue", err) + return + } + } +} diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index f9b5aa816b..96a61a527e 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -68,7 +68,7 @@ func ListIssueComments(ctx *context.APIContext) { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.Error(http.StatusInternalServerError, "GetRawIssueByIndex", err) return @@ -172,7 +172,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.Error(http.StatusInternalServerError, "GetRawIssueByIndex", err) return @@ -380,7 +380,7 @@ func CreateIssueComment(ctx *context.APIContext) { // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateIssueCommentOption) - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err) return @@ -445,7 +445,7 @@ func GetIssueComment(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -579,7 +579,7 @@ func EditIssueCommentDeprecated(ctx *context.APIContext) { } func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) { - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -696,7 +696,7 @@ func DeleteIssueCommentDeprecated(ctx *context.APIContext) { } func deleteIssueComment(ctx *context.APIContext) { - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrCommentNotExist(err) { ctx.NotFound(err) diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index ae7502c661..19dcf999b8 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -61,7 +61,7 @@ func GetIssueDependencies(ctx *context.APIContext) { return } - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound("IsErrIssueNotExist", err) @@ -499,7 +499,7 @@ func RemoveIssueBlocking(ctx *context.APIContext) { } func getParamsIssue(ctx *context.APIContext) *issues_model.Issue { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound("IsErrIssueNotExist", err) diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index cc517619e9..a2c81ceb16 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -47,7 +47,7 @@ func ListIssueLabels(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -163,7 +163,7 @@ func DeleteIssueLabel(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -178,7 +178,7 @@ func DeleteIssueLabel(ctx *context.APIContext) { return } - label, err := issues_model.GetLabelByID(ctx, ctx.PathParamInt64(":id")) + label, err := issues_model.GetLabelByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrLabelNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -285,7 +285,7 @@ func ClearIssueLabels(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -309,7 +309,7 @@ func ClearIssueLabels(ctx *context.APIContext) { } func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption) (*issues_model.Issue, []*issues_model.Label, error) { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go index 0ef9033291..388d4a3e99 100644 --- a/routers/api/v1/repo/issue_pin.go +++ b/routers/api/v1/repo/issue_pin.go @@ -41,7 +41,7 @@ func PinIssue(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -98,7 +98,7 @@ func UnpinIssue(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -159,7 +159,7 @@ func MoveIssuePin(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -169,7 +169,7 @@ func MoveIssuePin(ctx *context.APIContext) { return } - err = issue.MovePin(ctx, int(ctx.PathParamInt64(":position"))) + err = issue.MovePin(ctx, int(ctx.PathParamInt64("position"))) if err != nil { ctx.Error(http.StatusInternalServerError, "MovePin", err) return diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 8d43cd518b..ead86a717f 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -51,7 +51,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -188,7 +188,7 @@ func DeleteIssueCommentReaction(ctx *context.APIContext) { } func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) { - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -295,7 +295,7 @@ func GetIssueReactions(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -419,7 +419,7 @@ func DeleteIssueReaction(ctx *context.APIContext) { } func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) { - issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/issue_stopwatch.go b/routers/api/v1/repo/issue_stopwatch.go index 4605ae2110..e7fba6d0ed 100644 --- a/routers/api/v1/repo/issue_stopwatch.go +++ b/routers/api/v1/repo/issue_stopwatch.go @@ -161,7 +161,7 @@ func DeleteIssueStopwatch(ctx *context.APIContext) { } func prepareIssueStopwatch(ctx *context.APIContext, shouldExist bool) (*issues_model.Issue, error) { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index e51baad0b6..4fb80b1ec4 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -104,7 +104,7 @@ func DelIssueSubscription(ctx *context.APIContext) { } func setIssueSubscription(ctx *context.APIContext, watch bool) { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -115,7 +115,7 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - user, err := user_model.GetUserByName(ctx, ctx.PathParam(":user")) + user, err := user_model.GetUserByName(ctx, ctx.PathParam("user")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound() @@ -185,7 +185,7 @@ func CheckIssueSubscription(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() @@ -251,7 +251,7 @@ func GetIssueSubscribers(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 8d5e9fdad4..57961b0660 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -75,7 +75,7 @@ func ListTrackedTimes(ctx *context.APIContext) { ctx.NotFound("Timetracker is disabled") return } - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound(err) @@ -181,7 +181,7 @@ func AddTime(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" form := web.GetForm(ctx).(*api.AddTimeOption) - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound(err) @@ -264,7 +264,7 @@ func ResetIssueTime(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound(err) @@ -337,7 +337,7 @@ func DeleteTime(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound(err) @@ -356,7 +356,7 @@ func DeleteTime(ctx *context.APIContext) { return } - time, err := issues_model.GetTrackedTimeByID(ctx, ctx.PathParamInt64(":id")) + time, err := issues_model.GetTrackedTimeByID(ctx, ctx.PathParamInt64("id")) if err != nil { if db.IsErrNotExist(err) { ctx.NotFound(err) @@ -422,7 +422,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } - user, err := user_model.GetUserByName(ctx, ctx.PathParam(":timetrackingusername")) + user, err := user_model.GetUserByName(ctx, ctx.PathParam("timetrackingusername")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound(err) diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index 060694d085..23cc922628 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -143,7 +143,7 @@ func GetDeployKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - key, err := asymkey_model.GetDeployKeyByID(ctx, ctx.PathParamInt64(":id")) + key, err := asymkey_model.GetDeployKeyByID(ctx, ctx.PathParamInt64("id")) if err != nil { if asymkey_model.IsErrDeployKeyNotExist(err) { ctx.NotFound() @@ -279,7 +279,7 @@ func DeleteDeploykey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := asymkey_service.DeleteDeployKey(ctx, ctx.Repo.Repository, ctx.PathParamInt64(":id")); err != nil { + if err := asymkey_service.DeleteDeployKey(ctx, ctx.Repo.Repository, ctx.PathParamInt64("id")); err != nil { if asymkey_model.IsErrKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") } else { diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index c2c43db6a4..1ece2521e0 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -99,7 +99,7 @@ func GetLabel(ctx *context.APIContext) { l *issues_model.Label err error ) - strID := ctx.PathParam(":id") + strID := ctx.PathParam("id") if intID, err2 := strconv.ParseInt(strID, 10, 64); err2 != nil { l, err = issues_model.GetLabelInRepoByName(ctx, ctx.Repo.Repository.ID, strID) } else { @@ -212,7 +212,7 @@ func EditLabel(ctx *context.APIContext) { // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.EditLabelOption) - l, err := issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")) + l, err := issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrRepoLabelNotExist(err) { ctx.NotFound() @@ -276,7 +276,7 @@ func DeleteLabel(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := issues_model.DeleteLabel(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")); err != nil { + if err := issues_model.DeleteLabel(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteLabel", err) return } diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index 78907c85a5..8d7516491e 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -280,7 +280,7 @@ func DeleteMilestone(ctx *context.APIContext) { // getMilestoneByIDOrName get milestone by ID and if not available by name func getMilestoneByIDOrName(ctx *context.APIContext) *issues_model.Milestone { - mile := ctx.PathParam(":id") + mile := ctx.PathParam("id") mileID, _ := strconv.ParseInt(mile, 0, 64) if mileID != 0 { diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 047203501e..c911f6830c 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -223,7 +223,7 @@ func GetPushMirrorByName(ctx *context.APIContext) { return } - mirrorName := ctx.PathParam(":name") + mirrorName := ctx.PathParam("name") // Get push mirror of a specific repo by remoteName pushMirror, exist, err := db.Get[repo_model.PushMirror](ctx, repo_model.PushMirrorOptions{ RepoID: ctx.Repo.Repository.ID, @@ -324,7 +324,7 @@ func DeletePushMirrorByRemoteName(ctx *context.APIContext) { return } - remoteName := ctx.PathParam(":name") + remoteName := ctx.PathParam("name") // Delete push mirror on repo by name. err := repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{RepoID: ctx.Repo.Repository.ID, RemoteName: remoteName}) if err != nil { diff --git a/routers/api/v1/repo/notes.go b/routers/api/v1/repo/notes.go index 8689d25e15..8fec844cc4 100644 --- a/routers/api/v1/repo/notes.go +++ b/routers/api/v1/repo/notes.go @@ -52,7 +52,7 @@ func GetNote(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - sha := ctx.PathParam(":sha") + sha := ctx.PathParam("sha") if !git.IsValidRefPattern(sha) { ctx.Error(http.StatusUnprocessableEntity, "no valid ref or sha", fmt.Sprintf("no valid ref or sha: %s", sha)) return diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 71c4c81b67..d0c3459b63 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -179,7 +179,7 @@ func GetPullRequest(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -264,7 +264,7 @@ func GetPullRequestByBaseHead(ctx *context.APIContext) { headBranch = head } - pr, err := issues_model.GetPullRequestByBaseHeadInfo(ctx, ctx.Repo.Repository.ID, headRepoID, ctx.PathParam(":base"), headBranch) + pr, err := issues_model.GetPullRequestByBaseHeadInfo(ctx, ctx.Repo.Repository.ID, headRepoID, ctx.PathParam("base"), headBranch) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -324,7 +324,7 @@ func DownloadPullDiffOrPatch(ctx *context.APIContext) { // "$ref": "#/responses/string" // "404": // "$ref": "#/responses/notFound" - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -334,7 +334,7 @@ func DownloadPullDiffOrPatch(ctx *context.APIContext) { return } var patch bool - if ctx.PathParam(":diffType") == "diff" { + if ctx.PathParam("diffType") == "diff" { patch = false } else { patch = true @@ -603,7 +603,7 @@ func EditPullRequest(ctx *context.APIContext) { // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.EditPullRequestOption) - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -728,27 +728,11 @@ func EditPullRequest(ctx *context.APIContext) { return } - var isClosed bool - switch state := api.StateType(*form.State); state { - case api.StateOpen: - isClosed = false - case api.StateClosed: - isClosed = true - default: - ctx.Error(http.StatusPreconditionFailed, "UnknownPRStateError", fmt.Sprintf("unknown state: %s", state)) + state := api.StateType(*form.State) + closeOrReopenIssue(ctx, issue, state) + if ctx.Written() { return } - - if issue.IsClosed != isClosed { - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil { - if issues_model.IsErrDependenciesLeft(err) { - ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies") - return - } - ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) - return - } - } } // change pull target branch @@ -831,7 +815,7 @@ func IsPullRequestMerged(ctx *context.APIContext) { // "404": // description: pull request has not been merged - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -889,7 +873,7 @@ func MergePullRequest(ctx *context.APIContext) { form := web.GetForm(ctx).(*forms.MergePullRequestForm) - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -1256,7 +1240,7 @@ func UpdatePullRequest(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -1355,7 +1339,7 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - pullIndex := ctx.PathParamInt64(":index") + pullIndex := ctx.PathParamInt64("index") pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { @@ -1441,7 +1425,7 @@ func GetPullRequestCommits(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -1564,7 +1548,7 @@ func GetPullRequestFiles(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index def860eee8..6d7a326370 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -61,7 +61,7 @@ func ListPullReviews(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -306,7 +306,7 @@ func CreatePullReview(ctx *context.APIContext) { // "$ref": "#/responses/validationError" opts := web.GetForm(ctx).(*api.CreatePullReviewOptions) - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -533,7 +533,7 @@ func preparePullReviewType(ctx *context.APIContext, pr *issues_model.PullRequest // prepareSingleReview return review, related pull and false or nil, nil and true if an error happen func prepareSingleReview(ctx *context.APIContext) (*issues_model.Review, *issues_model.PullRequest, bool) { - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -543,7 +543,7 @@ func prepareSingleReview(ctx *context.APIContext) (*issues_model.Review, *issues return nil, nil, true } - review, err := issues_model.GetReviewByID(ctx, ctx.PathParamInt64(":id")) + review, err := issues_model.GetReviewByID(ctx, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrReviewNotExist(err) { ctx.NotFound("GetReviewByID", err) @@ -698,7 +698,7 @@ func parseReviewersByNames(ctx *context.APIContext, reviewerNames, teamReviewerN } func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions, isAdd bool) { - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 141f812172..076f00f1d1 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -50,7 +50,7 @@ func GetRelease(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") release, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id) if err != nil && !repo_model.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err) @@ -319,7 +319,7 @@ func EditRelease(ctx *context.APIContext) { // "$ref": "#/responses/notFound" form := web.GetForm(ctx).(*api.EditReleaseOption) - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id) if err != nil && !repo_model.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err) @@ -396,7 +396,7 @@ func DeleteRelease(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id) if err != nil && !repo_model.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err) diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index ed6cc8e1ea..54ca1fc843 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -72,12 +72,12 @@ func GetReleaseAttachment(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - releaseID := ctx.PathParamInt64(":id") + releaseID := ctx.PathParamInt64("id") if !checkReleaseMatchRepo(ctx, releaseID) { return } - attachID := ctx.PathParamInt64(":attachment_id") + attachID := ctx.PathParamInt64("attachment_id") attach, err := repo_model.GetAttachmentByID(ctx, attachID) if err != nil { if repo_model.IsErrAttachmentNotExist(err) { @@ -126,7 +126,7 @@ func ListReleaseAttachments(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - releaseID := ctx.PathParamInt64(":id") + releaseID := ctx.PathParamInt64("id") release, err := repo_model.GetReleaseByID(ctx, releaseID) if err != nil { if repo_model.IsErrReleaseNotExist(err) { @@ -199,7 +199,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) { } // Check if release exists an load release - releaseID := ctx.PathParamInt64(":id") + releaseID := ctx.PathParamInt64("id") if !checkReleaseMatchRepo(ctx, releaseID) { return } @@ -299,12 +299,12 @@ func EditReleaseAttachment(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.EditAttachmentOptions) // Check if release exists an load release - releaseID := ctx.PathParamInt64(":id") + releaseID := ctx.PathParamInt64("id") if !checkReleaseMatchRepo(ctx, releaseID) { return } - attachID := ctx.PathParamInt64(":attachment_id") + attachID := ctx.PathParamInt64("attachment_id") attach, err := repo_model.GetAttachmentByID(ctx, attachID) if err != nil { if repo_model.IsErrAttachmentNotExist(err) { @@ -372,12 +372,12 @@ func DeleteReleaseAttachment(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // Check if release exists an load release - releaseID := ctx.PathParamInt64(":id") + releaseID := ctx.PathParamInt64("id") if !checkReleaseMatchRepo(ctx, releaseID) { return } - attachID := ctx.PathParamInt64(":attachment_id") + attachID := ctx.PathParamInt64("attachment_id") attach, err := repo_model.GetAttachmentByID(ctx, attachID) if err != nil { if repo_model.IsErrAttachmentNotExist(err) { diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 99f7a8cbf2..7380c5231c 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -41,7 +41,7 @@ func GetReleaseByTag(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - tag := ctx.PathParam(":tag") + tag := ctx.PathParam("tag") release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tag) if err != nil { @@ -94,7 +94,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - tag := ctx.PathParam(":tag") + tag := ctx.PathParam("tag") release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tag) if err != nil { diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index f0f5db0536..a192e241b7 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -495,7 +495,7 @@ func CreateOrgRepo(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" opt := web.GetForm(ctx).(*api.CreateRepoOption) - org, err := organization.GetOrgByName(ctx, ctx.PathParam(":org")) + org, err := organization.GetOrgByName(ctx, ctx.PathParam("org")) if err != nil { if organization.IsErrOrgNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -575,7 +575,7 @@ func GetByID(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - repo, err := repo_model.GetRepositoryByID(ctx, ctx.PathParamInt64(":id")) + repo, err := repo_model.GetRepositoryByID(ctx, ctx.PathParamInt64("id")) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index fe0910c735..8447a8f1f2 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -357,7 +357,7 @@ func GetTagProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" repo := ctx.Repo.Repository - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") pt, err := git_model.GetProtectedTagByID(ctx, id) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedTagByID", err) @@ -521,7 +521,7 @@ func EditTagProtection(ctx *context.APIContext) { repo := ctx.Repo.Repository form := web.GetForm(ctx).(*api.EditTagProtectionOption) - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") pt, err := git_model.GetProtectedTagByID(ctx, id) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedTagByID", err) @@ -616,7 +616,7 @@ func DeleteTagProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" repo := ctx.Repo.Repository - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") pt, err := git_model.GetProtectedTagByID(ctx, id) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedTagByID", err) diff --git a/routers/api/v1/repo/teams.go b/routers/api/v1/repo/teams.go index 42fb0a1d75..e5a2d5c320 100644 --- a/routers/api/v1/repo/teams.go +++ b/routers/api/v1/repo/teams.go @@ -221,7 +221,7 @@ func changeRepoTeam(ctx *context.APIContext, add bool) { } func getTeamByParam(ctx *context.APIContext) *organization.Team { - team, err := organization.GetTeam(ctx, ctx.Repo.Owner.ID, ctx.PathParam(":team")) + team, err := organization.GetTeam(ctx, ctx.Repo.Owner.ID, ctx.PathParam("team")) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusNotFound, "TeamNotExit", err) diff --git a/routers/api/v1/repo/topic.go b/routers/api/v1/repo/topic.go index 6b9eedf6e0..a1a15e7f46 100644 --- a/routers/api/v1/repo/topic.go +++ b/routers/api/v1/repo/topic.go @@ -162,7 +162,7 @@ func AddTopic(ctx *context.APIContext) { // "422": // "$ref": "#/responses/invalidTopicsError" - topicName := strings.TrimSpace(strings.ToLower(ctx.PathParam(":topic"))) + topicName := strings.TrimSpace(strings.ToLower(ctx.PathParam("topic"))) if !repo_model.ValidateTopic(topicName) { ctx.JSON(http.StatusUnprocessableEntity, map[string]any{ @@ -229,7 +229,7 @@ func DeleteTopic(ctx *context.APIContext) { // "422": // "$ref": "#/responses/invalidTopicsError" - topicName := strings.TrimSpace(strings.ToLower(ctx.PathParam(":topic"))) + topicName := strings.TrimSpace(strings.ToLower(ctx.PathParam("topic"))) if !repo_model.ValidateTopic(topicName) { ctx.JSON(http.StatusUnprocessableEntity, map[string]any{ diff --git a/routers/api/v1/repo/tree.go b/routers/api/v1/repo/tree.go index efb247c19e..768e5d41c1 100644 --- a/routers/api/v1/repo/tree.go +++ b/routers/api/v1/repo/tree.go @@ -56,7 +56,7 @@ func GetTree(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - sha := ctx.PathParam(":sha") + sha := ctx.PathParam("sha") if len(sha) == 0 { ctx.Error(http.StatusBadRequest, "", "sha not provided") return diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index f9906ed250..352d8f48fc 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -136,7 +136,7 @@ func EditWikiPage(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.CreateWikiPageOptions) - oldWikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName")) + oldWikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("pageName")) newWikiName := wiki_service.UserTitleToWebPath("", form.Title) if len(newWikiName) == 0 { @@ -242,7 +242,7 @@ func DeleteWikiPage(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - wikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName")) + wikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("pageName")) if err := wiki_service.DeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName); err != nil { if err.Error() == "file does not exist" { @@ -370,7 +370,7 @@ func GetWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // get requested pagename - pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName")) + pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("pageName")) wikiPage := getWikiPage(ctx, pageName) if !ctx.Written() { @@ -420,7 +420,7 @@ func ListPageRevisions(ctx *context.APIContext) { } // get requested pagename - pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName")) + pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("pageName")) if len(pageName) == 0 { pageName = "Home" } diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index 9583bb548c..bfbc2ba622 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -165,7 +165,7 @@ func DeleteAccessToken(ctx *context.APIContext) { // "422": // "$ref": "#/responses/error" - token := ctx.PathParam(":id") + token := ctx.PathParam("id") tokenID, _ := strconv.ParseInt(token, 0, 64) if tokenID == 0 { @@ -306,7 +306,7 @@ func DeleteOauth2Application(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - appID := ctx.PathParamInt64(":id") + appID := ctx.PathParamInt64("id") if err := auth_model.DeleteOAuth2Application(ctx, appID, ctx.Doer.ID); err != nil { if auth_model.IsErrOAuthApplicationNotFound(err) { ctx.NotFound() @@ -338,7 +338,7 @@ func GetOauth2Application(ctx *context.APIContext) { // "$ref": "#/responses/OAuth2Application" // "404": // "$ref": "#/responses/notFound" - appID := ctx.PathParamInt64(":id") + appID := ctx.PathParamInt64("id") app, err := auth_model.GetOAuth2ApplicationByID(ctx, appID) if err != nil { if auth_model.IsErrOauthClientIDInvalid(err) || auth_model.IsErrOAuthApplicationNotFound(err) { @@ -382,7 +382,7 @@ func UpdateOauth2Application(ctx *context.APIContext) { // "$ref": "#/responses/OAuth2Application" // "404": // "$ref": "#/responses/notFound" - appID := ctx.PathParamInt64(":id") + appID := ctx.PathParamInt64("id") data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions) diff --git a/routers/api/v1/user/follower.go b/routers/api/v1/user/follower.go index 6abb70de19..8f46808f9e 100644 --- a/routers/api/v1/user/follower.go +++ b/routers/api/v1/user/follower.go @@ -201,7 +201,7 @@ func CheckFollowing(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - target := GetUserByParamsName(ctx, ":target") + target := GetUserByPathParam(ctx, "target") // FIXME: it is not right to call this function, it should load the "target" directly if ctx.Written() { return } diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index ba5c0fdc45..ef667a1883 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -116,7 +116,7 @@ func GetGPGKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - key, err := asymkey_model.GetGPGKeyForUserByID(ctx, ctx.Doer.ID, ctx.PathParamInt64(":id")) + key, err := asymkey_model.GetGPGKeyForUserByID(ctx, ctx.Doer.ID, ctx.PathParamInt64("id")) if err != nil { if asymkey_model.IsErrGPGKeyNotExist(err) { ctx.NotFound() @@ -280,7 +280,7 @@ func DeleteGPGKey(ctx *context.APIContext) { return } - if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.PathParamInt64(":id")); err != nil { + if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.PathParamInt64("id")); err != nil { if asymkey_model.IsErrGPGKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") } else { diff --git a/routers/api/v1/user/helper.go b/routers/api/v1/user/helper.go index 23a526cd67..9a6f305700 100644 --- a/routers/api/v1/user/helper.go +++ b/routers/api/v1/user/helper.go @@ -10,8 +10,9 @@ import ( "code.gitea.io/gitea/services/context" ) -// GetUserByParamsName get user by name -func GetUserByParamsName(ctx *context.APIContext, name string) *user_model.User { +// GetUserByPathParam get user by the path param name +// it will redirect to the user's new name if the user's name has been changed +func GetUserByPathParam(ctx *context.APIContext, name string) *user_model.User { username := ctx.PathParam(name) user, err := user_model.GetUserByName(ctx, username) if err != nil { @@ -29,7 +30,7 @@ func GetUserByParamsName(ctx *context.APIContext, name string) *user_model.User return user } -// GetUserByParams returns user whose name is presented in URL (":username"). -func GetUserByParams(ctx *context.APIContext) *user_model.User { - return GetUserByParamsName(ctx, ":username") +// GetContextUserByPathParam returns user whose name is presented in URL (path param "username"). +func GetContextUserByPathParam(ctx *context.APIContext) *user_model.User { + return GetUserByPathParam(ctx, "username") } diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index e4278c2ec0..5a9125b4f3 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -179,7 +179,7 @@ func GetPublicKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - key, err := asymkey_model.GetPublicKeyByID(ctx, ctx.PathParamInt64(":id")) + key, err := asymkey_model.GetPublicKeyByID(ctx, ctx.PathParamInt64("id")) if err != nil { if asymkey_model.IsErrKeyNotExist(err) { ctx.NotFound() @@ -274,7 +274,7 @@ func DeletePublicKey(ctx *context.APIContext) { return } - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") externallyManaged, err := asymkey_model.PublicKeyIsExternallyManaged(ctx, id) if err != nil { if asymkey_model.IsErrKeyNotExist(err) { diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index e668326861..43dabe1b60 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -121,7 +121,7 @@ func GetInfo(ctx *context.APIContext) { if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { // fake ErrUserNotExist error message to not leak information about existence - ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.PathParam(":username")}) + ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.PathParam("username")}) return } ctx.JSON(http.StatusOK, convert.ToUser(ctx, ctx.ContextUser, ctx.Doer)) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 047d327ce8..12b0c67b01 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -24,7 +24,7 @@ import ( func ProtocolMiddlewares() (handlers []any) { // the order is important handlers = append(handlers, ChiRoutePathHandler()) // make sure chi has correct paths - handlers = append(handlers, RequestContextHandler()) // // prepare the context and panic recovery + handlers = append(handlers, RequestContextHandler()) // prepare the context and panic recovery if setting.ReverseProxyLimit > 0 && len(setting.ReverseProxyTrustedProxies) > 0 { handlers = append(handlers, ForwardedHeadersHandler(setting.ReverseProxyLimit, setting.ReverseProxyTrustedProxies)) diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index 8f6e9084df..c375d70dc6 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -16,9 +16,9 @@ import ( // SetDefaultBranch updates the default branch func SetDefaultBranch(ctx *gitea_context.PrivateContext) { - ownerName := ctx.PathParam(":owner") - repoName := ctx.PathParam(":repo") - branch := ctx.PathParam(":branch") + ownerName := ctx.PathParam("owner") + repoName := ctx.PathParam("repo") + branch := ctx.PathParam("branch") ctx.Repo.Repository.DefaultBranch = branch if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch); err != nil { diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 8d12b7a953..32c2828739 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -40,8 +40,8 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // b) our update function will likely change the repository in the db so we will need to refresh it // c) we don't always need the repo - ownerName := ctx.PathParam(":owner") - repoName := ctx.PathParam(":repo") + ownerName := ctx.PathParam("owner") + repoName := ctx.PathParam("repo") // defer getting the repository at this point - as we should only retrieve it if we're going to call update var ( diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go index 4255be7e52..8a53e1ed23 100644 --- a/routers/private/internal_repo.go +++ b/routers/private/internal_repo.go @@ -18,8 +18,8 @@ import ( // RepoAssignment assigns the repository and git repository to the private context func RepoAssignment(ctx *gitea_context.PrivateContext) { - ownerName := ctx.PathParam(":owner") - repoName := ctx.PathParam(":repo") + ownerName := ctx.PathParam("owner") + repoName := ctx.PathParam("repo") repo := loadRepository(ctx, ownerName, repoName) if ctx.Written() { diff --git a/routers/private/key.go b/routers/private/key.go index 063db76520..9fd0a16c07 100644 --- a/routers/private/key.go +++ b/routers/private/key.go @@ -14,8 +14,8 @@ import ( // UpdatePublicKeyInRepo update public key and deploy key updates func UpdatePublicKeyInRepo(ctx *context.PrivateContext) { - keyID := ctx.PathParamInt64(":id") - repoID := ctx.PathParamInt64(":repoid") + keyID := ctx.PathParamInt64("id") + repoID := ctx.PathParamInt64("repoid") if err := asymkey_model.UpdatePublicKeyUpdated(ctx, keyID); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), diff --git a/routers/private/serv.go b/routers/private/serv.go index 4dd7d06fb3..ecff3b7a53 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -25,7 +25,7 @@ import ( // ServNoCommand returns information about the provided keyid func ServNoCommand(ctx *context.PrivateContext) { - keyID := ctx.PathParamInt64(":keyid") + keyID := ctx.PathParamInt64("keyid") if keyID <= 0 { ctx.JSON(http.StatusBadRequest, private.Response{ UserMsg: fmt.Sprintf("Bad key id: %d", keyID), @@ -77,9 +77,9 @@ func ServNoCommand(ctx *context.PrivateContext) { // ServCommand returns information about the provided keyid func ServCommand(ctx *context.PrivateContext) { - keyID := ctx.PathParamInt64(":keyid") - ownerName := ctx.PathParam(":owner") - repoName := ctx.PathParam(":repo") + keyID := ctx.PathParamInt64("keyid") + ownerName := ctx.PathParam("owner") + repoName := ctx.PathParam("repo") mode := perm.AccessMode(ctx.FormInt("mode")) // Set the basic parts of the results to return diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 6a65cfa697..249347e835 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -337,7 +337,7 @@ func EditAuthSource(ctx *context.Context) { oauth2providers := oauth2.GetSupportedOAuth2Providers() ctx.Data["OAuth2Providers"] = oauth2providers - source, err := auth.GetSourceByID(ctx, ctx.PathParamInt64(":authid")) + source, err := auth.GetSourceByID(ctx, ctx.PathParamInt64("authid")) if err != nil { ctx.ServerError("auth.GetSourceByID", err) return @@ -371,7 +371,7 @@ func EditAuthSourcePost(ctx *context.Context) { oauth2providers := oauth2.GetSupportedOAuth2Providers() ctx.Data["OAuth2Providers"] = oauth2providers - source, err := auth.GetSourceByID(ctx, ctx.PathParamInt64(":authid")) + source, err := auth.GetSourceByID(ctx, ctx.PathParamInt64("authid")) if err != nil { ctx.ServerError("auth.GetSourceByID", err) return @@ -442,7 +442,7 @@ func EditAuthSourcePost(ctx *context.Context) { // DeleteAuthSource response for deleting an auth source func DeleteAuthSource(ctx *context.Context) { - source, err := auth.GetSourceByID(ctx, ctx.PathParamInt64(":authid")) + source, err := auth.GetSourceByID(ctx, ctx.PathParamInt64("authid")) if err != nil { ctx.ServerError("auth.GetSourceByID", err) return @@ -454,7 +454,7 @@ func DeleteAuthSource(ctx *context.Context) { } else { ctx.Flash.Error(fmt.Sprintf("auth_service.DeleteSource: %v", err)) } - ctx.JSONRedirect(setting.AppSubURL + "/-/admin/auths/" + url.PathEscape(ctx.PathParam(":authid"))) + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/auths/" + url.PathEscape(ctx.PathParam("authid"))) return } log.Trace("Authentication deleted by admin(%s): %d", ctx.Doer.Name, source.ID) diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index cf158f7aa9..fdd18b2f9d 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -219,7 +219,7 @@ func NewUserPost(ctx *context.Context) { } func prepareUserInfo(ctx *context.Context) *user_model.User { - u, err := user_model.GetUserByID(ctx, ctx.PathParamInt64(":userid")) + u, err := user_model.GetUserByID(ctx, ctx.PathParamInt64("userid")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Redirect(setting.AppSubURL + "/-/admin/users") @@ -481,12 +481,12 @@ func EditUserPost(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success")) - ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam("userid"))) } // DeleteUser response for deleting a user func DeleteUser(ctx *context.Context) { - u, err := user_model.GetUserByID(ctx, ctx.PathParamInt64(":userid")) + u, err := user_model.GetUserByID(ctx, ctx.PathParamInt64("userid")) if err != nil { ctx.ServerError("GetUserByID", err) return @@ -495,7 +495,7 @@ func DeleteUser(ctx *context.Context) { // admin should not delete themself if u.ID == ctx.Doer.ID { ctx.Flash.Error(ctx.Tr("admin.users.cannot_delete_self")) - ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam("userid"))) return } @@ -503,16 +503,16 @@ func DeleteUser(ctx *context.Context) { switch { case repo_model.IsErrUserOwnRepos(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo")) - ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam("userid"))) case org_model.IsErrUserHasOrgs(err): ctx.Flash.Error(ctx.Tr("admin.users.still_has_org")) - ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam("userid"))) case packages_model.IsErrUserOwnPackages(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages")) - ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam("userid"))) case user_model.IsErrDeleteLastAdminUser(err): ctx.Flash.Error(ctx.Tr("auth.last_admin")) - ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam("userid"))) default: ctx.ServerError("DeleteUser", err) } diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 32c30c71e8..7a9721cf56 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -34,7 +34,7 @@ import ( // SignInOAuth handles the OAuth2 login buttons func SignInOAuth(ctx *context.Context) { - provider := ctx.PathParam(":provider") + provider := ctx.PathParam("provider") authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider) if err != nil { @@ -73,7 +73,7 @@ func SignInOAuth(ctx *context.Context) { // SignInOAuthCallback handles the callback from the given provider func SignInOAuthCallback(ctx *context.Context) { - provider := ctx.PathParam(":provider") + provider := ctx.PathParam("provider") if ctx.Req.FormValue("error") != "" { var errorKeyValues []string diff --git a/routers/web/feed/render.go b/routers/web/feed/render.go index f975fc7cb2..462ebb97b5 100644 --- a/routers/web/feed/render.go +++ b/routers/web/feed/render.go @@ -9,7 +9,7 @@ import ( // RenderBranchFeed render format for branch or file func RenderBranchFeed(ctx *context.Context) { - _, _, showFeedType := GetFeedType(ctx.PathParam(":reponame"), ctx.Req) + _, _, showFeedType := GetFeedType(ctx.PathParam("reponame"), ctx.Req) if ctx.Repo.TreePath == "" { ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType) } else { diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 7122aff6bd..bdc43acc30 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -28,14 +28,14 @@ const ( // Home show organization home page func Home(ctx *context.Context) { - uname := ctx.PathParam(":username") + uname := ctx.PathParam("username") if strings.HasSuffix(uname, ".keys") || strings.HasSuffix(uname, ".gpg") { ctx.NotFound("", nil) return } - ctx.SetPathParam(":org", uname) + ctx.SetPathParam("org", uname) context.HandleOrgAssignment(ctx) if ctx.Written() { return diff --git a/routers/web/org/members.go b/routers/web/org/members.go index f91062957e..5a134caecb 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -90,7 +90,7 @@ func MembersAction(ctx *context.Context) { org := ctx.Org.Organization - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "private": if ctx.Doer.ID != member.ID && !ctx.Org.IsOwner { ctx.Error(http.StatusNotFound) @@ -131,7 +131,7 @@ func MembersAction(ctx *context.Context) { } if err != nil { - log.Error("Action(%s): %v", ctx.PathParam(":action"), err) + log.Error("Action(%s): %v", ctx.PathParam("action"), err) ctx.JSON(http.StatusOK, map[string]any{ "ok": false, "err": err.Error(), @@ -140,7 +140,7 @@ func MembersAction(ctx *context.Context) { } redirect := ctx.Org.OrgLink + "/members" - if ctx.PathParam(":action") == "leave" { + if ctx.PathParam("action") == "leave" { redirect = setting.AppSubURL + "/" } diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 08201e5eaa..efcc8fadc8 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -196,7 +196,7 @@ func NewProjectPost(ctx *context.Context) { // ChangeProjectStatus updates the status of a project between "open" and "close" func ChangeProjectStatus(ctx *context.Context) { var toClose bool - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "open": toClose = false case "close": @@ -205,7 +205,7 @@ func ChangeProjectStatus(ctx *context.Context) { ctx.JSONRedirect(ctx.ContextUser.HomeLink() + "/-/projects") return } - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, 0, id, toClose); err != nil { ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) @@ -216,7 +216,7 @@ func ChangeProjectStatus(ctx *context.Context) { // DeleteProject delete a project func DeleteProject(ctx *context.Context) { - p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return @@ -245,7 +245,7 @@ func RenderEditProject(ctx *context.Context) { shared_user.RenderUserHeader(ctx) - p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return @@ -269,7 +269,7 @@ func RenderEditProject(ctx *context.Context) { // EditProjectPost response for editing a project func EditProjectPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.CreateProjectForm) - projectID := ctx.PathParamInt64(":id") + projectID := ctx.PathParamInt64("id") ctx.Data["Title"] = ctx.Tr("repo.projects.edit") ctx.Data["PageIsEditProjects"] = true ctx.Data["PageIsViewProjects"] = true @@ -318,7 +318,7 @@ func EditProjectPost(ctx *context.Context) { // ViewProject renders the project with board view for a project func ViewProject(ctx *context.Context) { - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return @@ -447,18 +447,18 @@ func DeleteProjectColumn(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - pb, err := project_model.GetColumn(ctx, ctx.PathParamInt64(":columnID")) + pb, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) if err != nil { ctx.ServerError("GetProjectColumn", err) return } - if pb.ProjectID != ctx.PathParamInt64(":id") { + if pb.ProjectID != ctx.PathParamInt64("id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", pb.ID, project.ID), }) @@ -472,7 +472,7 @@ func DeleteProjectColumn(ctx *context.Context) { return } - if err := project_model.DeleteColumnByID(ctx, ctx.PathParamInt64(":columnID")); err != nil { + if err := project_model.DeleteColumnByID(ctx, ctx.PathParamInt64("columnID")); err != nil { ctx.ServerError("DeleteProjectColumnByID", err) return } @@ -484,7 +484,7 @@ func DeleteProjectColumn(ctx *context.Context) { func AddColumnToProjectPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.EditProjectColumnForm) - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return @@ -512,18 +512,18 @@ func CheckProjectColumnChangePermissions(ctx *context.Context) (*project_model.P return nil, nil } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return nil, nil } - column, err := project_model.GetColumn(ctx, ctx.PathParamInt64(":columnID")) + column, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) if err != nil { ctx.ServerError("GetProjectColumn", err) return nil, nil } - if column.ProjectID != ctx.PathParamInt64(":id") { + if column.ProjectID != ctx.PathParamInt64("id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", column.ID, project.ID), }) @@ -587,7 +587,7 @@ func MoveIssues(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return @@ -597,7 +597,7 @@ func MoveIssues(ctx *context.Context) { return } - column, err := project_model.GetColumn(ctx, ctx.PathParamInt64(":columnID")) + column, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) if err != nil { ctx.NotFoundOrServerError("GetProjectColumn", project_model.IsErrProjectColumnNotExist, err) return diff --git a/routers/web/org/projects_test.go b/routers/web/org/projects_test.go index c52cb7ed4c..c3a769e621 100644 --- a/routers/web/org/projects_test.go +++ b/routers/web/org/projects_test.go @@ -18,8 +18,8 @@ func TestCheckProjectColumnChangePermissions(t *testing.T) { ctx, _ := contexttest.MockContext(t, "user2/-/projects/4/4") contexttest.LoadUser(t, ctx, 2) ctx.ContextUser = ctx.Doer // user2 - ctx.SetPathParam(":id", "4") - ctx.SetPathParam(":columnID", "4") + ctx.SetPathParam("id", "4") + ctx.SetPathParam("columnID", "4") project, column := org.CheckProjectColumnChangePermissions(ctx) assert.NotNil(t, project) diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 7414a11308..0137f2cc96 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -71,7 +71,7 @@ func Teams(ctx *context.Context) { func TeamsAction(ctx *context.Context) { page := ctx.FormString("page") var err error - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "join": if !ctx.Org.IsOwner { ctx.Error(http.StatusNotFound) @@ -84,7 +84,7 @@ func TeamsAction(ctx *context.Context) { if org_model.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) } else { - log.Error("Action(%s): %v", ctx.PathParam(":action"), err) + log.Error("Action(%s): %v", ctx.PathParam("action"), err) ctx.JSON(http.StatusOK, map[string]any{ "ok": false, "err": err.Error(), @@ -111,7 +111,7 @@ func TeamsAction(ctx *context.Context) { if org_model.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) } else { - log.Error("Action(%s): %v", ctx.PathParam(":action"), err) + log.Error("Action(%s): %v", ctx.PathParam("action"), err) ctx.JSON(http.StatusOK, map[string]any{ "ok": false, "err": err.Error(), @@ -178,7 +178,7 @@ func TeamsAction(ctx *context.Context) { } if err := org_model.RemoveInviteByID(ctx, iid, ctx.Org.Team.ID); err != nil { - log.Error("Action(%s): %v", ctx.PathParam(":action"), err) + log.Error("Action(%s): %v", ctx.PathParam("action"), err) ctx.ServerError("RemoveInviteByID", err) return } @@ -192,7 +192,7 @@ func TeamsAction(ctx *context.Context) { } else if errors.Is(err, user_model.ErrBlockedUser) { ctx.Flash.Error(ctx.Tr("org.teams.members.blocked_user")) } else { - log.Error("Action(%s): %v", ctx.PathParam(":action"), err) + log.Error("Action(%s): %v", ctx.PathParam("action"), err) ctx.JSON(http.StatusOK, map[string]any{ "ok": false, "err": err.Error(), @@ -233,7 +233,7 @@ func TeamsRepoAction(ctx *context.Context) { } var err error - action := ctx.PathParam(":action") + action := ctx.PathParam("action") switch action { case "add": repoName := path.Base(ctx.FormString("repo_name")) @@ -258,7 +258,7 @@ func TeamsRepoAction(ctx *context.Context) { } if err != nil { - log.Error("Action(%s): '%s' %v", ctx.PathParam(":action"), ctx.Org.Team.Name, err) + log.Error("Action(%s): '%s' %v", ctx.PathParam("action"), ctx.Org.Team.Name, err) ctx.ServerError("TeamsRepoAction", err) return } diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 04f480f611..f8e51521be 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -154,5 +154,5 @@ func ServeAttachment(ctx *context.Context, uuid string) { // GetAttachment serve attachments func GetAttachment(ctx *context.Context) { - ServeAttachment(ctx, ctx.PathParam(":uuid")) + ServeAttachment(ctx, ctx.PathParam("uuid")) } diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 30f4c8a90e..35f158df52 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -24,8 +24,8 @@ var tplCherryPick templates.TplName = "repo/editor/cherry_pick" // CherryPick handles cherrypick GETs func CherryPick(ctx *context.Context) { - ctx.Data["SHA"] = ctx.PathParam(":sha") - cherryPickCommit, err := ctx.Repo.GitRepo.GetCommit(ctx.PathParam(":sha")) + ctx.Data["SHA"] = ctx.PathParam("sha") + cherryPickCommit, err := ctx.Repo.GitRepo.GetCommit(ctx.PathParam("sha")) if err != nil { if git.IsErrNotExist(err) { ctx.NotFound("Missing Commit", err) @@ -37,7 +37,7 @@ func CherryPick(ctx *context.Context) { if ctx.FormString("cherry-pick-type") == "revert" { ctx.Data["CherryPickType"] = "revert" - ctx.Data["commit_summary"] = "revert " + ctx.PathParam(":sha") + ctx.Data["commit_summary"] = "revert " + ctx.PathParam("sha") ctx.Data["commit_message"] = "revert " + cherryPickCommit.Message() } else { ctx.Data["CherryPickType"] = "cherry-pick" @@ -66,7 +66,7 @@ func CherryPick(ctx *context.Context) { func CherryPickPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.CherryPickForm) - sha := ctx.PathParam(":sha") + sha := ctx.PathParam("sha") ctx.Data["SHA"] = sha if form.Revert { ctx.Data["CherryPickType"] = "revert" @@ -140,7 +140,7 @@ func CherryPickPost(ctx *context.Context) { if form.Revert { if err := git.GetReverseRawDiff(ctx, ctx.Repo.Repository.RepoPath(), sha, buf); err != nil { if git.IsErrNotExist(err) { - ctx.NotFound("GetRawDiff", errors.New("commit "+ctx.PathParam(":sha")+" does not exist.")) + ctx.NotFound("GetRawDiff", errors.New("commit "+ctx.PathParam("sha")+" does not exist.")) return } ctx.ServerError("GetRawDiff", err) @@ -149,7 +149,7 @@ func CherryPickPost(ctx *context.Context) { } else { if err := git.GetRawDiff(ctx.Repo.GitRepo, sha, git.RawDiffType("patch"), buf); err != nil { if git.IsErrNotExist(err) { - ctx.NotFound("GetRawDiff", errors.New("commit "+ctx.PathParam(":sha")+" does not exist.")) + ctx.NotFound("GetRawDiff", errors.New("commit "+ctx.PathParam("sha")+" does not exist.")) return } ctx.ServerError("GetRawDiff", err) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 1447b17a36..6f534b9e2e 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -282,7 +282,7 @@ func Diff(ctx *context.Context) { userName := ctx.Repo.Owner.Name repoName := ctx.Repo.Repository.Name - commitID := ctx.PathParam(":sha") + commitID := ctx.PathParam("sha") var ( gitRepo *git.Repository err error @@ -427,13 +427,13 @@ func RawDiff(ctx *context.Context) { } if err := git.GetRawDiff( gitRepo, - ctx.PathParam(":sha"), - git.RawDiffType(ctx.PathParam(":ext")), + ctx.PathParam("sha"), + git.RawDiffType(ctx.PathParam("ext")), ctx.Resp, ); err != nil { if git.IsErrNotExist(err) { ctx.NotFound("GetRawDiff", - errors.New("commit "+ctx.PathParam(":sha")+" does not exist.")) + errors.New("commit "+ctx.PathParam("sha")+" does not exist.")) return } ctx.ServerError("GetRawDiff", err) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 6c59421bda..8c4003690a 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -864,7 +864,7 @@ func ExcerptBlob(ctx *context.Context) { direction := ctx.FormString("direction") filePath := ctx.FormString("path") gitRepo := ctx.Repo.GitRepo - if ctx.FormBool("wiki") { + if ctx.Data["PageIsWiki"] == true { var err error gitRepo, err = gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository) if err != nil { diff --git a/routers/web/repo/editor_test.go b/routers/web/repo/editor_test.go index 68d69408ac..566db31693 100644 --- a/routers/web/repo/editor_test.go +++ b/routers/web/repo/editor_test.go @@ -43,7 +43,7 @@ func TestCleanUploadName(t *testing.T) { func TestGetUniquePatchBranchName(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -58,7 +58,7 @@ func TestGetUniquePatchBranchName(t *testing.T) { func TestGetClosestParentWithFiles(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index a8a7a4bd79..6b2a7fd076 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -57,8 +57,8 @@ func CorsHandler() func(next http.Handler) http.Handler { // httpBase implementation git smart HTTP protocol func httpBase(ctx *context.Context) *serviceHandler { - username := ctx.PathParam(":username") - reponame := strings.TrimSuffix(ctx.PathParam(":reponame"), ".git") + username := ctx.PathParam("username") + reponame := strings.TrimSuffix(ctx.PathParam("reponame"), ".git") if ctx.FormString("go-get") == "1" { context.EarlyResponseForGoGetMeta(ctx) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 23012dda3d..a3a4e73d7b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -181,7 +181,7 @@ func retrieveProjectsInternal(ctx *context.Context, repo *repo_model.Repository) // GetActionIssue will return the issue which is used in the context. func GetActionIssue(ctx *context.Context) *issues_model.Issue { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.NotFoundOrServerError("GetIssueByIndex", issues_model.IsErrIssueNotExist, err) return nil @@ -246,7 +246,7 @@ func getActionIssues(ctx *context.Context) issues_model.IssueList { // GetIssueInfo get an issue of a repository func GetIssueInfo(ctx *context.Context) { - issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.Error(http.StatusNotFound) @@ -379,7 +379,7 @@ func UpdateIssueContent(ctx *context.Context) { // UpdateIssueDeadline updates an issue deadline func UpdateIssueDeadline(ctx *context.Context) { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound("GetIssueByIndex", err) @@ -506,7 +506,7 @@ func ChangeIssueReaction(ctx *context.Context) { return } - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "react": reaction, err := issue_service.CreateIssueReaction(ctx, ctx.Doer, issue, form.Content) if err != nil { @@ -540,7 +540,7 @@ func ChangeIssueReaction(ctx *context.Context) { log.Trace("Reaction for issue removed: %d/%d", ctx.Repo.Repository.ID, issue.ID) default: - ctx.NotFound(fmt.Sprintf("Unknown action %s", ctx.PathParam(":action")), nil) + ctx.NotFound(fmt.Sprintf("Unknown action %s", ctx.PathParam("action")), nil) return } diff --git a/routers/web/repo/issue_comment.go b/routers/web/repo/issue_comment.go index 6b7b29d9d7..8564c613de 100644 --- a/routers/web/repo/issue_comment.go +++ b/routers/web/repo/issue_comment.go @@ -154,25 +154,28 @@ func NewComment(ctx *context.Context) { if pr != nil { ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index)) } else { - isClosed := form.Status == "close" - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil { - log.Error("ChangeStatus: %v", err) - - if issues_model.IsErrDependenciesLeft(err) { - if issue.IsPull { - ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked")) - } else { - ctx.JSONError(ctx.Tr("repo.issues.dependency.issue_close_blocked")) + if form.Status == "close" && !issue.IsClosed { + if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil { + log.Error("CloseIssue: %v", err) + if issues_model.IsErrDependenciesLeft(err) { + if issue.IsPull { + ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked")) + } else { + ctx.JSONError(ctx.Tr("repo.issues.dependency.issue_close_blocked")) + } + return } - return + } else { + if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil { + ctx.ServerError("stopTimerIfAvailable", err) + return + } + log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed) } - } else { - if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil { - ctx.ServerError("CreateOrStopIssueStopwatch", err) - return + } else if form.Status == "reopen" && issue.IsClosed { + if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil { + log.Error("ReopenIssue: %v", err) } - - log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed) } } } @@ -209,7 +212,7 @@ func NewComment(ctx *context.Context) { // UpdateCommentContent change comment of issue's content func UpdateCommentContent(ctx *context.Context) { - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err) return @@ -287,7 +290,7 @@ func UpdateCommentContent(ctx *context.Context) { // DeleteComment delete comment of issue func DeleteComment(ctx *context.Context) { - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err) return @@ -322,7 +325,7 @@ func DeleteComment(ctx *context.Context) { // ChangeCommentReaction create a reaction for comment func ChangeCommentReaction(ctx *context.Context) { form := web.GetForm(ctx).(*forms.ReactionForm) - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err) return @@ -366,7 +369,7 @@ func ChangeCommentReaction(ctx *context.Context) { return } - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "react": reaction, err := issue_service.CreateCommentReaction(ctx, ctx.Doer, comment, form.Content) if err != nil { @@ -400,7 +403,7 @@ func ChangeCommentReaction(ctx *context.Context) { log.Trace("Reaction for comment removed: %d/%d/%d", ctx.Repo.Repository.ID, comment.Issue.ID, comment.ID) default: - ctx.NotFound(fmt.Sprintf("Unknown action %s", ctx.PathParam(":action")), nil) + ctx.NotFound(fmt.Sprintf("Unknown action %s", ctx.PathParam("action")), nil) return } @@ -427,7 +430,7 @@ func ChangeCommentReaction(ctx *context.Context) { // GetCommentAttachments returns attachments for the comment func GetCommentAttachments(ctx *context.Context) { - comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64(":id")) + comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err) return diff --git a/routers/web/repo/issue_list.go b/routers/web/repo/issue_list.go index ff98bf8ec8..2f615a100e 100644 --- a/routers/web/repo/issue_list.go +++ b/routers/web/repo/issue_list.go @@ -418,14 +418,11 @@ func UpdateIssueStatus(ctx *context.Context) { return } - var isClosed bool - switch action := ctx.FormString("action"); action { - case "open": - isClosed = false - case "close": - isClosed = true - default: + action := ctx.FormString("action") + if action != "open" && action != "close" { log.Warn("Unrecognized action: %s", action) + ctx.JSONOK() + return } if _, err := issues.LoadRepositories(ctx); err != nil { @@ -441,15 +438,20 @@ func UpdateIssueStatus(ctx *context.Context) { if issue.IsPull && issue.PullRequest.HasMerged { continue } - if issue.IsClosed != isClosed { - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil { + if action == "close" && !issue.IsClosed { + if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil { if issues_model.IsErrDependenciesLeft(err) { ctx.JSON(http.StatusPreconditionFailed, map[string]any{ "error": ctx.Tr("repo.issues.dependency.issue_batch_close_blocked", issue.Index), }) return } - ctx.ServerError("ChangeStatus", err) + ctx.ServerError("CloseIssue", err) + return + } + } else if action == "open" && issue.IsClosed { + if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil { + ctx.ServerError("ReopenIssue", err) return } } @@ -748,7 +750,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt // Issues render issues page func Issues(ctx *context.Context) { - isPullList := ctx.PathParam(":type") == "pulls" + isPullList := ctx.PathParam("type") == "pulls" if isPullList { MustAllowPulls(ctx) if ctx.Written() { diff --git a/routers/web/repo/issue_pin.go b/routers/web/repo/issue_pin.go index 0074e31f03..d7d3205c37 100644 --- a/routers/web/repo/issue_pin.go +++ b/routers/web/repo/issue_pin.go @@ -39,7 +39,7 @@ func IssuePinOrUnpin(ctx *context.Context) { // IssueUnpin unpins a Issue func IssueUnpin(ctx *context.Context) { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.Status(http.StatusInternalServerError) log.Error(err.Error()) diff --git a/routers/web/repo/issue_timetrack.go b/routers/web/repo/issue_timetrack.go index 88c539488e..36e931a48f 100644 --- a/routers/web/repo/issue_timetrack.go +++ b/routers/web/repo/issue_timetrack.go @@ -60,7 +60,7 @@ func DeleteTime(c *context.Context) { return } - t, err := issues_model.GetTrackedTimeByID(c, c.PathParamInt64(":timeid")) + t, err := issues_model.GetTrackedTimeByID(c, c.PathParamInt64("timeid")) if err != nil { if db.IsErrNotExist(err) { c.NotFound("time not found", err) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 09b57f4e78..61e75e211b 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -265,13 +265,13 @@ func combineLabelComments(issue *issues_model.Issue) { // ViewIssue render issue view page func ViewIssue(ctx *context.Context) { - if ctx.PathParam(":type") == "issues" { + if ctx.PathParam("type") == "issues" { // If issue was requested we check if repo has external tracker and redirect extIssueUnit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker) if err == nil && extIssueUnit != nil { if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" { metas := ctx.Repo.Repository.ComposeMetas(ctx) - metas["index"] = ctx.PathParam(":index") + metas["index"] = ctx.PathParam("index") res, err := vars.Expand(extIssueUnit.ExternalTrackerConfig().ExternalTrackerFormat, metas) if err != nil { log.Error("unable to expand template vars for issue url. issue: %s, err: %v", metas["index"], err) @@ -287,7 +287,7 @@ func ViewIssue(ctx *context.Context) { } } - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound("GetIssueByIndex", err) @@ -301,10 +301,10 @@ func ViewIssue(ctx *context.Context) { } // Make sure type and URL matches. - if ctx.PathParam(":type") == "issues" && issue.IsPull { + if ctx.PathParam("type") == "issues" && issue.IsPull { ctx.Redirect(issue.Link()) return - } else if ctx.PathParam(":type") == "pulls" && !issue.IsPull { + } else if ctx.PathParam("type") == "pulls" && !issue.IsPull { ctx.Redirect(issue.Link()) return } diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index d6e41a89b2..392d87167a 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -147,7 +147,7 @@ func EditMilestone(ctx *context.Context) { ctx.Data["PageIsMilestones"] = true ctx.Data["PageIsEditMilestone"] = true - m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")) + m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrMilestoneNotExist(err) { ctx.NotFound("", nil) @@ -183,7 +183,7 @@ func EditMilestonePost(ctx *context.Context) { return } - m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")) + m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrMilestoneNotExist(err) { ctx.NotFound("", nil) @@ -207,7 +207,7 @@ func EditMilestonePost(ctx *context.Context) { // ChangeMilestoneStatus response for change a milestone's status func ChangeMilestoneStatus(ctx *context.Context) { var toClose bool - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "open": toClose = false case "close": @@ -216,7 +216,7 @@ func ChangeMilestoneStatus(ctx *context.Context) { ctx.JSONRedirect(ctx.Repo.RepoLink + "/milestones") return } - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") if err := issues_model.ChangeMilestoneStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { if issues_model.IsErrMilestoneNotExist(err) { @@ -226,7 +226,7 @@ func ChangeMilestoneStatus(ctx *context.Context) { } return } - ctx.JSONRedirect(ctx.Repo.RepoLink + "/milestones?state=" + url.QueryEscape(ctx.PathParam(":action"))) + ctx.JSONRedirect(ctx.Repo.RepoLink + "/milestones?state=" + url.QueryEscape(ctx.PathParam("action"))) } // DeleteMilestone delete a milestone @@ -242,7 +242,7 @@ func DeleteMilestone(ctx *context.Context) { // MilestoneIssuesAndPulls lists all the issues and pull requests of the milestone func MilestoneIssuesAndPulls(ctx *context.Context) { - milestoneID := ctx.PathParamInt64(":id") + milestoneID := ctx.PathParamInt64("id") projectID := ctx.FormInt64("project") milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, milestoneID) if err != nil { diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 92227e3f3e..4313b6c403 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -166,7 +166,7 @@ func NewProjectPost(ctx *context.Context) { // ChangeProjectStatus updates the status of a project between "open" and "close" func ChangeProjectStatus(ctx *context.Context) { var toClose bool - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "open": toClose = false case "close": @@ -175,7 +175,7 @@ func ChangeProjectStatus(ctx *context.Context) { ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects") return } - id := ctx.PathParamInt64(":id") + id := ctx.PathParamInt64("id") if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) @@ -186,7 +186,7 @@ func ChangeProjectStatus(ctx *context.Context) { // DeleteProject delete a project func DeleteProject(ctx *context.Context) { - p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -216,7 +216,7 @@ func RenderEditProject(ctx *context.Context) { ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects) ctx.Data["CardTypes"] = project_model.GetCardConfig() - p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -243,7 +243,7 @@ func RenderEditProject(ctx *context.Context) { // EditProjectPost response for editing a project func EditProjectPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.CreateProjectForm) - projectID := ctx.PathParamInt64(":id") + projectID := ctx.PathParamInt64("id") ctx.Data["Title"] = ctx.Tr("repo.projects.edit") ctx.Data["PageIsEditProjects"] = true @@ -288,7 +288,7 @@ func EditProjectPost(ctx *context.Context) { // ViewProject renders the project with board view func ViewProject(ctx *context.Context) { - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -468,7 +468,7 @@ func DeleteProjectColumn(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -478,12 +478,12 @@ func DeleteProjectColumn(ctx *context.Context) { return } - pb, err := project_model.GetColumn(ctx, ctx.PathParamInt64(":columnID")) + pb, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) if err != nil { ctx.ServerError("GetProjectColumn", err) return } - if pb.ProjectID != ctx.PathParamInt64(":id") { + if pb.ProjectID != ctx.PathParamInt64("id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", pb.ID, project.ID), }) @@ -497,7 +497,7 @@ func DeleteProjectColumn(ctx *context.Context) { return } - if err := project_model.DeleteColumnByID(ctx, ctx.PathParamInt64(":columnID")); err != nil { + if err := project_model.DeleteColumnByID(ctx, ctx.PathParamInt64("columnID")); err != nil { ctx.ServerError("DeleteProjectColumnByID", err) return } @@ -515,7 +515,7 @@ func AddColumnToProjectPost(ctx *context.Context) { return } - project, err := project_model.GetProjectForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -553,7 +553,7 @@ func checkProjectColumnChangePermissions(ctx *context.Context) (*project_model.P return nil, nil } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -563,12 +563,12 @@ func checkProjectColumnChangePermissions(ctx *context.Context) (*project_model.P return nil, nil } - column, err := project_model.GetColumn(ctx, ctx.PathParamInt64(":columnID")) + column, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) if err != nil { ctx.ServerError("GetProjectColumn", err) return nil, nil } - if column.ProjectID != ctx.PathParamInt64(":id") { + if column.ProjectID != ctx.PathParamInt64("id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", column.ID, project.ID), }) @@ -639,7 +639,7 @@ func MoveIssues(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("ProjectNotExist", nil) @@ -653,7 +653,7 @@ func MoveIssues(ctx *context.Context) { return } - column, err := project_model.GetColumn(ctx, ctx.PathParamInt64(":columnID")) + column, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) if err != nil { if project_model.IsErrProjectColumnNotExist(err) { ctx.NotFound("ProjectColumnNotExist", nil) diff --git a/routers/web/repo/projects_test.go b/routers/web/repo/projects_test.go index 1a42c615ab..d0690d9a4d 100644 --- a/routers/web/repo/projects_test.go +++ b/routers/web/repo/projects_test.go @@ -17,8 +17,8 @@ func TestCheckProjectColumnChangePermissions(t *testing.T) { ctx, _ := contexttest.MockContext(t, "user2/repo1/projects/1/2") contexttest.LoadUser(t, ctx, 2) contexttest.LoadRepo(t, ctx, 1) - ctx.SetPathParam(":id", "1") - ctx.SetPathParam(":columnID", "2") + ctx.SetPathParam("id", "1") + ctx.SetPathParam("columnID", "2") project, column := checkProjectColumnChangePermissions(ctx) assert.NotNil(t, project) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 0948282ca2..9f3d1c1b7c 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -108,7 +108,7 @@ func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository { } func getPullInfo(ctx *context.Context) (issue *issues_model.Issue, ok bool) { - issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { ctx.NotFound("GetIssueByIndex", err) @@ -1544,7 +1544,7 @@ func DownloadPullPatch(ctx *context.Context) { // DownloadPullDiffOrPatch render a pull's raw diff or patch func DownloadPullDiffOrPatch(ctx *context.Context, patch bool) { - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -1637,7 +1637,7 @@ func UpdatePullRequestTarget(ctx *context.Context) { func SetAllowEdits(ctx *context.Context) { form := web.GetForm(ctx).(*forms.UpdateAllowEditsForm) - pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index e96e096da5..4fa3179829 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -312,7 +312,7 @@ const ( // Action response for actions to a repository func Action(ctx *context.Context) { var err error - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "watch": err = repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, true) case "unwatch": @@ -340,12 +340,12 @@ func Action(ctx *context.Context) { if errors.Is(err, user_model.ErrBlockedUser) { ctx.Flash.Error(ctx.Tr("repo.action.blocked_user")) } else { - ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.PathParam(":action")), err) + ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.PathParam("action")), err) return } } - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "watch", "unwatch": ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) case "star", "unstar": @@ -355,17 +355,17 @@ func Action(ctx *context.Context) { // see the `hx-trigger="refreshUserCards ..."` comments in tmpl ctx.RespHeader().Add("hx-trigger", "refreshUserCards") - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "watch", "unwatch", "star", "unstar": // we have to reload the repository because NumStars or NumWatching (used in the templates) has just changed ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name) if err != nil { - ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.PathParam(":action")), err) + ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.PathParam("action")), err) return } } - switch ctx.PathParam(":action") { + switch ctx.PathParam("action") { case "watch", "unwatch": ctx.HTML(http.StatusOK, tplWatchUnwatch) return diff --git a/routers/web/repo/setting/git_hooks.go b/routers/web/repo/setting/git_hooks.go index 2e9caa4c86..1d92211303 100644 --- a/routers/web/repo/setting/git_hooks.go +++ b/routers/web/repo/setting/git_hooks.go @@ -30,7 +30,7 @@ func GitHooksEdit(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings.githooks") ctx.Data["PageIsSettingsGitHooks"] = true - name := ctx.PathParam(":name") + name := ctx.PathParam("name") hook, err := ctx.Repo.GitRepo.GetHook(name) if err != nil { if err == git.ErrNotValidHook { @@ -46,7 +46,7 @@ func GitHooksEdit(ctx *context.Context) { // GitHooksEditPost response for editing a git hook of a repository func GitHooksEditPost(ctx *context.Context) { - name := ctx.PathParam(":name") + name := ctx.PathParam("name") hook, err := ctx.Repo.GitRepo.GetHook(name) if err != nil { if err == git.ErrNotValidHook { diff --git a/routers/web/repo/setting/protected_tag.go b/routers/web/repo/setting/protected_tag.go index 1c24c8a7ba..1730ad4a8b 100644 --- a/routers/web/repo/setting/protected_tag.go +++ b/routers/web/repo/setting/protected_tag.go @@ -170,7 +170,7 @@ func setTagsContext(ctx *context.Context) error { func selectProtectedTagByContext(ctx *context.Context) *git_model.ProtectedTag { id := ctx.FormInt64("id") if id == 0 { - id = ctx.PathParamInt64(":id") + id = ctx.PathParamInt64("id") } tag, err := git_model.GetProtectedTagByID(ctx, id) diff --git a/routers/web/repo/setting/runners.go b/routers/web/repo/setting/runners.go index ec037baec1..94f2ae7a0c 100644 --- a/routers/web/repo/setting/runners.go +++ b/routers/web/repo/setting/runners.go @@ -147,7 +147,7 @@ func RunnersEdit(ctx *context.Context) { } actions_shared.RunnerDetails(ctx, page, - ctx.PathParamInt64(":runnerid"), rCtx.OwnerID, rCtx.RepoID, + ctx.PathParamInt64("runnerid"), rCtx.OwnerID, rCtx.RepoID, ) ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate) } @@ -158,9 +158,9 @@ func RunnersEditPost(ctx *context.Context) { ctx.ServerError("getRunnersCtx", err) return } - actions_shared.RunnerDetailsEditPost(ctx, ctx.PathParamInt64(":runnerid"), + actions_shared.RunnerDetailsEditPost(ctx, ctx.PathParamInt64("runnerid"), rCtx.OwnerID, rCtx.RepoID, - rCtx.RedirectLink+url.PathEscape(ctx.PathParam(":runnerid"))) + rCtx.RedirectLink+url.PathEscape(ctx.PathParam("runnerid"))) } func ResetRunnerRegistrationToken(ctx *context.Context) { @@ -179,7 +179,7 @@ func RunnerDeletePost(ctx *context.Context) { ctx.ServerError("getRunnersCtx", err) return } - actions_shared.RunnerDeletePost(ctx, ctx.PathParamInt64(":runnerid"), rCtx.RedirectLink, rCtx.RedirectLink+url.PathEscape(ctx.PathParam(":runnerid"))) + actions_shared.RunnerDeletePost(ctx, ctx.PathParamInt64("runnerid"), rCtx.RedirectLink, rCtx.RedirectLink+url.PathEscape(ctx.PathParam("runnerid"))) } func RedirectToDefaultSetting(ctx *context.Context) { diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go index bcf8a7eac0..1b0ba83af4 100644 --- a/routers/web/repo/setting/webhook.go +++ b/routers/web/repo/setting/webhook.go @@ -99,9 +99,9 @@ func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) { if ctx.Data["PageIsAdmin"] == true { return &ownerRepoCtx{ IsAdmin: true, - IsSystemWebhook: ctx.PathParam(":configType") == "system-hooks", + IsSystemWebhook: ctx.PathParam("configType") == "system-hooks", Link: path.Join(setting.AppSubURL, "/-/admin/hooks"), - LinkNew: path.Join(setting.AppSubURL, "/-/admin/", ctx.PathParam(":configType")), + LinkNew: path.Join(setting.AppSubURL, "/-/admin/", ctx.PathParam("configType")), NewTemplate: tplAdminHookNew, }, nil } @@ -110,7 +110,7 @@ func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) { } func checkHookType(ctx *context.Context) string { - hookType := strings.ToLower(ctx.PathParam(":type")) + hookType := strings.ToLower(ctx.PathParam("type")) if !util.SliceContainsString(setting.Webhook.Types, hookType, true) { ctx.NotFound("checkHookType", nil) return "" @@ -592,11 +592,11 @@ func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) { var w *webhook.Webhook if orCtx.RepoID > 0 { - w, err = webhook.GetWebhookByRepoID(ctx, orCtx.RepoID, ctx.PathParamInt64(":id")) + w, err = webhook.GetWebhookByRepoID(ctx, orCtx.RepoID, ctx.PathParamInt64("id")) } else if orCtx.OwnerID > 0 { - w, err = webhook.GetWebhookByOwnerID(ctx, orCtx.OwnerID, ctx.PathParamInt64(":id")) + w, err = webhook.GetWebhookByOwnerID(ctx, orCtx.OwnerID, ctx.PathParamInt64("id")) } else if orCtx.IsAdmin { - w, err = webhook.GetSystemOrDefaultWebhook(ctx, ctx.PathParamInt64(":id")) + w, err = webhook.GetSystemOrDefaultWebhook(ctx, ctx.PathParamInt64("id")) } if err != nil || w == nil { if webhook.IsErrWebhookNotExist(err) { @@ -645,7 +645,7 @@ func WebHooksEdit(ctx *context.Context) { // TestWebhook test if web hook is work fine func TestWebhook(ctx *context.Context) { - hookID := ctx.PathParamInt64(":id") + hookID := ctx.PathParamInt64("id") w, err := webhook.GetWebhookByRepoID(ctx, ctx.Repo.Repository.ID, hookID) if err != nil { ctx.Flash.Error("GetWebhookByRepoID: " + err.Error()) @@ -706,7 +706,7 @@ func TestWebhook(ctx *context.Context) { // ReplayWebhook replays a webhook func ReplayWebhook(ctx *context.Context) { - hookTaskUUID := ctx.PathParam(":uuid") + hookTaskUUID := ctx.PathParam("uuid") orCtx, w := checkWebhook(ctx) if ctx.Written() { diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index 707387f8e5..62d9fdae79 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -276,7 +276,7 @@ func prepareToRenderDirOrFile(entry *git.TreeEntry) func(ctx *context.Context) { func handleRepoHomeFeed(ctx *context.Context) bool { if setting.Other.EnableFeed { - isFeed, _, showFeedType := feed.GetFeedType(ctx.PathParam(":reponame"), ctx.Req) + isFeed, _, showFeedType := feed.GetFeedType(ctx.PathParam("reponame"), ctx.Req) if isFeed { switch { case ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType): diff --git a/routers/web/shared/actions/variables.go b/routers/web/shared/actions/variables.go index 5c5768243a..f895475748 100644 --- a/routers/web/shared/actions/variables.go +++ b/routers/web/shared/actions/variables.go @@ -40,7 +40,7 @@ func CreateVariable(ctx *context.Context, ownerID, repoID int64, redirectURL str } func UpdateVariable(ctx *context.Context, redirectURL string) { - id := ctx.PathParamInt64(":variable_id") + id := ctx.PathParamInt64("variable_id") form := web.GetForm(ctx).(*forms.EditVariableForm) if ok, err := actions_service.UpdateVariable(ctx, id, form.Name, form.Data); err != nil || !ok { @@ -53,7 +53,7 @@ func UpdateVariable(ctx *context.Context, redirectURL string) { } func DeleteVariable(ctx *context.Context, redirectURL string) { - id := ctx.PathParamInt64(":variable_id") + id := ctx.PathParamInt64("variable_id") if err := actions_service.DeleteVariableByID(ctx, id); err != nil { log.Error("Delete variable [%d] failed: %v", id, err) diff --git a/routers/web/shared/project/column.go b/routers/web/shared/project/column.go index ba1f527bea..141c80716f 100644 --- a/routers/web/shared/project/column.go +++ b/routers/web/shared/project/column.go @@ -11,7 +11,7 @@ import ( // MoveColumns moves or keeps columns in a project and sorts them inside that project func MoveColumns(ctx *context.Context) { - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return diff --git a/routers/web/user/avatar.go b/routers/web/user/avatar.go index 7000e25778..f77bd602b3 100644 --- a/routers/web/user/avatar.go +++ b/routers/web/user/avatar.go @@ -23,8 +23,8 @@ func cacheableRedirect(ctx *context.Context, location string) { // AvatarByUserName redirect browser to user avatar of requested size func AvatarByUserName(ctx *context.Context) { - userName := ctx.PathParam(":username") - size := int(ctx.PathParamInt64(":size")) + userName := ctx.PathParam("username") + size := int(ctx.PathParamInt64("size")) var user *user_model.User if strings.ToLower(userName) != user_model.GhostUserLowerName { @@ -46,7 +46,7 @@ func AvatarByUserName(ctx *context.Context) { // AvatarByEmailHash redirects the browser to the email avatar link func AvatarByEmailHash(ctx *context.Context) { - hash := ctx.PathParam(":hash") + hash := ctx.PathParam("hash") email, err := avatars.GetEmailForHash(ctx, hash) if err != nil { ctx.ServerError("invalid avatar hash: "+hash, err) diff --git a/routers/web/user/home.go b/routers/web/user/home.go index e118aa051e..b5d3a7294b 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -56,7 +56,7 @@ const ( // getDashboardContextUser finds out which context user dashboard is being viewed as . func getDashboardContextUser(ctx *context.Context) *user_model.User { ctxUser := ctx.Doer - orgName := ctx.PathParam(":org") + orgName := ctx.PathParam("org") if len(orgName) > 0 { ctxUser = ctx.Org.Organization.AsUser() ctx.Data["Teams"] = ctx.Org.Teams diff --git a/routers/web/user/package.go b/routers/web/user/package.go index d5aac513b6..8d78da7c5a 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -502,7 +502,7 @@ func PackageSettingsPost(ctx *context.Context) { // DownloadPackageFile serves the content of a package file func DownloadPackageFile(ctx *context.Context) { - pf, err := packages_model.GetFileForVersionByID(ctx, ctx.Package.Descriptor.Version.ID, ctx.PathParamInt64(":fileid")) + pf, err := packages_model.GetFileForVersionByID(ctx, ctx.Package.Descriptor.Version.ID, ctx.PathParamInt64("fileid")) if err != nil { if err == packages_model.ErrPackageFileNotExist { ctx.NotFound("", err) diff --git a/routers/web/web.go b/routers/web/web.go index 355871bd99..3bcb7eaf8f 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1171,7 +1171,7 @@ func registerRoutes(m *web.Router) { Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff). Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost) }, optSignIn, context.RepoAssignment, reqRepoCodeReader) - // end "/{username}/{reponame}": find, compare, list (code related) + // end "/{username}/{reponame}": repo code: find, compare, list m.Group("/{username}/{reponame}", func() { m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because it would conflict with other routes like "/pulls/{index}" @@ -1448,6 +1448,7 @@ func registerRoutes(m *web.Router) { m.Combo("/*"). Get(repo.Wiki). Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost) + m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff) m.Get("/raw/*", repo.WikiRaw) @@ -1523,27 +1524,6 @@ func registerRoutes(m *web.Router) { m.Get("", repo.Branches) }, repo.MustBeNotEmpty, context.RepoRef()) - m.Group("/blob_excerpt", func() { - m.Get("/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) - }, func(ctx *context.Context) { - // FIXME: refactor this function, use separate routes for wiki/code - if ctx.FormBool("wiki") { - ctx.Data["PageIsWiki"] = true - repo.MustEnableWiki(ctx) - return - } - - if ctx.Written() { - return - } - context.RepoRef()(ctx) - if ctx.Written() { - return - } - - repo.MustBeNotEmpty(ctx) - }) - m.Group("/media", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownloadOrLFS) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownloadOrLFS) @@ -1583,6 +1563,8 @@ func registerRoutes(m *web.Router) { m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefBlame) }, repo.MustBeNotEmpty) + m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) + m.Group("", func() { m.Get("/graph", repo.Graph) m.Get("/commit/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) diff --git a/services/context/base.go b/services/context/base.go index cb89cdea02..7a39353e09 100644 --- a/services/context/base.go +++ b/services/context/base.go @@ -9,20 +9,15 @@ import ( "html/template" "io" "net/http" - "net/url" - "strconv" "strings" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web/middleware" - - "github.com/go-chi/chi/v5" ) type BaseContextKeyType struct{} @@ -107,93 +102,6 @@ func (b *Base) RemoteAddr() string { return b.Req.RemoteAddr } -// PathParam returns the param in request path, eg: "/{var}" => "/a%2fb", then `var == "a/b"` -func (b *Base) PathParam(name string) string { - s, err := url.PathUnescape(b.PathParamRaw(name)) - if err != nil && !setting.IsProd { - panic("Failed to unescape path param: " + err.Error() + ", there seems to be a double-unescaping bug") - } - return s -} - -// PathParamRaw returns the raw param in request path, eg: "/{var}" => "/a%2fb", then `var == "a%2fb"` -func (b *Base) PathParamRaw(name string) string { - return chi.URLParam(b.Req, strings.TrimPrefix(name, ":")) -} - -// PathParamInt64 returns the param in request path as int64 -func (b *Base) PathParamInt64(p string) int64 { - v, _ := strconv.ParseInt(b.PathParam(p), 10, 64) - return v -} - -// SetPathParam set request path params into routes -func (b *Base) SetPathParam(k, v string) { - chiCtx := chi.RouteContext(b) - chiCtx.URLParams.Add(strings.TrimPrefix(k, ":"), url.PathEscape(v)) -} - -// FormString returns the first value matching the provided key in the form as a string -func (b *Base) FormString(key string) string { - return b.Req.FormValue(key) -} - -// FormStrings returns a string slice for the provided key from the form -func (b *Base) FormStrings(key string) []string { - if b.Req.Form == nil { - if err := b.Req.ParseMultipartForm(32 << 20); err != nil { - return nil - } - } - if v, ok := b.Req.Form[key]; ok { - return v - } - return nil -} - -// FormTrim returns the first value for the provided key in the form as a space trimmed string -func (b *Base) FormTrim(key string) string { - return strings.TrimSpace(b.Req.FormValue(key)) -} - -// FormInt returns the first value for the provided key in the form as an int -func (b *Base) FormInt(key string) int { - v, _ := strconv.Atoi(b.Req.FormValue(key)) - return v -} - -// FormInt64 returns the first value for the provided key in the form as an int64 -func (b *Base) FormInt64(key string) int64 { - v, _ := strconv.ParseInt(b.Req.FormValue(key), 10, 64) - return v -} - -// FormBool returns true if the value for the provided key in the form is "1", "true" or "on" -func (b *Base) FormBool(key string) bool { - s := b.Req.FormValue(key) - v, _ := strconv.ParseBool(s) - v = v || strings.EqualFold(s, "on") - return v -} - -// FormOptionalBool returns an optional.Some(true) or optional.Some(false) if the value -// for the provided key exists in the form else it returns optional.None[bool]() -func (b *Base) FormOptionalBool(key string) optional.Option[bool] { - value := b.Req.FormValue(key) - if len(value) == 0 { - return optional.None[bool]() - } - s := b.Req.FormValue(key) - v, _ := strconv.ParseBool(s) - v = v || strings.EqualFold(s, "on") - return optional.Some(v) -} - -func (b *Base) SetFormString(key, value string) { - _ = b.Req.FormValue(key) // force parse form - b.Req.Form.Set(key, value) -} - // PlainTextBytes renders bytes as plain text func (b *Base) plainTextInternal(skip, status int, bs []byte) { statusPrefix := status / 100 diff --git a/services/context/base_form.go b/services/context/base_form.go new file mode 100644 index 0000000000..ddf9734f57 --- /dev/null +++ b/services/context/base_form.go @@ -0,0 +1,72 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package context + +import ( + "strconv" + "strings" + + "code.gitea.io/gitea/modules/optional" +) + +// FormString returns the first value matching the provided key in the form as a string +func (b *Base) FormString(key string) string { + return b.Req.FormValue(key) +} + +// FormStrings returns a string slice for the provided key from the form +func (b *Base) FormStrings(key string) []string { + if b.Req.Form == nil { + if err := b.Req.ParseMultipartForm(32 << 20); err != nil { + return nil + } + } + if v, ok := b.Req.Form[key]; ok { + return v + } + return nil +} + +// FormTrim returns the first value for the provided key in the form as a space trimmed string +func (b *Base) FormTrim(key string) string { + return strings.TrimSpace(b.Req.FormValue(key)) +} + +// FormInt returns the first value for the provided key in the form as an int +func (b *Base) FormInt(key string) int { + v, _ := strconv.Atoi(b.Req.FormValue(key)) + return v +} + +// FormInt64 returns the first value for the provided key in the form as an int64 +func (b *Base) FormInt64(key string) int64 { + v, _ := strconv.ParseInt(b.Req.FormValue(key), 10, 64) + return v +} + +// FormBool returns true if the value for the provided key in the form is "1", "true" or "on" +func (b *Base) FormBool(key string) bool { + s := b.Req.FormValue(key) + v, _ := strconv.ParseBool(s) + v = v || strings.EqualFold(s, "on") + return v +} + +// FormOptionalBool returns an optional.Some(true) or optional.Some(false) if the value +// for the provided key exists in the form else it returns optional.None[bool]() +func (b *Base) FormOptionalBool(key string) optional.Option[bool] { + value := b.Req.FormValue(key) + if len(value) == 0 { + return optional.None[bool]() + } + s := b.Req.FormValue(key) + v, _ := strconv.ParseBool(s) + v = v || strings.EqualFold(s, "on") + return optional.Some(v) +} + +func (b *Base) SetFormString(key, value string) { + _ = b.Req.FormValue(key) // force parse form + b.Req.Form.Set(key, value) +} diff --git a/services/context/base_path.go b/services/context/base_path.go new file mode 100644 index 0000000000..3678deaff9 --- /dev/null +++ b/services/context/base_path.go @@ -0,0 +1,47 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package context + +import ( + "net/url" + "strconv" + "strings" + + "code.gitea.io/gitea/modules/setting" + + "github.com/go-chi/chi/v5" +) + +// PathParam returns the param in request path, eg: "/{var}" => "/a%2fb", then `var == "a/b"` +func (b *Base) PathParam(name string) string { + s, err := url.PathUnescape(b.PathParamRaw(name)) + if err != nil && !setting.IsProd { + panic("Failed to unescape path param: " + err.Error() + ", there seems to be a double-unescaping bug") + } + return s +} + +// PathParamRaw returns the raw param in request path, eg: "/{var}" => "/a%2fb", then `var == "a%2fb"` +func (b *Base) PathParamRaw(name string) string { + if strings.HasPrefix(name, ":") { + setting.PanicInDevOrTesting("path param should not start with ':'") + name = name[1:] + } + return chi.URLParam(b.Req, name) +} + +// PathParamInt64 returns the param in request path as int64 +func (b *Base) PathParamInt64(p string) int64 { + v, _ := strconv.ParseInt(b.PathParam(p), 10, 64) + return v +} + +// SetPathParam set request path params into routes +func (b *Base) SetPathParam(name, value string) { + if strings.HasPrefix(name, ":") { + setting.PanicInDevOrTesting("path param should not start with ':'") + name = name[1:] + } + chi.RouteContext(b).URLParams.Add(name, url.PathEscape(value)) +} diff --git a/services/context/org.go b/services/context/org.go index bf482fa754..be87cef7a3 100644 --- a/services/context/org.go +++ b/services/context/org.go @@ -40,7 +40,7 @@ func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool { } func GetOrganizationByParams(ctx *Context) { - orgName := ctx.PathParam(":org") + orgName := ctx.PathParam("org") var err error @@ -220,7 +220,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { ctx.Data["NumTeams"] = len(ctx.Org.Teams) } - teamName := ctx.PathParam(":team") + teamName := ctx.PathParam("team") if len(teamName) > 0 { teamExists := false for _, team := range ctx.Org.Teams { diff --git a/services/context/repo.go b/services/context/repo.go index db5308415e..b537a05036 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -316,8 +316,8 @@ func ComposeGoGetImport(ctx context.Context, owner, repo string) string { // This is particular a workaround for "go get" command which does not respect // .netrc file. func EarlyResponseForGoGetMeta(ctx *Context) { - username := ctx.PathParam(":username") - reponame := strings.TrimSuffix(ctx.PathParam(":reponame"), ".git") + username := ctx.PathParam("username") + reponame := strings.TrimSuffix(ctx.PathParam("reponame"), ".git") if username == "" || reponame == "" { ctx.PlainText(http.StatusBadRequest, "invalid repository path") return @@ -336,8 +336,8 @@ func EarlyResponseForGoGetMeta(ctx *Context) { // RedirectToRepo redirect to a differently-named repository func RedirectToRepo(ctx *Base, redirectRepoID int64) { - ownerName := ctx.PathParam(":username") - previousRepoName := ctx.PathParam(":reponame") + ownerName := ctx.PathParam("username") + previousRepoName := ctx.PathParam("reponame") repo, err := repo_model.GetRepositoryByID(ctx, redirectRepoID) if err != nil { @@ -412,8 +412,8 @@ func RepoAssignment(ctx *Context) { err error ) - userName := ctx.PathParam(":username") - repoName := ctx.PathParam(":reponame") + userName := ctx.PathParam("username") + repoName := ctx.PathParam("reponame") repoName = strings.TrimSuffix(repoName, ".git") if setting.Other.EnableFeed { repoName = strings.TrimSuffix(repoName, ".rss") @@ -456,7 +456,7 @@ func RepoAssignment(ctx *Context) { if strings.HasSuffix(repoName, ".wiki") { // ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added // Now we happen to know that all of our paths are: /:username/:reponame/whatever_else - originalRepoName := ctx.PathParam(":reponame") + originalRepoName := ctx.PathParam("reponame") redirectRepoName := strings.TrimSuffix(repoName, ".wiki") redirectRepoName += originalRepoName[len(redirectRepoName)+5:] redirectPath := strings.Replace( diff --git a/services/context/upload/upload.go b/services/context/upload/upload.go index cefd13ebb6..da4370a433 100644 --- a/services/context/upload/upload.go +++ b/services/context/upload/upload.go @@ -97,8 +97,8 @@ func AddUploadContext(ctx *context.Context, uploadType string) { } else if uploadType == "comment" { ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments" ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove" - if len(ctx.PathParam(":index")) > 0 { - ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.PathParam(":index")) + "/attachments" + if len(ctx.PathParam("index")) > 0 { + ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.PathParam("index")) + "/attachments" } else { ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/attachments" } diff --git a/services/context/user.go b/services/context/user.go index b0e855e923..dbc35e198d 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -33,7 +33,7 @@ func UserAssignmentWeb() func(ctx *Context) { // UserIDAssignmentAPI returns a middleware to handle context-user assignment for api routes func UserIDAssignmentAPI() func(ctx *APIContext) { return func(ctx *APIContext) { - userID := ctx.PathParamInt64(":user-id") + userID := ctx.PathParamInt64("user-id") if ctx.IsSigned && ctx.Doer.ID == userID { ctx.ContextUser = ctx.Doer @@ -59,7 +59,7 @@ func UserAssignmentAPI() func(ctx *APIContext) { } func userAssignment(ctx *Base, doer *user_model.User, errCb func(int, string, any)) (contextUser *user_model.User) { - username := ctx.PathParam(":username") + username := ctx.PathParam("username") if doer != nil && doer.LowerName == strings.ToLower(username) { contextUser = doer diff --git a/services/issue/commit.go b/services/issue/commit.go index 0579e0f5c5..963d0359fd 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -188,15 +188,19 @@ func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_m continue } } - isClosed := ref.Action == references.XRefActionCloses - if isClosed && len(ref.TimeLog) > 0 { - if err := issueAddTime(ctx, refIssue, doer, c.Timestamp, ref.TimeLog); err != nil { + + refIssue.Repo = refRepo + if ref.Action == references.XRefActionCloses && !refIssue.IsClosed { + if len(ref.TimeLog) > 0 { + if err := issueAddTime(ctx, refIssue, doer, c.Timestamp, ref.TimeLog); err != nil { + return err + } + } + if err := CloseIssue(ctx, refIssue, doer, c.Sha1); err != nil { return err } - } - if isClosed != refIssue.IsClosed { - refIssue.Repo = refRepo - if err := ChangeStatus(ctx, refIssue, doer, c.Sha1, isClosed); err != nil { + } else if ref.Action == references.XRefActionReopens && refIssue.IsClosed { + if err := ReopenIssue(ctx, refIssue, doer, c.Sha1); err != nil { return err } } diff --git a/services/issue/milestone.go b/services/issue/milestone.go index ff645744a7..beb6f131a9 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -59,6 +59,10 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *is } } + if issue.MilestoneID == 0 { + issue.Milestone = nil + } + return nil } diff --git a/services/issue/milestone_test.go b/services/issue/milestone_test.go index 42b910166f..bf5abc85b7 100644 --- a/services/issue/milestone_test.go +++ b/services/issue/milestone_test.go @@ -23,6 +23,7 @@ func TestChangeMilestoneAssign(t *testing.T) { oldMilestoneID := issue.MilestoneID issue.MilestoneID = 2 + assert.NoError(t, issue.LoadMilestone(db.DefaultContext)) assert.NoError(t, ChangeMilestoneAssign(db.DefaultContext, issue, doer, oldMilestoneID)) unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ IssueID: issue.ID, @@ -31,4 +32,11 @@ func TestChangeMilestoneAssign(t *testing.T) { OldMilestoneID: oldMilestoneID, }) unittest.CheckConsistencyFor(t, &issues_model.Milestone{}, &issues_model.Issue{}) + assert.NotNil(t, issue.Milestone) + + oldMilestoneID = issue.MilestoneID + issue.MilestoneID = 0 + assert.NoError(t, ChangeMilestoneAssign(db.DefaultContext, issue, doer, oldMilestoneID)) + assert.EqualValues(t, 0, issue.MilestoneID) + assert.Nil(t, issue.Milestone) } diff --git a/services/issue/status.go b/services/issue/status.go index 967c29bd22..e18b891175 100644 --- a/services/issue/status.go +++ b/services/issue/status.go @@ -6,34 +6,54 @@ package issue import ( "context" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" notify_service "code.gitea.io/gitea/services/notify" ) -// ChangeStatus changes issue status to open or closed. -// closed means the target status -// Fix me: you should check whether the current issue status is same to the target status before call this function -// as in function changeIssueStatus we will return WasClosedError, even the issue status and target status are both open -func ChangeStatus(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, commitID string, closed bool) error { - comment, err := issues_model.ChangeIssueStatus(ctx, issue, doer, closed) +// CloseIssue close an issue. +func CloseIssue(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, commitID string) error { + dbCtx, committer, err := db.TxContext(ctx) if err != nil { - if issues_model.IsErrDependenciesLeft(err) && closed { - if err := issues_model.FinishIssueStopwatchIfPossible(ctx, doer, issue); err != nil { + return err + } + defer committer.Close() + + comment, err := issues_model.CloseIssue(dbCtx, issue, doer) + if err != nil { + if issues_model.IsErrDependenciesLeft(err) { + if err := issues_model.FinishIssueStopwatchIfPossible(dbCtx, doer, issue); err != nil { log.Error("Unable to stop stopwatch for issue[%d]#%d: %v", issue.ID, issue.Index, err) } } return err } - if closed { - if err := issues_model.FinishIssueStopwatchIfPossible(ctx, doer, issue); err != nil { - return err - } + if err := issues_model.FinishIssueStopwatchIfPossible(dbCtx, doer, issue); err != nil { + return err } - notify_service.IssueChangeStatus(ctx, doer, commitID, issue, comment, closed) + if err := committer.Commit(); err != nil { + return err + } + committer.Close() + + notify_service.IssueChangeStatus(ctx, doer, commitID, issue, comment, true) + + return nil +} + +// ReopenIssue reopen an issue. +// FIXME: If some issues dependent this one are closed, should we also reopen them? +func ReopenIssue(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, commitID string) error { + comment, err := issues_model.ReopenIssue(ctx, issue, doer) + if err != nil { + return err + } + + notify_service.IssueChangeStatus(ctx, doer, commitID, issue, comment, false) return nil } diff --git a/services/pull/merge.go b/services/pull/merge.go index fba85f1e51..75011a697c 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -263,14 +263,17 @@ func handleCloseCrossReferences(ctx context.Context, pr *issues_model.PullReques if err = ref.Issue.LoadRepo(ctx); err != nil { return err } - isClosed := ref.RefAction == references.XRefActionCloses - if isClosed != ref.Issue.IsClosed { - if err = issue_service.ChangeStatus(ctx, ref.Issue, doer, pr.MergedCommitID, isClosed); err != nil { + if ref.RefAction == references.XRefActionCloses && !ref.Issue.IsClosed { + if err = issue_service.CloseIssue(ctx, ref.Issue, doer, pr.MergedCommitID); err != nil { // Allow ErrDependenciesLeft if !issues_model.IsErrDependenciesLeft(err) { return err } } + } else if ref.RefAction == references.XRefActionReopens && ref.Issue.IsClosed { + if err = issue_service.ReopenIssue(ctx, ref.Issue, doer, pr.MergedCommitID); err != nil { + return err + } } } return nil diff --git a/services/pull/pull.go b/services/pull/pull.go index 0256c2c3f6..ac91fd6409 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -706,7 +706,7 @@ func CloseBranchPulls(ctx context.Context, doer *user_model.User, repoID int64, var errs errlist for _, pr := range prs { - if err = issue_service.ChangeStatus(ctx, pr.Issue, doer, "", true); err != nil && !issues_model.IsErrPullWasClosed(err) && !issues_model.IsErrDependenciesLeft(err) { + if err = issue_service.CloseIssue(ctx, pr.Issue, doer, ""); err != nil && !issues_model.IsErrPullWasClosed(err) && !issues_model.IsErrDependenciesLeft(err) { errs = append(errs, err) } } @@ -740,7 +740,7 @@ func CloseRepoBranchesPulls(ctx context.Context, doer *user_model.User, repo *re if pr.BaseRepoID == repo.ID { continue } - if err = issue_service.ChangeStatus(ctx, pr.Issue, doer, "", true); err != nil && !issues_model.IsErrPullWasClosed(err) { + if err = issue_service.CloseIssue(ctx, pr.Issue, doer, ""); err != nil && !issues_model.IsErrPullWasClosed(err) { errs = append(errs, err) } } diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go index a899be70e3..7cb46c0bb6 100644 --- a/services/repository/files/content_test.go +++ b/services/repository/files/content_test.go @@ -53,7 +53,7 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { func TestGetContents(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -81,7 +81,7 @@ func TestGetContents(t *testing.T) { func TestGetContentsOrListForDir(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -116,7 +116,7 @@ func TestGetContentsOrListForDir(t *testing.T) { func TestGetContentsOrListForFile(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -144,7 +144,7 @@ func TestGetContentsOrListForFile(t *testing.T) { func TestGetContentsErrors(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -175,7 +175,7 @@ func TestGetContentsErrors(t *testing.T) { func TestGetContentsOrListErrors(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -206,7 +206,7 @@ func TestGetContentsOrListErrors(t *testing.T) { func TestGetContentsOrListOfEmptyRepos(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user30/empty") - ctx.SetPathParam(":id", "52") + ctx.SetPathParam("id", "52") contexttest.LoadRepo(t, ctx, 52) contexttest.LoadUser(t, ctx, 30) contexttest.LoadGitRepo(t, ctx) @@ -231,15 +231,15 @@ func TestGetBlobBySHA(t *testing.T) { defer ctx.Repo.GitRepo.Close() sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" - ctx.SetPathParam(":id", "1") - ctx.SetPathParam(":sha", sha) + ctx.SetPathParam("id", "1") + ctx.SetPathParam("sha", sha) gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) if err != nil { t.Fail() } - gbr, err := GetBlobBySHA(ctx, ctx.Repo.Repository, gitRepo, ctx.PathParam(":sha")) + gbr, err := GetBlobBySHA(ctx, ctx.Repo.Repository, gitRepo, ctx.PathParam("sha")) expectedGBR := &api.GitBlobResponse{ Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK", Encoding: "base64", diff --git a/services/repository/files/diff_test.go b/services/repository/files/diff_test.go index ea6ffe60c3..b7bdcd8ecf 100644 --- a/services/repository/files/diff_test.go +++ b/services/repository/files/diff_test.go @@ -18,7 +18,7 @@ import ( func TestGetDiffPreview(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) @@ -140,7 +140,7 @@ func TestGetDiffPreview(t *testing.T) { func TestGetDiffPreviewErrors(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) diff --git a/services/repository/files/file_test.go b/services/repository/files/file_test.go index b2f51e3c82..52c0574883 100644 --- a/services/repository/files/file_test.go +++ b/services/repository/files/file_test.go @@ -99,7 +99,7 @@ func getExpectedFileResponse() *api.FileResponse { func TestGetFileResponseFromCommit(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam(":id", "1") + ctx.SetPathParam("id", "1") contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) diff --git a/services/repository/files/tree_test.go b/services/repository/files/tree_test.go index a329a39405..49188b72e7 100644 --- a/services/repository/files/tree_test.go +++ b/services/repository/files/tree_test.go @@ -26,10 +26,10 @@ func TestGetTreeBySHA(t *testing.T) { sha := ctx.Repo.Repository.DefaultBranch page := 1 perPage := 10 - ctx.SetPathParam(":id", "1") - ctx.SetPathParam(":sha", sha) + ctx.SetPathParam("id", "1") + ctx.SetPathParam("sha", sha) - tree, err := GetTreeBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam(":sha"), page, perPage, true) + tree, err := GetTreeBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("sha"), page, perPage, true) assert.NoError(t, err) expectedTree := &api.GitTreeResponse{ SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", diff --git a/templates/base/head_script.tmpl b/templates/base/head_script.tmpl index c0c7235e3b..7c931e7404 100644 --- a/templates/base/head_script.tmpl +++ b/templates/base/head_script.tmpl @@ -1,5 +1,4 @@ -{{/* -==== DO NOT EDIT ==== +{{/* ==== DO NOT EDIT ==== If you are customizing Gitea, please do not change this file. If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly. */}} diff --git a/templates/base/modal_actions_confirm.tmpl b/templates/base/modal_actions_confirm.tmpl index 9f7eb4adf2..ec6942b9e7 100644 --- a/templates/base/modal_actions_confirm.tmpl +++ b/templates/base/modal_actions_confirm.tmpl @@ -1,5 +1,4 @@ -{{/* -Two buttons (negative, positive): +{{/* Two buttons (negative, positive): * ModalButtonTypes: "yes" (default) or "confirm" * ModalButtonCancelText * ModalButtonOkText diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index cc2237029b..4089d8fb33 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -1,3 +1,4 @@ +{{$blobExcerptLink := print $.RepoLink (Iif $.PageIsWiki "/wiki" "") "/blob_excerpt/" (PathEscape $.AfterCommitID) (QueryBuild "?" "anchor" $.Anchor)}} {{if $.IsSplitStyle}} {{range $k, $line := $.section.Lines}} @@ -6,42 +7,48 @@
{{if or (eq $expandDirection 3) (eq $expandDirection 5)}} - {{end}} {{if or (eq $expandDirection 3) (eq $expandDirection 4)}} - {{end}} {{if eq $expandDirection 2}} - {{end}}
- {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}}{{/* - */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}} + + {{- $inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale -}} + {{- template "repo/diff/section_code" dict "diff" $inlineDiff -}} + {{else}} {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} {{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} {{if $line.LeftIdx}}{{end}} - {{/* - */}}{{if $line.LeftIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}} + + {{- if $line.LeftIdx -}} + {{- template "repo/diff/section_code" dict "diff" $inlineDiff -}} + {{- else -}} + + {{- end -}} + {{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} {{if $line.RightIdx}}{{end}} - {{/* - */}}{{if $line.RightIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}} + + {{- if $line.RightIdx -}} + {{- template "repo/diff/section_code" dict "diff" $inlineDiff -}} + {{- else -}} + + {{- end -}} + {{end}} {{end}} @@ -53,17 +60,17 @@
{{if or (eq $expandDirection 3) (eq $expandDirection 5)}} - {{end}} {{if or (eq $expandDirection 3) (eq $expandDirection 4)}} - {{end}} {{if eq $expandDirection 2}} - {{end}} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 53ea4fd2e3..0dfb1fd5a1 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -36,10 +36,7 @@ {{template "repo/diff/options_dropdown" .}} {{if .PageIsPullFiles}}
- {{/* - the following will be replaced by vue component - but this avoids any loading artifacts till the vue component is initialized - */}} + {{/* the following will be replaced by vue component, but this avoids any loading artifacts till the vue component is initialized */}} diff --git a/templates/repo/diff/escape_title.tmpl b/templates/repo/diff/escape_title.tmpl index e70f4021c7..9787ae1d42 100644 --- a/templates/repo/diff/escape_title.tmpl +++ b/templates/repo/diff/escape_title.tmpl @@ -1,2 +1,2 @@ -{{if .diff.EscapeStatus.HasInvisible}}{{ctx.Locale.Tr "repo.invisible_runes_line"}} {{end}}{{/* -*/}}{{if .diff.EscapeStatus.HasAmbiguous}}{{ctx.Locale.Tr "repo.ambiguous_runes_line"}}{{end}} +{{if .diff.EscapeStatus.HasInvisible}}{{ctx.Locale.Tr "repo.invisible_runes_line"}} {{end -}} +{{- if .diff.EscapeStatus.HasAmbiguous}}{{ctx.Locale.Tr "repo.ambiguous_runes_line"}}{{end}} diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl index 37b42bcb37..9953db5eb2 100644 --- a/templates/repo/diff/section_split.tmpl +++ b/templates/repo/diff/section_split.tmpl @@ -1,5 +1,5 @@ {{$file := .file}} -{{$blobExcerptRepoLink := or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink}} +{{$blobExcerptLink := print (or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink) (Iif $.root.PageIsWiki "/wiki" "") "/blob_excerpt/" (PathEscape $.root.AfterCommitID) "?"}} @@ -20,26 +20,24 @@
{{if or (eq $expandDirection 3) (eq $expandDirection 5)}} - {{end}} {{if or (eq $expandDirection 3) (eq $expandDirection 4)}} - {{end}} {{if eq $expandDirection 2}} - {{end}}
{{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale}} {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} - {{/* - */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* - */}} + {{template "repo/diff/section_code" dict "diff" $inlineDiff}} {{else if and (eq .GetType 3) $hasmatch}}{{/* DEL */}} {{$match := index $section.Lines $line.Match}} {{- $leftDiff := ""}}{{if $line.LeftIdx}}{{$leftDiff = $section.GetComputedInlineDiffFor $line ctx.Locale}}{{end}} @@ -47,65 +45,65 @@ {{if $line.LeftIdx}}{{if $leftDiff.EscapeStatus.Escaped}}{{end}}{{end}} - {{/* - */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}}{{if $line.LeftIdx}}{{/* - */}}{{template "repo/diff/section_code" dict "diff" $leftDiff}}{{/* - */}}{{else}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}} + + {{- if and $.root.SignedUserID $.root.PageIsPullFiles -}} + + {{- end -}} + {{- if $line.LeftIdx -}} + {{- template "repo/diff/section_code" dict "diff" $leftDiff -}} + {{- else -}} + + {{- end -}} + {{if $match.RightIdx}}{{if $rightDiff.EscapeStatus.Escaped}}{{end}}{{end}} {{if $match.RightIdx}}{{end}} - {{/* - */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}}{{if $match.RightIdx}}{{/* - */}}{{template "repo/diff/section_code" dict "diff" $rightDiff}}{{/* - */}}{{else}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}} + + {{- if and $.root.SignedUserID $.root.PageIsPullFiles -}} + + {{- end -}} + {{- if $match.RightIdx -}} + {{- template "repo/diff/section_code" dict "diff" $rightDiff -}} + {{- else -}} + + {{- end -}} + {{else}} {{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale}} {{if $line.LeftIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} {{if $line.LeftIdx}}{{end}} - {{/* - */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 2))}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}}{{if $line.LeftIdx}}{{/* - */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* - */}}{{else}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}} + + {{- if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 2)) -}} + + {{- end -}} + {{- if $line.LeftIdx -}} + {{- template "repo/diff/section_code" dict "diff" $inlineDiff -}} + {{- else -}} + + {{- end -}} + {{if $line.RightIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} {{if $line.RightIdx}}{{end}} - {{/* - */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 3))}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}}{{if $line.RightIdx}}{{/* - */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* - */}}{{else}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}} + + {{- if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 3)) -}} + + {{- end -}} + {{- if $line.RightIdx -}} + {{- template "repo/diff/section_code" dict "diff" $inlineDiff -}} + {{- else -}} + + {{- end -}} + {{end}} {{if and (eq .GetType 3) $hasmatch}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 708b333291..a06cd2ddd1 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -1,5 +1,5 @@ {{$file := .file}} -{{$blobExcerptRepoLink := or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink}} +{{$blobExcerptLink := print (or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink) (Iif $.root.PageIsWiki "/wiki" "") "/blob_excerpt/" (PathEscape $.root.AfterCommitID) "?"}} @@ -16,17 +16,17 @@
{{if or (eq $expandDirection 3) (eq $expandDirection 5)}} - {{end}} {{if or (eq $expandDirection 3) (eq $expandDirection 4)}} - {{end}} {{if eq $expandDirection 2}} - {{end}} @@ -48,18 +48,16 @@ {{if eq .GetType 4}} - {{/* - */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* - */}} + {{template "repo/diff/section_code" dict "diff" $inlineDiff}} {{else}} - {{/* - */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/* - */}}{{/* - */}}{{end}}{{/* - */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* - */}} + + {{- if and $.root.SignedUserID $.root.PageIsPullFiles -}} + + {{- end -}} + {{- template "repo/diff/section_code" dict "diff" $inlineDiff -}} + {{end}} {{if $line.Comments}} diff --git a/templates/repo/issue/filter_item_label.tmpl b/templates/repo/issue/filter_item_label.tmpl index 88e2e43120..0883d93804 100644 --- a/templates/repo/issue/filter_item_label.tmpl +++ b/templates/repo/issue/filter_item_label.tmpl @@ -1,4 +1,4 @@ -{{/* +{{/* Template Attributes: * "labels" from query string (needed by JS) * QueryLink * Labels diff --git a/templates/repo/issue/sidebar/milestone_list.tmpl b/templates/repo/issue/sidebar/milestone_list.tmpl index 0e926f7b03..8b3e5b0eee 100644 --- a/templates/repo/issue/sidebar/milestone_list.tmpl +++ b/templates/repo/issue/sidebar/milestone_list.tmpl @@ -6,7 +6,7 @@ {{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/milestone?issue_ids={{$pageMeta.Issue.ID}}"{{end}} > -