diff --git a/Dockerfile b/Dockerfile index 2a6b1dd6b7..b95ba83289 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.23-alpine3.20 AS build-env +FROM docker.io/library/golang:1.23-alpine3.21 AS build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} @@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM docker.io/library/alpine:3.20 +FROM docker.io/library/alpine:3.21 LABEL maintainer="maintainers@gitea.io" EXPOSE 22 3000 @@ -78,7 +78,7 @@ ENV GITEA_CUSTOM=/data/gitea VOLUME ["/data"] ENTRYPOINT ["/usr/bin/entrypoint"] -CMD ["/bin/s6-svscan", "/etc/s6"] +CMD ["/usr/bin/s6-svscan", "/etc/s6"] COPY --from=build-env /tmp/local / COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea diff --git a/Dockerfile.rootless b/Dockerfile.rootless index 26f02205a7..be6f125104 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.23-alpine3.20 AS build-env +FROM docker.io/library/golang:1.23-alpine3.21 AS build-env ARG GOPROXY ENV GOPROXY=${GOPROXY:-direct} @@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM docker.io/library/alpine:3.20 +FROM docker.io/library/alpine:3.21 LABEL maintainer="maintainers@gitea.io" EXPOSE 2222 3000 diff --git a/models/actions/runner_token.go b/models/actions/runner_token.go index fd6ba7ecad..1eab5efcce 100644 --- a/models/actions/runner_token.go +++ b/models/actions/runner_token.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" ) @@ -51,7 +52,7 @@ func GetRunnerToken(ctx context.Context, token string) (*ActionRunnerToken, erro if err != nil { return nil, err } else if !has { - return nil, fmt.Errorf("runner token %q: %w", token, util.ErrNotExist) + return nil, fmt.Errorf(`runner token "%s...": %w`, base.TruncateString(token, 3), util.ErrNotExist) } return &runnerToken, nil } @@ -68,19 +69,15 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string return err } -// NewRunnerToken creates a new active runner token and invalidate all old tokens +// NewRunnerTokenWithValue creates a new active runner token and invalidate all old tokens // ownerID will be ignored and treated as 0 if repoID is non-zero. -func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { +func NewRunnerTokenWithValue(ctx context.Context, ownerID, repoID int64, token string) (*ActionRunnerToken, error) { if ownerID != 0 && repoID != 0 { // It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally. // Remove OwnerID to avoid confusion; it's not worth returning an error here. ownerID = 0 } - token, err := util.CryptoRandomString(40) - if err != nil { - return nil, err - } runnerToken := &ActionRunnerToken{ OwnerID: ownerID, RepoID: repoID, @@ -95,11 +92,19 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo return err } - _, err = db.GetEngine(ctx).Insert(runnerToken) + _, err := db.GetEngine(ctx).Insert(runnerToken) return err }) } +func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { + token, err := util.CryptoRandomString(40) + if err != nil { + return nil, err + } + return NewRunnerTokenWithValue(ctx, ownerID, repoID, token) +} + // GetLatestRunnerToken returns the latest runner token func GetLatestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { if ownerID != 0 && repoID != 0 { diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index c2134f702a..2eb85cd8a7 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -13,9 +13,9 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/testlogger" "github.com/stretchr/testify/require" @@ -92,10 +92,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu func MainTest(m *testing.M) { testlogger.Init() - giteaRoot := base.SetupGiteaRoot() - if giteaRoot == "" { - testlogger.Fatalf("Environment variable $GITEA_ROOT not set\n") - } + giteaRoot := test.SetupGiteaRoot() giteaBinary := "gitea" if runtime.GOOS == "windows" { giteaBinary += ".exe" diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 5a1c27dbea..12f3c25676 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -14,13 +14,13 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/auth/password/hash" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting/config" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -206,7 +206,7 @@ func CreateTestEngine(opts FixturesOptions) error { x, err := xorm.NewEngine("sqlite3", "file::memory:?cache=shared&_txlock=immediate") if err != nil { if strings.Contains(err.Error(), "unknown driver") { - return fmt.Errorf(`sqlite3 requires: import _ "github.com/mattn/go-sqlite3" or -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err) + return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err) } return err } @@ -235,5 +235,5 @@ func PrepareTestEnv(t testing.TB) { assert.NoError(t, PrepareTestDatabase()) metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta") assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath)) - base.SetupGiteaRoot() // Makes sure GITEA_ROOT is set + test.SetupGiteaRoot() // Makes sure GITEA_ROOT is set } diff --git a/modules/base/base.go b/modules/base/base.go deleted file mode 100644 index dddce202da..0000000000 --- a/modules/base/base.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2014 The Gogs Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package base - -type ( - // TplName template relative path type - TplName string -) diff --git a/modules/base/tool.go b/modules/base/tool.go index 928c80700b..2303e64a68 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -13,9 +13,6 @@ import ( "errors" "fmt" "hash" - "os" - "path/filepath" - "runtime" "strconv" "strings" "time" @@ -189,49 +186,3 @@ func EntryIcon(entry *git.TreeEntry) string { return "file" } - -// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value -func SetupGiteaRoot() string { - giteaRoot := os.Getenv("GITEA_ROOT") - if giteaRoot == "" { - _, filename, _, _ := runtime.Caller(0) - giteaRoot = strings.TrimSuffix(filename, "modules/base/tool.go") - wd, err := os.Getwd() - if err != nil { - rel, err := filepath.Rel(giteaRoot, wd) - if err != nil && strings.HasPrefix(filepath.ToSlash(rel), "../") { - giteaRoot = wd - } - } - if _, err := os.Stat(filepath.Join(giteaRoot, "gitea")); os.IsNotExist(err) { - giteaRoot = "" - } else if err := os.Setenv("GITEA_ROOT", giteaRoot); err != nil { - giteaRoot = "" - } - } - return giteaRoot -} - -// FormatNumberSI format a number -func FormatNumberSI(data any) string { - var num int64 - if num1, ok := data.(int64); ok { - num = num1 - } else if num1, ok := data.(int); ok { - num = int64(num1) - } else { - return "" - } - - if num < 1000 { - return fmt.Sprintf("%d", num) - } else if num < 1000000 { - num2 := float32(num) / float32(1000.0) - return fmt.Sprintf("%.1fk", num2) - } else if num < 1000000000 { - num2 := float32(num) / float32(1000000.0) - return fmt.Sprintf("%.1fM", num2) - } - num2 := float32(num) / float32(1000000000.0) - return fmt.Sprintf("%.1fG", num2) -} diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index f63679048e..de6c311856 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -169,18 +169,3 @@ func TestInt64sToStrings(t *testing.T) { } // TODO: Test EntryIcon - -func TestSetupGiteaRoot(t *testing.T) { - t.Setenv("GITEA_ROOT", "test") - assert.Equal(t, "test", SetupGiteaRoot()) - t.Setenv("GITEA_ROOT", "") - assert.NotEqual(t, "test", SetupGiteaRoot()) -} - -func TestFormatNumberSI(t *testing.T) { - assert.Equal(t, "125", FormatNumberSI(int(125))) - assert.Equal(t, "1.3k", FormatNumberSI(int64(1317))) - assert.Equal(t, "21.3M", FormatNumberSI(21317675)) - assert.Equal(t, "45.7G", FormatNumberSI(45721317675)) - assert.Equal(t, "", FormatNumberSI("test")) -} diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 9ffadb833d..647894bb21 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -216,8 +216,6 @@ type CommitsByFileAndRangeOptions struct { // CommitsByFileAndRange return the commits according revision file and the page func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) ([]*Commit, error) { - skip := (opts.Page - 1) * setting.Git.CommitsRangeSize - stdoutReader, stdoutWriter := io.Pipe() defer func() { _ = stdoutReader.Close() @@ -226,8 +224,8 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) go func() { stderr := strings.Builder{} gitCmd := NewCommand(repo.Ctx, "rev-list"). - AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize*opts.Page). - AddOptionFormat("--skip=%d", skip) + AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize). + AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize) gitCmd.AddDynamicArguments(opts.Revision) if opts.Not != "" { diff --git a/modules/git/repo_commit_test.go b/modules/git/repo_commit_test.go index 4c26fa2a48..e9f469accd 100644 --- a/modules/git/repo_commit_test.go +++ b/modules/git/repo_commit_test.go @@ -8,7 +8,11 @@ import ( "path/filepath" "testing" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRepository_GetCommitBranches(t *testing.T) { @@ -126,3 +130,21 @@ func TestGetRefCommitID(t *testing.T) { } } } + +func TestCommitsByFileAndRange(t *testing.T) { + defer test.MockVariableValue(&setting.Git.CommitsRangeSize, 2)() + + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + bareRepo1, err := openRepositoryWithDefaultContext(bareRepo1Path) + require.NoError(t, err) + defer bareRepo1.Close() + + // "foo" has 3 commits in "master" branch + commits, err := bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 1}) + require.NoError(t, err) + assert.Len(t, commits, 2) + + commits, err = bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 2}) + require.NoError(t, err) + assert.Len(t, commits, 1) +} diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index 16fcdcf4c8..877a7ff3b8 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -233,72 +233,34 @@ func parseDiffStat(stdout string) (numFiles, totalAdditions, totalDeletions int, return numFiles, totalAdditions, totalDeletions, err } -// GetDiffOrPatch generates either diff or formatted patch data between given revisions -func (repo *Repository) GetDiffOrPatch(base, head string, w io.Writer, patch, binary bool) error { - if patch { - return repo.GetPatch(base, head, w) - } - if binary { - return repo.GetDiffBinary(base, head, w) - } - return repo.GetDiff(base, head, w) -} - // GetDiff generates and returns patch data between given revisions, optimized for human readability -func (repo *Repository) GetDiff(base, head string, w io.Writer) error { +func (repo *Repository) GetDiff(compareArg string, w io.Writer) error { stderr := new(bytes.Buffer) - err := NewCommand(repo.Ctx, "diff", "-p").AddDynamicArguments(base + "..." + head). + return NewCommand(repo.Ctx, "diff", "-p").AddDynamicArguments(compareArg). Run(&RunOpts{ Dir: repo.Path, Stdout: w, Stderr: stderr, }) - if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) { - return NewCommand(repo.Ctx, "diff", "-p").AddDynamicArguments(base, head). - Run(&RunOpts{ - Dir: repo.Path, - Stdout: w, - }) - } - return err } // GetDiffBinary generates and returns patch data between given revisions, including binary diffs. -func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error { - stderr := new(bytes.Buffer) - err := NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram").AddDynamicArguments(base + "..." + head). - Run(&RunOpts{ - Dir: repo.Path, - Stdout: w, - Stderr: stderr, - }) - if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) { - return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram").AddDynamicArguments(base, head). - Run(&RunOpts{ - Dir: repo.Path, - Stdout: w, - }) - } - return err +func (repo *Repository) GetDiffBinary(compareArg string, w io.Writer) error { + return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram").AddDynamicArguments(compareArg).Run(&RunOpts{ + Dir: repo.Path, + Stdout: w, + }) } // GetPatch generates and returns format-patch data between given revisions, able to be used with `git apply` -func (repo *Repository) GetPatch(base, head string, w io.Writer) error { +func (repo *Repository) GetPatch(compareArg string, w io.Writer) error { stderr := new(bytes.Buffer) - err := NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout").AddDynamicArguments(base + "..." + head). + return NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout").AddDynamicArguments(compareArg). Run(&RunOpts{ Dir: repo.Path, Stdout: w, Stderr: stderr, }) - if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) { - return NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout").AddDynamicArguments(base, head). - Run(&RunOpts{ - Dir: repo.Path, - Stdout: w, - }) - } - return err } // GetFilesChangedBetween returns a list of all files that have been changed between the given commits @@ -329,21 +291,6 @@ func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, err return split, err } -// GetDiffFromMergeBase generates and return patch data from merge base to head -func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) error { - stderr := new(bytes.Buffer) - err := NewCommand(repo.Ctx, "diff", "-p", "--binary").AddDynamicArguments(base + "..." + head). - Run(&RunOpts{ - Dir: repo.Path, - Stdout: w, - Stderr: stderr, - }) - if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) { - return repo.GetDiffBinary(base, head, w) - } - return err -} - // ReadPatchCommit will check if a diff patch exists and return stats func (repo *Repository) ReadPatchCommit(prID int64) (commitSHA string, err error) { // Migrated repositories download patches to "pulls" location diff --git a/modules/git/repo_compare_test.go b/modules/git/repo_compare_test.go index 454ed6b9f8..25ee4c5198 100644 --- a/modules/git/repo_compare_test.go +++ b/modules/git/repo_compare_test.go @@ -28,7 +28,7 @@ func TestGetFormatPatch(t *testing.T) { defer repo.Close() rd := &bytes.Buffer{} - err = repo.GetPatch("8d92fc95^", "8d92fc95", rd) + err = repo.GetPatch("8d92fc95^...8d92fc95", rd) if err != nil { assert.NoError(t, err) return diff --git a/modules/gitrepo/gitrepo.go b/modules/gitrepo/gitrepo.go index 14d809aedb..831b9d7bb7 100644 --- a/modules/gitrepo/gitrepo.go +++ b/modules/gitrepo/gitrepo.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -38,63 +39,32 @@ func OpenWikiRepository(ctx context.Context, repo Repository) (*git.Repository, // contextKey is a value for use with context.WithValue. type contextKey struct { - name string -} - -// RepositoryContextKey is a context key. It is used with context.Value() to get the current Repository for the context -var RepositoryContextKey = &contextKey{"repository"} - -// RepositoryFromContext attempts to get the repository from the context -func repositoryFromContext(ctx context.Context, repo Repository) *git.Repository { - value := ctx.Value(RepositoryContextKey) - if value == nil { - return nil - } - - if gitRepo, ok := value.(*git.Repository); ok && gitRepo != nil { - if gitRepo.Path == repoPath(repo) { - return gitRepo - } - } - - return nil + repoPath string } // RepositoryFromContextOrOpen attempts to get the repository from the context or just opens it func RepositoryFromContextOrOpen(ctx context.Context, repo Repository) (*git.Repository, io.Closer, error) { - gitRepo := repositoryFromContext(ctx, repo) - if gitRepo != nil { - return gitRepo, util.NopCloser{}, nil + ds := reqctx.GetRequestDataStore(ctx) + if ds != nil { + gitRepo, err := RepositoryFromRequestContextOrOpen(ctx, ds, repo) + return gitRepo, util.NopCloser{}, err } - gitRepo, err := OpenRepository(ctx, repo) return gitRepo, gitRepo, err } -// repositoryFromContextPath attempts to get the repository from the context -func repositoryFromContextPath(ctx context.Context, path string) *git.Repository { - value := ctx.Value(RepositoryContextKey) - if value == nil { - return nil +// RepositoryFromRequestContextOrOpen opens the repository at the given relative path in the provided request context +// The repo will be automatically closed when the request context is done +func RepositoryFromRequestContextOrOpen(ctx context.Context, ds reqctx.RequestDataStore, repo Repository) (*git.Repository, error) { + ck := contextKey{repoPath: repoPath(repo)} + if gitRepo, ok := ctx.Value(ck).(*git.Repository); ok { + return gitRepo, nil } - - if repo, ok := value.(*git.Repository); ok && repo != nil { - if repo.Path == path { - return repo - } + gitRepo, err := git.OpenRepository(ctx, ck.repoPath) + if err != nil { + return nil, err } - - return nil -} - -// RepositoryFromContextOrOpenPath attempts to get the repository from the context or just opens it -// Deprecated: Use RepositoryFromContextOrOpen instead -func RepositoryFromContextOrOpenPath(ctx context.Context, path string) (*git.Repository, io.Closer, error) { - gitRepo := repositoryFromContextPath(ctx, path) - if gitRepo != nil { - return gitRepo, util.NopCloser{}, nil - } - - gitRepo, err := git.OpenRepository(ctx, path) - return gitRepo, gitRepo, err + ds.AddCloser(gitRepo) + ds.SetContextValue(ck, gitRepo) + return gitRepo, nil } diff --git a/modules/gitrepo/walk_gogit.go b/modules/gitrepo/walk_gogit.go index 6370faf08e..709897ba0c 100644 --- a/modules/gitrepo/walk_gogit.go +++ b/modules/gitrepo/walk_gogit.go @@ -14,15 +14,11 @@ import ( // WalkReferences walks all the references from the repository // refname is empty, ObjectTag or ObjectBranch. All other values should be treated as equivalent to empty. func WalkReferences(ctx context.Context, repo Repository, walkfn func(sha1, refname string) error) (int, error) { - gitRepo := repositoryFromContext(ctx, repo) - if gitRepo == nil { - var err error - gitRepo, err = OpenRepository(ctx, repo) - if err != nil { - return 0, err - } - defer gitRepo.Close() + gitRepo, closer, err := RepositoryFromContextOrOpen(ctx, repo) + if err != nil { + return 0, err } + defer closer.Close() i := 0 iter, err := gitRepo.GoGitRepo().References() diff --git a/modules/markup/html_commit.go b/modules/markup/html_commit.go index 358e7b06ba..aa1b7d034a 100644 --- a/modules/markup/html_commit.go +++ b/modules/markup/html_commit.go @@ -8,6 +8,7 @@ import ( "strings" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/util" "golang.org/x/net/html" @@ -194,3 +195,21 @@ func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) { node = node.NextSibling.NextSibling } } + +func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) { + next := node.NextSibling + + for node != nil && node != next { + found, ref := references.FindRenderizableCommitCrossReference(node.Data) + if !found { + return + } + + reftext := ref.Owner + "/" + ref.Name + "@" + base.ShortSha(ref.CommitSha) + linkHref := ctx.RenderHelper.ResolveLink(util.URLJoin(ref.Owner, ref.Name, "commit", ref.CommitSha), LinkTypeApp) + link := createLink(ctx, linkHref, reftext, "commit") + + replaceContent(node, ref.RefLocation.Start, ref.RefLocation.End, link) + node = node.NextSibling.NextSibling + } +} diff --git a/modules/markup/html_issue.go b/modules/markup/html_issue.go index e64ec76c3d..7a6f33011a 100644 --- a/modules/markup/html_issue.go +++ b/modules/markup/html_issue.go @@ -4,9 +4,9 @@ package markup import ( + "strconv" "strings" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/references" @@ -16,8 +16,16 @@ import ( "code.gitea.io/gitea/modules/util" "golang.org/x/net/html" + "golang.org/x/net/html/atom" ) +type RenderIssueIconTitleOptions struct { + OwnerName string + RepoName string + LinkHref string + IssueIndex int64 +} + func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) { if ctx.RenderOptions.Metas == nil { return @@ -66,6 +74,27 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) { } } +func createIssueLinkContentWithSummary(ctx *RenderContext, linkHref string, ref *references.RenderizableReference) *html.Node { + if DefaultRenderHelperFuncs.RenderRepoIssueIconTitle == nil { + return nil + } + issueIndex, _ := strconv.ParseInt(ref.Issue, 10, 64) + h, err := DefaultRenderHelperFuncs.RenderRepoIssueIconTitle(ctx, RenderIssueIconTitleOptions{ + OwnerName: ref.Owner, + RepoName: ref.Name, + LinkHref: linkHref, + IssueIndex: issueIndex, + }) + if err != nil { + log.Error("RenderRepoIssueIconTitle failed: %v", err) + return nil + } + if h == "" { + return nil + } + return &html.Node{Type: html.RawNode, Data: string(ctx.RenderInternal.ProtectSafeAttrs(h))} +} + func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { if ctx.RenderOptions.Metas == nil { return @@ -76,32 +105,28 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { // old logic: crossLinkOnly := ctx.RenderOptions.Metas["mode"] == "document" && !ctx.IsWiki crossLinkOnly := ctx.RenderOptions.Metas["markupAllowShortIssuePattern"] != "true" - var ( - found bool - ref *references.RenderizableReference - ) + var ref *references.RenderizableReference next := node.NextSibling - for node != nil && node != next { _, hasExtTrackFormat := ctx.RenderOptions.Metas["format"] // Repos with external issue trackers might still need to reference local PRs // We need to concern with the first one that shows up in the text, whichever it is isNumericStyle := ctx.RenderOptions.Metas["style"] == "" || ctx.RenderOptions.Metas["style"] == IssueNameStyleNumeric - foundNumeric, refNumeric := references.FindRenderizableReferenceNumeric(node.Data, hasExtTrackFormat && !isNumericStyle, crossLinkOnly) + refNumeric := references.FindRenderizableReferenceNumeric(node.Data, hasExtTrackFormat && !isNumericStyle, crossLinkOnly) switch ctx.RenderOptions.Metas["style"] { case "", IssueNameStyleNumeric: - found, ref = foundNumeric, refNumeric + ref = refNumeric case IssueNameStyleAlphanumeric: - found, ref = references.FindRenderizableReferenceAlphanumeric(node.Data) + ref = references.FindRenderizableReferenceAlphanumeric(node.Data) case IssueNameStyleRegexp: pattern, err := regexplru.GetCompiled(ctx.RenderOptions.Metas["regexp"]) if err != nil { return } - found, ref = references.FindRenderizableReferenceRegexp(node.Data, pattern) + ref = references.FindRenderizableReferenceRegexp(node.Data, pattern) } // Repos with external issue trackers might still need to reference local PRs @@ -109,17 +134,17 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { if hasExtTrackFormat && !isNumericStyle && refNumeric != nil { // If numeric (PR) was found, and it was BEFORE the non-numeric pattern, use that // Allow a free-pass when non-numeric pattern wasn't found. - if found && (ref == nil || refNumeric.RefLocation.Start < ref.RefLocation.Start) { - found = foundNumeric + if ref == nil || refNumeric.RefLocation.Start < ref.RefLocation.Start { ref = refNumeric } } - if !found { + + if ref == nil { return } var link *html.Node - reftext := node.Data[ref.RefLocation.Start:ref.RefLocation.End] + refText := node.Data[ref.RefLocation.Start:ref.RefLocation.End] if hasExtTrackFormat && !ref.IsPull { ctx.RenderOptions.Metas["index"] = ref.Issue @@ -129,18 +154,23 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { log.Error("unable to expand template vars for ref %s, err: %v", ref.Issue, err) } - link = createLink(ctx, res, reftext, "ref-issue ref-external-issue") + link = createLink(ctx, res, refText, "ref-issue ref-external-issue") } else { // Path determines the type of link that will be rendered. It's unknown at this point whether // the linked item is actually a PR or an issue. Luckily it's of no real consequence because // Gitea will redirect on click as appropriate. + issueOwner := util.Iif(ref.Owner == "", ctx.RenderOptions.Metas["user"], ref.Owner) + issueRepo := util.Iif(ref.Owner == "", ctx.RenderOptions.Metas["repo"], ref.Name) issuePath := util.Iif(ref.IsPull, "pulls", "issues") - if ref.Owner == "" { - linkHref := ctx.RenderHelper.ResolveLink(util.URLJoin(ctx.RenderOptions.Metas["user"], ctx.RenderOptions.Metas["repo"], issuePath, ref.Issue), LinkTypeApp) - link = createLink(ctx, linkHref, reftext, "ref-issue") - } else { - linkHref := ctx.RenderHelper.ResolveLink(util.URLJoin(ref.Owner, ref.Name, issuePath, ref.Issue), LinkTypeApp) - link = createLink(ctx, linkHref, reftext, "ref-issue") + linkHref := ctx.RenderHelper.ResolveLink(util.URLJoin(issueOwner, issueRepo, issuePath, ref.Issue), LinkTypeApp) + + // at the moment, only render the issue index in a full line (or simple line) as icon+title + // otherwise it would be too noisy for "take #1 as an example" in a sentence + if node.Parent.DataAtom == atom.Li && ref.RefLocation.Start < 20 && ref.RefLocation.End == len(node.Data) { + link = createIssueLinkContentWithSummary(ctx, linkHref, ref) + } + if link == nil { + link = createLink(ctx, linkHref, refText, "ref-issue") } } @@ -168,21 +198,3 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { node = node.NextSibling.NextSibling.NextSibling.NextSibling } } - -func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) { - next := node.NextSibling - - for node != nil && node != next { - found, ref := references.FindRenderizableCommitCrossReference(node.Data) - if !found { - return - } - - reftext := ref.Owner + "/" + ref.Name + "@" + base.ShortSha(ref.CommitSha) - linkHref := ctx.RenderHelper.ResolveLink(util.URLJoin(ref.Owner, ref.Name, "commit", ref.CommitSha), LinkTypeApp) - link := createLink(ctx, linkHref, reftext, "commit") - - replaceContent(node, ref.RefLocation.Start, ref.RefLocation.End, link) - node = node.NextSibling.NextSibling - } -} diff --git a/modules/markup/html_issue_test.go b/modules/markup/html_issue_test.go new file mode 100644 index 0000000000..8d189fbdf6 --- /dev/null +++ b/modules/markup/html_issue_test.go @@ -0,0 +1,72 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup_test + +import ( + "context" + "html/template" + "strings" + "testing" + + "code.gitea.io/gitea/modules/htmlutil" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" + testModule "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRender_IssueList(t *testing.T) { + defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)() + markup.Init(&markup.RenderHelperFuncs{ + RenderRepoIssueIconTitle: func(ctx context.Context, opts markup.RenderIssueIconTitleOptions) (template.HTML, error) { + return htmlutil.HTMLFormat("
issue #%d
", opts.IssueIndex), nil + }, + }) + + test := func(input, expected string) { + rctx := markup.NewTestRenderContext(markup.TestAppURL, map[string]string{ + "user": "test-user", "repo": "test-repo", + "markupAllowShortIssuePattern": "true", + }) + out, err := markdown.RenderString(rctx, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(out))) + } + + t.Run("NormalIssueRef", func(t *testing.T) { + test( + "#12345", + `

#12345

`, + ) + }) + + t.Run("ListIssueRef", func(t *testing.T) { + test( + "* #12345", + ``, + ) + }) + + t.Run("ListIssueRefNormal", func(t *testing.T) { + test( + "* foo #12345 bar", + ``, + ) + }) + + t.Run("ListTodoIssueRef", func(t *testing.T) { + test( + "* [ ] #12345", + ``, + ) + }) +} diff --git a/modules/markup/render_helper.go b/modules/markup/render_helper.go index 82796ef274..8ff0e7d6fb 100644 --- a/modules/markup/render_helper.go +++ b/modules/markup/render_helper.go @@ -38,6 +38,7 @@ type RenderHelper interface { type RenderHelperFuncs struct { IsUsernameMentionable func(ctx context.Context, username string) bool RenderRepoFileCodePreview func(ctx context.Context, options RenderCodePreviewOptions) (template.HTML, error) + RenderRepoIssueIconTitle func(ctx context.Context, options RenderIssueIconTitleOptions) (template.HTML, error) } var DefaultRenderHelperFuncs *RenderHelperFuncs diff --git a/modules/references/references.go b/modules/references/references.go index 6e549cb875..a5b102b7f2 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -32,7 +32,7 @@ var ( // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`) // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 - issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`) + issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`) // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository // e.g. org/repo#12345 crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) @@ -330,22 +330,22 @@ func FindAllIssueReferences(content string) []IssueReference { } // FindRenderizableReferenceNumeric returns the first unvalidated reference found in a string. -func FindRenderizableReferenceNumeric(content string, prOnly, crossLinkOnly bool) (bool, *RenderizableReference) { +func FindRenderizableReferenceNumeric(content string, prOnly, crossLinkOnly bool) *RenderizableReference { var match []int if !crossLinkOnly { match = issueNumericPattern.FindStringSubmatchIndex(content) } if match == nil { if match = crossReferenceIssueNumericPattern.FindStringSubmatchIndex(content); match == nil { - return false, nil + return nil } } r := getCrossReference(util.UnsafeStringToBytes(content), match[2], match[3], false, prOnly) if r == nil { - return false, nil + return nil } - return true, &RenderizableReference{ + return &RenderizableReference{ Issue: r.issue, Owner: r.owner, Name: r.name, @@ -372,15 +372,14 @@ func FindRenderizableCommitCrossReference(content string) (bool, *RenderizableRe } // FindRenderizableReferenceRegexp returns the first regexp unvalidated references found in a string. -func FindRenderizableReferenceRegexp(content string, pattern *regexp.Regexp) (bool, *RenderizableReference) { +func FindRenderizableReferenceRegexp(content string, pattern *regexp.Regexp) *RenderizableReference { match := pattern.FindStringSubmatchIndex(content) if len(match) < 4 { - return false, nil + return nil } action, location := findActionKeywords([]byte(content), match[2]) - - return true, &RenderizableReference{ + return &RenderizableReference{ Issue: content[match[2]:match[3]], RefLocation: &RefSpan{Start: match[0], End: match[1]}, Action: action, @@ -390,15 +389,14 @@ func FindRenderizableReferenceRegexp(content string, pattern *regexp.Regexp) (bo } // FindRenderizableReferenceAlphanumeric returns the first alphanumeric unvalidated references found in a string. -func FindRenderizableReferenceAlphanumeric(content string) (bool, *RenderizableReference) { +func FindRenderizableReferenceAlphanumeric(content string) *RenderizableReference { match := issueAlphanumericPattern.FindStringSubmatchIndex(content) if match == nil { - return false, nil + return nil } action, location := findActionKeywords([]byte(content), match[2]) - - return true, &RenderizableReference{ + return &RenderizableReference{ Issue: content[match[2]:match[3]], RefLocation: &RefSpan{Start: match[2], End: match[3]}, Action: action, diff --git a/modules/references/references_test.go b/modules/references/references_test.go index e224c919e9..1b6a968d6a 100644 --- a/modules/references/references_test.go +++ b/modules/references/references_test.go @@ -249,11 +249,10 @@ func TestFindAllIssueReferences(t *testing.T) { } for _, fixture := range alnumFixtures { - found, ref := FindRenderizableReferenceAlphanumeric(fixture.input) + ref := FindRenderizableReferenceAlphanumeric(fixture.input) if fixture.issue == "" { - assert.False(t, found, "Failed to parse: {%s}", fixture.input) + assert.Nil(t, ref, "Failed to parse: {%s}", fixture.input) } else { - assert.True(t, found, "Failed to parse: {%s}", fixture.input) assert.Equal(t, fixture.issue, ref.Issue, "Failed to parse: {%s}", fixture.input) assert.Equal(t, fixture.refLocation, ref.RefLocation, "Failed to parse: {%s}", fixture.input) assert.Equal(t, fixture.action, ref.Action, "Failed to parse: {%s}", fixture.input) @@ -463,6 +462,7 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) { "ABC-123:", "\"ABC-123\"", "'ABC-123'", + "ABC-123, unknown PR", } falseTestCases := []string{ "RC-08", diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 3b0cfa1eed..d00156a496 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -31,12 +31,7 @@ func Test_getLicense(t *testing.T) { Copyright (c) 2023 Gitea -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -`, +Permission is hereby granted`, wantErr: assert.NoError, }, { @@ -53,7 +48,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) { return } - assert.Equalf(t, tt.want, string(got), "GetLicense(%v, %v)", tt.args.name, tt.args.values) + assert.Contains(t, string(got), tt.want, "GetLicense(%v, %v)", tt.args.name, tt.args.values) }) } } diff --git a/modules/reqctx/datastore.go b/modules/reqctx/datastore.go new file mode 100644 index 0000000000..66361a4587 --- /dev/null +++ b/modules/reqctx/datastore.go @@ -0,0 +1,123 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package reqctx + +import ( + "context" + "io" + "sync" + + "code.gitea.io/gitea/modules/process" +) + +type ContextDataProvider interface { + GetData() ContextData +} + +type ContextData map[string]any + +func (ds ContextData) GetData() ContextData { + return ds +} + +func (ds ContextData) MergeFrom(other ContextData) ContextData { + for k, v := range other { + ds[k] = v + } + return ds +} + +// RequestDataStore is a short-lived context-related object that is used to store request-specific data. +type RequestDataStore interface { + GetData() ContextData + SetContextValue(k, v any) + GetContextValue(key any) any + AddCleanUp(f func()) + AddCloser(c io.Closer) +} + +type requestDataStoreKeyType struct{} + +var RequestDataStoreKey requestDataStoreKeyType + +type requestDataStore struct { + data ContextData + + mu sync.RWMutex + values map[any]any + cleanUpFuncs []func() +} + +func (r *requestDataStore) GetContextValue(key any) any { + if key == RequestDataStoreKey { + return r + } + r.mu.RLock() + defer r.mu.RUnlock() + return r.values[key] +} + +func (r *requestDataStore) SetContextValue(k, v any) { + r.mu.Lock() + r.values[k] = v + r.mu.Unlock() +} + +// GetData and the underlying ContextData are not thread-safe, callers should ensure thread-safety. +func (r *requestDataStore) GetData() ContextData { + if r.data == nil { + r.data = make(ContextData) + } + return r.data +} + +func (r *requestDataStore) AddCleanUp(f func()) { + r.mu.Lock() + r.cleanUpFuncs = append(r.cleanUpFuncs, f) + r.mu.Unlock() +} + +func (r *requestDataStore) AddCloser(c io.Closer) { + r.AddCleanUp(func() { _ = c.Close() }) +} + +func (r *requestDataStore) cleanUp() { + for _, f := range r.cleanUpFuncs { + f() + } +} + +func GetRequestDataStore(ctx context.Context) RequestDataStore { + if req, ok := ctx.Value(RequestDataStoreKey).(*requestDataStore); ok { + return req + } + return nil +} + +type requestContext struct { + context.Context + dataStore *requestDataStore +} + +func (c *requestContext) Value(key any) any { + if v := c.dataStore.GetContextValue(key); v != nil { + return v + } + return c.Context.Value(key) +} + +func NewRequestContext(parentCtx context.Context, profDesc string) (_ context.Context, finished func()) { + ctx, _, processFinished := process.GetManager().AddTypedContext(parentCtx, profDesc, process.RequestProcessType, true) + reqCtx := &requestContext{Context: ctx, dataStore: &requestDataStore{values: make(map[any]any)}} + return reqCtx, func() { + reqCtx.dataStore.cleanUp() + processFinished() + } +} + +// NewRequestContextForTest creates a new RequestContext for testing purposes +// It doesn't add the context to the process manager, nor do cleanup +func NewRequestContextForTest(parentCtx context.Context) context.Context { + return &requestContext{Context: parentCtx, dataStore: &requestDataStore{values: make(map[any]any)}} +} 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/svg/processor.go b/modules/svg/processor.go index 82248fb0c1..4fcb11a57d 100644 --- a/modules/svg/processor.go +++ b/modules/svg/processor.go @@ -10,7 +10,7 @@ import ( "sync" ) -type normalizeVarsStruct struct { +type globalVarsStruct struct { reXMLDoc, reComment, reAttrXMLNs, @@ -18,26 +18,23 @@ type normalizeVarsStruct struct { reAttrClassPrefix *regexp.Regexp } -var ( - normalizeVars *normalizeVarsStruct - normalizeVarsOnce sync.Once -) +var globalVars = sync.OnceValue(func() *globalVarsStruct { + return &globalVarsStruct{ + reXMLDoc: regexp.MustCompile(`(?s)<\?xml.*?>`), + reComment: regexp.MustCompile(`(?s)`), + + reAttrXMLNs: regexp.MustCompile(`(?s)\s+xmlns\s*=\s*"[^"]*"`), + reAttrSize: regexp.MustCompile(`(?s)\s+(width|height)\s*=\s*"[^"]+"`), + reAttrClassPrefix: regexp.MustCompile(`(?s)\s+class\s*=\s*"`), + } +}) // Normalize normalizes the SVG content: set default width/height, remove unnecessary tags/attributes // It's designed to work with valid SVG content. For invalid SVG content, the returned content is not guaranteed. func Normalize(data []byte, size int) []byte { - normalizeVarsOnce.Do(func() { - normalizeVars = &normalizeVarsStruct{ - reXMLDoc: regexp.MustCompile(`(?s)<\?xml.*?>`), - reComment: regexp.MustCompile(`(?s)`), - - reAttrXMLNs: regexp.MustCompile(`(?s)\s+xmlns\s*=\s*"[^"]*"`), - reAttrSize: regexp.MustCompile(`(?s)\s+(width|height)\s*=\s*"[^"]+"`), - reAttrClassPrefix: regexp.MustCompile(`(?s)\s+class\s*=\s*"`), - } - }) - data = normalizeVars.reXMLDoc.ReplaceAll(data, nil) - data = normalizeVars.reComment.ReplaceAll(data, nil) + vars := globalVars() + data = vars.reXMLDoc.ReplaceAll(data, nil) + data = vars.reComment.ReplaceAll(data, nil) data = bytes.TrimSpace(data) svgTag, svgRemaining, ok := bytes.Cut(data, []byte(">")) @@ -45,9 +42,9 @@ func Normalize(data []byte, size int) []byte { return data } normalized := bytes.Clone(svgTag) - normalized = normalizeVars.reAttrXMLNs.ReplaceAll(normalized, nil) - normalized = normalizeVars.reAttrSize.ReplaceAll(normalized, nil) - normalized = normalizeVars.reAttrClassPrefix.ReplaceAll(normalized, []byte(` class="`)) + normalized = vars.reAttrXMLNs.ReplaceAll(normalized, nil) + normalized = vars.reAttrSize.ReplaceAll(normalized, nil) + normalized = vars.reAttrClassPrefix.ReplaceAll(normalized, []byte(` class="`)) normalized = bytes.TrimSpace(normalized) normalized = fmt.Appendf(normalized, ` width="%d" height="%d"`, size, size) if !bytes.Contains(normalized, []byte(` class="`)) { diff --git a/modules/templates/helper.go b/modules/templates/helper.go index ff9673ccef..b673450f5a 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -9,7 +9,6 @@ import ( "html" "html/template" "net/url" - "reflect" "strings" "time" @@ -69,7 +68,7 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // time / number / format "FileSize": base.FileSize, - "CountFmt": base.FormatNumberSI, + "CountFmt": countFmt, "Sec2Time": util.SecToTime, "TimeEstimateString": timeEstimateString, @@ -239,29 +238,8 @@ func iif(condition any, vals ...any) any { } func isTemplateTruthy(v any) bool { - if v == nil { - return false - } - - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Bool: - return rv.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int() != 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint() != 0 - case reflect.Float32, reflect.Float64: - return rv.Float() != 0 - case reflect.Complex64, reflect.Complex128: - return rv.Complex() != 0 - case reflect.String, reflect.Slice, reflect.Array, reflect.Map: - return rv.Len() > 0 - case reflect.Struct: - return true - default: - return !rv.IsNil() - } + truth, _ := template.IsTrue(v) + return truth } // evalTokens evaluates the expression by tokens and returns the result, see the comment of eval.Expr for details. @@ -286,14 +264,6 @@ func userThemeName(user *user_model.User) string { return setting.UI.DefaultTheme } -func timeEstimateString(timeSec any) string { - v, _ := util.ToInt64(timeSec) - if v == 0 { - return "" - } - return util.TimeEstimateString(v) -} - // QueryBuild builds a query string from a list of key-value pairs. // It omits the nil and empty strings, but it doesn't omit other zero values, // because the zero value of number types may have a meaning. @@ -361,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/templates/helper_test.go b/modules/templates/helper_test.go index 3e17e86c66..a530d484bc 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "code.gitea.io/gitea/modules/htmlutil" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -65,31 +66,12 @@ func TestSanitizeHTML(t *testing.T) { assert.Equal(t, template.HTML(`link xss
inline
`), SanitizeHTML(`link xss
inline
`)) } -func TestTemplateTruthy(t *testing.T) { +func TestTemplateIif(t *testing.T) { tmpl := template.New("test") tmpl.Funcs(template.FuncMap{"Iif": iif}) template.Must(tmpl.Parse(`{{if .Value}}true{{else}}false{{end}}:{{Iif .Value "true" "false"}}`)) - cases := []any{ - nil, false, true, "", "string", 0, 1, - byte(0), byte(1), int64(0), int64(1), float64(0), float64(1), - complex(0, 0), complex(1, 0), - (chan int)(nil), make(chan int), - (func())(nil), func() {}, - util.ToPointer(0), util.ToPointer(util.ToPointer(0)), - util.ToPointer(1), util.ToPointer(util.ToPointer(1)), - [0]int{}, - [1]int{0}, - []int(nil), - []int{}, - []int{0}, - map[any]any(nil), - map[any]any{}, - map[any]any{"k": "v"}, - (*struct{})(nil), - struct{}{}, - util.ToPointer(struct{}{}), - } + cases := []any{nil, false, true, "", "string", 0, 1} w := &strings.Builder{} truthyCount := 0 for i, v := range cases { @@ -102,3 +84,37 @@ func TestTemplateTruthy(t *testing.T) { } assert.True(t, truthyCount != 0 && truthyCount != len(cases)) } + +func TestTemplateEscape(t *testing.T) { + execTmpl := func(code string) string { + tmpl := template.New("test") + tmpl.Funcs(template.FuncMap{"QueryBuild": QueryBuild, "HTMLFormat": htmlutil.HTMLFormat}) + template.Must(tmpl.Parse(code)) + w := &strings.Builder{} + assert.NoError(t, tmpl.Execute(w, nil)) + return w.String() + } + + t.Run("Golang URL Escape", func(t *testing.T) { + // Golang template considers "href", "*src*", "*uri*", "*url*" (and more) ... attributes as contentTypeURL and does auto-escaping + actual := execTmpl(``) + assert.Equal(t, ``, actual) + actual = execTmpl(``) + assert.Equal(t, ``, actual) + }) + t.Run("Golang URL No-escape", func(t *testing.T) { + // non-URL content isn't auto-escaped + actual := execTmpl(``) + assert.Equal(t, ``, actual) + }) + t.Run("QueryBuild", func(t *testing.T) { + actual := execTmpl(``) + assert.Equal(t, ``, actual) + actual = execTmpl(``) + assert.Equal(t, ``, actual) + }) + t.Run("HTMLFormat", func(t *testing.T) { + actual := execTmpl("{{HTMLFormat `%s` `\"` `<>`}}") + assert.Equal(t, `<>`, actual) + }) +} diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index e7e805ed30..529284f7e8 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -29,6 +29,8 @@ import ( type TemplateExecutor scopedtmpl.TemplateExecutor +type TplName string + type HTMLRender struct { templates atomic.Pointer[scopedtmpl.ScopedTemplate] } @@ -40,7 +42,8 @@ var ( var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors") -func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any, ctx context.Context) error { //nolint:revive +func (h *HTMLRender) HTML(w io.Writer, status int, tplName TplName, data any, ctx context.Context) error { //nolint:revive + name := string(tplName) if respWriter, ok := w.(http.ResponseWriter); ok { if respWriter.Header().Get("Content-Type") == "" { respWriter.Header().Set("Content-Type", "text/html; charset=utf-8") diff --git a/modules/templates/util_format.go b/modules/templates/util_format.go new file mode 100644 index 0000000000..bee6fb7b75 --- /dev/null +++ b/modules/templates/util_format.go @@ -0,0 +1,37 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package templates + +import ( + "fmt" + + "code.gitea.io/gitea/modules/util" +) + +func timeEstimateString(timeSec any) string { + v, _ := util.ToInt64(timeSec) + if v == 0 { + return "" + } + return util.TimeEstimateString(v) +} + +func countFmt(data any) string { + // legacy code, not ideal, still used in some places + num, err := util.ToInt64(data) + if err != nil { + return "" + } + if num < 1000 { + return fmt.Sprintf("%d", num) + } else if num < 1_000_000 { + num2 := float32(num) / 1000.0 + return fmt.Sprintf("%.1fk", num2) + } else if num < 1_000_000_000 { + num2 := float32(num) / 1_000_000.0 + return fmt.Sprintf("%.1fM", num2) + } + num2 := float32(num) / 1_000_000_000.0 + return fmt.Sprintf("%.1fG", num2) +} diff --git a/modules/templates/util_format_test.go b/modules/templates/util_format_test.go new file mode 100644 index 0000000000..8d466faff0 --- /dev/null +++ b/modules/templates/util_format_test.go @@ -0,0 +1,18 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package templates + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCountFmt(t *testing.T) { + assert.Equal(t, "125", countFmt(125)) + assert.Equal(t, "1.3k", countFmt(int64(1317))) + assert.Equal(t, "21.3M", countFmt(21317675)) + assert.Equal(t, "45.7G", countFmt(45721317675)) + assert.Equal(t, "", countFmt("test")) +} diff --git a/modules/test/utils.go b/modules/test/utils.go index 8dee92fbce..ec4c976388 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -4,11 +4,16 @@ package test import ( + "fmt" "net/http" "net/http/httptest" + "os" + "path/filepath" + "runtime" "strings" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" ) // RedirectURL returns the redirect URL of a http response. @@ -41,3 +46,19 @@ func MockVariableValue[T any](p *T, v ...T) (reset func()) { } return func() { *p = old } } + +// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value +func SetupGiteaRoot() string { + giteaRoot := os.Getenv("GITEA_ROOT") + if giteaRoot != "" { + return giteaRoot + } + _, filename, _, _ := runtime.Caller(0) + giteaRoot = filepath.Dir(filepath.Dir(filepath.Dir(filename))) + fixturesDir := filepath.Join(giteaRoot, "models", "fixtures") + if exist, _ := util.IsDir(fixturesDir); !exist { + panic(fmt.Sprintf("fixtures directory not found: %s", fixturesDir)) + } + _ = os.Setenv("GITEA_ROOT", giteaRoot) + return giteaRoot +} diff --git a/modules/test/utils_test.go b/modules/test/utils_test.go new file mode 100644 index 0000000000..0469ce97f2 --- /dev/null +++ b/modules/test/utils_test.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package test + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSetupGiteaRoot(t *testing.T) { + t.Setenv("GITEA_ROOT", "test") + assert.Equal(t, "test", SetupGiteaRoot()) + t.Setenv("GITEA_ROOT", "") + assert.NotEqual(t, "test", SetupGiteaRoot()) +} diff --git a/modules/web/handler.go b/modules/web/handler.go index 1812c664b3..9a3e4a7f17 100644 --- a/modules/web/handler.go +++ b/modules/web/handler.go @@ -4,7 +4,6 @@ package web import ( - goctx "context" "fmt" "net/http" "reflect" @@ -51,7 +50,6 @@ func (r *responseWriter) WriteHeader(statusCode int) { var ( httpReqType = reflect.TypeOf((*http.Request)(nil)) respWriterType = reflect.TypeOf((*http.ResponseWriter)(nil)).Elem() - cancelFuncType = reflect.TypeOf((*goctx.CancelFunc)(nil)).Elem() ) // preCheckHandler checks whether the handler is valid, developers could get first-time feedback, all mistakes could be found at startup @@ -65,11 +63,8 @@ func preCheckHandler(fn reflect.Value, argsIn []reflect.Value) { if !hasStatusProvider { panic(fmt.Sprintf("handler should have at least one ResponseStatusProvider argument, but got %s", fn.Type())) } - if fn.Type().NumOut() != 0 && fn.Type().NumIn() != 1 { - panic(fmt.Sprintf("handler should have no return value or only one argument, but got %s", fn.Type())) - } - if fn.Type().NumOut() == 1 && fn.Type().Out(0) != cancelFuncType { - panic(fmt.Sprintf("handler should return a cancel function, but got %s", fn.Type())) + if fn.Type().NumOut() != 0 { + panic(fmt.Sprintf("handler should have no return value other than registered ones, but got %s", fn.Type())) } } @@ -105,16 +100,10 @@ func prepareHandleArgsIn(resp http.ResponseWriter, req *http.Request, fn reflect return argsIn } -func handleResponse(fn reflect.Value, ret []reflect.Value) goctx.CancelFunc { - if len(ret) == 1 { - if cancelFunc, ok := ret[0].Interface().(goctx.CancelFunc); ok { - return cancelFunc - } - panic(fmt.Sprintf("unsupported return type: %s", ret[0].Type())) - } else if len(ret) > 1 { +func handleResponse(fn reflect.Value, ret []reflect.Value) { + if len(ret) != 0 { panic(fmt.Sprintf("unsupported return values: %s", fn.Type())) } - return nil } func hasResponseBeenWritten(argsIn []reflect.Value) bool { @@ -171,11 +160,8 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler { routing.UpdateFuncInfo(req.Context(), funcInfo) ret := fn.Call(argsIn) - // handle the return value, and defer the cancel function if there is one - cancelFunc := handleResponse(fn, ret) - if cancelFunc != nil { - defer cancelFunc() - } + // handle the return value (no-op at the moment) + handleResponse(fn, ret) // if the response has not been written, call the next handler if next != nil && !hasResponseBeenWritten(argsIn) { diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index 08d83f94be..a47da0f836 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -7,46 +7,21 @@ import ( "context" "time" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/setting" ) -// ContextDataStore represents a data store -type ContextDataStore interface { - GetData() ContextData -} - -type ContextData map[string]any - -func (ds ContextData) GetData() ContextData { - return ds -} - -func (ds ContextData) MergeFrom(other ContextData) ContextData { - for k, v := range other { - ds[k] = v - } - return ds -} - const ContextDataKeySignedUser = "SignedUser" -type contextDataKeyType struct{} - -var contextDataKey contextDataKeyType - -func WithContextData(c context.Context) context.Context { - return context.WithValue(c, contextDataKey, make(ContextData, 10)) -} - -func GetContextData(c context.Context) ContextData { - if ds, ok := c.Value(contextDataKey).(ContextData); ok { - return ds +func GetContextData(c context.Context) reqctx.ContextData { + if rc := reqctx.GetRequestDataStore(c); rc != nil { + return rc.GetData() } return nil } -func CommonTemplateContextData() ContextData { - return ContextData{ +func CommonTemplateContextData() reqctx.ContextData { + return reqctx.ContextData{ "IsLandingPageOrganizations": setting.LandingPageURL == setting.LandingPageOrganizations, "ShowRegistrationButton": setting.Service.ShowRegistrationButton, diff --git a/modules/web/middleware/flash.go b/modules/web/middleware/flash.go index 88da2049a4..0caaa8c036 100644 --- a/modules/web/middleware/flash.go +++ b/modules/web/middleware/flash.go @@ -7,11 +7,13 @@ import ( "fmt" "html/template" "net/url" + + "code.gitea.io/gitea/modules/reqctx" ) // Flash represents a one time data transfer between two requests. type Flash struct { - DataStore ContextDataStore + DataStore reqctx.RequestDataStore url.Values ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string } diff --git a/modules/web/route.go b/modules/web/route.go index 787521dfb0..533ac3eaf1 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/modules/htmlutil" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web/middleware" @@ -29,12 +30,12 @@ func Bind[T any](_ T) http.HandlerFunc { } // SetForm set the form object -func SetForm(dataStore middleware.ContextDataStore, obj any) { +func SetForm(dataStore reqctx.ContextDataProvider, obj any) { dataStore.GetData()["__form"] = obj } // GetForm returns the validate form information -func GetForm(dataStore middleware.ContextDataStore) any { +func GetForm(dataStore reqctx.RequestDataStore) any { return dataStore.GetData()["__form"] } diff --git a/options/gitignore/AutomationStudio b/options/gitignore/AutomationStudio new file mode 100644 index 0000000000..b5552b17a0 --- /dev/null +++ b/options/gitignore/AutomationStudio @@ -0,0 +1,31 @@ +# gitignore template for B&R Automation Studio (AS) 4 +# website: https://www.br-automation.com/en-us/products/software/automation-software/automation-studio/ + +# AS temporary directories +Binaries/ +Diagnosis/ +Temp/ +TempObjects/ + +# AS transfer files +*artransfer.br +*arTrsfmode.nv + +# 'ignored' directory +ignored/ + +# ARNC0ext +*arnc0ext.br + +# AS File types +*.bak +*.isopen +*.orig +*.log +*.asar +*.csvlog* +*.set +!**/Physical/**/*.set + +# RevInfo variables +*RevInfo.var diff --git a/options/gitignore/Firebase b/options/gitignore/Firebase new file mode 100644 index 0000000000..55b8b0ea7f --- /dev/null +++ b/options/gitignore/Firebase @@ -0,0 +1,28 @@ +# Firebase build and deployment files +/firebase-debug.log +/firebase-debug.*.log +.firebaserc + +# Firebase Hosting +/firebase.json +*.cache +hosting/.cache + +# Firebase Functions +/functions/node_modules/ +/functions/.env +/functions/package-lock.json + +# Firebase Emulators +/firebase-*.zip +/.firebase/ +/emulator-ui/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment files (local configs) +/.env.* diff --git a/options/gitignore/Modelica b/options/gitignore/Modelica new file mode 100644 index 0000000000..aa2cc996da --- /dev/null +++ b/options/gitignore/Modelica @@ -0,0 +1,42 @@ +# Modelica - an object-oriented language for modeling of cyber-physical systems +# https://modelica.org/ +# Ignore temporary files, build results, simulation files + +## Modelica-specific files +*~ +*.bak +*.bak-mo +*.mof +\#*\# +*.moe +*.mol + +## Build artefacts +*.exe +*.exp +*.o +*.pyc + +## Simulation files +*.mat + +## Package files +*.gz +*.rar +*.tar +*.zip + +## Dymola-specific files +buildlog.txt +dsfinal.txt +dsin.txt +dslog.txt +dsmodel* +dsres.txt +dymosim* +request +stat +status +stop +success +*. diff --git a/options/gitignore/Python b/options/gitignore/Python index c2fb773388..15201acc11 100644 --- a/options/gitignore/Python +++ b/options/gitignore/Python @@ -166,3 +166,6 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# PyPI configuration file +.pypirc diff --git a/options/gitignore/TeX b/options/gitignore/TeX index a1f5212090..45e1706c28 100644 --- a/options/gitignore/TeX +++ b/options/gitignore/TeX @@ -26,6 +26,7 @@ ## Bibliography auxiliary files (bibtex/biblatex/biber): *.bbl +*.bbl-SAVE-ERROR *.bcf *.blg *-blx.aux diff --git a/options/license/Elastic-2.0 b/options/license/Elastic-2.0 index 809108b857..9496955678 100644 --- a/options/license/Elastic-2.0 +++ b/options/license/Elastic-2.0 @@ -2,18 +2,18 @@ Elastic License 2.0 URL: https://www.elastic.co/licensing/elastic-license -## Acceptance +Acceptance By using the software, you agree to all of the terms and conditions below. -## Copyright License +Copyright License The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below. -## Limitations +Limitations You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of @@ -27,7 +27,7 @@ You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law. -## Patents +Patents The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for @@ -40,7 +40,7 @@ the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. -## Notices +Notices You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. @@ -53,7 +53,7 @@ software prominent notices stating that you have modified the software. These terms do not imply any licenses other than those expressly granted in these terms. -## Termination +Termination If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you @@ -63,31 +63,31 @@ reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently. -## No Liability +No Liability -*As far as the law allows, the software comes as is, without any warranty or +As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of -legal claim.* +legal claim. -## Definitions +Definitions -The **licensor** is the entity offering these terms, and the **software** is the +The licensor is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it. -**you** refers to the individual or entity agreeing to these terms. +you refers to the individual or entity agreeing to these terms. -**your company** is any legal entity, sole proprietorship, or other kind of +your company is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that -organization. **control** means ownership of substantially all the assets of an +organization. control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. -**your licenses** are all the licenses granted to you for the software under +your licenses are all the licenses granted to you for the software under these terms. -**use** means anything you do with the software requiring one of your licenses. +use means anything you do with the software requiring one of your licenses. -**trademark** means trademarks, service marks, and similar rights. +trademark means trademarks, service marks, and similar rights. diff --git a/options/license/MIT b/options/license/MIT index 2071b23b0e..fc2cf8e6b6 100644 --- a/options/license/MIT +++ b/options/license/MIT @@ -2,8 +2,17 @@ MIT License Copyright (c) -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 2abe3672cd..3c7e247d13 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -3742,6 +3742,7 @@ variables.creation.success=Proměnná „%s“ byla přidána. variables.update.failed=Úprava proměnné se nezdařila. variables.update.success=Proměnná byla upravena. + [projects] deleted.display_name=Odstraněný projekt type-1.display_name=Samostatný projekt diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index c8dd3f71a2..78bfb26d73 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -3556,6 +3556,7 @@ variables.creation.success=Die Variable „%s“ wurde hinzugefügt. variables.update.failed=Fehler beim Bearbeiten der Variable. variables.update.success=Die Variable wurde bearbeitet. + [projects] type-1.display_name=Individuelles Projekt type-2.display_name=Repository-Projekt diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 193441828a..db7b3ffae3 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -3439,6 +3439,7 @@ variables.creation.success=Η μεταβλητή "%s" έχει προστεθε variables.update.failed=Αποτυχία επεξεργασίας μεταβλητής. variables.update.success=Η μεταβλητή έχει τροποποιηθεί. + [projects] type-1.display_name=Ατομικό Έργο type-2.display_name=Έργο Αποθετηρίου diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 92ce4f2db9..ea4d36fb1c 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1946,8 +1946,8 @@ pulls.delete.title = Delete this pull request? pulls.delete.text = Do you really want to delete this pull request? (This will permanently remove all content. Consider closing it instead, if you intend to keep it archived) pulls.recently_pushed_new_branches = You pushed on branch %[1]s %[2]s -pulls.upstream_diverging_prompt_behind_1 = This branch is %d commit behind %s -pulls.upstream_diverging_prompt_behind_n = This branch is %d commits behind %s +pulls.upstream_diverging_prompt_behind_1 = This branch is %[1]d commit behind %[2]s +pulls.upstream_diverging_prompt_behind_n = This branch is %[1]d commits behind %[2]s pulls.upstream_diverging_prompt_base_newer = The base branch %s has new changes pulls.upstream_diverging_merge = Sync fork @@ -3722,6 +3722,7 @@ runners.status.active = Active runners.status.offline = Offline runners.version = Version runners.reset_registration_token = Reset registration token +runners.reset_registration_token_confirm = Would you like to invalidate the current token and generate a new one? runners.reset_registration_token_success = Runner registration token reset successfully runs.all_workflows = All Workflows @@ -3773,6 +3774,9 @@ variables.creation.success = The variable "%s" has been added. variables.update.failed = Failed to edit variable. variables.update.success = The variable has been edited. +logs.always_auto_scroll = Always auto scroll logs +logs.always_expand_running = Always expand running logs + [projects] deleted.display_name = Deleted Project type-1.display_name = Individual Project diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index e95513766b..010bee186d 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -3415,6 +3415,7 @@ variables.creation.success=La variable "%s" ha sido añadida. variables.update.failed=Error al editar la variable. variables.update.success=La variable ha sido editada. + [projects] type-1.display_name=Proyecto individual type-2.display_name=Proyecto repositorio diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 640592f2bf..b92361db34 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -2529,6 +2529,7 @@ runs.commit=کامیت + [projects] [git.filemode] diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 375c7b11bf..b4f3869db4 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -1707,6 +1707,7 @@ runs.commit=Commit + [projects] [git.filemode] diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 08a40a2494..0898d0fd29 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -3772,6 +3772,7 @@ variables.creation.success=La variable « %s » a été ajoutée. variables.update.failed=Impossible d’éditer la variable. variables.update.success=La variable a bien été modifiée. + [projects] deleted.display_name=Projet supprimé type-1.display_name=Projet personnel diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini index c37c8e0157..20672569ac 100644 --- a/options/locale/locale_ga-IE.ini +++ b/options/locale/locale_ga-IE.ini @@ -1945,8 +1945,6 @@ pulls.delete.title=Scrios an t-iarratas tarraingthe seo? pulls.delete.text=An bhfuil tú cinnte gur mhaith leat an t-iarratas tarraingthe seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann) pulls.recently_pushed_new_branches=Bhrúigh tú ar bhrainse %[1]s %[2]s -pulls.upstream_diverging_prompt_behind_1=Tá an brainse seo %d tiomantas taobh thiar de %s -pulls.upstream_diverging_prompt_behind_n=Tá an brainse seo %d geallta taobh thiar de %s pulls.upstream_diverging_prompt_base_newer=Tá athruithe nua ar an mbunbhrainse %s pulls.upstream_diverging_merge=Forc sionc @@ -3772,6 +3770,7 @@ variables.creation.success=Tá an athróg "%s" curtha leis. variables.update.failed=Theip ar athróg a chur in eagar. variables.update.success=Tá an t-athróg curtha in eagar. + [projects] deleted.display_name=Tionscadal scriosta type-1.display_name=Tionscadal Aonair diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 88ccc9fac2..8e11f07d33 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -1615,6 +1615,7 @@ runs.commit=Commit + [projects] [git.filemode] diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 00a406aae4..7c8271b98b 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -1444,6 +1444,7 @@ variables.creation.success=Variabel "%s" telah ditambahkan. variables.update.failed=Gagal mengedit variabel. variables.update.success=Variabel telah diedit. + [projects] type-1.display_name=Proyek Individu type-2.display_name=Proyek Repositori diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 0564d49b1c..d3824f83a2 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -1342,6 +1342,7 @@ runs.commit=Framlag + [projects] [git.filemode] diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 567e6acdce..26b4f9e27b 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -2807,6 +2807,7 @@ runs.commit=Commit + [projects] [git.filemode] diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 4d3c7118d7..da07d77825 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1940,8 +1940,6 @@ pulls.delete.title=このプルリクエストを削除しますか? pulls.delete.text=本当にこのプルリクエストを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください) pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ %[1]s にプッシュしました -pulls.upstream_diverging_prompt_behind_1=このブランチは %[2]s よりも %[1]d コミット遅れています -pulls.upstream_diverging_prompt_behind_n=このブランチは %[2]s よりも %[1]d コミット遅れています pulls.upstream_diverging_prompt_base_newer=ベースブランチ %s に新しい変更があります pulls.upstream_diverging_merge=フォークを同期 @@ -3764,6 +3762,7 @@ variables.creation.success=変数 "%s" を追加しました。 variables.update.failed=変数を更新できませんでした。 variables.update.success=変数を更新しました。 + [projects] deleted.display_name=削除されたプロジェクト type-1.display_name=個人プロジェクト diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index 48220d5c99..361ab23e4c 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -1563,6 +1563,7 @@ runs.commit=커밋 + [projects] [git.filemode] diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index fd412b95b4..27a061d722 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -3443,6 +3443,7 @@ variables.creation.success=Mainīgais "%s" tika pievienots. variables.update.failed=Neizdevās labot mainīgo. variables.update.success=Mainīgais tika labots. + [projects] type-1.display_name=Individuālais projekts type-2.display_name=Repozitorija projekts diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index a4da8177bc..5c07b521e9 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -2537,6 +2537,7 @@ runs.commit=Commit + [projects] [git.filemode] diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 22f701219d..13c05eebe0 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -2430,6 +2430,7 @@ runs.commit=Commit + [projects] [git.filemode] diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 8fb869898b..c053b33210 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -3353,6 +3353,7 @@ runs.empty_commit_message=(mensagem de commit vazia) need_approval_desc=Precisa de aprovação para executar workflows para pull request do fork. + [projects] type-1.display_name=Projeto individual type-2.display_name=Projeto do repositório diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index b959e7fdba..13e7318c6f 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1945,8 +1945,6 @@ pulls.delete.title=Eliminar este pedido de integração? pulls.delete.text=Tem a certeza que quer eliminar este pedido de integração? Isso irá remover todo o conteúdo permanentemente. Como alternativa considere fechá-lo, se pretender mantê-lo em arquivo. pulls.recently_pushed_new_branches=Enviou para o ramo %[1]s %[2]s -pulls.upstream_diverging_prompt_behind_1=Este ramo está %d cometimento atrás de %s -pulls.upstream_diverging_prompt_behind_n=Este ramo está %d cometimentos atrás de %s pulls.upstream_diverging_prompt_base_newer=O ramo base %s tem novas modificações pulls.upstream_diverging_merge=Sincronizar derivação @@ -3772,6 +3770,9 @@ variables.creation.success=A variável "%s" foi adicionada. variables.update.failed=Falha ao editar a variável. variables.update.success=A variável foi editada. +logs.always_auto_scroll=Rolar registos de forma automática e permanente +logs.always_expand_running=Expandir sempre os registos que vão rolando + [projects] deleted.display_name=Planeamento eliminado type-1.display_name=Planeamento individual diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 735077bd41..0662c1f5f9 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -3373,6 +3373,7 @@ variables.creation.success=Переменная «%s» добавлена. variables.update.failed=Не удалось изменить переменную. variables.update.success=Переменная изменена. + [projects] type-1.display_name=Индивидуальный проект type-2.display_name=Проект репозитория diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 506fa5b492..debcf8e3e9 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -2470,6 +2470,7 @@ runs.commit=කැප + [projects] [git.filemode] diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index b4bf6fb552..39c13c358e 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -1328,6 +1328,7 @@ runners.labels=Štítky + [projects] [git.filemode] diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index fc138381db..2fd8277b76 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -2005,6 +2005,7 @@ runs.commit=Commit + [projects] [git.filemode] diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 9b7f2cb5c6..d17985dba5 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -3633,6 +3633,7 @@ variables.creation.success=`"%s" değişkeni eklendi.` variables.update.failed=Değişken düzenlenemedi. variables.update.success=Değişken düzenlendi. + [projects] deleted.display_name=Silinmiş Proje type-1.display_name=Kişisel Proje diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index efefeeb436..541a5bd0b5 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -2538,6 +2538,7 @@ runs.commit=Коміт + [projects] [git.filemode] diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 8c6392a4dc..a1fc26528e 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1945,8 +1945,8 @@ pulls.delete.title=删除此合并请求? pulls.delete.text=你真的要删除这个合并请求吗? (这将永久删除所有内容。如果你打算将内容存档,请考虑关闭它) pulls.recently_pushed_new_branches=您已经于%[2]s推送了分支 %[1]s -pulls.upstream_diverging_prompt_behind_1=该分支落后于 %s %d 个提交 -pulls.upstream_diverging_prompt_behind_n=该分支落后于 %s %d 个提交 +pulls.upstream_diverging_prompt_behind_1=该分支落后于 %[2]s %[1]d 个提交 +pulls.upstream_diverging_prompt_behind_n=该分支落后于 %[2]s %[1]d 个提交 pulls.upstream_diverging_prompt_base_newer=基础分支 %s 有新的更改 pulls.upstream_diverging_merge=同步派生 @@ -3772,6 +3772,7 @@ variables.creation.success=变量 “%s” 添加成功。 variables.update.failed=编辑变量失败。 variables.update.success=该变量已被编辑。 + [projects] deleted.display_name=已删除项目 type-1.display_name=个人项目 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 6f37d30efc..e1ca6ebfc8 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -975,6 +975,7 @@ runners.task_list.repository=儲存庫 + [projects] [git.filemode] diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index fb93a2ff07..267f8b4947 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -1938,8 +1938,6 @@ pulls.delete.title=刪除此合併請求? pulls.delete.text=您真的要刪除此合併請求嗎?(這將會永久移除所有內容。若您還想保留,請考慮改為關閉它。) pulls.recently_pushed_new_branches=您在分支 %[1]s 上推送了 %[2]s -pulls.upstream_diverging_prompt_behind_1=此分支落後 %s %d 次提交 -pulls.upstream_diverging_prompt_behind_n=此分支落後 %s %d 次提交 pulls.upstream_diverging_prompt_base_newer=基底分支 %s 有新變更 pulls.upstream_diverging_merge=同步 fork @@ -3765,6 +3763,7 @@ variables.creation.success=已新增變數「%s」。 variables.update.failed=編輯變數失敗。 variables.update.success=已編輯變數。 + [projects] deleted.display_name=已刪除的專案 type-1.display_name=個人專案 diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 0a7f92ac40..910edd6d58 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -126,11 +126,10 @@ func ArtifactsRoutes(prefix string) *web.Router { func ArtifactContexter() func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - base, baseCleanUp := context.NewBaseContext(resp, req) - defer baseCleanUp() + base := context.NewBaseContext(resp, req) ctx := &ArtifactContext{Base: base} - ctx.AppendContextValue(artifactContextKey, ctx) + ctx.SetContextValue(artifactContextKey, ctx) // action task call server api with Bearer ACTIONS_RUNTIME_TOKEN // we should verify the ACTIONS_RUNTIME_TOKEN diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go index 6dd36888d2..8917a7a8a2 100644 --- a/routers/api/actions/artifactsv4.go +++ b/routers/api/actions/artifactsv4.go @@ -126,12 +126,9 @@ type artifactV4Routes struct { func ArtifactV4Contexter() func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - base, baseCleanUp := context.NewBaseContext(resp, req) - defer baseCleanUp() - + base := context.NewBaseContext(resp, req) ctx := &ArtifactContext{Base: base} - ctx.AppendContextValue(artifactContextKey, ctx) - + ctx.SetContextValue(artifactContextKey, ctx) next.ServeHTTP(ctx.Resp, ctx.Req) }) } 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 9a31aec314..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) @@ -729,15 +729,11 @@ func CreateBranchProtection(ctx *context.APIContext) { } else { if !isPlainRule { if ctx.Repo.GitRepo == nil { - ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, "OpenRepository", err) return } - defer func() { - ctx.Repo.GitRepo.Close() - ctx.Repo.GitRepo = nil - }() } // FIXME: since we only need to recheck files protected rules, we could improve this matchedBranches, err := git_model.FindAllMatchedBranches(ctx, ctx.Repo.Repository.ID, ruleName) @@ -809,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) @@ -1061,15 +1057,11 @@ func EditBranchProtection(ctx *context.APIContext) { } else { if !isPlainRule { if ctx.Repo.GitRepo == nil { - ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, "OpenRepository", err) return } - defer func() { - ctx.Repo.GitRepo.Close() - ctx.Repo.GitRepo = nil - }() } // FIXME: since we only need to recheck files protected rules, we could improve this @@ -1132,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/compare.go b/routers/api/v1/repo/compare.go index 1678bc033c..87b890cb62 100644 --- a/routers/api/v1/repo/compare.go +++ b/routers/api/v1/repo/compare.go @@ -44,13 +44,12 @@ func CompareDiff(ctx *context.APIContext) { // "$ref": "#/responses/notFound" if ctx.Repo.GitRepo == nil { - gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + var err error + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, "OpenRepository", err) return } - ctx.Repo.GitRepo = gitRepo - defer gitRepo.Close() } infoPath := ctx.PathParam("*") diff --git a/routers/api/v1/repo/download.go b/routers/api/v1/repo/download.go index 3620c1465f..eb967772ed 100644 --- a/routers/api/v1/repo/download.go +++ b/routers/api/v1/repo/download.go @@ -28,13 +28,12 @@ func DownloadArchive(ctx *context.APIContext) { } if ctx.Repo.GitRepo == nil { - gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + var err error + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, "OpenRepository", err) return } - ctx.Repo.GitRepo = gitRepo - defer gitRepo.Close() } r, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, ctx.PathParam("*"), tp) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 83848b7add..6591b9a752 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -287,13 +287,12 @@ func GetArchive(ctx *context.APIContext) { // "$ref": "#/responses/notFound" if ctx.Repo.GitRepo == nil { - gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + var err error + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, "OpenRepository", err) return } - ctx.Repo.GitRepo = gitRepo - defer gitRepo.Close() } archiveDownload(ctx) 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..6f45fce226 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() @@ -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() @@ -976,7 +976,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 +1032,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() 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..ca5120eef5 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() @@ -831,7 +831,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 +889,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 +1256,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 +1355,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 +1441,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 +1564,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 40990a28cb..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() @@ -726,12 +726,11 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err if ctx.Repo.GitRepo == nil && !repo.IsEmpty { var err error - ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, repo) + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "Unable to OpenRepository", err) return err } - defer ctx.Repo.GitRepo.Close() } // Default branch only updated if changed and exist or the repository is empty 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/transfer.go b/routers/api/v1/repo/transfer.go index 787ec34404..b2090cac41 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -100,7 +100,7 @@ func Transfer(ctx *context.APIContext) { } if ctx.Repo.GitRepo != nil { - ctx.Repo.GitRepo.Close() + _ = ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo = nil } 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/errpage.go b/routers/common/errpage.go index 402ca44c12..c0b16dbdde 100644 --- a/routers/common/errpage.go +++ b/routers/common/errpage.go @@ -8,7 +8,6 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -18,7 +17,7 @@ import ( "code.gitea.io/gitea/services/context" ) -const tplStatus500 base.TplName = "status/500" +const tplStatus500 templates.TplName = "status/500" // RenderPanicErrorPage renders a 500 page, and it never panics func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) { @@ -47,7 +46,7 @@ func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) { ctxData["ErrorMsg"] = "PANIC: " + combinedErr } - err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), ctxData, tmplCtx) + err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, tplStatus500, ctxData, tmplCtx) if err != nil { log.Error("Error occurs again when rendering error page: %v", err) w.WriteHeader(http.StatusInternalServerError) diff --git a/routers/common/errpage_test.go b/routers/common/errpage_test.go index 4fd63ba49e..dfea55f510 100644 --- a/routers/common/errpage_test.go +++ b/routers/common/errpage_test.go @@ -12,8 +12,8 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/web/middleware" "github.com/stretchr/testify/assert" ) @@ -21,7 +21,7 @@ import ( func TestRenderPanicErrorPage(t *testing.T) { w := httptest.NewRecorder() req := &http.Request{URL: &url.URL{}} - req = req.WithContext(middleware.WithContextData(context.Background())) + req = req.WithContext(reqctx.NewRequestContextForTest(context.Background())) RenderPanicErrorPage(w, req, errors.New("fake panic error (for test only)")) respContent := w.Body.String() assert.Contains(t, respContent, `class="page-content status-page-500"`) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 51e42d87a0..047d327ce8 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -4,16 +4,14 @@ package common import ( - go_context "context" "fmt" "net/http" "strings" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/modules/web/routing" "code.gitea.io/gitea/services/context" @@ -24,54 +22,12 @@ import ( // ProtocolMiddlewares returns HTTP protocol related middlewares, and it provides a global panic recovery func ProtocolMiddlewares() (handlers []any) { - // make sure chi uses EscapedPath(RawPath) as RoutePath, then "%2f" could be handled correctly - handlers = append(handlers, func(next http.Handler) http.Handler { - return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - ctx := chi.RouteContext(req.Context()) - if req.URL.RawPath == "" { - ctx.RoutePath = req.URL.EscapedPath() - } else { - ctx.RoutePath = req.URL.RawPath - } - next.ServeHTTP(resp, req) - }) - }) + // the order is important + handlers = append(handlers, ChiRoutePathHandler()) // make sure chi has correct paths + handlers = append(handlers, RequestContextHandler()) // // prepare the context and panic recovery - // prepare the ContextData and panic recovery - handlers = append(handlers, func(next http.Handler) http.Handler { - return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - defer func() { - if err := recover(); err != nil { - RenderPanicErrorPage(resp, req, err) // it should never panic - } - }() - req = req.WithContext(middleware.WithContextData(req.Context())) - req = req.WithContext(go_context.WithValue(req.Context(), httplib.RequestContextKey, req)) - next.ServeHTTP(resp, req) - }) - }) - - // wrap the request and response, use the process context and add it to the process manager - handlers = append(handlers, func(next http.Handler) http.Handler { - return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - ctx, _, finished := process.GetManager().AddTypedContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI), process.RequestProcessType, true) - defer finished() - next.ServeHTTP(context.WrapResponseWriter(resp), req.WithContext(cache.WithCacheContext(ctx))) - }) - }) - - if setting.ReverseProxyLimit > 0 { - opt := proxy.NewForwardedHeadersOptions(). - WithForwardLimit(setting.ReverseProxyLimit). - ClearTrustedProxies() - for _, n := range setting.ReverseProxyTrustedProxies { - if !strings.Contains(n, "/") { - opt.AddTrustedProxy(n) - } else { - opt.AddTrustedNetwork(n) - } - } - handlers = append(handlers, proxy.ForwardedHeaders(opt)) + if setting.ReverseProxyLimit > 0 && len(setting.ReverseProxyTrustedProxies) > 0 { + handlers = append(handlers, ForwardedHeadersHandler(setting.ReverseProxyLimit, setting.ReverseProxyTrustedProxies)) } if setting.IsRouteLogEnabled() { @@ -85,6 +41,59 @@ func ProtocolMiddlewares() (handlers []any) { return handlers } +func RequestContextHandler() func(h http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + profDesc := fmt.Sprintf("%s: %s", req.Method, req.RequestURI) + ctx, finished := reqctx.NewRequestContext(req.Context(), profDesc) + defer finished() + + defer func() { + if err := recover(); err != nil { + RenderPanicErrorPage(resp, req, err) // it should never panic + } + }() + + ds := reqctx.GetRequestDataStore(ctx) + req = req.WithContext(cache.WithCacheContext(ctx)) + ds.SetContextValue(httplib.RequestContextKey, req) + ds.AddCleanUp(func() { + if req.MultipartForm != nil { + _ = req.MultipartForm.RemoveAll() // remove the temp files buffered to tmp directory + } + }) + next.ServeHTTP(context.WrapResponseWriter(resp), req) + }) + } +} + +func ChiRoutePathHandler() func(h http.Handler) http.Handler { + // make sure chi uses EscapedPath(RawPath) as RoutePath, then "%2f" could be handled correctly + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + ctx := chi.RouteContext(req.Context()) + if req.URL.RawPath == "" { + ctx.RoutePath = req.URL.EscapedPath() + } else { + ctx.RoutePath = req.URL.RawPath + } + next.ServeHTTP(resp, req) + }) + } +} + +func ForwardedHeadersHandler(limit int, trustedProxies []string) func(h http.Handler) http.Handler { + opt := proxy.NewForwardedHeadersOptions().WithForwardLimit(limit).ClearTrustedProxies() + for _, n := range trustedProxies { + if !strings.Contains(n, "/") { + opt.AddTrustedProxy(n) + } else { + opt.AddTrustedNetwork(n) + } + } + return proxy.ForwardedHeaders(opt) +} + func Sessioner() func(next http.Handler) http.Handler { return session.Sessioner(session.Options{ Provider: setting.SessionConfig.Provider, diff --git a/routers/init.go b/routers/init.go index 2091f5967a..e7aa765bf0 100644 --- a/routers/init.go +++ b/routers/init.go @@ -133,7 +133,7 @@ func InitWebInstalled(ctx context.Context) { highlight.NewContext() external.RegisterRenderers() - markup.Init(markup_service.ProcessorHelper()) + markup.Init(markup_service.FormalRenderHelperFuncs()) if setting.EnableSQLite3 { log.Info("SQLite3 support is enabled") @@ -171,7 +171,7 @@ func InitWebInstalled(ctx context.Context) { auth.Init() mustInit(svg.Init) - actions_service.Init() + mustInitCtx(ctx, actions_service.Init) mustInit(repo_service.InitLicenseClassifier) diff --git a/routers/install/install.go b/routers/install/install.go index e420d36da5..8a1d57aa0b 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -21,11 +21,11 @@ import ( system_model "code.gitea.io/gitea/models/system" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password/hash" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/graceful" "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/templates" "code.gitea.io/gitea/modules/timeutil" @@ -43,8 +43,8 @@ import ( const ( // tplInstall template for installation page - tplInstall base.TplName = "install" - tplPostInstall base.TplName = "post-install" + tplInstall templates.TplName = "install" + tplPostInstall templates.TplName = "post-install" ) // getSupportedDbTypeNames returns a slice for supported database types and names. The slice is used to keep the order @@ -62,15 +62,11 @@ func Contexter() func(next http.Handler) http.Handler { envConfigKeys := setting.CollectEnvConfigKeys() return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - base, baseCleanUp := context.NewBaseContext(resp, req) - defer baseCleanUp() - + base := context.NewBaseContext(resp, req) ctx := context.NewWebContext(base, rnd, session.GetSession(req)) - ctx.AppendContextValue(context.WebContextKey, ctx) + ctx.SetContextValue(context.WebContextKey, ctx) ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) - ctx.Data.MergeFrom(middleware.ContextData{ - "Context": ctx, // TODO: use "ctx" in template and remove this - "locale": ctx.Locale, + ctx.Data.MergeFrom(reqctx.ContextData{ "Title": ctx.Locale.Tr("install.install"), "PageIsInstall": true, "DbTypeNames": dbTypeNames, 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.go b/routers/private/internal.go index 1fb72f13d9..a78c76f897 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -63,8 +63,8 @@ func Routes() *web.Router { r.Post("/ssh/{id}/update/{repoid}", UpdatePublicKeyInRepo) r.Post("/ssh/log", bind(private.SSHLogOption{}), SSHLog) r.Post("/hook/pre-receive/{owner}/{repo}", RepoAssignment, bind(private.HookOptions{}), HookPreReceive) - r.Post("/hook/post-receive/{owner}/{repo}", context.OverrideContext, bind(private.HookOptions{}), HookPostReceive) - r.Post("/hook/proc-receive/{owner}/{repo}", context.OverrideContext, RepoAssignment, bind(private.HookOptions{}), HookProcReceive) + r.Post("/hook/post-receive/{owner}/{repo}", context.OverrideContext(), bind(private.HookOptions{}), HookPostReceive) + r.Post("/hook/proc-receive/{owner}/{repo}", context.OverrideContext(), RepoAssignment, bind(private.HookOptions{}), HookProcReceive) r.Post("/hook/set-default-branch/{owner}/{repo}/{branch}", RepoAssignment, SetDefaultBranch) r.Get("/serv/none/{keyid}", ServNoCommand) r.Get("/serv/command/{keyid}/{owner}/{repo}", ServCommand) @@ -88,7 +88,7 @@ func Routes() *web.Router { // Fortunately, the LFS handlers are able to handle requests without a complete web context common.AddOwnerRepoGitLFSRoutes(r, func(ctx *context.PrivateContext) { webContext := &context.Context{Base: ctx.Base} - ctx.AppendContextValue(context.WebContextKey, webContext) + ctx.SetContextValue(context.WebContextKey, webContext) }) }) diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go index aad0a3fb1a..8a53e1ed23 100644 --- a/routers/private/internal_repo.go +++ b/routers/private/internal_repo.go @@ -4,7 +4,6 @@ package private import ( - "context" "fmt" "net/http" @@ -17,40 +16,29 @@ import ( // This file contains common functions relating to setting the Repository for the internal routes -// RepoAssignment assigns the repository and gitrepository to the private context -func RepoAssignment(ctx *gitea_context.PrivateContext) context.CancelFunc { - ownerName := ctx.PathParam(":owner") - repoName := ctx.PathParam(":repo") +// 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") repo := loadRepository(ctx, ownerName, repoName) if ctx.Written() { // Error handled in loadRepository - return nil + return } - gitRepo, err := gitrepo.OpenRepository(ctx, repo) + gitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, repo) if err != nil { log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err), }) - return nil + return } - ctx.Repo = &gitea_context.Repository{ Repository: repo, GitRepo: gitRepo, } - - // We opened it, we should close it - cancel := func() { - // If it's been set to nil then assume someone else has closed it. - if ctx.Repo.GitRepo != nil { - ctx.Repo.GitRepo.Close() - } - } - - return cancel } func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName string) *repo_model.Repository { 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/admin.go b/routers/web/admin/admin.go index 37c54b5362..3902a1efb1 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/updatechecker" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" @@ -31,14 +32,14 @@ import ( ) const ( - tplDashboard base.TplName = "admin/dashboard" - tplSystemStatus base.TplName = "admin/system_status" - tplSelfCheck base.TplName = "admin/self_check" - tplCron base.TplName = "admin/cron" - tplQueue base.TplName = "admin/queue" - tplStacktrace base.TplName = "admin/stacktrace" - tplQueueManage base.TplName = "admin/queue_manage" - tplStats base.TplName = "admin/stats" + tplDashboard templates.TplName = "admin/dashboard" + tplSystemStatus templates.TplName = "admin/system_status" + tplSelfCheck templates.TplName = "admin/self_check" + tplCron templates.TplName = "admin/cron" + tplQueue templates.TplName = "admin/queue" + tplStacktrace templates.TplName = "admin/stacktrace" + tplQueueManage templates.TplName = "admin/queue_manage" + tplStats templates.TplName = "admin/stats" ) var sysStatus struct { diff --git a/routers/web/admin/applications.go b/routers/web/admin/applications.go index 9b48f21eca..aec6349f21 100644 --- a/routers/web/admin/applications.go +++ b/routers/web/admin/applications.go @@ -9,15 +9,15 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" user_setting "code.gitea.io/gitea/routers/web/user/setting" "code.gitea.io/gitea/services/context" ) var ( - tplSettingsApplications base.TplName = "admin/applications/list" - tplSettingsOauth2ApplicationEdit base.TplName = "admin/applications/oauth2_edit" + tplSettingsApplications templates.TplName = "admin/applications/list" + tplSettingsOauth2ApplicationEdit templates.TplName = "admin/applications/oauth2_edit" ) func newOAuth2CommonHandlers() *user_setting.OAuth2CommonHandlers { diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 60e2b7c86f..249347e835 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -15,9 +15,9 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/auth/pam" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" @@ -33,9 +33,9 @@ import ( ) const ( - tplAuths base.TplName = "admin/auth/list" - tplAuthNew base.TplName = "admin/auth/new" - tplAuthEdit base.TplName = "admin/auth/edit" + tplAuths templates.TplName = "admin/auth/list" + tplAuthNew templates.TplName = "admin/auth/new" + tplAuthEdit templates.TplName = "admin/auth/edit" ) var ( @@ -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/config.go b/routers/web/admin/config.go index d067250a5b..520f14e89f 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -11,13 +11,13 @@ import ( "strings" system_model "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting/config" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/mailer" @@ -26,8 +26,8 @@ import ( ) const ( - tplConfig base.TplName = "admin/config" - tplConfigSettings base.TplName = "admin/config_settings" + tplConfig templates.TplName = "admin/config" + tplConfigSettings templates.TplName = "admin/config_settings" ) // SendTestMail send test mail to confirm mail service is OK diff --git a/routers/web/admin/emails.go b/routers/web/admin/emails.go index e9c97d8b8f..e925de8937 100644 --- a/routers/web/admin/emails.go +++ b/routers/web/admin/emails.go @@ -10,16 +10,16 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/user" ) const ( - tplEmails base.TplName = "admin/emails/list" + tplEmails templates.TplName = "admin/emails/list" ) // Emails show all emails diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go index 91ca6e3fa7..34dc0fc9b0 100644 --- a/routers/web/admin/hooks.go +++ b/routers/web/admin/hooks.go @@ -7,15 +7,15 @@ import ( "net/http" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( // tplAdminHooks template path to render hook settings - tplAdminHooks base.TplName = "admin/hooks" + tplAdminHooks templates.TplName = "admin/hooks" ) // DefaultOrSystemWebhooks renders both admin default and system webhook list pages diff --git a/routers/web/admin/notice.go b/routers/web/admin/notice.go index 5f7432e629..21a8ab0d17 100644 --- a/routers/web/admin/notice.go +++ b/routers/web/admin/notice.go @@ -10,14 +10,14 @@ import ( "code.gitea.io/gitea/models/db" system_model "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( - tplNotices base.TplName = "admin/notice" + tplNotices templates.TplName = "admin/notice" ) // Notices show notices for admin diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index cea28f8220..35e61efa17 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -7,15 +7,15 @@ package admin import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/routers/web/explore" "code.gitea.io/gitea/services/context" ) const ( - tplOrgs base.TplName = "admin/org/list" + tplOrgs templates.TplName = "admin/org/list" ) // Organizations show all the organizations diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 2b9edc622d..da345f2f89 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -10,16 +10,16 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup" ) const ( - tplPackagesList base.TplName = "admin/packages/list" + tplPackagesList templates.TplName = "admin/packages/list" ) // Packages shows all packages diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go index 75e5ee5d86..27d39dcf4b 100644 --- a/routers/web/admin/repos.go +++ b/routers/web/admin/repos.go @@ -12,9 +12,9 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/web/explore" "code.gitea.io/gitea/services/context" @@ -22,8 +22,8 @@ import ( ) const ( - tplRepos base.TplName = "admin/repo/list" - tplUnadoptedRepos base.TplName = "admin/repo/unadopted" + tplRepos templates.TplName = "admin/repo/list" + tplUnadoptedRepos templates.TplName = "admin/repo/unadopted" ) // Repos show all the repositories diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 1eaa37bfbd..fdd18b2f9d 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -18,10 +18,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/explore" @@ -33,10 +33,10 @@ import ( ) const ( - tplUsers base.TplName = "admin/user/list" - tplUserNew base.TplName = "admin/user/new" - tplUserView base.TplName = "admin/user/view" - tplUserEdit base.TplName = "admin/user/edit" + tplUsers templates.TplName = "admin/user/list" + tplUserNew templates.TplName = "admin/user/new" + tplUserView templates.TplName = "admin/user/view" + tplUserEdit templates.TplName = "admin/user/edit" ) // UserSearchDefaultAdminSort is the default sort type for admin view @@ -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/2fa.go b/routers/web/auth/2fa.go index f93177bf96..fe363fe90a 100644 --- a/routers/web/auth/2fa.go +++ b/routers/web/auth/2fa.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" @@ -18,8 +18,8 @@ import ( ) var ( - tplTwofa base.TplName = "user/auth/twofa" - tplTwofaScratch base.TplName = "user/auth/twofa_scratch" + tplTwofa templates.TplName = "user/auth/twofa" + tplTwofaScratch templates.TplName = "user/auth/twofa_scratch" ) // TwoFactor shows the user a two-factor authentication page. diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 3f16da3cdd..42736a423f 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -15,13 +15,13 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/eventsource" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -38,10 +38,10 @@ import ( ) const ( - tplSignIn base.TplName = "user/auth/signin" // for sign in page - tplSignUp base.TplName = "user/auth/signup" // for sign up page - TplActivate base.TplName = "user/auth/activate" // for activate user - TplActivatePrompt base.TplName = "user/auth/activate_prompt" // for showing a message for user activation + tplSignIn templates.TplName = "user/auth/signin" // for sign in page + tplSignUp templates.TplName = "user/auth/signup" // for sign up page + TplActivate templates.TplName = "user/auth/activate" // for activate user + TplActivatePrompt templates.TplName = "user/auth/activate_prompt" // for showing a message for user activation ) // autoSignIn reads cookie and try to auto-login. @@ -517,7 +517,7 @@ func SignUpPost(ctx *context.Context) { // createAndHandleCreatedUser calls createUserInContext and // then handleUserCreated. -func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool { +func createAndHandleCreatedUser(ctx *context.Context, tpl templates.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool { if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) { return false } @@ -526,7 +526,7 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any // createUserInContext creates a user and handles errors within a given context. // Optionally a template can be specified. -func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) { +func createUserInContext(ctx *context.Context, tpl templates.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) { meta := &user_model.Meta{ InitialIP: ctx.RemoteAddr(), InitialUserAgent: ctx.Req.UserAgent(), diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 519431d92b..147d8d3802 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" @@ -25,7 +25,7 @@ import ( "github.com/markbates/goth" ) -var tplLinkAccount base.TplName = "user/auth/link_account" +var tplLinkAccount templates.TplName = "user/auth/link_account" // LinkAccount shows the page where the user can decide to login or create a new account func LinkAccount(ctx *context.Context) { @@ -92,7 +92,7 @@ func LinkAccount(ctx *context.Context) { ctx.HTML(http.StatusOK, tplLinkAccount) } -func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl base.TplName, invoker string, err error) { +func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl templates.TplName, invoker string, err error) { if errors.Is(err, util.ErrNotExist) { ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm) } else if errors.Is(err, util.ErrInvalidArgument) { diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 75f94de0ed..7a9721cf56 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -15,11 +15,11 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" auth_module "code.gitea.io/gitea/modules/auth" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web/middleware" source_service "code.gitea.io/gitea/services/auth/source" "code.gitea.io/gitea/services/auth/source/oauth2" @@ -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 @@ -194,7 +194,7 @@ func SignInOAuthCallback(ctx *context.Context) { u.IsAdmin = isAdmin.ValueOrDefault(false) u.IsRestricted = isRestricted.ValueOrDefault(false) - if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) { + if !createAndHandleCreatedUser(ctx, templates.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) { // error already handled return } diff --git a/routers/web/auth/oauth2_provider.go b/routers/web/auth/oauth2_provider.go index 1aebc047bd..6262ad8a6d 100644 --- a/routers/web/auth/oauth2_provider.go +++ b/routers/web/auth/oauth2_provider.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/context" @@ -29,8 +30,8 @@ import ( ) const ( - tplGrantAccess base.TplName = "user/auth/grant" - tplGrantError base.TplName = "user/auth/grant_error" + tplGrantAccess templates.TplName = "user/auth/grant" + tplGrantError templates.TplName = "user/auth/grant_error" ) // TODO move error and responses to SDK or models diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 83268faacb..41d37ecb8b 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -10,9 +10,9 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/openid" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/auth" @@ -21,9 +21,9 @@ import ( ) const ( - tplSignInOpenID base.TplName = "user/auth/signin_openid" - tplConnectOID base.TplName = "user/auth/signup_openid_connect" - tplSignUpOID base.TplName = "user/auth/signup_openid_register" + tplSignInOpenID templates.TplName = "user/auth/signin_openid" + tplConnectOID templates.TplName = "user/auth/signup_openid_connect" + tplSignUpOID templates.TplName = "user/auth/signup_openid_register" ) // SignInOpenID render sign in page diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index 334d864c6a..3812d582e5 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -11,10 +11,10 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" @@ -26,9 +26,9 @@ import ( var ( // tplMustChangePassword template for updating a user's password - tplMustChangePassword base.TplName = "user/auth/change_passwd" - tplForgotPassword base.TplName = "user/auth/forgot_passwd" - tplResetPassword base.TplName = "user/auth/reset_passwd" + tplMustChangePassword templates.TplName = "user/auth/change_passwd" + tplForgotPassword templates.TplName = "user/auth/forgot_passwd" + tplResetPassword templates.TplName = "user/auth/reset_passwd" ) // ForgotPasswd render the forget password page diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go index ba25d45070..69031adeaa 100644 --- a/routers/web/auth/webauthn.go +++ b/routers/web/auth/webauthn.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" wa "code.gitea.io/gitea/modules/auth/webauthn" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" @@ -21,7 +21,7 @@ import ( "github.com/go-webauthn/webauthn/webauthn" ) -var tplWebAuthn base.TplName = "user/auth/webauthn" +var tplWebAuthn templates.TplName = "user/auth/webauthn" // WebAuthn shows the WebAuthn login page func WebAuthn(ctx *context.Context) { diff --git a/routers/web/devtest/devtest.go b/routers/web/devtest/devtest.go index 0068c9fe88..0bc84d2d1e 100644 --- a/routers/web/devtest/devtest.go +++ b/routers/web/devtest/devtest.go @@ -9,7 +9,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) @@ -62,5 +61,5 @@ func Tmpl(ctx *context.Context) { time.Sleep(2 * time.Second) } - ctx.HTML(http.StatusOK, base.TplName("devtest"+path.Clean("/"+ctx.PathParam("sub")))) + ctx.HTML(http.StatusOK, templates.TplName("devtest"+path.Clean("/"+ctx.PathParam("sub")))) } diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go index 46e302d634..f29b8e4046 100644 --- a/routers/web/devtest/mock_actions.go +++ b/routers/web/devtest/mock_actions.go @@ -31,7 +31,11 @@ func generateMockStepsLog(logCur actions.LogCursor) (stepsLog []*actions.ViewSte "##[endgroup]", } cur := logCur.Cursor // usually the cursor is the "file offset", but here we abuse it as "line number" to make the mock easier, intentionally - for i := 0; i < util.Iif(logCur.Step == 0, 3, 1); i++ { + mockCount := util.Iif(logCur.Step == 0, 3, 1) + if logCur.Step == 1 && logCur.Cursor == 0 { + mockCount = 30 // for the first batch, return as many as possible to test the auto-expand and auto-scroll + } + for i := 0; i < mockCount; i++ { logStr := mockedLogs[int(cur)%len(mockedLogs)] cur++ logStr = strings.ReplaceAll(logStr, "{step}", fmt.Sprintf("%d", logCur.Step)) @@ -56,6 +60,21 @@ func MockActionsRunsJobs(ctx *context.Context) { resp.State.Run.Status = actions_model.StatusRunning.String() resp.State.Run.CanCancel = true resp.State.Run.CanDeleteArtifact = true + resp.State.Run.WorkflowID = "workflow-id" + resp.State.Run.WorkflowLink = "./workflow-link" + resp.State.Run.Commit = actions.ViewCommit{ + ShortSha: "ccccdddd", + Link: "./commit-link", + Pusher: actions.ViewUser{ + DisplayName: "pusher user", + Link: "./pusher-link", + }, + Branch: actions.ViewBranch{ + Name: "commit-branch", + Link: "./branch-link", + IsDeleted: false, + }, + } resp.Artifacts = append(resp.Artifacts, &actions.ArtifactsViewItem{ Name: "artifact-a", Size: 100 * 1024, diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go index 48f890332b..4df89253b4 100644 --- a/routers/web/explore/code.go +++ b/routers/web/explore/code.go @@ -8,15 +8,15 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/base" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( // tplExploreCode explore code page template - tplExploreCode base.TplName = "explore/code" + tplExploreCode templates.TplName = "explore/code" ) // Code render explore code page diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index 5b6f612e72..c421aea715 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -9,17 +9,17 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sitemap" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( // tplExploreRepos explore repositories page template - tplExploreRepos base.TplName = "explore/repos" - relevantReposOnlyParam string = "only_show_relevant" + tplExploreRepos templates.TplName = "explore/repos" + relevantReposOnlyParam string = "only_show_relevant" ) // RepoSearchOptions when calling search repositories @@ -29,7 +29,7 @@ type RepoSearchOptions struct { Restricted bool PageSize int OnlyShowRelevant bool - TplName base.TplName + TplName templates.TplName } // RenderRepoSearch render repositories search page diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index c009982d42..ef103af8cf 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -9,20 +9,20 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sitemap" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" ) const ( // tplExploreUsers explore users page template - tplExploreUsers base.TplName = "explore/users" + tplExploreUsers templates.TplName = "explore/users" ) var nullByte = []byte{0x00} @@ -32,7 +32,7 @@ func isKeywordValid(keyword string) bool { } // RenderUserSearch render user search page -func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, tplName base.TplName) { +func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, tplName templates.TplName) { // Sitemap index for sitemap paths opts.Page = int(ctx.PathParamInt64("idx")) isSitemap := ctx.PathParam("idx") != "" 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/home.go b/routers/web/home.go index d4be0931e8..9ad495d54f 100644 --- a/routers/web/home.go +++ b/routers/web/home.go @@ -11,12 +11,12 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sitemap" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/routers/web/auth" "code.gitea.io/gitea/routers/web/user" @@ -25,7 +25,7 @@ import ( const ( // tplHome home page template - tplHome base.TplName = "home" + tplHome templates.TplName = "home" ) // Home render home page diff --git a/routers/web/misc/swagger.go b/routers/web/misc/swagger.go index 5fddfa8885..1ca347551c 100644 --- a/routers/web/misc/swagger.go +++ b/routers/web/misc/swagger.go @@ -6,12 +6,12 @@ package misc import ( "net/http" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) // tplSwagger swagger page template -const tplSwagger base.TplName = "swagger/ui" +const tplSwagger templates.TplName = "swagger/ui" // Swagger render swagger-ui page with v1 json func Swagger(ctx *context.Context) { diff --git a/routers/web/org/block.go b/routers/web/org/block.go index d40458e250..aeb4bd51a8 100644 --- a/routers/web/org/block.go +++ b/routers/web/org/block.go @@ -6,13 +6,13 @@ package org import ( "net/http" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsBlockedUsers base.TplName = "org/settings/blocked_users" + tplSettingsBlockedUsers templates.TplName = "org/settings/blocked_users" ) func BlockedUsers(ctx *context.Context) { diff --git a/routers/web/org/home.go b/routers/web/org/home.go index f02c08ae76..bdc43acc30 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -13,29 +13,29 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" ) const ( - tplOrgHome base.TplName = "org/home" + tplOrgHome templates.TplName = "org/home" ) // 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 7af087c4df..5a134caecb 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -9,9 +9,9 @@ import ( "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" org_service "code.gitea.io/gitea/services/org" @@ -19,7 +19,7 @@ import ( const ( // tplMembers template for organization members page - tplMembers base.TplName = "org/member/members" + tplMembers templates.TplName = "org/member/members" ) // Members render organization users page @@ -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/org.go b/routers/web/org/org.go index f94dd16eae..856a605764 100644 --- a/routers/web/org/org.go +++ b/routers/web/org/org.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -21,7 +21,7 @@ import ( const ( // tplCreateOrg template path for create organization - tplCreateOrg base.TplName = "org/create" + tplCreateOrg templates.TplName = "org/create" ) // Create render the page for create organization diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 3b9ec2a7b8..efcc8fadc8 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -15,7 +15,6 @@ import ( project_model "code.gitea.io/gitea/models/project" attachment_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -29,9 +28,9 @@ import ( ) const ( - tplProjects base.TplName = "org/projects/list" - tplProjectsNew base.TplName = "org/projects/new" - tplProjectsView base.TplName = "org/projects/view" + tplProjects templates.TplName = "org/projects/list" + tplProjectsNew templates.TplName = "org/projects/new" + tplProjectsView templates.TplName = "org/projects/view" ) // MustEnableProjects check if projects are enabled in settings @@ -197,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": @@ -206,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) @@ -217,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 @@ -246,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 @@ -270,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 @@ -319,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 @@ -448,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), }) @@ -473,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 } @@ -485,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 @@ -513,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), }) @@ -588,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 @@ -598,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/setting.go b/routers/web/org/setting.go index 551019c717..cb1c4213c9 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -13,11 +13,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" @@ -30,13 +30,13 @@ import ( const ( // tplSettingsOptions template path for render settings - tplSettingsOptions base.TplName = "org/settings/options" + tplSettingsOptions templates.TplName = "org/settings/options" // tplSettingsDelete template path for render delete repository - tplSettingsDelete base.TplName = "org/settings/delete" + tplSettingsDelete templates.TplName = "org/settings/delete" // tplSettingsHooks template path for render hook settings - tplSettingsHooks base.TplName = "org/settings/hooks" + tplSettingsHooks templates.TplName = "org/settings/hooks" // tplSettingsLabels template path for render labels settings - tplSettingsLabels base.TplName = "org/settings/labels" + tplSettingsLabels templates.TplName = "org/settings/labels" ) // Settings render the main settings page diff --git a/routers/web/org/setting_oauth2.go b/routers/web/org/setting_oauth2.go index 7f855795d3..c93058477e 100644 --- a/routers/web/org/setting_oauth2.go +++ b/routers/web/org/setting_oauth2.go @@ -9,16 +9,16 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared_user "code.gitea.io/gitea/routers/web/shared/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsApplications base.TplName = "org/settings/applications" - tplSettingsOAuthApplicationEdit base.TplName = "org/settings/applications_oauth2_edit" + tplSettingsApplications templates.TplName = "org/settings/applications" + tplSettingsOAuthApplicationEdit templates.TplName = "org/settings/applications_oauth2_edit" ) func newOAuth2CommonHandlers(org *context.Organization) *user_setting.OAuth2CommonHandlers { diff --git a/routers/web/org/setting_packages.go b/routers/web/org/setting_packages.go index af9836e42c..0912a9e0fd 100644 --- a/routers/web/org/setting_packages.go +++ b/routers/web/org/setting_packages.go @@ -7,17 +7,17 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared "code.gitea.io/gitea/routers/web/shared/packages" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsPackages base.TplName = "org/settings/packages" - tplSettingsPackagesRuleEdit base.TplName = "org/settings/packages_cleanup_rules_edit" - tplSettingsPackagesRulePreview base.TplName = "org/settings/packages_cleanup_rules_preview" + tplSettingsPackages templates.TplName = "org/settings/packages" + tplSettingsPackagesRuleEdit templates.TplName = "org/settings/packages_cleanup_rules_edit" + tplSettingsPackagesRulePreview templates.TplName = "org/settings/packages_cleanup_rules_preview" ) func Packages(ctx *context.Context) { diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index b03b18bd9c..0137f2cc96 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -19,9 +19,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" @@ -33,15 +33,15 @@ import ( const ( // tplTeams template path for teams list page - tplTeams base.TplName = "org/team/teams" + tplTeams templates.TplName = "org/team/teams" // tplTeamNew template path for create new team page - tplTeamNew base.TplName = "org/team/new" + tplTeamNew templates.TplName = "org/team/new" // tplTeamMembers template path for showing team members page - tplTeamMembers base.TplName = "org/team/members" + tplTeamMembers templates.TplName = "org/team/members" // tplTeamRepositories template path for showing team repositories page - tplTeamRepositories base.TplName = "org/team/repositories" + tplTeamRepositories templates.TplName = "org/team/repositories" // tplTeamInvite template path for team invites page - tplTeamInvite base.TplName = "org/team/invite" + tplTeamInvite templates.TplName = "org/team/invite" ) // Teams render teams list page @@ -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/actions/actions.go b/routers/web/repo/actions/actions.go index 1de1835936..099593bff0 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -17,12 +17,12 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/actions" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" @@ -33,8 +33,8 @@ import ( ) const ( - tplListActions base.TplName = "repo/actions/list" - tplViewActions base.TplName = "repo/actions/view" + tplListActions templates.TplName = "repo/actions/list" + tplViewActions templates.TplName = "repo/actions/view" ) type Workflow struct { diff --git a/routers/web/repo/activity.go b/routers/web/repo/activity.go index 65dd9e392f..1d809ad8e9 100644 --- a/routers/web/repo/activity.go +++ b/routers/web/repo/activity.go @@ -9,12 +9,12 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( - tplActivity base.TplName = "repo/activity" + tplActivity templates.TplName = "repo/activity" ) // Activity render the page to show repository latest changes 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/branch.go b/routers/web/repo/branch.go index 3e1c6fc61c..72fd958e28 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -14,12 +14,12 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" @@ -31,7 +31,7 @@ import ( ) const ( - tplBranch base.TplName = "repo/branch/list" + tplBranch templates.TplName = "repo/branch/list" ) // Branches render repository branch page diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 71671ec628..35f158df52 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -10,9 +10,9 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" @@ -20,12 +20,12 @@ import ( "code.gitea.io/gitea/services/repository/files" ) -var tplCherryPick base.TplName = "repo/editor/cherry_pick" +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/code_frequency.go b/routers/web/repo/code_frequency.go index c76f492da0..6572adce74 100644 --- a/routers/web/repo/code_frequency.go +++ b/routers/web/repo/code_frequency.go @@ -7,13 +7,13 @@ import ( "errors" "net/http" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" contributors_service "code.gitea.io/gitea/services/repository" ) const ( - tplCodeFrequency base.TplName = "repo/activity" + tplCodeFrequency templates.TplName = "repo/activity" ) // CodeFrequency renders the page to show repository code frequency diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 6d53df7c10..6f534b9e2e 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -27,6 +27,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/gitdiff" @@ -34,10 +35,10 @@ import ( ) const ( - tplCommits base.TplName = "repo/commits" - tplGraph base.TplName = "repo/graph" - tplGraphDiv base.TplName = "repo/graph/div" - tplCommitPage base.TplName = "repo/commit_page" + tplCommits templates.TplName = "repo/commits" + tplGraph templates.TplName = "repo/graph" + tplGraphDiv templates.TplName = "repo/graph/div" + tplCommitPage templates.TplName = "repo/commit_page" ) // RefCommits render commits page @@ -281,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 @@ -426,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 278974bec3..6c59421bda 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -33,6 +33,7 @@ import ( "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/common" @@ -42,9 +43,9 @@ import ( ) const ( - tplCompare base.TplName = "repo/diff/compare" - tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt" - tplDiffBox base.TplName = "repo/diff/box" + tplCompare templates.TplName = "repo/diff/compare" + tplBlobExcerpt templates.TplName = "repo/diff/blob_excerpt" + tplDiffBox templates.TplName = "repo/diff/box" ) // setCompareContext sets context data. diff --git a/routers/web/repo/contributors.go b/routers/web/repo/contributors.go index 762fbf9379..e9c0919955 100644 --- a/routers/web/repo/contributors.go +++ b/routers/web/repo/contributors.go @@ -7,13 +7,13 @@ import ( "errors" "net/http" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" contributors_service "code.gitea.io/gitea/services/repository" ) const ( - tplContributors base.TplName = "repo/activity" + tplContributors templates.TplName = "repo/activity" ) // Contributors render the page to show repository contributors graph diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index afc69bffdf..5fbdeee27e 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -13,13 +13,13 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -31,10 +31,10 @@ import ( ) const ( - tplEditFile base.TplName = "repo/editor/edit" - tplEditDiffPreview base.TplName = "repo/editor/diff_preview" - tplDeleteFile base.TplName = "repo/editor/delete" - tplUploadFile base.TplName = "repo/editor/upload" + tplEditFile templates.TplName = "repo/editor/edit" + tplEditDiffPreview templates.TplName = "repo/editor/diff_preview" + tplDeleteFile templates.TplName = "repo/editor/delete" + tplUploadFile templates.TplName = "repo/editor/upload" frmCommitChoiceDirect string = "direct" frmCommitChoiceNewBranch string = "commit-to-new-branch" 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/find.go b/routers/web/repo/find.go index 2c44552f9c..3a3a7610e7 100644 --- a/routers/web/repo/find.go +++ b/routers/web/repo/find.go @@ -6,13 +6,13 @@ package repo import ( "net/http" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" ) const ( - tplFindFiles base.TplName = "repo/find/files" + tplFindFiles templates.TplName = "repo/find/files" ) // FindFiles render the page to find repository files diff --git a/routers/web/repo/fork.go b/routers/web/repo/fork.go index 86af705617..786b5d7e43 100644 --- a/routers/web/repo/fork.go +++ b/routers/web/repo/fork.go @@ -13,12 +13,12 @@ import ( "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -26,7 +26,7 @@ import ( ) const ( - tplFork base.TplName = "repo/pulls/fork" + tplFork templates.TplName = "repo/pulls/fork" ) func getForkRepository(ctx *context.Context) *repo_model.Repository { 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 5397411b59..a3a4e73d7b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -21,7 +21,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" @@ -37,14 +36,14 @@ import ( ) const ( - tplAttachment base.TplName = "repo/issue/view_content/attachments" + tplAttachment templates.TplName = "repo/issue/view_content/attachments" - tplIssues base.TplName = "repo/issue/list" - tplIssueNew base.TplName = "repo/issue/new" - tplIssueChoose base.TplName = "repo/issue/choose" - tplIssueView base.TplName = "repo/issue/view" + tplIssues templates.TplName = "repo/issue/list" + tplIssueNew templates.TplName = "repo/issue/new" + tplIssueChoose templates.TplName = "repo/issue/choose" + tplIssueView templates.TplName = "repo/issue/view" - tplReactions base.TplName = "repo/issue/view_content/reactions" + tplReactions templates.TplName = "repo/issue/view_content/reactions" issueTemplateKey = "IssueTemplate" issueTemplateTitleKey = "IssueTemplateTitle" @@ -182,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 @@ -247,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) @@ -380,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) @@ -507,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 { @@ -541,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..438822431d 100644 --- a/routers/web/repo/issue_comment.go +++ b/routers/web/repo/issue_comment.go @@ -209,7 +209,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 +287,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 +322,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 +366,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 +400,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 +427,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_label.go b/routers/web/repo/issue_label.go index 4874baaa54..5ef6b09faa 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -9,10 +9,10 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/label" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -20,7 +20,7 @@ import ( ) const ( - tplLabels base.TplName = "repo/issue/labels" + tplLabels templates.TplName = "repo/issue/labels" ) // Labels render issue's labels page diff --git a/routers/web/repo/issue_list.go b/routers/web/repo/issue_list.go index ff98bf8ec8..2c73a24632 100644 --- a/routers/web/repo/issue_list.go +++ b/routers/web/repo/issue_list.go @@ -748,7 +748,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/issue_watch.go b/routers/web/repo/issue_watch.go index 8b033f3b17..a2a4be1758 100644 --- a/routers/web/repo/issue_watch.go +++ b/routers/web/repo/issue_watch.go @@ -8,13 +8,13 @@ import ( "strconv" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( - tplWatching base.TplName = "repo/issue/view_content/watching" + tplWatching templates.TplName = "repo/issue/view_content/watching" ) // IssueWatch sets issue watching diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go index a2c257940e..3a7dc29466 100644 --- a/routers/web/repo/migrate.go +++ b/routers/web/repo/migrate.go @@ -13,13 +13,13 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" @@ -29,7 +29,7 @@ import ( ) const ( - tplMigrate base.TplName = "repo/migrate/migrate" + tplMigrate templates.TplName = "repo/migrate/migrate" ) // Migrate render migration of repository page @@ -67,10 +67,10 @@ func Migrate(ctx *context.Context) { } ctx.Data["ContextUser"] = ctxUser - ctx.HTML(http.StatusOK, base.TplName("repo/migrate/"+serviceType.Name())) + ctx.HTML(http.StatusOK, templates.TplName("repo/migrate/"+serviceType.Name())) } -func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl base.TplName, form *forms.MigrateRepoForm) { +func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl templates.TplName, form *forms.MigrateRepoForm) { if setting.Repository.DisableMigrations { ctx.Error(http.StatusForbidden, "MigrateError: the site administrator has disabled migrations") return @@ -122,7 +122,7 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, } } -func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl base.TplName, form *forms.MigrateRepoForm) { +func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl templates.TplName, form *forms.MigrateRepoForm) { if git.IsErrInvalidCloneAddr(err) { addrErr := err.(*git.ErrInvalidCloneAddr) switch { @@ -169,7 +169,7 @@ func MigratePost(ctx *context.Context) { } ctx.Data["ContextUser"] = ctxUser - tpl := base.TplName("repo/migrate/" + form.Service.Name()) + tpl := templates.TplName("repo/migrate/" + form.Service.Name()) if ctx.HasError() { ctx.HTML(http.StatusOK, tpl) diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index 33c15e7767..392d87167a 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -11,10 +11,10 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/renderhelper" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" @@ -25,9 +25,9 @@ import ( ) const ( - tplMilestone base.TplName = "repo/issue/milestones" - tplMilestoneNew base.TplName = "repo/issue/milestone_new" - tplMilestoneIssues base.TplName = "repo/issue/milestone_issues" + tplMilestone templates.TplName = "repo/issue/milestones" + tplMilestoneNew templates.TplName = "repo/issue/milestone_new" + tplMilestoneIssues templates.TplName = "repo/issue/milestone_issues" ) // Milestones render milestones page @@ -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/packages.go b/routers/web/repo/packages.go index 57e578da37..c8d3719bc0 100644 --- a/routers/web/repo/packages.go +++ b/routers/web/repo/packages.go @@ -9,14 +9,14 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( - tplPackagesList base.TplName = "repo/packages" + tplPackagesList templates.TplName = "repo/packages" ) // Packages displays a list of all packages in the repository diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go index 5906ec6f3d..1807cf31a1 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -8,8 +8,8 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" @@ -18,7 +18,7 @@ import ( ) const ( - tplPatchFile base.TplName = "repo/editor/patch" + tplPatchFile templates.TplName = "repo/editor/patch" ) // NewDiffPatch render create patch page diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 3be9578670..4313b6c403 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -16,11 +16,11 @@ import ( "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/shared/issue" @@ -31,9 +31,9 @@ import ( ) const ( - tplProjects base.TplName = "repo/projects/list" - tplProjectsNew base.TplName = "repo/projects/new" - tplProjectsView base.TplName = "repo/projects/view" + tplProjects templates.TplName = "repo/projects/list" + tplProjectsNew templates.TplName = "repo/projects/new" + tplProjectsView templates.TplName = "repo/projects/view" ) // MustEnableRepoProjects check if repo projects are enabled in settings @@ -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 7cc7bf58d2..9f3d1c1b7c 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -23,13 +23,13 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" issue_template "code.gitea.io/gitea/modules/issue/template" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" @@ -49,9 +49,9 @@ import ( ) const ( - tplCompareDiff base.TplName = "repo/diff/compare" - tplPullCommits base.TplName = "repo/pulls/commits" - tplPullFiles base.TplName = "repo/pulls/files" + tplCompareDiff templates.TplName = "repo/diff/compare" + tplPullCommits templates.TplName = "repo/pulls/commits" + tplPullFiles templates.TplName = "repo/pulls/files" pullRequestTemplateKey = "PullRequestTemplate" ) @@ -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/pull_review.go b/routers/web/repo/pull_review.go index aa2e689e42..3e9e615b15 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -12,10 +12,10 @@ import ( "code.gitea.io/gitea/models/organization" pull_model "code.gitea.io/gitea/models/pull" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/context/upload" @@ -26,10 +26,10 @@ import ( ) const ( - tplDiffConversation base.TplName = "repo/diff/conversation" - tplConversationOutdated base.TplName = "repo/diff/conversation_outdated" - tplTimelineConversation base.TplName = "repo/issue/view_content/conversation" - tplNewComment base.TplName = "repo/diff/new_comment" + tplDiffConversation templates.TplName = "repo/diff/conversation" + tplConversationOutdated templates.TplName = "repo/diff/conversation_outdated" + tplTimelineConversation templates.TplName = "repo/issue/view_content/conversation" + tplNewComment templates.TplName = "repo/diff/new_comment" ) // RenderNewCodeCommentForm will render the form for creating a new review comment diff --git a/routers/web/repo/recent_commits.go b/routers/web/repo/recent_commits.go index c158fb30b6..dc72081900 100644 --- a/routers/web/repo/recent_commits.go +++ b/routers/web/repo/recent_commits.go @@ -7,13 +7,13 @@ import ( "errors" "net/http" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" contributors_service "code.gitea.io/gitea/services/repository" ) const ( - tplRecentCommits base.TplName = "repo/activity" + tplRecentCommits templates.TplName = "repo/activity" ) // RecentCommits renders the page to show recent commit frequency on repository diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 5c5191fc3b..b8176cb70b 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -16,12 +16,12 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/feed" @@ -33,9 +33,9 @@ import ( ) const ( - tplReleasesList base.TplName = "repo/release/list" - tplReleaseNew base.TplName = "repo/release/new" - tplTagsList base.TplName = "repo/tag/list" + tplReleasesList templates.TplName = "repo/release/list" + tplReleaseNew templates.TplName = "repo/release/new" + tplTagsList templates.TplName = "repo/tag/list" ) // calReleaseNumCommitsBehind calculates given release has how many commits behind release target. diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 4b017f61c4..85a745acbd 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -18,7 +18,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" @@ -27,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" @@ -38,8 +38,8 @@ import ( ) const ( - tplCreate base.TplName = "repo/create" - tplAlertDetails base.TplName = "base/alert_details" + tplCreate templates.TplName = "repo/create" + tplAlertDetails templates.TplName = "base/alert_details" ) // MustBeNotEmpty render when a repo is a empty git dir @@ -185,7 +185,7 @@ func Create(ctx *context.Context) { ctx.HTML(http.StatusOK, tplCreate) } -func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl base.TplName, form any) { +func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl templates.TplName, form any) { switch { case repo_model.IsErrReachLimitOfRepo(err): maxCreationLimit := owner.MaxCreationLimit() @@ -304,14 +304,14 @@ func CreatePost(ctx *context.Context) { } const ( - tplWatchUnwatch base.TplName = "repo/watch_unwatch" - tplStarUnstar base.TplName = "repo/star_unstar" + tplWatchUnwatch templates.TplName = "repo/watch_unwatch" + tplStarUnstar templates.TplName = "repo/star_unstar" ) // 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": @@ -339,12 +339,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": @@ -354,17 +354,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/search.go b/routers/web/repo/search.go index 920a865555..a037a34833 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -8,14 +8,14 @@ import ( "strings" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) -const tplSearch base.TplName = "repo/search" +const tplSearch templates.TplName = "repo/search" func indexSettingToGitGrepPathspecList() (list []string) { for _, expr := range setting.Indexer.IncludePatterns { 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/lfs.go b/routers/web/repo/setting/lfs.go index fad6359668..2df483fa34 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -15,7 +15,6 @@ import ( "strings" git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" @@ -25,17 +24,18 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsLFS base.TplName = "repo/settings/lfs" - tplSettingsLFSLocks base.TplName = "repo/settings/lfs_locks" - tplSettingsLFSFile base.TplName = "repo/settings/lfs_file" - tplSettingsLFSFileFind base.TplName = "repo/settings/lfs_file_find" - tplSettingsLFSPointers base.TplName = "repo/settings/lfs_pointers" + tplSettingsLFS templates.TplName = "repo/settings/lfs" + tplSettingsLFSLocks templates.TplName = "repo/settings/lfs_locks" + tplSettingsLFSFile templates.TplName = "repo/settings/lfs_file" + tplSettingsLFSFileFind templates.TplName = "repo/settings/lfs_file_find" + tplSettingsLFSPointers templates.TplName = "repo/settings/lfs_pointers" ) // LFSFiles shows a repository's LFS files diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index f651d8f318..022a24a9ad 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/repo" "code.gitea.io/gitea/services/context" @@ -26,7 +27,7 @@ import ( ) const ( - tplProtectedBranch base.TplName = "repo/settings/protected_branch" + tplProtectedBranch templates.TplName = "repo/settings/protected_branch" ) // ProtectedBranchRules render the page to protect the repository diff --git a/routers/web/repo/setting/protected_tag.go b/routers/web/repo/setting/protected_tag.go index fcfa77aa8c..1730ad4a8b 100644 --- a/routers/web/repo/setting/protected_tag.go +++ b/routers/web/repo/setting/protected_tag.go @@ -14,13 +14,14 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) const ( - tplTags base.TplName = "repo/settings/tags" + tplTags templates.TplName = "repo/settings/tags" ) // Tags render the page to protect tags @@ -169,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 3141d8f42a..94f2ae7a0c 100644 --- a/routers/web/repo/setting/runners.go +++ b/routers/web/repo/setting/runners.go @@ -10,8 +10,8 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" actions_shared "code.gitea.io/gitea/routers/web/shared/actions" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" @@ -19,14 +19,14 @@ import ( const ( // TODO: Separate secrets from runners when layout is ready - tplRepoRunners base.TplName = "repo/settings/actions" - tplOrgRunners base.TplName = "org/settings/actions" - tplAdminRunners base.TplName = "admin/actions" - tplUserRunners base.TplName = "user/settings/actions" - tplRepoRunnerEdit base.TplName = "repo/settings/runner_edit" - tplOrgRunnerEdit base.TplName = "org/settings/runners_edit" - tplAdminRunnerEdit base.TplName = "admin/runners/edit" - tplUserRunnerEdit base.TplName = "user/settings/runner_edit" + tplRepoRunners templates.TplName = "repo/settings/actions" + tplOrgRunners templates.TplName = "org/settings/actions" + tplAdminRunners templates.TplName = "admin/actions" + tplUserRunners templates.TplName = "user/settings/actions" + tplRepoRunnerEdit templates.TplName = "repo/settings/runner_edit" + tplOrgRunnerEdit templates.TplName = "org/settings/runners_edit" + tplAdminRunnerEdit templates.TplName = "admin/runners/edit" + tplUserRunnerEdit templates.TplName = "user/settings/runner_edit" ) type runnersCtx struct { @@ -36,8 +36,8 @@ type runnersCtx struct { IsOrg bool IsAdmin bool IsUser bool - RunnersTemplate base.TplName - RunnerEditTemplate base.TplName + RunnersTemplate templates.TplName + RunnerEditTemplate templates.TplName RedirectLink string } @@ -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/secrets.go b/routers/web/repo/setting/secrets.go index df11729344..46cb875f9b 100644 --- a/routers/web/repo/setting/secrets.go +++ b/routers/web/repo/setting/secrets.go @@ -8,8 +8,8 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared "code.gitea.io/gitea/routers/web/shared/secrets" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" @@ -17,9 +17,9 @@ import ( const ( // TODO: Separate secrets from runners when layout is ready - tplRepoSecrets base.TplName = "repo/settings/actions" - tplOrgSecrets base.TplName = "org/settings/actions" - tplUserSecrets base.TplName = "user/settings/actions" + tplRepoSecrets templates.TplName = "repo/settings/actions" + tplOrgSecrets templates.TplName = "org/settings/actions" + tplUserSecrets templates.TplName = "user/settings/actions" ) type secretsCtx struct { @@ -28,7 +28,7 @@ type secretsCtx struct { IsRepo bool IsOrg bool IsUser bool - SecretsTemplate base.TplName + SecretsTemplate templates.TplName RedirectLink string } diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 1c7f9441f8..7399c681e2 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -18,7 +18,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/indexer/code" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" @@ -27,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" @@ -41,12 +41,12 @@ import ( ) const ( - tplSettingsOptions base.TplName = "repo/settings/options" - tplCollaboration base.TplName = "repo/settings/collaboration" - tplBranches base.TplName = "repo/settings/branches" - tplGithooks base.TplName = "repo/settings/githooks" - tplGithookEdit base.TplName = "repo/settings/githook_edit" - tplDeployKeys base.TplName = "repo/settings/deploy_keys" + tplSettingsOptions templates.TplName = "repo/settings/options" + tplCollaboration templates.TplName = "repo/settings/collaboration" + tplBranches templates.TplName = "repo/settings/branches" + tplGithooks templates.TplName = "repo/settings/githooks" + tplGithookEdit templates.TplName = "repo/settings/githook_edit" + tplDeployKeys templates.TplName = "repo/settings/deploy_keys" ) // SettingsCtxData is a middleware that sets all the general context data for the diff --git a/routers/web/repo/setting/variables.go b/routers/web/repo/setting/variables.go index cc2e619f66..9b5453f043 100644 --- a/routers/web/repo/setting/variables.go +++ b/routers/web/repo/setting/variables.go @@ -7,18 +7,18 @@ import ( "errors" "net/http" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared "code.gitea.io/gitea/routers/web/shared/actions" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" ) const ( - tplRepoVariables base.TplName = "repo/settings/actions" - tplOrgVariables base.TplName = "org/settings/actions" - tplUserVariables base.TplName = "user/settings/actions" - tplAdminVariables base.TplName = "admin/actions" + tplRepoVariables templates.TplName = "repo/settings/actions" + tplOrgVariables templates.TplName = "org/settings/actions" + tplUserVariables templates.TplName = "user/settings/actions" + tplAdminVariables templates.TplName = "admin/actions" ) type variablesCtx struct { @@ -28,7 +28,7 @@ type variablesCtx struct { IsOrg bool IsUser bool IsGlobal bool - VariablesTemplate base.TplName + VariablesTemplate templates.TplName RedirectLink string } diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go index 8d548c4e3d..1b0ba83af4 100644 --- a/routers/web/repo/setting/webhook.go +++ b/routers/web/repo/setting/webhook.go @@ -17,11 +17,11 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" webhook_module "code.gitea.io/gitea/modules/webhook" @@ -32,11 +32,11 @@ import ( ) const ( - tplHooks base.TplName = "repo/settings/webhook/base" - tplHookNew base.TplName = "repo/settings/webhook/new" - tplOrgHookNew base.TplName = "org/settings/hook_new" - tplUserHookNew base.TplName = "user/settings/hook_new" - tplAdminHookNew base.TplName = "admin/hook_new" + tplHooks templates.TplName = "repo/settings/webhook/base" + tplHookNew templates.TplName = "repo/settings/webhook/new" + tplOrgHookNew templates.TplName = "org/settings/hook_new" + tplUserHookNew templates.TplName = "user/settings/hook_new" + tplAdminHookNew templates.TplName = "admin/hook_new" ) // Webhooks render web hooks list page @@ -64,7 +64,7 @@ type ownerRepoCtx struct { IsSystemWebhook bool Link string LinkNew string - NewTemplate base.TplName + NewTemplate templates.TplName } // getOwnerRepoCtx determines whether this is a repo, owner, or admin (both default and system) context. @@ -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.go b/routers/web/repo/view.go index e43841acd3..14fc9038f3 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -35,6 +35,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" @@ -45,12 +46,12 @@ import ( ) const ( - tplRepoEMPTY base.TplName = "repo/empty" - tplRepoHome base.TplName = "repo/home" - tplRepoViewList base.TplName = "repo/view_list" - tplWatchers base.TplName = "repo/watchers" - tplForks base.TplName = "repo/forks" - tplMigrating base.TplName = "repo/migrate/migrating" + tplRepoEMPTY templates.TplName = "repo/empty" + tplRepoHome templates.TplName = "repo/home" + tplRepoViewList templates.TplName = "repo/view_list" + tplWatchers templates.TplName = "repo/watchers" + tplForks templates.TplName = "repo/forks" + tplMigrating templates.TplName = "repo/migrate/migrating" ) type fileInfo struct { @@ -314,7 +315,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri } // RenderUserCards render a page show users according the input template -func RenderUserCards(ctx *context.Context, total int, getter func(opts db.ListOptions) ([]*user_model.User, error), tpl base.TplName) { +func RenderUserCards(ctx *context.Context, total int, getter func(opts db.ListOptions) ([]*user_model.User, error), tpl templates.TplName) { page := ctx.FormInt("page") if page <= 0 { page = 1 diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index b318c4a621..70ba07f9a8 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/repo/wiki.go b/routers/web/repo/wiki.go index fec72c9253..3fca7cebea 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -37,11 +38,11 @@ import ( ) const ( - tplWikiStart base.TplName = "repo/wiki/start" - tplWikiView base.TplName = "repo/wiki/view" - tplWikiRevision base.TplName = "repo/wiki/revision" - tplWikiNew base.TplName = "repo/wiki/new" - tplWikiPages base.TplName = "repo/wiki/pages" + tplWikiStart templates.TplName = "repo/wiki/start" + tplWikiView templates.TplName = "repo/wiki/view" + tplWikiRevision templates.TplName = "repo/wiki/revision" + tplWikiNew templates.TplName = "repo/wiki/new" + tplWikiPages templates.TplName = "repo/wiki/pages" ) // MustEnableWiki check if wiki is enabled, if external then redirect diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index f38933226b..6d77bdd2fa 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -136,9 +136,8 @@ func RunnerResetRegistrationToken(ctx *context.Context, ownerID, repoID int64, r ctx.ServerError("ResetRunnerRegistrationToken", err) return } - ctx.Flash.Success(ctx.Tr("actions.runners.reset_registration_token_success")) - ctx.Redirect(redirectTo) + ctx.JSONRedirect(redirectTo) } // RunnerDeletePost response for deleting a runner 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/packages/packages.go b/routers/web/shared/packages/packages.go index 1d3cabf71b..a1bcb09850 100644 --- a/routers/web/shared/packages/packages.go +++ b/routers/web/shared/packages/packages.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -54,11 +54,11 @@ func setRuleEditContext(ctx *context.Context, pcr *packages_model.PackageCleanup ctx.Data["AvailableTypes"] = packages_model.TypeList } -func PerformRuleAddPost(ctx *context.Context, owner *user_model.User, redirectURL string, template base.TplName) { +func PerformRuleAddPost(ctx *context.Context, owner *user_model.User, redirectURL string, template templates.TplName) { performRuleEditPost(ctx, owner, nil, redirectURL, template) } -func PerformRuleEditPost(ctx *context.Context, owner *user_model.User, redirectURL string, template base.TplName) { +func PerformRuleEditPost(ctx *context.Context, owner *user_model.User, redirectURL string, template templates.TplName) { pcr := getCleanupRuleByContext(ctx, owner) if pcr == nil { return @@ -79,7 +79,7 @@ func PerformRuleEditPost(ctx *context.Context, owner *user_model.User, redirectU } } -func performRuleEditPost(ctx *context.Context, owner *user_model.User, pcr *packages_model.PackageCleanupRule, redirectURL string, template base.TplName) { +func performRuleEditPost(ctx *context.Context, owner *user_model.User, pcr *packages_model.PackageCleanupRule, redirectURL string, template templates.TplName) { isEditRule := pcr != nil if pcr == nil { 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/code.go b/routers/web/user/code.go index 785c37b124..f805f2b028 100644 --- a/routers/web/user/code.go +++ b/routers/web/user/code.go @@ -8,15 +8,15 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/base" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" ) const ( - tplUserCode base.TplName = "user/code" + tplUserCode templates.TplName = "user/code" ) // CodeSearch render user/organization code search page diff --git a/routers/web/user/home.go b/routers/web/user/home.go index befa33b0c0..b5d3a7294b 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -31,6 +31,7 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/web/feed" "code.gitea.io/gitea/routers/web/shared/issue" @@ -46,16 +47,16 @@ import ( ) const ( - tplDashboard base.TplName = "user/dashboard/dashboard" - tplIssues base.TplName = "user/dashboard/issues" - tplMilestones base.TplName = "user/dashboard/milestones" - tplProfile base.TplName = "user/profile" + tplDashboard templates.TplName = "user/dashboard/dashboard" + tplIssues templates.TplName = "user/dashboard/issues" + tplMilestones templates.TplName = "user/dashboard/milestones" + tplProfile templates.TplName = "user/profile" ) // 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/notification.go b/routers/web/user/notification.go index 414cb0be49..732fac2595 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" issue_service "code.gitea.io/gitea/services/issue" @@ -29,9 +30,9 @@ import ( ) const ( - tplNotification base.TplName = "user/notification/notification" - tplNotificationDiv base.TplName = "user/notification/notification_div" - tplNotificationSubscriptions base.TplName = "user/notification/notification_subscriptions" + tplNotification templates.TplName = "user/notification/notification" + tplNotificationDiv templates.TplName = "user/notification/notification_div" + tplNotificationSubscriptions templates.TplName = "user/notification/notification_subscriptions" ) // GetNotificationCount is the middleware that sets the notification count in the context diff --git a/routers/web/user/package.go b/routers/web/user/package.go index c6f85ac734..8d78da7c5a 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -14,7 +14,6 @@ import ( "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" @@ -24,6 +23,7 @@ import ( debian_module "code.gitea.io/gitea/modules/packages/debian" rpm_module "code.gitea.io/gitea/modules/packages/rpm" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" packages_helper "code.gitea.io/gitea/routers/api/packages/helper" @@ -34,10 +34,10 @@ import ( ) const ( - tplPackagesList base.TplName = "user/overview/packages" - tplPackagesView base.TplName = "package/view" - tplPackageVersionList base.TplName = "user/overview/package_versions" - tplPackagesSettings base.TplName = "package/settings" + tplPackagesList templates.TplName = "user/overview/packages" + tplPackagesView templates.TplName = "package/view" + tplPackageVersionList templates.TplName = "user/overview/package_versions" + tplPackagesSettings templates.TplName = "package/settings" ) // ListPackages displays a list of all packages of the context user @@ -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/user/profile.go b/routers/web/user/profile.go index c41030a5e2..44824de752 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -15,12 +15,12 @@ import ( "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/web/feed" "code.gitea.io/gitea/routers/web/org" @@ -30,8 +30,8 @@ import ( ) const ( - tplProfileBigAvatar base.TplName = "shared/user/profile_big_avatar" - tplFollowUnfollow base.TplName = "org/follow_unfollow" + tplProfileBigAvatar templates.TplName = "shared/user/profile_big_avatar" + tplFollowUnfollow templates.TplName = "org/follow_unfollow" ) // OwnerProfile render profile page for a user or a organization (aka, repo owner) diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 00fe02c886..3acc3c7a54 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -15,10 +15,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/auth" @@ -31,7 +31,7 @@ import ( ) const ( - tplSettingsAccount base.TplName = "user/settings/account" + tplSettingsAccount templates.TplName = "user/settings/account" ) // Account renders change user's password, user's email and user suicide page diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go index 356c2ea5de..cf71d01dc1 100644 --- a/routers/web/user/setting/applications.go +++ b/routers/web/user/setting/applications.go @@ -10,15 +10,15 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) const ( - tplSettingsApplications base.TplName = "user/settings/applications" + tplSettingsApplications templates.TplName = "user/settings/applications" ) // Applications render manage access token page diff --git a/routers/web/user/setting/block.go b/routers/web/user/setting/block.go index d419fb321b..3756495fd2 100644 --- a/routers/web/user/setting/block.go +++ b/routers/web/user/setting/block.go @@ -7,14 +7,14 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsBlockedUsers base.TplName = "user/settings/blocked_users" + tplSettingsBlockedUsers templates.TplName = "user/settings/blocked_users" ) func BlockedUsers(ctx *context.Context) { diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go index c492715fb5..127aed9845 100644 --- a/routers/web/user/setting/keys.go +++ b/routers/web/user/setting/keys.go @@ -11,8 +11,8 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/context" @@ -20,7 +20,7 @@ import ( ) const ( - tplSettingsKeys base.TplName = "user/settings/keys" + tplSettingsKeys templates.TplName = "user/settings/keys" ) // Keys render user's SSH/GPG public keys page diff --git a/routers/web/user/setting/oauth2.go b/routers/web/user/setting/oauth2.go index 1f485e06c8..d50728c24e 100644 --- a/routers/web/user/setting/oauth2.go +++ b/routers/web/user/setting/oauth2.go @@ -4,13 +4,13 @@ package setting import ( - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsOAuthApplicationEdit base.TplName = "user/settings/applications_oauth2_edit" + tplSettingsOAuthApplicationEdit templates.TplName = "user/settings/applications_oauth2_edit" ) func newOAuth2CommonHandlers(userID int64) *OAuth2CommonHandlers { diff --git a/routers/web/user/setting/oauth2_common.go b/routers/web/user/setting/oauth2_common.go index e93e9e1954..783deca710 100644 --- a/routers/web/user/setting/oauth2_common.go +++ b/routers/web/user/setting/oauth2_common.go @@ -8,7 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" @@ -17,10 +17,10 @@ import ( ) type OAuth2CommonHandlers struct { - OwnerID int64 // 0 for instance-wide, otherwise OrgID or UserID - BasePathList string // the base URL for the application list page, eg: "/user/setting/applications" - BasePathEditPrefix string // the base URL for the application edit page, will be appended with app id, eg: "/user/setting/applications/oauth2" - TplAppEdit base.TplName // the template for the application edit page + OwnerID int64 // 0 for instance-wide, otherwise OrgID or UserID + BasePathList string // the base URL for the application list page, eg: "/user/setting/applications" + BasePathEditPrefix string // the base URL for the application edit page, will be appended with app id, eg: "/user/setting/applications/oauth2" + TplAppEdit templates.TplName // the template for the application edit page } func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) { diff --git a/routers/web/user/setting/packages.go b/routers/web/user/setting/packages.go index 50521c11c0..9692cd9db0 100644 --- a/routers/web/user/setting/packages.go +++ b/routers/web/user/setting/packages.go @@ -8,18 +8,18 @@ import ( "strings" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" chef_module "code.gitea.io/gitea/modules/packages/chef" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" shared "code.gitea.io/gitea/routers/web/shared/packages" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsPackages base.TplName = "user/settings/packages" - tplSettingsPackagesRuleEdit base.TplName = "user/settings/packages_cleanup_rules_edit" - tplSettingsPackagesRulePreview base.TplName = "user/settings/packages_cleanup_rules_preview" + tplSettingsPackages templates.TplName = "user/settings/packages" + tplSettingsPackagesRuleEdit templates.TplName = "user/settings/packages_cleanup_rules_edit" + tplSettingsPackagesRulePreview templates.TplName = "user/settings/packages_cleanup_rules_preview" ) func Packages(ctx *context.Context) { diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 3b051c9b5f..4b3c214096 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -19,10 +19,10 @@ import ( "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" @@ -35,10 +35,10 @@ import ( ) const ( - tplSettingsProfile base.TplName = "user/settings/profile" - tplSettingsAppearance base.TplName = "user/settings/appearance" - tplSettingsOrganization base.TplName = "user/settings/organization" - tplSettingsRepositories base.TplName = "user/settings/repos" + tplSettingsProfile templates.TplName = "user/settings/profile" + tplSettingsAppearance templates.TplName = "user/settings/appearance" + tplSettingsOrganization templates.TplName = "user/settings/organization" + tplSettingsRepositories templates.TplName = "user/settings/repos" ) // Profile render user's profile page diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go index b44cb4dd49..38d1910e2d 100644 --- a/routers/web/user/setting/security/security.go +++ b/routers/web/user/setting/security/security.go @@ -11,16 +11,16 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/auth/source/oauth2" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsSecurity base.TplName = "user/settings/security/security" - tplSettingsTwofaEnroll base.TplName = "user/settings/security/twofa_enroll" + tplSettingsSecurity templates.TplName = "user/settings/security/security" + tplSettingsTwofaEnroll templates.TplName = "user/settings/security/twofa_enroll" ) // Security render change user's password page and 2FA diff --git a/routers/web/user/setting/webhooks.go b/routers/web/user/setting/webhooks.go index 3732ca27c0..ca7c7ec1ac 100644 --- a/routers/web/user/setting/webhooks.go +++ b/routers/web/user/setting/webhooks.go @@ -9,13 +9,13 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/services/context" ) const ( - tplSettingsHooks base.TplName = "user/settings/hooks" + tplSettingsHooks templates.TplName = "user/settings/hooks" ) // Webhooks render webhook list page diff --git a/routers/web/web.go b/routers/web/web.go index aa37d4dc10..4f2a8b72c0 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -4,7 +4,6 @@ package web import ( - gocontext "context" "net/http" "strings" @@ -463,7 +462,7 @@ func registerRoutes(m *web.Router) { m.Combo("/{runnerid}").Get(repo_setting.RunnersEdit). Post(web.Bind(forms.EditRunnerForm{}), repo_setting.RunnersEditPost) m.Post("/{runnerid}/delete", repo_setting.RunnerDeletePost) - m.Get("/reset_registration_token", repo_setting.ResetRunnerRegistrationToken) + m.Post("/reset_registration_token", repo_setting.ResetRunnerRegistrationToken) }) } @@ -1521,24 +1520,23 @@ func registerRoutes(m *web.Router) { m.Group("/blob_excerpt", func() { m.Get("/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) - }, func(ctx *context.Context) gocontext.CancelFunc { + }, 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 nil + return } if ctx.Written() { - return nil + return } - cancel := context.RepoRef()(ctx) + context.RepoRef()(ctx) if ctx.Written() { - return cancel + return } repo.MustBeNotEmpty(ctx) - return cancel }) m.Group("/media", func() { diff --git a/services/actions/init.go b/services/actions/init.go index 0f49cb6297..7136da05ed 100644 --- a/services/actions/init.go +++ b/services/actions/init.go @@ -4,23 +4,68 @@ package actions import ( + "context" + "errors" + "fmt" + "os" + "strings" + + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" notify_service "code.gitea.io/gitea/services/notify" ) -func Init() { +func initGlobalRunnerToken(ctx context.Context) error { + // use the same env name as the runner, for consistency + token := os.Getenv("GITEA_RUNNER_REGISTRATION_TOKEN") + tokenFile := os.Getenv("GITEA_RUNNER_REGISTRATION_TOKEN_FILE") + if token != "" && tokenFile != "" { + return errors.New("both GITEA_RUNNER_REGISTRATION_TOKEN and GITEA_RUNNER_REGISTRATION_TOKEN_FILE are set, only one can be used") + } + if tokenFile != "" { + file, err := os.ReadFile(tokenFile) + if err != nil { + return fmt.Errorf("unable to read GITEA_RUNNER_REGISTRATION_TOKEN_FILE: %w", err) + } + token = strings.TrimSpace(string(file)) + } + if token == "" { + return nil + } + + if len(token) < 32 { + return errors.New("GITEA_RUNNER_REGISTRATION_TOKEN must be at least 32 random characters") + } + + existing, err := actions_model.GetRunnerToken(ctx, token) + if err != nil && !errors.Is(err, util.ErrNotExist) { + return fmt.Errorf("unable to check existing token: %w", err) + } + if existing != nil { + if !existing.IsActive { + log.Warn("The token defined by GITEA_RUNNER_REGISTRATION_TOKEN is already invalidated, please use the latest one from web UI") + } + return nil + } + _, err = actions_model.NewRunnerTokenWithValue(ctx, 0, 0, token) + return err +} + +func Init(ctx context.Context) error { if !setting.Actions.Enabled { - return + return nil } jobEmitterQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "actions_ready_job", jobEmitterQueueHandler) if jobEmitterQueue == nil { - log.Fatal("Unable to create actions_ready_job queue") + return errors.New("unable to create actions_ready_job queue") } go graceful.GetManager().RunWithCancel(jobEmitterQueue) notify_service.RegisterNotifier(NewNotifier()) + return initGlobalRunnerToken(ctx) } diff --git a/services/actions/init_test.go b/services/actions/init_test.go new file mode 100644 index 0000000000..59c321ccd7 --- /dev/null +++ b/services/actions/init_test.go @@ -0,0 +1,80 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "os" + "testing" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m, &unittest.TestOptions{ + FixtureFiles: []string{"action_runner_token.yml"}, + }) + os.Exit(m.Run()) +} + +func TestInitToken(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + t.Run("NoToken", func(t *testing.T) { + _, _ = db.Exec(db.DefaultContext, "DELETE FROM action_runner_token") + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN", "") + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN_FILE", "") + err := initGlobalRunnerToken(db.DefaultContext) + require.NoError(t, err) + notEmpty, err := db.IsTableNotEmpty(&actions_model.ActionRunnerToken{}) + require.NoError(t, err) + assert.False(t, notEmpty) + }) + + t.Run("EnvToken", func(t *testing.T) { + tokenValue, _ := util.CryptoRandomString(32) + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN", tokenValue) + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN_FILE", "") + err := initGlobalRunnerToken(db.DefaultContext) + require.NoError(t, err) + token := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunnerToken{Token: tokenValue}) + assert.True(t, token.IsActive) + + // init with the same token again, should not create a new token + err = initGlobalRunnerToken(db.DefaultContext) + require.NoError(t, err) + token2 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunnerToken{Token: tokenValue}) + assert.Equal(t, token.ID, token2.ID) + assert.True(t, token.IsActive) + }) + + t.Run("EnvFileToken", func(t *testing.T) { + tokenValue, _ := util.CryptoRandomString(32) + f := t.TempDir() + "/token" + _ = os.WriteFile(f, []byte(tokenValue), 0o644) + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN", "") + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN_FILE", f) + err := initGlobalRunnerToken(db.DefaultContext) + require.NoError(t, err) + token := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunnerToken{Token: tokenValue}) + assert.True(t, token.IsActive) + + // if the env token is invalidated by another new token, then it shouldn't be active anymore + _, err = actions_model.NewRunnerToken(db.DefaultContext, 0, 0) + require.NoError(t, err) + token = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunnerToken{Token: tokenValue}) + assert.False(t, token.IsActive) + }) + + t.Run("InvalidToken", func(t *testing.T) { + t.Setenv("GITEA_RUNNER_REGISTRATION_TOKEN", "abc") + err := initGlobalRunnerToken(db.DefaultContext) + assert.ErrorContains(t, err, "must be at least") + }) +} diff --git a/services/auth/interface.go b/services/auth/interface.go index ece28af12d..275b4dd56c 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -8,12 +8,11 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/session" - "code.gitea.io/gitea/modules/web/middleware" ) -// DataStore represents a data store -type DataStore middleware.ContextDataStore +type DataStore = reqctx.ContextDataProvider // SessionStore represents a session store type SessionStore session.Store diff --git a/services/auth/oauth2_test.go b/services/auth/oauth2_test.go index b706847e8e..0d9e793cf3 100644 --- a/services/auth/oauth2_test.go +++ b/services/auth/oauth2_test.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/services/actions" "github.com/stretchr/testify/assert" @@ -23,7 +23,7 @@ func TestUserIDFromToken(t *testing.T) { token, err := actions.CreateAuthorizationToken(RunningTaskID, 1, 2) assert.NoError(t, err) - ds := make(middleware.ContextData) + ds := make(reqctx.ContextData) o := OAuth2{} uid := o.userIDFromToken(context.Background(), token, ds) diff --git a/services/auth/sspi.go b/services/auth/sspi.go index 7f8a03a4c6..8ac83dcb04 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -13,10 +13,10 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/services/auth/source/sspi" gitea_context "code.gitea.io/gitea/services/context" @@ -25,7 +25,7 @@ import ( ) const ( - tplSignIn base.TplName = "user/auth/signin" + tplSignIn templates.TplName = "user/auth/signin" ) type SSPIAuth interface { diff --git a/services/context/api.go b/services/context/api.go index b45e80a329..7b604c5ea1 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -5,7 +5,6 @@ package context import ( - "context" "fmt" "net/http" "net/url" @@ -212,17 +211,15 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) { func APIContexter() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - base, baseCleanUp := NewBaseContext(w, req) + base := NewBaseContext(w, req) ctx := &APIContext{ Base: base, Cache: cache.GetCache(), Repo: &Repository{PullRequest: &PullRequest{}}, Org: &APIOrganization{}, } - defer baseCleanUp() - ctx.Base.AppendContextValue(apiContextKey, ctx) - ctx.Base.AppendContextValueFunc(gitrepo.RepositoryContextKey, func() any { return ctx.Repo.GitRepo }) + ctx.SetContextValue(apiContextKey, ctx) // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid. if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") { @@ -267,31 +264,22 @@ func (ctx *APIContext) NotFound(objs ...any) { // ReferencesGitRepo injects the GitRepo into the Context // you can optional skip the IsEmpty check -func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context.CancelFunc) { - return func(ctx *APIContext) (cancel context.CancelFunc) { +func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) { + return func(ctx *APIContext) { // Empty repository does not have reference information. if ctx.Repo.Repository.IsEmpty && !(len(allowEmpty) != 0 && allowEmpty[0]) { - return nil + return } // For API calls. if ctx.Repo.GitRepo == nil { - gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + var err error + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err) - return cancel - } - ctx.Repo.GitRepo = gitRepo - // We opened it, we should close it - return func() { - // If it's been set to nil then assume someone else has closed it. - if ctx.Repo.GitRepo != nil { - _ = ctx.Repo.GitRepo.Close() - } + return } } - - return cancel } } diff --git a/services/context/base.go b/services/context/base.go index d627095584..7a39353e09 100644 --- a/services/context/base.go +++ b/services/context/base.go @@ -9,81 +9,36 @@ import ( "html/template" "io" "net/http" - "net/url" - "strconv" "strings" - "time" "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 contextValuePair struct { - key any - valueFn func() any -} - type BaseContextKeyType struct{} var BaseContextKey BaseContextKeyType type Base struct { - originCtx context.Context - contextValues []contextValuePair + context.Context + reqctx.RequestDataStore Resp ResponseWriter Req *http.Request // Data is prepared by ContextDataStore middleware, this field only refers to the pre-created/prepared ContextData. // Although it's mainly used for MVC templates, sometimes it's also used to pass data between middlewares/handler - Data middleware.ContextData + Data reqctx.ContextData // Locale is mainly for Web context, although the API context also uses it in some cases: message response, form validation Locale translation.Locale } -func (b *Base) Deadline() (deadline time.Time, ok bool) { - return b.originCtx.Deadline() -} - -func (b *Base) Done() <-chan struct{} { - return b.originCtx.Done() -} - -func (b *Base) Err() error { - return b.originCtx.Err() -} - -func (b *Base) Value(key any) any { - for _, pair := range b.contextValues { - if pair.key == key { - return pair.valueFn() - } - } - return b.originCtx.Value(key) -} - -func (b *Base) AppendContextValueFunc(key any, valueFn func() any) any { - b.contextValues = append(b.contextValues, contextValuePair{key, valueFn}) - return b -} - -func (b *Base) AppendContextValue(key, value any) any { - b.contextValues = append(b.contextValues, contextValuePair{key, func() any { return value }}) - return b -} - -func (b *Base) GetData() middleware.ContextData { - return b.Data -} - // AppendAccessControlExposeHeaders append headers by name to "Access-Control-Expose-Headers" header func (b *Base) AppendAccessControlExposeHeaders(names ...string) { val := b.RespHeader().Get("Access-Control-Expose-Headers") @@ -147,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 @@ -295,13 +163,6 @@ func (b *Base) ServeContent(r io.ReadSeeker, opts *ServeHeaderOptions) { http.ServeContent(b.Resp, b.Req, opts.Filename, opts.LastModified, r) } -// Close frees all resources hold by Context -func (b *Base) cleanUp() { - if b.Req != nil && b.Req.MultipartForm != nil { - _ = b.Req.MultipartForm.RemoveAll() // remove the temp files buffered to tmp directory - } -} - func (b *Base) Tr(msg string, args ...any) template.HTML { return b.Locale.Tr(msg, args...) } @@ -310,17 +171,28 @@ func (b *Base) TrN(cnt any, key1, keyN string, args ...any) template.HTML { return b.Locale.TrN(cnt, key1, keyN, args...) } -func NewBaseContext(resp http.ResponseWriter, req *http.Request) (b *Base, closeFunc func()) { - b = &Base{ - originCtx: req.Context(), - Req: req, - Resp: WrapResponseWriter(resp), - Locale: middleware.Locale(resp, req), - Data: middleware.GetContextData(req.Context()), +func NewBaseContext(resp http.ResponseWriter, req *http.Request) *Base { + ds := reqctx.GetRequestDataStore(req.Context()) + b := &Base{ + Context: req.Context(), + RequestDataStore: ds, + Req: req, + Resp: WrapResponseWriter(resp), + Locale: middleware.Locale(resp, req), + Data: ds.GetData(), } b.Req = b.Req.WithContext(b) - b.AppendContextValue(BaseContextKey, b) - b.AppendContextValue(translation.ContextKey, b.Locale) - b.AppendContextValue(httplib.RequestContextKey, b.Req) - return b, b.cleanUp + ds.SetContextValue(BaseContextKey, b) + ds.SetContextValue(translation.ContextKey, b.Locale) + ds.SetContextValue(httplib.RequestContextKey, b.Req) + return b +} + +func NewBaseContextForTest(resp http.ResponseWriter, req *http.Request) *Base { + if !setting.IsInTesting { + panic("This function is only for testing") + } + ctx := reqctx.NewRequestContextForTest(req.Context()) + *req = *req.WithContext(ctx) + return NewBaseContext(resp, req) } 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/base_test.go b/services/context/base_test.go index 823f20e00b..b936b76f58 100644 --- a/services/context/base_test.go +++ b/services/context/base_test.go @@ -14,6 +14,7 @@ import ( ) func TestRedirect(t *testing.T) { + setting.IsInTesting = true req, _ := http.NewRequest("GET", "/", nil) cases := []struct { @@ -28,10 +29,9 @@ func TestRedirect(t *testing.T) { } for _, c := range cases { resp := httptest.NewRecorder() - b, cleanup := NewBaseContext(resp, req) + b := NewBaseContextForTest(resp, req) resp.Header().Add("Set-Cookie", (&http.Cookie{Name: setting.SessionConfig.CookieName, Value: "dummy"}).String()) b.Redirect(c.url) - cleanup() has := resp.Header().Get("Set-Cookie") == "i_like_gitea=dummy" assert.Equal(t, c.keep, has, "url = %q", c.url) } @@ -39,9 +39,8 @@ func TestRedirect(t *testing.T) { req, _ = http.NewRequest("GET", "/", nil) resp := httptest.NewRecorder() req.Header.Add("HX-Request", "true") - b, cleanup := NewBaseContext(resp, req) + b := NewBaseContextForTest(resp, req) b.Redirect("/other") - cleanup() assert.Equal(t, "/other", resp.Header().Get("HX-Redirect")) assert.Equal(t, http.StatusNoContent, resp.Code) } diff --git a/services/context/captcha.go b/services/context/captcha.go index 41afe0e7d2..9272e7a65a 100644 --- a/services/context/captcha.go +++ b/services/context/captcha.go @@ -7,13 +7,13 @@ import ( "fmt" "sync" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/hcaptcha" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/turnstile" "gitea.com/go-chi/captcha" @@ -60,7 +60,7 @@ const ( // VerifyCaptcha verifies Captcha data // No-op if captchas are not enabled -func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) { +func VerifyCaptcha(ctx *Context, tpl templates.TplName, form any) { if !setting.Service.EnableCaptcha { return } diff --git a/services/context/context.go b/services/context/context.go index 812a8c27ee..6715c5663d 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" @@ -32,7 +31,7 @@ import ( // Render represents a template render type Render interface { TemplateLookup(tmpl string, templateCtx context.Context) (templates.TemplateExecutor, error) - HTML(w io.Writer, status int, name string, data any, templateCtx context.Context) error + HTML(w io.Writer, status int, name templates.TplName, data any, templateCtx context.Context) error } // Context represents context of a request. @@ -153,14 +152,9 @@ func Contexter() func(next http.Handler) http.Handler { } return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - base, baseCleanUp := NewBaseContext(resp, req) - defer baseCleanUp() + base := NewBaseContext(resp, req) ctx := NewWebContext(base, rnd, session.GetContextSession(req)) - ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) - if setting.IsProd && !setting.IsInTesting { - ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this - } ctx.Data["CurrentURL"] = setting.AppSubURL + req.URL.RequestURI() ctx.Data["Link"] = ctx.Link @@ -168,9 +162,7 @@ func Contexter() func(next http.Handler) http.Handler { ctx.PageData = map[string]any{} ctx.Data["PageData"] = ctx.PageData - ctx.Base.AppendContextValue(WebContextKey, ctx) - ctx.Base.AppendContextValueFunc(gitrepo.RepositoryContextKey, func() any { return ctx.Repo.GitRepo }) - + ctx.Base.SetContextValue(WebContextKey, ctx) ctx.Csrf = NewCSRFProtector(csrfOpts) // Get the last flash message from cookie diff --git a/services/context/context_response.go b/services/context/context_response.go index c43a649b49..c7044791eb 100644 --- a/services/context/context_response.go +++ b/services/context/context_response.go @@ -17,7 +17,6 @@ import ( "time" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -63,10 +62,10 @@ func (ctx *Context) RedirectToCurrentSite(location ...string) { ctx.Redirect(setting.AppSubURL + "/") } -const tplStatus500 base.TplName = "status/500" +const tplStatus500 templates.TplName = "status/500" // HTML calls Context.HTML and renders the template to HTTP response -func (ctx *Context) HTML(status int, name base.TplName) { +func (ctx *Context) HTML(status int, name templates.TplName) { log.Debug("Template: %s", name) tmplStartTime := time.Now() @@ -77,7 +76,7 @@ func (ctx *Context) HTML(status int, name base.TplName) { return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms" } - err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext) + err := ctx.Render.HTML(ctx.Resp, status, name, ctx.Data, ctx.TemplateContext) if err == nil || errors.Is(err, syscall.EPIPE) { return } @@ -94,7 +93,7 @@ func (ctx *Context) HTML(status int, name base.TplName) { // JSONTemplate renders the template as JSON response // keep in mind that the template is processed in HTML context, so JSON-things should be handled carefully, eg: by JSEscape -func (ctx *Context) JSONTemplate(tmpl base.TplName) { +func (ctx *Context) JSONTemplate(tmpl templates.TplName) { t, err := ctx.Render.TemplateLookup(string(tmpl), nil) if err != nil { ctx.ServerError("unable to find template", err) @@ -107,14 +106,14 @@ func (ctx *Context) JSONTemplate(tmpl base.TplName) { } // RenderToHTML renders the template content to a HTML string -func (ctx *Context) RenderToHTML(name base.TplName, data map[string]any) (template.HTML, error) { +func (ctx *Context) RenderToHTML(name templates.TplName, data any) (template.HTML, error) { var buf strings.Builder - err := ctx.Render.HTML(&buf, 0, string(name), data, ctx.TemplateContext) + err := ctx.Render.HTML(&buf, 0, name, data, ctx.TemplateContext) return template.HTML(buf.String()), err } // RenderWithErr used for page has form validation but need to prompt error to users. -func (ctx *Context) RenderWithErr(msg any, tpl base.TplName, form any) { +func (ctx *Context) RenderWithErr(msg any, tpl templates.TplName, form any) { if form != nil { middleware.AssignForm(form, ctx.Data) } @@ -151,7 +150,7 @@ func (ctx *Context) notFoundInternal(logMsg string, logErr error) { ctx.Data["IsRepo"] = ctx.Repo.Repository != nil ctx.Data["Title"] = "Page Not Found" - ctx.HTML(http.StatusNotFound, base.TplName("status/404")) + ctx.HTML(http.StatusNotFound, templates.TplName("status/404")) } // ServerError displays a 500 (Internal Server Error) page and prints the given error, if any. diff --git a/services/context/context_test.go b/services/context/context_test.go index 984593398d..54044644f0 100644 --- a/services/context/context_test.go +++ b/services/context/context_test.go @@ -26,6 +26,7 @@ func TestRemoveSessionCookieHeader(t *testing.T) { } func TestRedirectToCurrentSite(t *testing.T) { + setting.IsInTesting = true defer test.MockVariableValue(&setting.AppURL, "http://localhost:3000/sub/")() defer test.MockVariableValue(&setting.AppSubURL, "/sub")() cases := []struct { @@ -40,8 +41,7 @@ func TestRedirectToCurrentSite(t *testing.T) { t.Run(c.location, func(t *testing.T) { req := &http.Request{URL: &url.URL{Path: "/"}} resp := httptest.NewRecorder() - base, baseCleanUp := NewBaseContext(resp, req) - defer baseCleanUp() + base := NewBaseContextForTest(resp, req) ctx := NewWebContext(base, nil, nil) ctx.RedirectToCurrentSite(c.location) redirect := test.RedirectURL(resp) 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/package.go b/services/context/package.go index 271b61e99c..e98e01acbb 100644 --- a/services/context/package.go +++ b/services/context/package.go @@ -153,12 +153,10 @@ func PackageContexter() func(next http.Handler) http.Handler { renderer := templates.HTMLRenderer() return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - base, baseCleanUp := NewBaseContext(resp, req) - defer baseCleanUp() - + base := NewBaseContext(resp, req) // it is still needed when rendering 500 page in a package handler ctx := NewWebContext(base, renderer, nil) - ctx.Base.AppendContextValue(WebContextKey, ctx) + ctx.SetContextValue(WebContextKey, ctx) next.ServeHTTP(ctx.Resp, ctx.Req) }) } diff --git a/services/context/private.go b/services/context/private.go index 8b41949f60..51857da8fe 100644 --- a/services/context/private.go +++ b/services/context/private.go @@ -64,11 +64,9 @@ func GetPrivateContext(req *http.Request) *PrivateContext { func PrivateContexter() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - base, baseCleanUp := NewBaseContext(w, req) + base := NewBaseContext(w, req) ctx := &PrivateContext{Base: base} - defer baseCleanUp() - ctx.Base.AppendContextValue(privateContextKey, ctx) - + ctx.SetContextValue(privateContextKey, ctx) next.ServeHTTP(ctx.Resp, ctx.Req) }) } @@ -78,8 +76,15 @@ func PrivateContexter() func(http.Handler) http.Handler { // This function should be used when there is a need for work to continue even if the request has been cancelled. // Primarily this affects hook/post-receive and hook/proc-receive both of which need to continue working even if // the underlying request has timed out from the ssh/http push -func OverrideContext(ctx *PrivateContext) (cancel context.CancelFunc) { - // We now need to override the request context as the base for our work because even if the request is cancelled we have to continue this work - ctx.Override, _, cancel = process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI), process.RequestProcessType, true) - return cancel +func OverrideContext() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + // We now need to override the request context as the base for our work because even if the request is cancelled we have to continue this work + ctx := GetPrivateContext(req) + var finished func() + ctx.Override, _, finished = process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI), process.RequestProcessType, true) + defer finished() + next.ServeHTTP(ctx.Resp, ctx.Req) + }) + } } diff --git a/services/context/repo.go b/services/context/repo.go index e96916ca42..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 { @@ -397,11 +397,13 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { } // RepoAssignment returns a middleware to handle repository assignment -func RepoAssignment(ctx *Context) context.CancelFunc { +func RepoAssignment(ctx *Context) { if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce { // FIXME: it should panic in dev/test modes to have a clear behavior - log.Trace("RepoAssignment was exec already, skipping second call ...") - return nil + if !setting.IsProd || setting.IsInTesting { + panic("RepoAssignment should not be executed twice") + } + return } ctx.Data["repoAssignmentExecuted"] = true @@ -410,8 +412,8 @@ func RepoAssignment(ctx *Context) context.CancelFunc { 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") @@ -429,7 +431,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { // https://github.com/golang/go/issues/19760 if ctx.FormString("go-get") == "1" { EarlyResponseForGoGetMeta(ctx) - return nil + return } if redirectUserID, err := user_model.LookupUserRedirect(ctx, userName); err == nil { @@ -442,7 +444,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { } else { ctx.ServerError("GetUserByName", err) } - return nil + return } } ctx.Repo.Owner = owner @@ -454,7 +456,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { 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( @@ -467,7 +469,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { redirectPath += "?" + ctx.Req.URL.RawQuery } ctx.Redirect(path.Join(setting.AppSubURL, redirectPath)) - return nil + return } // Get repository. @@ -480,7 +482,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { } else if repo_model.IsErrRedirectNotExist(err) { if ctx.FormString("go-get") == "1" { EarlyResponseForGoGetMeta(ctx) - return nil + return } ctx.NotFound("GetRepositoryByName", nil) } else { @@ -489,13 +491,13 @@ func RepoAssignment(ctx *Context) context.CancelFunc { } else { ctx.ServerError("GetRepositoryByName", err) } - return nil + return } repo.Owner = owner repoAssignment(ctx, repo) if ctx.Written() { - return nil + return } ctx.Repo.RepoLink = repo.Link() @@ -520,7 +522,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { }) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) - return nil + return } ctx.Data["NumReleases"], err = db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{ // only show draft releases for users who can write, read-only users shouldn't see draft releases. @@ -529,7 +531,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { }) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) - return nil + return } ctx.Data["Title"] = owner.Name + "/" + repo.Name @@ -546,14 +548,14 @@ func RepoAssignment(ctx *Context) context.CancelFunc { canSignedUserFork, err := repo_module.CanUserForkRepo(ctx, ctx.Doer, ctx.Repo.Repository) if err != nil { ctx.ServerError("CanUserForkRepo", err) - return nil + return } ctx.Data["CanSignedUserFork"] = canSignedUserFork userAndOrgForks, err := repo_model.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository) if err != nil { ctx.ServerError("GetForksByUserAndOrgs", err) - return nil + return } ctx.Data["UserAndOrgForks"] = userAndOrgForks @@ -587,14 +589,14 @@ func RepoAssignment(ctx *Context) context.CancelFunc { if repo.IsFork { RetrieveBaseRepo(ctx, repo) if ctx.Written() { - return nil + return } } if repo.IsGenerated() { RetrieveTemplateRepo(ctx, repo) if ctx.Written() { - return nil + return } } @@ -609,10 +611,18 @@ func RepoAssignment(ctx *Context) context.CancelFunc { if !isHomeOrSettings { ctx.Redirect(ctx.Repo.RepoLink) } - return nil + return } - gitRepo, err := gitrepo.OpenRepository(ctx, repo) + if ctx.Repo.GitRepo != nil { + if !setting.IsProd || setting.IsInTesting { + panic("RepoAssignment: GitRepo should be nil") + } + _ = ctx.Repo.GitRepo.Close() + ctx.Repo.GitRepo = nil + } + + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, repo) if err != nil { if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") { log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err) @@ -622,28 +632,16 @@ func RepoAssignment(ctx *Context) context.CancelFunc { if !isHomeOrSettings { ctx.Redirect(ctx.Repo.RepoLink) } - return nil + return } ctx.ServerError("RepoAssignment Invalid repo "+repo.FullName(), err) - return nil - } - if ctx.Repo.GitRepo != nil { - ctx.Repo.GitRepo.Close() - } - ctx.Repo.GitRepo = gitRepo - - // We opened it, we should close it - cancel := func() { - // If it's been set to nil then assume someone else has closed it. - if ctx.Repo.GitRepo != nil { - ctx.Repo.GitRepo.Close() - } + return } // Stop at this point when the repo is empty. if ctx.Repo.Repository.IsEmpty { ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch - return cancel + return } branchOpts := git_model.FindBranchOptions{ @@ -654,7 +652,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { branchesTotal, err := db.Count[git_model.Branch](ctx, branchOpts) if err != nil { ctx.ServerError("CountBranches", err) - return cancel + return } // non-empty repo should have at least 1 branch, so this repository's branches haven't been synced yet @@ -662,7 +660,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { branchesTotal, err = repo_module.SyncRepoBranches(ctx, ctx.Repo.Repository.ID, 0) if err != nil { ctx.ServerError("SyncRepoBranches", err) - return cancel + return } } @@ -670,7 +668,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { // If no branch is set in the request URL, try to guess a default one. if len(ctx.Repo.BranchName) == 0 { - if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { + if len(ctx.Repo.Repository.DefaultBranch) > 0 && ctx.Repo.GitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch } else { ctx.Repo.BranchName, _ = gitrepo.GetDefaultBranch(ctx, ctx.Repo.Repository) @@ -711,12 +709,12 @@ func RepoAssignment(ctx *Context) context.CancelFunc { repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { ctx.ServerError("GetPendingRepositoryTransfer", err) - return cancel + return } if err := repoTransfer.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadRecipient", err) - return cancel + return } ctx.Data["RepoTransfer"] = repoTransfer @@ -731,7 +729,6 @@ func RepoAssignment(ctx *Context) context.CancelFunc { ctx.Data["GoDocDirectory"] = fullURLPrefix + "{/dir}" ctx.Data["GoDocFile"] = fullURLPrefix + "{/dir}/{file}#L{line}" } - return cancel } // RepoRefType type of repo reference @@ -750,7 +747,7 @@ const headRefName = "HEAD" // RepoRef handles repository reference names when the ref name is not // explicitly given -func RepoRef() func(*Context) context.CancelFunc { +func RepoRef() func(*Context) { // since no ref name is explicitly specified, ok to just use branch return RepoRefByType(RepoRefBranch) } @@ -865,9 +862,9 @@ type RepoRefByTypeOptions struct { // RepoRefByType handles repository reference name for a specific type // of repository reference -func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func(*Context) context.CancelFunc { +func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func(*Context) { opt := util.OptionalArg(opts) - return func(ctx *Context) (cancel context.CancelFunc) { + return func(ctx *Context) { refType := detectRefType // Empty repository does not have reference information. if ctx.Repo.Repository.IsEmpty { @@ -875,7 +872,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Repo.IsViewBranch = true ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch ctx.Data["TreePath"] = "" - return nil + return } var ( @@ -884,17 +881,10 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ) if ctx.Repo.GitRepo == nil { - ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx, ctx.Repo.Repository) if err != nil { ctx.ServerError(fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err) - return nil - } - // We opened it, we should close it - cancel = func() { - // If it's been set to nil then assume someone else has closed it. - if ctx.Repo.GitRepo != nil { - ctx.Repo.GitRepo.Close() - } + return } } @@ -924,7 +914,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Repo.Repository.MarkAsBrokenEmpty() } else { ctx.ServerError("GetBranchCommit", err) - return cancel + return } ctx.Repo.IsViewBranch = true } else { @@ -941,7 +931,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, renamedBranchName)) link := setting.AppSubURL + strings.Replace(ctx.Req.URL.EscapedPath(), util.PathEscapeSegments(refName), util.PathEscapeSegments(renamedBranchName), 1) ctx.Redirect(link) - return cancel + return } if refType == RepoRefBranch && ctx.Repo.GitRepo.IsBranchExist(refName) { @@ -951,7 +941,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName) if err != nil { ctx.ServerError("GetBranchCommit", err) - return cancel + return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() } else if refType == RepoRefTag && ctx.Repo.GitRepo.IsTagExist(refName) { @@ -962,10 +952,10 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func if err != nil { if git.IsErrNotExist(err) { ctx.NotFound("GetTagCommit", err) - return cancel + return } ctx.ServerError("GetTagCommit", err) - return cancel + return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() } else if git.IsStringLikelyCommitID(ctx.Repo.GetObjectFormat(), refName, 7) { @@ -975,7 +965,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { ctx.NotFound("GetCommit", err) - return cancel + return } // If short commit ID add canonical link header if len(refName) < ctx.Repo.GetObjectFormat().FullLength() { @@ -984,10 +974,10 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func } } else { if opt.IgnoreNotExistErr { - return cancel + return } ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName)) - return cancel + return } if guessLegacyPath { @@ -999,7 +989,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Repo.BranchNameSubURL(), util.PathEscapeSegments(ctx.Repo.TreePath)) ctx.Redirect(redirect) - return cancel + return } } @@ -1017,12 +1007,10 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount() if err != nil { ctx.ServerError("GetCommitsCount", err) - return cancel + return } ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount ctx.Repo.GitRepo.LastCommitCache = git.NewLastCommitCache(ctx.Repo.CommitsCount, ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, cache.GetCache()) - - return cancel } } 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/contexttest/context_tests.go b/services/contexttest/context_tests.go index 3c3fa76e3c..b0f71cad20 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -21,6 +21,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" @@ -40,7 +41,7 @@ func mockRequest(t *testing.T, reqPath string) *http.Request { requestURL, err := url.Parse(path) assert.NoError(t, err) req := &http.Request{Method: method, Host: requestURL.Host, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}} - req = req.WithContext(middleware.WithContextData(req.Context())) + req = req.WithContext(reqctx.NewRequestContextForTest(req.Context())) return req } @@ -60,17 +61,16 @@ func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*cont } resp := httptest.NewRecorder() req := mockRequest(t, reqPath) - base, baseCleanUp := context.NewBaseContext(resp, req) - _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later + base := context.NewBaseContext(resp, req) base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} chiCtx := chi.NewRouteContext() ctx := context.NewWebContext(base, opt.Render, nil) - ctx.AppendContextValue(context.WebContextKey, ctx) - ctx.AppendContextValue(chi.RouteCtxKey, chiCtx) + ctx.SetContextValue(context.WebContextKey, ctx) + ctx.SetContextValue(chi.RouteCtxKey, chiCtx) if opt.SessionStore != nil { - ctx.AppendContextValue(session.MockStoreContextKey, opt.SessionStore) + ctx.SetContextValue(session.MockStoreContextKey, opt.SessionStore) ctx.Session = opt.SessionStore } ctx.Cache = cache.GetCache() @@ -83,27 +83,24 @@ func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*cont func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) { resp := httptest.NewRecorder() req := mockRequest(t, reqPath) - base, baseCleanUp := context.NewBaseContext(resp, req) + base := context.NewBaseContext(resp, req) base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} ctx := &context.APIContext{Base: base} - _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later - chiCtx := chi.NewRouteContext() - ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) + ctx.SetContextValue(chi.RouteCtxKey, chiCtx) return ctx, resp } func MockPrivateContext(t *testing.T, reqPath string) (*context.PrivateContext, *httptest.ResponseRecorder) { resp := httptest.NewRecorder() req := mockRequest(t, reqPath) - base, baseCleanUp := context.NewBaseContext(resp, req) + base := context.NewBaseContext(resp, req) base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} ctx := &context.PrivateContext{Base: base} - _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later chiCtx := chi.NewRouteContext() - ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) + ctx.SetContextValue(chi.RouteCtxKey, chiCtx) return ctx, resp } @@ -183,7 +180,7 @@ func (tr *MockRender) TemplateLookup(tmpl string, _ gocontext.Context) (template return nil, nil } -func (tr *MockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error { +func (tr *MockRender) HTML(w io.Writer, status int, _ templates.TplName, _ any, _ gocontext.Context) error { if resp, ok := w.(http.ResponseWriter); ok { resp.WriteHeader(status) } diff --git a/services/mailer/mail.go b/services/mailer/mail.go index ee2c8c0963..a6763e4f03 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -21,11 +21,11 @@ import ( "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/translation" incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload" @@ -34,14 +34,14 @@ import ( ) const ( - mailAuthActivate base.TplName = "auth/activate" - mailAuthActivateEmail base.TplName = "auth/activate_email" - mailAuthResetPassword base.TplName = "auth/reset_passwd" - mailAuthRegisterNotify base.TplName = "auth/register_notify" + mailAuthActivate templates.TplName = "auth/activate" + mailAuthActivateEmail templates.TplName = "auth/activate_email" + mailAuthResetPassword templates.TplName = "auth/reset_passwd" + mailAuthRegisterNotify templates.TplName = "auth/register_notify" - mailNotifyCollaborator base.TplName = "notify/collaborator" + mailNotifyCollaborator templates.TplName = "notify/collaborator" - mailRepoTransferNotify base.TplName = "notify/repo_transfer" + mailRepoTransferNotify templates.TplName = "notify/repo_transfer" // There's no actual limit for subject in RFC 5322 mailMaxSubjectRunes = 256 @@ -63,7 +63,7 @@ func SendTestMail(email string) error { } // sendUserMail sends a mail to the user -func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, subject, info string) { +func sendUserMail(language string, u *user_model.User, tpl templates.TplName, code, subject, info string) { locale := translation.NewLocale(language) data := map[string]any{ "locale": locale, diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go index 1d73d77612..796d63d27a 100644 --- a/services/mailer/mail_release.go +++ b/services/mailer/mail_release.go @@ -10,16 +10,16 @@ import ( "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" sender_service "code.gitea.io/gitea/services/mailer/sender" ) const ( - tplNewReleaseMail base.TplName = "release" + tplNewReleaseMail templates.TplName = "release" ) // MailNewRelease send new release notify to all repo watchers. diff --git a/services/mailer/mail_team_invite.go b/services/mailer/mail_team_invite.go index 4f2d5e4ca7..5ca44442f3 100644 --- a/services/mailer/mail_team_invite.go +++ b/services/mailer/mail_team_invite.go @@ -11,15 +11,15 @@ import ( org_model "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" sender_service "code.gitea.io/gitea/services/mailer/sender" ) const ( - tplTeamInviteMail base.TplName = "team_invite" + tplTeamInviteMail templates.TplName = "team_invite" ) // MailTeamInvite sends team invites diff --git a/services/markup/main_test.go b/services/markup/main_test.go index 5553ebc058..d04a18bfa1 100644 --- a/services/markup/main_test.go +++ b/services/markup/main_test.go @@ -11,6 +11,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - FixtureFiles: []string{"user.yml", "repository.yml", "access.yml", "repo_unit.yml"}, + FixtureFiles: []string{"user.yml", "repository.yml", "access.yml", "repo_unit.yml", "issue.yml"}, }) } diff --git a/services/markup/processorhelper.go b/services/markup/renderhelper.go similarity index 88% rename from services/markup/processorhelper.go rename to services/markup/renderhelper.go index 1f1abf496a..4b9852b48b 100644 --- a/services/markup/processorhelper.go +++ b/services/markup/renderhelper.go @@ -11,9 +11,10 @@ import ( gitea_context "code.gitea.io/gitea/services/context" ) -func ProcessorHelper() *markup.RenderHelperFuncs { +func FormalRenderHelperFuncs() *markup.RenderHelperFuncs { return &markup.RenderHelperFuncs{ RenderRepoFileCodePreview: renderRepoFileCodePreview, + RenderRepoIssueIconTitle: renderRepoIssueIconTitle, IsUsernameMentionable: func(ctx context.Context, username string) bool { mentionedUser, err := user.GetUserByName(ctx, username) if err != nil { diff --git a/services/markup/processorhelper_codepreview.go b/services/markup/renderhelper_codepreview.go similarity index 97% rename from services/markup/processorhelper_codepreview.go rename to services/markup/renderhelper_codepreview.go index 0500e57e46..170c70c409 100644 --- a/services/markup/processorhelper_codepreview.go +++ b/services/markup/renderhelper_codepreview.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" gitea_context "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/repository/files" ) @@ -46,7 +47,7 @@ func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePrevie return "", err } if !perms.CanRead(unit.TypeCode) { - return "", fmt.Errorf("no permission") + return "", util.ErrPermissionDenied } gitRepo, err := gitrepo.OpenRepository(ctx, dbRepo) diff --git a/services/markup/processorhelper_codepreview_test.go b/services/markup/renderhelper_codepreview_test.go similarity index 95% rename from services/markup/processorhelper_codepreview_test.go rename to services/markup/renderhelper_codepreview_test.go index 154e4e8e44..ea945584b4 100644 --- a/services/markup/processorhelper_codepreview_test.go +++ b/services/markup/renderhelper_codepreview_test.go @@ -9,12 +9,13 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) -func TestProcessorHelperCodePreview(t *testing.T) { +func TestRenderHelperCodePreview(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) @@ -79,5 +80,5 @@ func TestProcessorHelperCodePreview(t *testing.T) { LineStart: 1, LineStop: 10, }) - assert.ErrorContains(t, err, "no permission") + assert.ErrorIs(t, err, util.ErrPermissionDenied) } diff --git a/services/markup/renderhelper_issueicontitle.go b/services/markup/renderhelper_issueicontitle.go new file mode 100644 index 0000000000..53a508e908 --- /dev/null +++ b/services/markup/renderhelper_issueicontitle.go @@ -0,0 +1,66 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup + +import ( + "context" + "fmt" + "html/template" + + "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/perm/access" + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/htmlutil" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/util" + gitea_context "code.gitea.io/gitea/services/context" +) + +func renderRepoIssueIconTitle(ctx context.Context, opts markup.RenderIssueIconTitleOptions) (_ template.HTML, err error) { + webCtx, ok := ctx.Value(gitea_context.WebContextKey).(*gitea_context.Context) + if !ok { + return "", fmt.Errorf("context is not a web context") + } + + textIssueIndex := fmt.Sprintf("(#%d)", opts.IssueIndex) + dbRepo := webCtx.Repo.Repository + if opts.OwnerName != "" { + dbRepo, err = repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName) + if err != nil { + return "", err + } + textIssueIndex = fmt.Sprintf("(%s/%s#%d)", dbRepo.OwnerName, dbRepo.Name, opts.IssueIndex) + } + if dbRepo == nil { + return "", nil + } + + issue, err := issues.GetIssueByIndex(ctx, dbRepo.ID, opts.IssueIndex) + if err != nil { + return "", err + } + + if webCtx.Repo.Repository == nil || dbRepo.ID != webCtx.Repo.Repository.ID { + perms, err := access.GetUserRepoPermission(ctx, dbRepo, webCtx.Doer) + if err != nil { + return "", err + } + if !perms.CanReadIssuesOrPulls(issue.IsPull) { + return "", util.ErrPermissionDenied + } + } + + if issue.IsPull { + if err = issue.LoadPullRequest(ctx); err != nil { + return "", err + } + } + + htmlIcon, err := webCtx.RenderToHTML("shared/issueicon", issue) + if err != nil { + return "", err + } + + return htmlutil.HTMLFormat(`%s %s %s`, opts.LinkHref, htmlIcon, issue.Title, textIssueIndex), nil +} diff --git a/services/markup/renderhelper_issueicontitle_test.go b/services/markup/renderhelper_issueicontitle_test.go new file mode 100644 index 0000000000..adce8401e0 --- /dev/null +++ b/services/markup/renderhelper_issueicontitle_test.go @@ -0,0 +1,49 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup + +import ( + "testing" + + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/contexttest" + + "github.com/stretchr/testify/assert" +) + +func TestRenderHelperIssueIconTitle(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + ctx.Repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) + htm, err := renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + LinkHref: "/link", + IssueIndex: 1, + }) + assert.NoError(t, err) + assert.Equal(t, `octicon-issue-opened(16/text green) issue1 (#1)`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + htm, err = renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + OwnerName: "user2", + RepoName: "repo1", + LinkHref: "/link", + IssueIndex: 1, + }) + assert.NoError(t, err) + assert.Equal(t, `octicon-issue-opened(16/text green) issue1 (user2/repo1#1)`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + _, err = renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + OwnerName: "user2", + RepoName: "repo2", + LinkHref: "/link", + IssueIndex: 2, + }) + assert.ErrorIs(t, err, util.ErrPermissionDenied) +} diff --git a/services/markup/processorhelper_test.go b/services/markup/renderhelper_mention_test.go similarity index 57% rename from services/markup/processorhelper_test.go rename to services/markup/renderhelper_mention_test.go index 170edae0e0..c244fa3d21 100644 --- a/services/markup/processorhelper_test.go +++ b/services/markup/renderhelper_mention_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestProcessorHelper(t *testing.T) { +func TestRenderHelperMention(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) userPublic := "user1" @@ -32,23 +32,22 @@ func TestProcessorHelper(t *testing.T) { unittest.AssertCount(t, &user.User{Name: userNoSuch}, 0) // when using general context, use user's visibility to check - assert.True(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userPublic)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userLimited)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userPrivate)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), userNoSuch)) + assert.True(t, FormalRenderHelperFuncs().IsUsernameMentionable(context.Background(), userPublic)) + assert.False(t, FormalRenderHelperFuncs().IsUsernameMentionable(context.Background(), userLimited)) + assert.False(t, FormalRenderHelperFuncs().IsUsernameMentionable(context.Background(), userPrivate)) + assert.False(t, FormalRenderHelperFuncs().IsUsernameMentionable(context.Background(), userNoSuch)) // when using web context, use user.IsUserVisibleToViewer to check req, err := http.NewRequest("GET", "/", nil) assert.NoError(t, err) - base, baseCleanUp := gitea_context.NewBaseContext(httptest.NewRecorder(), req) - defer baseCleanUp() + base := gitea_context.NewBaseContextForTest(httptest.NewRecorder(), req) giteaCtx := gitea_context.NewWebContext(base, &contexttest.MockRender{}, nil) - assert.True(t, ProcessorHelper().IsUsernameMentionable(giteaCtx, userPublic)) - assert.False(t, ProcessorHelper().IsUsernameMentionable(giteaCtx, userPrivate)) + assert.True(t, FormalRenderHelperFuncs().IsUsernameMentionable(giteaCtx, userPublic)) + assert.False(t, FormalRenderHelperFuncs().IsUsernameMentionable(giteaCtx, userPrivate)) giteaCtx.Doer, err = user.GetUserByName(db.DefaultContext, userPrivate) assert.NoError(t, err) - assert.True(t, ProcessorHelper().IsUsernameMentionable(giteaCtx, userPublic)) - assert.True(t, ProcessorHelper().IsUsernameMentionable(giteaCtx, userPrivate)) + assert.True(t, FormalRenderHelperFuncs().IsUsernameMentionable(giteaCtx, userPublic)) + assert.True(t, FormalRenderHelperFuncs().IsUsernameMentionable(giteaCtx, userPrivate)) } diff --git a/services/pull/merge_squash.go b/services/pull/merge_squash.go index 197d8102dd..8f8a5d82e7 100644 --- a/services/pull/merge_squash.go +++ b/services/pull/merge_squash.go @@ -10,7 +10,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -25,12 +24,12 @@ func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) { // Try to get an signature from the same user in one of the commits, as the // poster email might be private or commits might have a different signature // than the primary email address of the poster. - gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpenPath(ctx, ctx.tmpBasePath) + gitRepo, err := git.OpenRepository(ctx, ctx.tmpBasePath) if err != nil { log.Error("%-v Unable to open base repository: %v", ctx.pr, err) return nil, err } - defer closer.Close() + defer gitRepo.Close() commits, err := gitRepo.CommitsBetweenIDs(trackingBranch, "HEAD") if err != nil { diff --git a/services/pull/patch.go b/services/pull/patch.go index 36ca9dbdb6..13623d73c6 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -41,9 +41,19 @@ func DownloadDiffOrPatch(ctx context.Context, pr *issues_model.PullRequest, w io } defer closer.Close() - if err := gitRepo.GetDiffOrPatch(pr.MergeBase, pr.GetGitRefName(), w, patch, binary); err != nil { - log.Error("Unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err) - return fmt.Errorf("Unable to get patch file from %s to %s in %s Error: %w", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err) + compareArg := pr.MergeBase + "..." + pr.GetGitRefName() + switch { + case patch: + err = gitRepo.GetPatch(compareArg, w) + case binary: + err = gitRepo.GetDiffBinary(compareArg, w) + default: + err = gitRepo.GetDiff(compareArg, w) + } + + if err != nil { + log.Error("unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err) + return fmt.Errorf("unable to get patch file from %s to %s in %s Error: %w", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err) } return nil } @@ -354,7 +364,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * _ = util.Remove(tmpPatchFile.Name()) }() - if err := gitRepo.GetDiffBinary(pr.MergeBase, "tracking", tmpPatchFile); err != nil { + if err := gitRepo.GetDiffBinary(pr.MergeBase+"...tracking", tmpPatchFile); err != nil { tmpPatchFile.Close() log.Error("Unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err) return false, fmt.Errorf("unable to get patch file from %s to %s in %s Error: %w", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err) diff --git a/services/repository/avatar.go b/services/repository/avatar.go index 38c2621bc4..15e51d4a25 100644 --- a/services/repository/avatar.go +++ b/services/repository/avatar.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "strconv" - "strings" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" @@ -107,7 +106,8 @@ func RemoveRandomAvatars(ctx context.Context) error { // generateAvatar generates the avatar from a template repository func generateAvatar(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { - generateRepo.Avatar = strings.Replace(templateRepo.Avatar, strconv.FormatInt(templateRepo.ID, 10), strconv.FormatInt(generateRepo.ID, 10), 1) + // generate a new different hash, whatever the "hash data" is, it doesn't matter + generateRepo.Avatar = avatar.HashAvatar(generateRepo.ID, []byte("new-avatar")) if _, err := storage.Copy(storage.RepoAvatars, generateRepo.CustomAvatarRelativePath(), storage.RepoAvatars, templateRepo.CustomAvatarRelativePath()); err != nil { return err } diff --git a/services/repository/avatar_test.go b/services/repository/avatar_test.go index 4a0ba61853..bea820e85f 100644 --- a/services/repository/avatar_test.go +++ b/services/repository/avatar_test.go @@ -61,3 +61,11 @@ func TestDeleteAvatar(t *testing.T) { assert.Equal(t, "", repo.Avatar) } + +func TestGenerateAvatar(t *testing.T) { + templateRepo := &repo_model.Repository{ID: 10, Avatar: "a"} + generateRepo := &repo_model.Repository{ID: 11} + _ = generateAvatar(db.DefaultContext, templateRepo, generateRepo) + assert.NotEmpty(t, generateRepo.Avatar) + assert.NotEqual(t, templateRepo.Avatar, generateRepo.Avatar) +} diff --git a/services/repository/delete.go b/services/repository/delete.go index 61e39fe105..2166b4dd5c 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -317,7 +317,8 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID if len(repo.Avatar) > 0 { if err := storage.RepoAvatars.Delete(repo.CustomAvatarRelativePath()); err != nil { - return fmt.Errorf("Failed to remove %s: %w", repo.Avatar, err) + log.Error("remove avatar file %q: %v", repo.CustomAvatarRelativePath(), err) + // go on } } 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 786bc15857..0c60fddf7b 100644 --- a/services/repository/files/tree_test.go +++ b/services/repository/files/tree_test.go @@ -25,10 +25,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/devtest/repo-action-view.tmpl b/templates/devtest/repo-action-view.tmpl index 1fa71c0e5f..9c6bdf13da 100644 --- a/templates/devtest/repo-action-view.tmpl +++ b/templates/devtest/repo-action-view.tmpl @@ -1,30 +1,9 @@ {{template "base/head" .}}
-
+ {{template "repo/actions/view_component" (dict + "RunIndex" 1 + "JobIndex" 2 + "ActionsURL" (print AppSubUrl "/devtest/actions-mock") + )}}
{{template "base/footer" .}} diff --git a/templates/package/metadata/arch.tmpl b/templates/package/metadata/arch.tmpl index 2aea036ec2..62308e4aa0 100644 --- a/templates/package/metadata/arch.tmpl +++ b/templates/package/metadata/arch.tmpl @@ -1,4 +1,4 @@ {{if eq .PackageDescriptor.Package.Type "arch"}} - {{range .PackageDescriptor.Metadata.Licenses}}
{{svg "octicon-law"}} {{.}}
{{end}} + {{range .PackageDescriptor.Metadata.Licenses}}
{{svg "octicon-law"}} {{.}}
{{end}} {{if .PackageDescriptor.Metadata.ProjectURL}}{{end}} {{end}} diff --git a/templates/repo/actions/view.tmpl b/templates/repo/actions/view.tmpl index f7b03608ee..bde579f882 100644 --- a/templates/repo/actions/view.tmpl +++ b/templates/repo/actions/view.tmpl @@ -2,33 +2,11 @@
{{template "repo/header" .}} -
-
+ {{template "repo/actions/view_component" (dict + "RunIndex" .RunIndex + "JobIndex" .JobIndex + "ActionsURL" .ActionsURL + )}}
{{template "base/footer" .}} diff --git a/templates/repo/actions/view_component.tmpl b/templates/repo/actions/view_component.tmpl new file mode 100644 index 0000000000..8d1de41f70 --- /dev/null +++ b/templates/repo/actions/view_component.tmpl @@ -0,0 +1,30 @@ +
+
diff --git a/templates/repo/clone_panel.tmpl b/templates/repo/clone_panel.tmpl index 8cbeda132d..d3496bdb73 100644 --- a/templates/repo/clone_panel.tmpl +++ b/templates/repo/clone_panel.tmpl @@ -1,4 +1,4 @@ - diff --git a/templates/repo/code/upstream_diverging_info.tmpl b/templates/repo/code/upstream_diverging_info.tmpl index 299ba63e9e..51402598f9 100644 --- a/templates/repo/code/upstream_diverging_info.tmpl +++ b/templates/repo/code/upstream_diverging_info.tmpl @@ -10,7 +10,7 @@ {{end}} {{if .CanWriteCode}} - {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 3f9af18027..9fdbf45939 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -693,7 +693,7 @@ {{else if eq .Type 38}}
{{svg "octicon-clock"}} - {{template "shared/user/avatarlink" dict "Context" $.Context "user" .Poster}} + {{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/authorlink" .Poster}} {{$timeStr := .Content|TimeEstimateString}} diff --git a/templates/shared/actions/runner_list.tmpl b/templates/shared/actions/runner_list.tmpl index f652d56e09..e5907da8e8 100644 --- a/templates/shared/actions/runner_list.tmpl +++ b/templates/shared/actions/runner_list.tmpl @@ -3,7 +3,7 @@

{{ctx.Locale.Tr "actions.runners.runner_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})
-
diff --git a/templates/shared/issueicon.tmpl b/templates/shared/issueicon.tmpl index a62714e988..f828de5c66 100644 --- a/templates/shared/issueicon.tmpl +++ b/templates/shared/issueicon.tmpl @@ -1,25 +1,25 @@ -{{if .IsPull}} - {{if not .PullRequest}} +{{- if .IsPull -}} + {{- if not .PullRequest -}} No PullRequest - {{else}} - {{if .IsClosed}} - {{if .PullRequest.HasMerged}} - {{svg "octicon-git-merge" 16 "text purple"}} - {{else}} - {{svg "octicon-git-pull-request" 16 "text red"}} - {{end}} - {{else}} - {{if .PullRequest.IsWorkInProgress ctx}} - {{svg "octicon-git-pull-request-draft" 16 "text grey"}} - {{else}} - {{svg "octicon-git-pull-request" 16 "text green"}} - {{end}} - {{end}} - {{end}} -{{else}} - {{if .IsClosed}} - {{svg "octicon-issue-closed" 16 "text red"}} - {{else}} - {{svg "octicon-issue-opened" 16 "text green"}} - {{end}} -{{end}} + {{- else -}} + {{- if .IsClosed -}} + {{- if .PullRequest.HasMerged -}} + {{- svg "octicon-git-merge" 16 "text purple" -}} + {{- else -}} + {{- svg "octicon-git-pull-request" 16 "text red" -}} + {{- end -}} + {{- else -}} + {{- if .PullRequest.IsWorkInProgress ctx -}} + {{- svg "octicon-git-pull-request-draft" 16 "text grey" -}} + {{- else -}} + {{- svg "octicon-git-pull-request" 16 "text green" -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- else -}} + {{- if .IsClosed -}} + {{- svg "octicon-issue-closed" 16 "text red" -}} + {{- else -}} + {{- svg "octicon-issue-opened" 16 "text green" -}} + {{- end -}} +{{- end -}} diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index 462cb73eee..616ccf291a 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -21,11 +21,11 @@ import ( "code.gitea.io/gitea/models/migrations" migrate_base "code.gitea.io/gitea/models/migrations/base" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/testlogger" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -37,12 +37,7 @@ var currentEngine *xorm.Engine func initMigrationTest(t *testing.T) func() { testlogger.Init() - - deferFn := testlogger.PrintCurrentTest(t, 2) - giteaRoot := base.SetupGiteaRoot() - if giteaRoot == "" { - testlogger.Fatalf("Environment variable $GITEA_ROOT not set\n") - } + giteaRoot := test.SetupGiteaRoot() setting.AppPath = path.Join(giteaRoot, "gitea") if _, err := os.Stat(setting.AppPath); err != nil { testlogger.Fatalf(fmt.Sprintf("Could not find gitea binary at %s\n", setting.AppPath)) @@ -64,7 +59,8 @@ func initMigrationTest(t *testing.T) func() { assert.NoError(t, git.InitFull(context.Background())) setting.LoadDBSetting() setting.InitLoggersForTest() - return deferFn + + return testlogger.PrintCurrentTest(t, 2) } func availableVersions() ([]string, error) { diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index 9f938c4099..d86dcc01fe 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -247,7 +247,7 @@ func TestChangeRepoFilesForCreate(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { 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) @@ -284,7 +284,7 @@ func TestChangeRepoFilesForUpdate(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { 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) @@ -318,7 +318,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { 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) @@ -369,7 +369,7 @@ func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { 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) @@ -405,7 +405,7 @@ func testDeleteRepoFiles(t *testing.T, u *url.URL) { // setup 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) @@ -444,7 +444,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { // setup 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) @@ -474,7 +474,7 @@ func TestChangeRepoFilesErrors(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { 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/tests/test_utils.go b/tests/test_utils.go index deefdd43c5..96eb5731b4 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -15,13 +15,13 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/testlogger" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers" @@ -32,10 +32,7 @@ import ( func InitTest(requireGitea bool) { testlogger.Init() - giteaRoot := base.SetupGiteaRoot() - if giteaRoot == "" { - testlogger.Fatalf("Environment variable $GITEA_ROOT not set\n") - } + giteaRoot := test.SetupGiteaRoot() // TODO: Speedup tests that rely on the event source ticker, confirm whether there is any bug or failure. // setting.UI.Notification.EventSourceUpdateTime = time.Second @@ -61,7 +58,7 @@ func InitTest(requireGitea bool) { _ = os.Setenv("GITEA_CONF", giteaConf) fmt.Printf("Environment variable $GITEA_CONF not set, use default: %s\n", giteaConf) if !setting.EnableSQLite3 { - testlogger.Fatalf(`sqlite3 requires: import _ "github.com/mattn/go-sqlite3" or -tags sqlite,sqlite_unlock_notify` + "\n") + testlogger.Fatalf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify` + "\n") } } if !filepath.IsAbs(giteaConf) { diff --git a/tsconfig.json b/tsconfig.json index 7d0316db29..d32cca0aaa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,7 @@ "verbatimModuleSyntax": true, "stripInternal": true, "strict": false, + "strictFunctionTypes": true, "noUnusedLocals": true, "noUnusedParameters": true, "noPropertyAccessFromIndexSignature": false, diff --git a/web_src/js/components/ActionRunStatus.vue b/web_src/js/components/ActionRunStatus.vue index deab5f6469..96c6c441be 100644 --- a/web_src/js/components/ActionRunStatus.vue +++ b/web_src/js/components/ActionRunStatus.vue @@ -7,8 +7,8 @@ import {SvgIcon} from '../svg.ts'; withDefaults(defineProps<{ status: 'success' | 'skipped' | 'waiting' | 'blocked' | 'running' | 'failure' | 'cancelled' | 'unknown', - size: number, - className: string, + size?: number, + className?: string, localeStatus?: string, }>(), { size: 16, diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index b0e8447302..0aae202d42 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -25,10 +25,9 @@ const body = computed(() => { const root = ref(null); onMounted(() => { - root.value.addEventListener('ce-load-context-popup', (e: CustomEvent) => { - const data: IssuePathInfo = e.detail; + root.value.addEventListener('ce-load-context-popup', (e: CustomEventInit) => { if (!loading.value && issue.value === null) { - load(data); + load(e.detail); } }); }); diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index cb65a98edd..914c9e76de 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -38,6 +38,25 @@ function parseLineCommand(line: LogLine): LogLineCommand | null { return null; } +function isLogElementInViewport(el: HTMLElement): boolean { + const rect = el.getBoundingClientRect(); + return rect.top >= 0 && rect.bottom <= window.innerHeight; // only check height but not width +} + +type LocaleStorageOptions = { + autoScroll: boolean; + expandRunning: boolean; +}; + +function getLocaleStorageOptions(): LocaleStorageOptions { + try { + const optsJson = localStorage.getItem('actions-view-options'); + if (optsJson) return JSON.parse(optsJson); + } catch {} + // if no options in localStorage, or failed to parse, return default options + return {autoScroll: true, expandRunning: false}; +} + const sfc = { name: 'RepoActionView', components: { @@ -51,7 +70,17 @@ const sfc = { locale: Object, }, + watch: { + optionAlwaysAutoScroll() { + this.saveLocaleStorageOptions(); + }, + optionAlwaysExpandRunning() { + this.saveLocaleStorageOptions(); + }, + }, + data() { + const {autoScroll, expandRunning} = getLocaleStorageOptions(); return { // internal state loadingAbortController: null, @@ -65,6 +94,8 @@ const sfc = { 'log-time-stamp': false, 'log-time-seconds': false, }, + optionAlwaysAutoScroll: autoScroll ?? false, + optionAlwaysExpandRunning: expandRunning ?? false, // provided by backend run: { @@ -142,9 +173,19 @@ const sfc = { }, methods: { - // get the active container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group` - getLogsContainer(stepIndex: number) { - const el = this.$refs.logs[stepIndex]; + saveLocaleStorageOptions() { + const opts: LocaleStorageOptions = {autoScroll: this.optionAlwaysAutoScroll, expandRunning: this.optionAlwaysExpandRunning}; + localStorage.setItem('actions-view-options', JSON.stringify(opts)); + }, + + // get the job step logs container ('.job-step-logs') + getJobStepLogsContainer(stepIndex: number): HTMLElement { + return this.$refs.logs[stepIndex]; + }, + + // get the active logs container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group` + getActiveLogsContainer(stepIndex: number): HTMLElement { + const el = this.getJobStepLogsContainer(stepIndex); return el._stepLogsActiveContainer ?? el; }, // begin a log group @@ -217,9 +258,17 @@ const sfc = { ); }, + shouldAutoScroll(stepIndex: number): boolean { + if (!this.optionAlwaysAutoScroll) return false; + const el = this.getJobStepLogsContainer(stepIndex); + // if the logs container is empty, then auto-scroll if the step is expanded + if (!el.lastChild) return this.currentJobStepsStates[stepIndex].expanded; + return isLogElementInViewport(el.lastChild); + }, + appendLogs(stepIndex: number, startTime: number, logLines: LogLine[]) { for (const line of logLines) { - const el = this.getLogsContainer(stepIndex); + const el = this.getActiveLogsContainer(stepIndex); const cmd = parseLineCommand(line); if (cmd?.name === 'group') { this.beginLogGroup(stepIndex, startTime, line, cmd); @@ -264,6 +313,7 @@ const sfc = { const abortController = new AbortController(); this.loadingAbortController = abortController; try { + const isFirstLoad = !this.run.status; const job = await this.fetchJobData(abortController); if (this.loadingAbortController !== abortController) return; @@ -273,11 +323,20 @@ const sfc = { // sync the currentJobStepsStates to store the job step states for (let i = 0; i < this.currentJob.steps.length; i++) { + const expanded = isFirstLoad && this.optionAlwaysExpandRunning && this.currentJob.steps[i].status === 'running'; if (!this.currentJobStepsStates[i]) { // initial states for job steps - this.currentJobStepsStates[i] = {cursor: null, expanded: false}; + this.currentJobStepsStates[i] = {cursor: null, expanded}; } } + + // find the step indexes that need to auto-scroll + const autoScrollStepIndexes = new Map(); + for (const logs of job.logs.stepsLog ?? []) { + if (autoScrollStepIndexes.has(logs.step)) continue; + autoScrollStepIndexes.set(logs.step, this.shouldAutoScroll(logs.step)); + } + // append logs to the UI for (const logs of job.logs.stepsLog ?? []) { // save the cursor, it will be passed to backend next time @@ -285,6 +344,15 @@ const sfc = { this.appendLogs(logs.step, logs.started, logs.lines); } + // auto-scroll to the last log line of the last step + let autoScrollJobStepElement: HTMLElement; + for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) { + if (!autoScrollStepIndexes.get(stepIndex)) continue; + autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex); + } + autoScrollJobStepElement?.lastElementChild.scrollIntoView({behavior: 'smooth', block: 'nearest'}); + + // clear the interval timer if the job is done if (this.run.done && this.intervalID) { clearInterval(this.intervalID); this.intervalID = null; @@ -393,6 +461,8 @@ export function initRepositoryActionView() { skipped: el.getAttribute('data-locale-status-skipped'), blocked: el.getAttribute('data-locale-status-blocked'), }, + logsAlwaysAutoScroll: el.getAttribute('data-locale-logs-always-auto-scroll'), + logsAlwaysExpandRunning: el.getAttribute('data-locale-logs-always-expand-running'), }, }); view.mount(el); @@ -495,6 +565,17 @@ export function initRepositoryActionView() { {{ locale.showFullScreen }} + +
+ + + {{ locale.logsAlwaysAutoScroll }} + + + + {{ locale.logsAlwaysExpandRunning }} + +
diff --git a/web_src/js/features/clipboard.ts b/web_src/js/features/clipboard.ts index 8f40f34f74..22c264d774 100644 --- a/web_src/js/features/clipboard.ts +++ b/web_src/js/features/clipboard.ts @@ -1,6 +1,7 @@ import {showTemporaryTooltip} from '../modules/tippy.ts'; import {toAbsoluteUrl} from '../utils.ts'; import {clippie} from 'clippie'; +import type {DOMEvent} from '../utils/dom.ts'; const {copy_success, copy_error} = window.config.i18n; @@ -9,7 +10,7 @@ const {copy_success, copy_error} = window.config.i18n; // - data-clipboard-target: Holds a selector for a or