]> source.dussan.org Git - gitea.git/commitdiff
Move context from modules to services (#29440)
authorLunny Xiao <xiaolunwen@gmail.com>
Tue, 27 Feb 2024 07:12:22 +0000 (15:12 +0800)
committerGitHub <noreply@github.com>
Tue, 27 Feb 2024 07:12:22 +0000 (08:12 +0100)
Since `modules/context` has to depend on `models` and many other
packages, it should be moved from `modules/context` to
`services/context` according to design principles. There is no logic
code change on this PR, only move packages.

- Move `code.gitea.io/gitea/modules/context` to
`code.gitea.io/gitea/services/context`
- Move `code.gitea.io/gitea/modules/contexttest` to
`code.gitea.io/gitea/services/contexttest` because of depending on
context
- Move `code.gitea.io/gitea/modules/upload` to
`code.gitea.io/gitea/services/context/upload` because of depending on
context

387 files changed:
modules/context/access_log.go [deleted file]
modules/context/api.go [deleted file]
modules/context/api_org.go [deleted file]
modules/context/api_test.go [deleted file]
modules/context/base.go [deleted file]
modules/context/captcha.go [deleted file]
modules/context/context.go [deleted file]
modules/context/context_cookie.go [deleted file]
modules/context/context_model.go [deleted file]
modules/context/context_request.go [deleted file]
modules/context/context_response.go [deleted file]
modules/context/context_template.go [deleted file]
modules/context/context_test.go [deleted file]
modules/context/csrf.go [deleted file]
modules/context/org.go [deleted file]
modules/context/package.go [deleted file]
modules/context/pagination.go [deleted file]
modules/context/permission.go [deleted file]
modules/context/private.go [deleted file]
modules/context/repo.go [deleted file]
modules/context/response.go [deleted file]
modules/context/utils.go [deleted file]
modules/context/xsrf.go [deleted file]
modules/context/xsrf_test.go [deleted file]
modules/contexttest/context_tests.go [deleted file]
modules/upload/upload.go [deleted file]
modules/upload/upload_test.go [deleted file]
routers/api/actions/artifacts.go
routers/api/packages/alpine/alpine.go
routers/api/packages/api.go
routers/api/packages/cargo/cargo.go
routers/api/packages/chef/chef.go
routers/api/packages/composer/composer.go
routers/api/packages/conan/conan.go
routers/api/packages/conan/search.go
routers/api/packages/conda/conda.go
routers/api/packages/container/container.go
routers/api/packages/cran/cran.go
routers/api/packages/debian/debian.go
routers/api/packages/generic/generic.go
routers/api/packages/goproxy/goproxy.go
routers/api/packages/helm/helm.go
routers/api/packages/helper/helper.go
routers/api/packages/maven/maven.go
routers/api/packages/npm/npm.go
routers/api/packages/nuget/nuget.go
routers/api/packages/pub/pub.go
routers/api/packages/pypi/pypi.go
routers/api/packages/rpm/rpm.go
routers/api/packages/rubygems/rubygems.go
routers/api/packages/swift/swift.go
routers/api/packages/vagrant/vagrant.go
routers/api/v1/activitypub/person.go
routers/api/v1/activitypub/reqsignature.go
routers/api/v1/admin/adopt.go
routers/api/v1/admin/cron.go
routers/api/v1/admin/email.go
routers/api/v1/admin/hooks.go
routers/api/v1/admin/org.go
routers/api/v1/admin/repo.go
routers/api/v1/admin/runners.go
routers/api/v1/admin/user.go
routers/api/v1/api.go
routers/api/v1/misc/gitignore.go
routers/api/v1/misc/label_templates.go
routers/api/v1/misc/licenses.go
routers/api/v1/misc/markup.go
routers/api/v1/misc/markup_test.go
routers/api/v1/misc/nodeinfo.go
routers/api/v1/misc/signing.go
routers/api/v1/misc/version.go
routers/api/v1/notify/notifications.go
routers/api/v1/notify/repo.go
routers/api/v1/notify/threads.go
routers/api/v1/notify/user.go
routers/api/v1/org/avatar.go
routers/api/v1/org/hook.go
routers/api/v1/org/label.go
routers/api/v1/org/member.go
routers/api/v1/org/org.go
routers/api/v1/org/runners.go
routers/api/v1/org/secrets.go
routers/api/v1/org/team.go
routers/api/v1/packages/package.go
routers/api/v1/repo/action.go
routers/api/v1/repo/avatar.go
routers/api/v1/repo/blob.go
routers/api/v1/repo/branch.go
routers/api/v1/repo/collaborators.go
routers/api/v1/repo/commits.go
routers/api/v1/repo/file.go
routers/api/v1/repo/fork.go
routers/api/v1/repo/git_hook.go
routers/api/v1/repo/git_ref.go
routers/api/v1/repo/hook.go
routers/api/v1/repo/hook_test.go
routers/api/v1/repo/issue.go
routers/api/v1/repo/issue_attachment.go
routers/api/v1/repo/issue_comment.go
routers/api/v1/repo/issue_comment_attachment.go
routers/api/v1/repo/issue_dependency.go
routers/api/v1/repo/issue_label.go
routers/api/v1/repo/issue_pin.go
routers/api/v1/repo/issue_reaction.go
routers/api/v1/repo/issue_stopwatch.go
routers/api/v1/repo/issue_subscription.go
routers/api/v1/repo/issue_tracked_time.go
routers/api/v1/repo/key.go
routers/api/v1/repo/label.go
routers/api/v1/repo/language.go
routers/api/v1/repo/migrate.go
routers/api/v1/repo/milestone.go
routers/api/v1/repo/mirror.go
routers/api/v1/repo/notes.go
routers/api/v1/repo/patch.go
routers/api/v1/repo/pull.go
routers/api/v1/repo/pull_review.go
routers/api/v1/repo/release.go
routers/api/v1/repo/release_attachment.go
routers/api/v1/repo/release_tags.go
routers/api/v1/repo/repo.go
routers/api/v1/repo/repo_test.go
routers/api/v1/repo/runners.go
routers/api/v1/repo/star.go
routers/api/v1/repo/status.go
routers/api/v1/repo/subscriber.go
routers/api/v1/repo/tag.go
routers/api/v1/repo/teams.go
routers/api/v1/repo/topic.go
routers/api/v1/repo/transfer.go
routers/api/v1/repo/tree.go
routers/api/v1/repo/wiki.go
routers/api/v1/settings/settings.go
routers/api/v1/shared/runners.go
routers/api/v1/user/action.go
routers/api/v1/user/app.go
routers/api/v1/user/avatar.go
routers/api/v1/user/email.go
routers/api/v1/user/follower.go
routers/api/v1/user/gpg_key.go
routers/api/v1/user/helper.go
routers/api/v1/user/hook.go
routers/api/v1/user/key.go
routers/api/v1/user/repo.go
routers/api/v1/user/runners.go
routers/api/v1/user/settings.go
routers/api/v1/user/star.go
routers/api/v1/user/user.go
routers/api/v1/user/watch.go
routers/api/v1/utils/git.go
routers/api/v1/utils/hook.go
routers/api/v1/utils/page.go
routers/common/auth.go
routers/common/errpage.go
routers/common/markup.go
routers/common/middleware.go
routers/common/serve.go
routers/install/install.go
routers/private/actions.go
routers/private/default_branch.go
routers/private/hook_post_receive.go
routers/private/hook_pre_receive.go
routers/private/hook_proc_receive.go
routers/private/internal.go
routers/private/internal_repo.go
routers/private/key.go
routers/private/mail.go
routers/private/manager.go
routers/private/manager_process.go
routers/private/manager_unix.go
routers/private/manager_windows.go
routers/private/restore_repo.go
routers/private/serv.go
routers/private/ssh_log.go
routers/web/admin/admin.go
routers/web/admin/applications.go
routers/web/admin/auths.go
routers/web/admin/config.go
routers/web/admin/diagnosis.go
routers/web/admin/emails.go
routers/web/admin/hooks.go
routers/web/admin/notice.go
routers/web/admin/orgs.go
routers/web/admin/packages.go
routers/web/admin/queue.go
routers/web/admin/repos.go
routers/web/admin/runners.go
routers/web/admin/stacktrace.go
routers/web/admin/users.go
routers/web/admin/users_test.go
routers/web/auth/2fa.go
routers/web/auth/auth.go
routers/web/auth/linkaccount.go
routers/web/auth/oauth.go
routers/web/auth/openid.go
routers/web/auth/password.go
routers/web/auth/webauthn.go
routers/web/devtest/devtest.go
routers/web/events/events.go
routers/web/explore/code.go
routers/web/explore/org.go
routers/web/explore/repo.go
routers/web/explore/topic.go
routers/web/explore/user.go
routers/web/feed/branch.go
routers/web/feed/convert.go
routers/web/feed/file.go
routers/web/feed/profile.go
routers/web/feed/release.go
routers/web/feed/render.go
routers/web/feed/repo.go
routers/web/githttp.go
routers/web/goget.go
routers/web/home.go
routers/web/misc/markup.go
routers/web/misc/swagger.go
routers/web/nodeinfo.go
routers/web/org/home.go
routers/web/org/members.go
routers/web/org/org.go
routers/web/org/org_labels.go
routers/web/org/projects.go
routers/web/org/projects_test.go
routers/web/org/setting.go
routers/web/org/setting/runners.go
routers/web/org/setting_oauth2.go
routers/web/org/setting_packages.go
routers/web/org/teams.go
routers/web/passkey.go
routers/web/repo/actions/actions.go
routers/web/repo/actions/view.go
routers/web/repo/activity.go
routers/web/repo/attachment.go
routers/web/repo/blame.go
routers/web/repo/branch.go
routers/web/repo/cherry_pick.go
routers/web/repo/code_frequency.go
routers/web/repo/commit.go
routers/web/repo/compare.go
routers/web/repo/contributors.go
routers/web/repo/download.go
routers/web/repo/editor.go
routers/web/repo/editor_test.go
routers/web/repo/find.go
routers/web/repo/githttp.go
routers/web/repo/helper.go
routers/web/repo/issue.go
routers/web/repo/issue_content_history.go
routers/web/repo/issue_dependency.go
routers/web/repo/issue_label.go
routers/web/repo/issue_label_test.go
routers/web/repo/issue_lock.go
routers/web/repo/issue_pin.go
routers/web/repo/issue_stopwatch.go
routers/web/repo/issue_timetrack.go
routers/web/repo/issue_watch.go
routers/web/repo/middlewares.go
routers/web/repo/migrate.go
routers/web/repo/milestone.go
routers/web/repo/packages.go
routers/web/repo/patch.go
routers/web/repo/projects.go
routers/web/repo/projects_test.go
routers/web/repo/pull.go
routers/web/repo/pull_review.go
routers/web/repo/pull_review_test.go
routers/web/repo/recent_commits.go
routers/web/repo/release.go
routers/web/repo/release_test.go
routers/web/repo/render.go
routers/web/repo/repo.go
routers/web/repo/search.go
routers/web/repo/setting/avatar.go
routers/web/repo/setting/collaboration.go
routers/web/repo/setting/default_branch.go
routers/web/repo/setting/deploy_key.go
routers/web/repo/setting/git_hooks.go
routers/web/repo/setting/lfs.go
routers/web/repo/setting/protected_branch.go
routers/web/repo/setting/protected_tag.go
routers/web/repo/setting/runners.go
routers/web/repo/setting/secrets.go
routers/web/repo/setting/setting.go
routers/web/repo/setting/settings_test.go
routers/web/repo/setting/variables.go
routers/web/repo/setting/webhook.go
routers/web/repo/topic.go
routers/web/repo/treelist.go
routers/web/repo/view.go
routers/web/repo/wiki.go
routers/web/repo/wiki_test.go
routers/web/shared/actions/runners.go
routers/web/shared/actions/variables.go
routers/web/shared/packages/packages.go
routers/web/shared/secrets/secrets.go
routers/web/shared/user/header.go
routers/web/swagger_json.go
routers/web/user/avatar.go
routers/web/user/code.go
routers/web/user/home.go
routers/web/user/home_test.go
routers/web/user/notification.go
routers/web/user/package.go
routers/web/user/profile.go
routers/web/user/search.go
routers/web/user/setting/account.go
routers/web/user/setting/account_test.go
routers/web/user/setting/adopt.go
routers/web/user/setting/applications.go
routers/web/user/setting/keys.go
routers/web/user/setting/oauth2.go
routers/web/user/setting/oauth2_common.go
routers/web/user/setting/packages.go
routers/web/user/setting/profile.go
routers/web/user/setting/runner.go
routers/web/user/setting/security/2fa.go
routers/web/user/setting/security/openid.go
routers/web/user/setting/security/security.go
routers/web/user/setting/security/webauthn.go
routers/web/user/setting/webhooks.go
routers/web/user/stop_watch.go
routers/web/user/task.go
routers/web/web.go
routers/web/webfinger.go
services/attachment/attachment.go
services/auth/auth.go
services/auth/sspi.go
services/context/access_log.go [new file with mode: 0644]
services/context/api.go [new file with mode: 0644]
services/context/api_org.go [new file with mode: 0644]
services/context/api_test.go [new file with mode: 0644]
services/context/base.go [new file with mode: 0644]
services/context/captcha.go [new file with mode: 0644]
services/context/context.go [new file with mode: 0644]
services/context/context_cookie.go [new file with mode: 0644]
services/context/context_model.go [new file with mode: 0644]
services/context/context_request.go [new file with mode: 0644]
services/context/context_response.go [new file with mode: 0644]
services/context/context_template.go [new file with mode: 0644]
services/context/context_test.go [new file with mode: 0644]
services/context/csrf.go [new file with mode: 0644]
services/context/org.go [new file with mode: 0644]
services/context/package.go [new file with mode: 0644]
services/context/pagination.go [new file with mode: 0644]
services/context/permission.go [new file with mode: 0644]
services/context/private.go [new file with mode: 0644]
services/context/repo.go [new file with mode: 0644]
services/context/response.go [new file with mode: 0644]
services/context/upload/upload.go [new file with mode: 0644]
services/context/upload/upload_test.go [new file with mode: 0644]
services/context/user.go
services/context/utils.go [new file with mode: 0644]
services/context/xsrf.go [new file with mode: 0644]
services/context/xsrf_test.go [new file with mode: 0644]
services/contexttest/context_tests.go [new file with mode: 0644]
services/convert/git_commit.go
services/forms/admin.go
services/forms/auth_form.go
services/forms/org.go
services/forms/package_form.go
services/forms/repo_branch_form.go
services/forms/repo_form.go
services/forms/repo_tag_form.go
services/forms/runner.go
services/forms/user_form.go
services/forms/user_form_auth_openid.go
services/forms/user_form_hidden_comments.go
services/lfs/locks.go
services/lfs/server.go
services/mailer/incoming/incoming_handler.go
services/markup/processorhelper.go
services/markup/processorhelper_test.go
services/pull/pull.go
services/repository/archiver/archiver_test.go
services/repository/commit.go
services/repository/files/content_test.go
services/repository/files/diff_test.go
services/repository/files/file_test.go
services/repository/files/tree_test.go
tests/integration/api_repo_file_create_test.go
tests/integration/api_repo_file_update_test.go
tests/integration/api_repo_files_change_test.go
tests/integration/editor_test.go
tests/integration/git_test.go
tests/integration/integration_test.go
tests/integration/mirror_push_test.go
tests/integration/repofiles_change_test.go

diff --git a/modules/context/access_log.go b/modules/context/access_log.go
deleted file mode 100644 (file)
index 0926748..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "bytes"
-       "fmt"
-       "net"
-       "net/http"
-       "strings"
-       "text/template"
-       "time"
-
-       user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/log"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/web/middleware"
-)
-
-type routerLoggerOptions struct {
-       req            *http.Request
-       Identity       *string
-       Start          *time.Time
-       ResponseWriter http.ResponseWriter
-       Ctx            map[string]any
-       RequestID      *string
-}
-
-const keyOfRequestIDInTemplate = ".RequestID"
-
-// According to:
-// TraceId: A valid trace identifier is a 16-byte array with at least one non-zero byte
-// MD5 output is 16 or 32 bytes: md5-bytes is 16, md5-hex is 32
-// SHA1: similar, SHA1-bytes is 20, SHA1-hex is 40.
-// UUID is 128-bit, 32 hex chars, 36 ASCII chars with 4 dashes
-// So, we accept a Request ID with a maximum character length of 40
-const maxRequestIDByteLength = 40
-
-func parseRequestIDFromRequestHeader(req *http.Request) string {
-       requestID := "-"
-       for _, key := range setting.Log.RequestIDHeaders {
-               if req.Header.Get(key) != "" {
-                       requestID = req.Header.Get(key)
-                       break
-               }
-       }
-       if len(requestID) > maxRequestIDByteLength {
-               requestID = fmt.Sprintf("%s...", requestID[:maxRequestIDByteLength])
-       }
-       return requestID
-}
-
-// AccessLogger returns a middleware to log access logger
-func AccessLogger() func(http.Handler) http.Handler {
-       logger := log.GetLogger("access")
-       needRequestID := len(setting.Log.RequestIDHeaders) > 0 && strings.Contains(setting.Log.AccessLogTemplate, keyOfRequestIDInTemplate)
-       logTemplate, _ := template.New("log").Parse(setting.Log.AccessLogTemplate)
-       return func(next http.Handler) http.Handler {
-               return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
-                       start := time.Now()
-
-                       var requestID string
-                       if needRequestID {
-                               requestID = parseRequestIDFromRequestHeader(req)
-                       }
-
-                       reqHost, _, err := net.SplitHostPort(req.RemoteAddr)
-                       if err != nil {
-                               reqHost = req.RemoteAddr
-                       }
-
-                       next.ServeHTTP(w, req)
-                       rw := w.(ResponseWriter)
-
-                       identity := "-"
-                       data := middleware.GetContextData(req.Context())
-                       if signedUser, ok := data[middleware.ContextDataKeySignedUser].(*user_model.User); ok {
-                               identity = signedUser.Name
-                       }
-                       buf := bytes.NewBuffer([]byte{})
-                       err = logTemplate.Execute(buf, routerLoggerOptions{
-                               req:            req,
-                               Identity:       &identity,
-                               Start:          &start,
-                               ResponseWriter: rw,
-                               Ctx: map[string]any{
-                                       "RemoteAddr": req.RemoteAddr,
-                                       "RemoteHost": reqHost,
-                                       "Req":        req,
-                               },
-                               RequestID: &requestID,
-                       })
-                       if err != nil {
-                               log.Error("Could not execute access logger template: %v", err.Error())
-                       }
-
-                       logger.Info("%s", buf.String())
-               })
-       }
-}
diff --git a/modules/context/api.go b/modules/context/api.go
deleted file mode 100644 (file)
index b18a206..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-// Copyright 2016 The Gogs Authors. All rights reserved.
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "context"
-       "fmt"
-       "net/http"
-       "net/url"
-       "strings"
-
-       "code.gitea.io/gitea/models/unit"
-       user_model "code.gitea.io/gitea/models/user"
-       mc "code.gitea.io/gitea/modules/cache"
-       "code.gitea.io/gitea/modules/git"
-       "code.gitea.io/gitea/modules/gitrepo"
-       "code.gitea.io/gitea/modules/httpcache"
-       "code.gitea.io/gitea/modules/log"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/web"
-       web_types "code.gitea.io/gitea/modules/web/types"
-
-       "gitea.com/go-chi/cache"
-)
-
-// APIContext is a specific context for API service
-type APIContext struct {
-       *Base
-
-       Cache cache.Cache
-
-       Doer        *user_model.User // current signed-in user
-       IsSigned    bool
-       IsBasicAuth bool
-
-       ContextUser *user_model.User // the user which is being visited, in most cases it differs from Doer
-
-       Repo    *Repository
-       Org     *APIOrganization
-       Package *Package
-}
-
-func init() {
-       web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider {
-               return req.Context().Value(apiContextKey).(*APIContext)
-       })
-}
-
-// Currently, we have the following common fields in error response:
-// * message: the message for end users (it shouldn't be used for error type detection)
-//            if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType
-// * url:     the swagger document URL
-
-// APIError is error format response
-// swagger:response error
-type APIError struct {
-       Message string `json:"message"`
-       URL     string `json:"url"`
-}
-
-// APIValidationError is error format response related to input validation
-// swagger:response validationError
-type APIValidationError struct {
-       Message string `json:"message"`
-       URL     string `json:"url"`
-}
-
-// APIInvalidTopicsError is error format response to invalid topics
-// swagger:response invalidTopicsError
-type APIInvalidTopicsError struct {
-       Message       string   `json:"message"`
-       InvalidTopics []string `json:"invalidTopics"`
-}
-
-// APIEmpty is an empty response
-// swagger:response empty
-type APIEmpty struct{}
-
-// APIForbiddenError is a forbidden error response
-// swagger:response forbidden
-type APIForbiddenError struct {
-       APIError
-}
-
-// APINotFound is a not found empty response
-// swagger:response notFound
-type APINotFound struct{}
-
-// APIConflict is a conflict empty response
-// swagger:response conflict
-type APIConflict struct{}
-
-// APIRedirect is a redirect response
-// swagger:response redirect
-type APIRedirect struct{}
-
-// APIString is a string response
-// swagger:response string
-type APIString string
-
-// APIRepoArchivedError is an error that is raised when an archived repo should be modified
-// swagger:response repoArchivedError
-type APIRepoArchivedError struct {
-       APIError
-}
-
-// ServerError responds with error message, status is 500
-func (ctx *APIContext) ServerError(title string, err error) {
-       ctx.Error(http.StatusInternalServerError, title, err)
-}
-
-// Error responds with an error message to client with given obj as the message.
-// If status is 500, also it prints error to log.
-func (ctx *APIContext) Error(status int, title string, obj any) {
-       var message string
-       if err, ok := obj.(error); ok {
-               message = err.Error()
-       } else {
-               message = fmt.Sprintf("%s", obj)
-       }
-
-       if status == http.StatusInternalServerError {
-               log.ErrorWithSkip(1, "%s: %s", title, message)
-
-               if setting.IsProd && !(ctx.Doer != nil && ctx.Doer.IsAdmin) {
-                       message = ""
-               }
-       }
-
-       ctx.JSON(status, APIError{
-               Message: message,
-               URL:     setting.API.SwaggerURL,
-       })
-}
-
-// InternalServerError responds with an error message to the client with the error as a message
-// and the file and line of the caller.
-func (ctx *APIContext) InternalServerError(err error) {
-       log.ErrorWithSkip(1, "InternalServerError: %v", err)
-
-       var message string
-       if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
-               message = err.Error()
-       }
-
-       ctx.JSON(http.StatusInternalServerError, APIError{
-               Message: message,
-               URL:     setting.API.SwaggerURL,
-       })
-}
-
-type apiContextKeyType struct{}
-
-var apiContextKey = apiContextKeyType{}
-
-// GetAPIContext returns a context for API routes
-func GetAPIContext(req *http.Request) *APIContext {
-       return req.Context().Value(apiContextKey).(*APIContext)
-}
-
-func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string {
-       page := NewPagination(total, pageSize, curPage, 0)
-       paginater := page.Paginater
-       links := make([]string, 0, 4)
-
-       if paginater.HasNext() {
-               u := *curURL
-               queries := u.Query()
-               queries.Set("page", fmt.Sprintf("%d", paginater.Next()))
-               u.RawQuery = queries.Encode()
-
-               links = append(links, fmt.Sprintf("<%s%s>; rel=\"next\"", setting.AppURL, u.RequestURI()[1:]))
-       }
-       if !paginater.IsLast() {
-               u := *curURL
-               queries := u.Query()
-               queries.Set("page", fmt.Sprintf("%d", paginater.TotalPages()))
-               u.RawQuery = queries.Encode()
-
-               links = append(links, fmt.Sprintf("<%s%s>; rel=\"last\"", setting.AppURL, u.RequestURI()[1:]))
-       }
-       if !paginater.IsFirst() {
-               u := *curURL
-               queries := u.Query()
-               queries.Set("page", "1")
-               u.RawQuery = queries.Encode()
-
-               links = append(links, fmt.Sprintf("<%s%s>; rel=\"first\"", setting.AppURL, u.RequestURI()[1:]))
-       }
-       if paginater.HasPrevious() {
-               u := *curURL
-               queries := u.Query()
-               queries.Set("page", fmt.Sprintf("%d", paginater.Previous()))
-               u.RawQuery = queries.Encode()
-
-               links = append(links, fmt.Sprintf("<%s%s>; rel=\"prev\"", setting.AppURL, u.RequestURI()[1:]))
-       }
-       return links
-}
-
-// SetLinkHeader sets pagination link header by given total number and page size.
-func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
-       links := genAPILinks(ctx.Req.URL, total, pageSize, ctx.FormInt("page"))
-
-       if len(links) > 0 {
-               ctx.RespHeader().Set("Link", strings.Join(links, ","))
-               ctx.AppendAccessControlExposeHeaders("Link")
-       }
-}
-
-// APIContexter returns apicontext as middleware
-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)
-                       ctx := &APIContext{
-                               Base:  base,
-                               Cache: mc.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 })
-
-                       // 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") {
-                               if err := ctx.Req.ParseMultipartForm(setting.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
-                                       ctx.InternalServerError(err)
-                                       return
-                               }
-                       }
-
-                       httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
-                       ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
-
-                       next.ServeHTTP(ctx.Resp, ctx.Req)
-               })
-       }
-}
-
-// NotFound handles 404s for APIContext
-// String will replace message, errors will be added to a slice
-func (ctx *APIContext) NotFound(objs ...any) {
-       message := ctx.Locale.TrString("error.not_found")
-       var errors []string
-       for _, obj := range objs {
-               // Ignore nil
-               if obj == nil {
-                       continue
-               }
-
-               if err, ok := obj.(error); ok {
-                       errors = append(errors, err.Error())
-               } else {
-                       message = obj.(string)
-               }
-       }
-
-       ctx.JSON(http.StatusNotFound, map[string]any{
-               "message": message,
-               "url":     setting.API.SwaggerURL,
-               "errors":  errors,
-       })
-}
-
-// 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) {
-               // Empty repository does not have reference information.
-               if ctx.Repo.Repository.IsEmpty && !(len(allowEmpty) != 0 && allowEmpty[0]) {
-                       return nil
-               }
-
-               // For API calls.
-               if ctx.Repo.GitRepo == nil {
-                       gitRepo, err := gitrepo.OpenRepository(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 cancel
-       }
-}
-
-// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
-func RepoRefForAPI(next http.Handler) http.Handler {
-       return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
-               ctx := GetAPIContext(req)
-
-               if ctx.Repo.GitRepo == nil {
-                       ctx.InternalServerError(fmt.Errorf("no open git repo"))
-                       return
-               }
-
-               if ref := ctx.FormTrim("ref"); len(ref) > 0 {
-                       commit, err := ctx.Repo.GitRepo.GetCommit(ref)
-                       if err != nil {
-                               if git.IsErrNotExist(err) {
-                                       ctx.NotFound()
-                               } else {
-                                       ctx.Error(http.StatusInternalServerError, "GetCommit", err)
-                               }
-                               return
-                       }
-                       ctx.Repo.Commit = commit
-                       ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
-                       ctx.Repo.TreePath = ctx.Params("*")
-                       next.ServeHTTP(w, req)
-                       return
-               }
-
-               refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
-               var err error
-
-               if ctx.Repo.GitRepo.IsBranchExist(refName) {
-                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
-                       if err != nil {
-                               ctx.InternalServerError(err)
-                               return
-                       }
-                       ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
-               } else if ctx.Repo.GitRepo.IsTagExist(refName) {
-                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
-                       if err != nil {
-                               ctx.InternalServerError(err)
-                               return
-                       }
-                       ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
-               } else if len(refName) == ctx.Repo.GetObjectFormat().FullLength() {
-                       ctx.Repo.CommitID = refName
-                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
-                       if err != nil {
-                               ctx.NotFound("GetCommit", err)
-                               return
-                       }
-               } else {
-                       ctx.NotFound(fmt.Errorf("not exist: '%s'", ctx.Params("*")))
-                       return
-               }
-
-               next.ServeHTTP(w, req)
-       })
-}
-
-// HasAPIError returns true if error occurs in form validation.
-func (ctx *APIContext) HasAPIError() bool {
-       hasErr, ok := ctx.Data["HasError"]
-       if !ok {
-               return false
-       }
-       return hasErr.(bool)
-}
-
-// GetErrMsg returns error message in form validation.
-func (ctx *APIContext) GetErrMsg() string {
-       msg, _ := ctx.Data["ErrorMsg"].(string)
-       if msg == "" {
-               msg = "invalid form data"
-       }
-       return msg
-}
-
-// NotFoundOrServerError use error check function to determine if the error
-// is about not found. It responds with 404 status code for not found error,
-// or error context description for logging purpose of 500 server error.
-func (ctx *APIContext) NotFoundOrServerError(logMsg string, errCheck func(error) bool, logErr error) {
-       if errCheck(logErr) {
-               ctx.JSON(http.StatusNotFound, nil)
-               return
-       }
-       ctx.Error(http.StatusInternalServerError, "NotFoundOrServerError", logMsg)
-}
-
-// IsUserSiteAdmin returns true if current user is a site admin
-func (ctx *APIContext) IsUserSiteAdmin() bool {
-       return ctx.IsSigned && ctx.Doer.IsAdmin
-}
-
-// IsUserRepoAdmin returns true if current user is admin in current repo
-func (ctx *APIContext) IsUserRepoAdmin() bool {
-       return ctx.Repo.IsAdmin()
-}
-
-// IsUserRepoWriter returns true if current user has write privilege in current repo
-func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool {
-       for _, unitType := range unitTypes {
-               if ctx.Repo.CanWrite(unitType) {
-                       return true
-               }
-       }
-
-       return false
-}
diff --git a/modules/context/api_org.go b/modules/context/api_org.go
deleted file mode 100644 (file)
index dad02b1..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 The Gogs Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import "code.gitea.io/gitea/models/organization"
-
-// APIOrganization contains organization and team
-type APIOrganization struct {
-       Organization *organization.Organization
-       Team         *organization.Team
-}
diff --git a/modules/context/api_test.go b/modules/context/api_test.go
deleted file mode 100644 (file)
index 911a499..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "net/url"
-       "strconv"
-       "testing"
-
-       "code.gitea.io/gitea/modules/setting"
-
-       "github.com/stretchr/testify/assert"
-)
-
-func TestGenAPILinks(t *testing.T) {
-       setting.AppURL = "http://localhost:3000/"
-       kases := map[string][]string{
-               "api/v1/repos/jerrykan/example-repo/issues?state=all": {
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=2&state=all>; rel="next"`,
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
-               },
-               "api/v1/repos/jerrykan/example-repo/issues?state=all&page=1": {
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=2&state=all>; rel="next"`,
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
-               },
-               "api/v1/repos/jerrykan/example-repo/issues?state=all&page=2": {
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=3&state=all>; rel="next"`,
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="first"`,
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="prev"`,
-               },
-               "api/v1/repos/jerrykan/example-repo/issues?state=all&page=5": {
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="first"`,
-                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=4&state=all>; rel="prev"`,
-               },
-       }
-
-       for req, response := range kases {
-               u, err := url.Parse(setting.AppURL + req)
-               assert.NoError(t, err)
-
-               p := u.Query().Get("page")
-               curPage, _ := strconv.Atoi(p)
-
-               links := genAPILinks(u, 100, 20, curPage)
-
-               assert.EqualValues(t, links, response)
-       }
-}
diff --git a/modules/context/base.go b/modules/context/base.go
deleted file mode 100644 (file)
index ddd04f4..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "context"
-       "fmt"
-       "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/translation"
-       "code.gitea.io/gitea/modules/util"
-       "code.gitea.io/gitea/modules/web/middleware"
-
-       "github.com/go-chi/chi/v5"
-)
-
-type contextValuePair struct {
-       key     any
-       valueFn func() any
-}
-
-type Base struct {
-       originCtx     context.Context
-       contextValues []contextValuePair
-
-       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
-
-       // 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")
-       if len(val) != 0 {
-               b.RespHeader().Set("Access-Control-Expose-Headers", fmt.Sprintf("%s, %s", val, strings.Join(names, ", ")))
-       } else {
-               b.RespHeader().Set("Access-Control-Expose-Headers", strings.Join(names, ", "))
-       }
-}
-
-// SetTotalCountHeader set "X-Total-Count" header
-func (b *Base) SetTotalCountHeader(total int64) {
-       b.RespHeader().Set("X-Total-Count", fmt.Sprint(total))
-       b.AppendAccessControlExposeHeaders("X-Total-Count")
-}
-
-// Written returns true if there are something sent to web browser
-func (b *Base) Written() bool {
-       return b.Resp.WrittenStatus() != 0
-}
-
-func (b *Base) WrittenStatus() int {
-       return b.Resp.WrittenStatus()
-}
-
-// Status writes status code
-func (b *Base) Status(status int) {
-       b.Resp.WriteHeader(status)
-}
-
-// Write writes data to web browser
-func (b *Base) Write(bs []byte) (int, error) {
-       return b.Resp.Write(bs)
-}
-
-// RespHeader returns the response header
-func (b *Base) RespHeader() http.Header {
-       return b.Resp.Header()
-}
-
-// Error returned an error to web browser
-func (b *Base) Error(status int, contents ...string) {
-       v := http.StatusText(status)
-       if len(contents) > 0 {
-               v = contents[0]
-       }
-       http.Error(b.Resp, v, status)
-}
-
-// JSON render content as JSON
-func (b *Base) JSON(status int, content any) {
-       b.Resp.Header().Set("Content-Type", "application/json;charset=utf-8")
-       b.Resp.WriteHeader(status)
-       if err := json.NewEncoder(b.Resp).Encode(content); err != nil {
-               log.Error("Render JSON failed: %v", err)
-       }
-}
-
-// RemoteAddr returns the client machine ip address
-func (b *Base) RemoteAddr() string {
-       return b.Req.RemoteAddr
-}
-
-// Params returns the param on route
-func (b *Base) Params(p string) string {
-       s, _ := url.PathUnescape(chi.URLParam(b.Req, strings.TrimPrefix(p, ":")))
-       return s
-}
-
-func (b *Base) PathParamRaw(p string) string {
-       return chi.URLParam(b.Req, strings.TrimPrefix(p, ":"))
-}
-
-// ParamsInt64 returns the param on route as int64
-func (b *Base) ParamsInt64(p string) int64 {
-       v, _ := strconv.ParseInt(b.Params(p), 10, 64)
-       return v
-}
-
-// SetParams set params into routes
-func (b *Base) SetParams(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 OptionalBoolTrue or OptionalBoolFalse if the value
-// for the provided key exists in the form else it returns OptionalBoolNone
-func (b *Base) FormOptionalBool(key string) util.OptionalBool {
-       value := b.Req.FormValue(key)
-       if len(value) == 0 {
-               return util.OptionalBoolNone
-       }
-       s := b.Req.FormValue(key)
-       v, _ := strconv.ParseBool(s)
-       v = v || strings.EqualFold(s, "on")
-       return util.OptionalBoolOf(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
-       if statusPrefix == 4 || statusPrefix == 5 {
-               log.Log(skip, log.TRACE, "plainTextInternal (status=%d): %s", status, string(bs))
-       }
-       b.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8")
-       b.Resp.Header().Set("X-Content-Type-Options", "nosniff")
-       b.Resp.WriteHeader(status)
-       if _, err := b.Resp.Write(bs); err != nil {
-               log.ErrorWithSkip(skip, "plainTextInternal (status=%d): write bytes failed: %v", status, err)
-       }
-}
-
-// PlainTextBytes renders bytes as plain text
-func (b *Base) PlainTextBytes(status int, bs []byte) {
-       b.plainTextInternal(2, status, bs)
-}
-
-// PlainText renders content as plain text
-func (b *Base) PlainText(status int, text string) {
-       b.plainTextInternal(2, status, []byte(text))
-}
-
-// Redirect redirects the request
-func (b *Base) Redirect(location string, status ...int) {
-       code := http.StatusSeeOther
-       if len(status) == 1 {
-               code = status[0]
-       }
-
-       if strings.Contains(location, "://") || strings.HasPrefix(location, "//") {
-               // Some browsers (Safari) have buggy behavior for Cookie + Cache + External Redirection, eg: /my-path => https://other/path
-               // 1. the first request to "/my-path" contains cookie
-               // 2. some time later, the request to "/my-path" doesn't contain cookie (caused by Prevent web tracking)
-               // 3. Gitea's Sessioner doesn't see the session cookie, so it generates a new session id, and returns it to browser
-               // 4. then the browser accepts the empty session, then the user is logged out
-               // So in this case, we should remove the session cookie from the response header
-               removeSessionCookieHeader(b.Resp)
-       }
-       // in case the request is made by htmx, have it redirect the browser instead of trying to follow the redirect inside htmx
-       if b.Req.Header.Get("HX-Request") == "true" {
-               b.Resp.Header().Set("HX-Redirect", location)
-               // we have to return a non-redirect status code so XMLHTTPRequest will not immediately follow the redirect
-               // so as to give htmx redirect logic a chance to run
-               b.Status(http.StatusNoContent)
-               return
-       }
-       http.Redirect(b.Resp, b.Req, location, code)
-}
-
-type ServeHeaderOptions httplib.ServeHeaderOptions
-
-func (b *Base) SetServeHeaders(opt *ServeHeaderOptions) {
-       httplib.ServeSetHeaders(b.Resp, (*httplib.ServeHeaderOptions)(opt))
-}
-
-// ServeContent serves content to http request
-func (b *Base) ServeContent(r io.ReadSeeker, opts *ServeHeaderOptions) {
-       httplib.ServeSetHeaders(b.Resp, (*httplib.ServeHeaderOptions)(opts))
-       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...)
-}
-
-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()),
-       }
-       b.AppendContextValue(translation.ContextKey, b.Locale)
-       b.Req = b.Req.WithContext(b)
-       return b, b.cleanUp
-}
diff --git a/modules/context/captcha.go b/modules/context/captcha.go
deleted file mode 100644 (file)
index a199990..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-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/turnstile"
-
-       "gitea.com/go-chi/captcha"
-)
-
-var (
-       imageCaptchaOnce sync.Once
-       cpt              *captcha.Captcha
-)
-
-// GetImageCaptcha returns global image captcha
-func GetImageCaptcha() *captcha.Captcha {
-       imageCaptchaOnce.Do(func() {
-               cpt = captcha.NewCaptcha(captcha.Options{
-                       SubURL: setting.AppSubURL,
-               })
-               cpt.Store = cache.GetCache()
-       })
-       return cpt
-}
-
-// SetCaptchaData sets common captcha data
-func SetCaptchaData(ctx *Context) {
-       if !setting.Service.EnableCaptcha {
-               return
-       }
-       ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
-       ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
-       ctx.Data["Captcha"] = GetImageCaptcha()
-       ctx.Data["CaptchaType"] = setting.Service.CaptchaType
-       ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
-       ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
-       ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
-       ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
-       ctx.Data["CfTurnstileSitekey"] = setting.Service.CfTurnstileSitekey
-}
-
-const (
-       gRecaptchaResponseField  = "g-recaptcha-response"
-       hCaptchaResponseField    = "h-captcha-response"
-       mCaptchaResponseField    = "m-captcha-response"
-       cfTurnstileResponseField = "cf-turnstile-response"
-)
-
-// VerifyCaptcha verifies Captcha data
-// No-op if captchas are not enabled
-func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) {
-       if !setting.Service.EnableCaptcha {
-               return
-       }
-
-       var valid bool
-       var err error
-       switch setting.Service.CaptchaType {
-       case setting.ImageCaptcha:
-               valid = GetImageCaptcha().VerifyReq(ctx.Req)
-       case setting.ReCaptcha:
-               valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField))
-       case setting.HCaptcha:
-               valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(hCaptchaResponseField))
-       case setting.MCaptcha:
-               valid, err = mcaptcha.Verify(ctx, ctx.Req.Form.Get(mCaptchaResponseField))
-       case setting.CfTurnstile:
-               valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField))
-       default:
-               ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
-               return
-       }
-       if err != nil {
-               log.Debug("%v", err)
-       }
-
-       if !valid {
-               ctx.Data["Err_Captcha"] = true
-               ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, form)
-       }
-}
diff --git a/modules/context/context.go b/modules/context/context.go
deleted file mode 100644 (file)
index 4b318f7..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "context"
-       "encoding/hex"
-       "fmt"
-       "html/template"
-       "io"
-       "net/http"
-       "net/url"
-       "strings"
-       "time"
-
-       "code.gitea.io/gitea/models/unit"
-       user_model "code.gitea.io/gitea/models/user"
-       mc "code.gitea.io/gitea/modules/cache"
-       "code.gitea.io/gitea/modules/gitrepo"
-       "code.gitea.io/gitea/modules/httpcache"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/templates"
-       "code.gitea.io/gitea/modules/translation"
-       "code.gitea.io/gitea/modules/web"
-       "code.gitea.io/gitea/modules/web/middleware"
-       web_types "code.gitea.io/gitea/modules/web/types"
-
-       "gitea.com/go-chi/cache"
-       "gitea.com/go-chi/session"
-)
-
-// 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
-}
-
-// Context represents context of a request.
-type Context struct {
-       *Base
-
-       TemplateContext TemplateContext
-
-       Render   Render
-       PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
-
-       Cache   cache.Cache
-       Csrf    CSRFProtector
-       Flash   *middleware.Flash
-       Session session.Store
-
-       Link string // current request URL (without query string)
-
-       Doer        *user_model.User // current signed-in user
-       IsSigned    bool
-       IsBasicAuth bool
-
-       ContextUser *user_model.User // the user which is being visited, in most cases it differs from Doer
-
-       Repo    *Repository
-       Org     *Organization
-       Package *Package
-}
-
-type TemplateContext map[string]any
-
-func init() {
-       web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider {
-               return req.Context().Value(WebContextKey).(*Context)
-       })
-}
-
-type webContextKeyType struct{}
-
-var WebContextKey = webContextKeyType{}
-
-func GetWebContext(req *http.Request) *Context {
-       ctx, _ := req.Context().Value(WebContextKey).(*Context)
-       return ctx
-}
-
-// ValidateContext is a special context for form validation middleware. It may be different from other contexts.
-type ValidateContext struct {
-       *Base
-}
-
-// GetValidateContext gets a context for middleware form validation
-func GetValidateContext(req *http.Request) (ctx *ValidateContext) {
-       if ctxAPI, ok := req.Context().Value(apiContextKey).(*APIContext); ok {
-               ctx = &ValidateContext{Base: ctxAPI.Base}
-       } else if ctxWeb, ok := req.Context().Value(WebContextKey).(*Context); ok {
-               ctx = &ValidateContext{Base: ctxWeb.Base}
-       } else {
-               panic("invalid context, expect either APIContext or Context")
-       }
-       return ctx
-}
-
-func NewTemplateContextForWeb(ctx *Context) TemplateContext {
-       tmplCtx := NewTemplateContext(ctx)
-       tmplCtx["Locale"] = ctx.Base.Locale
-       tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx)
-       return tmplCtx
-}
-
-func NewWebContext(base *Base, render Render, session session.Store) *Context {
-       ctx := &Context{
-               Base:    base,
-               Render:  render,
-               Session: session,
-
-               Cache: mc.GetCache(),
-               Link:  setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
-               Repo:  &Repository{PullRequest: &PullRequest{}},
-               Org:   &Organization{},
-       }
-       ctx.TemplateContext = NewTemplateContextForWeb(ctx)
-       ctx.Flash = &middleware.Flash{DataStore: ctx, Values: url.Values{}}
-       return ctx
-}
-
-// Contexter initializes a classic context for a request.
-func Contexter() func(next http.Handler) http.Handler {
-       rnd := templates.HTMLRenderer()
-       csrfOpts := CsrfOptions{
-               Secret:         hex.EncodeToString(setting.GetGeneralTokenSigningSecret()),
-               Cookie:         setting.CSRFCookieName,
-               SetCookie:      true,
-               Secure:         setting.SessionConfig.Secure,
-               CookieHTTPOnly: setting.CSRFCookieHTTPOnly,
-               Header:         "X-Csrf-Token",
-               CookieDomain:   setting.SessionConfig.Domain,
-               CookiePath:     setting.SessionConfig.CookiePath,
-               SameSite:       setting.SessionConfig.SameSite,
-       }
-       if !setting.IsProd {
-               CsrfTokenRegenerationInterval = 5 * time.Second // in dev, re-generate the tokens more aggressively for debug purpose
-       }
-       return func(next http.Handler) http.Handler {
-               return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
-                       base, baseCleanUp := NewBaseContext(resp, req)
-                       defer baseCleanUp()
-                       ctx := NewWebContext(base, rnd, session.GetSession(req))
-
-                       ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
-                       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
-
-                       // PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules
-                       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.Csrf = PrepareCSRFProtector(csrfOpts, ctx)
-
-                       // Get the last flash message from cookie
-                       lastFlashCookie := middleware.GetSiteCookie(ctx.Req, CookieNameFlash)
-                       if vals, _ := url.ParseQuery(lastFlashCookie); len(vals) > 0 {
-                               // store last Flash message into the template data, to render it
-                               ctx.Data["Flash"] = &middleware.Flash{
-                                       DataStore:  ctx,
-                                       Values:     vals,
-                                       ErrorMsg:   vals.Get("error"),
-                                       SuccessMsg: vals.Get("success"),
-                                       InfoMsg:    vals.Get("info"),
-                                       WarningMsg: vals.Get("warning"),
-                               }
-                       }
-
-                       // if there are new messages in the ctx.Flash, write them into cookie
-                       ctx.Resp.Before(func(resp ResponseWriter) {
-                               if val := ctx.Flash.Encode(); val != "" {
-                                       middleware.SetSiteCookie(ctx.Resp, CookieNameFlash, val, 0)
-                               } else if lastFlashCookie != "" {
-                                       middleware.SetSiteCookie(ctx.Resp, CookieNameFlash, "", -1)
-                               }
-                       })
-
-                       // 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") {
-                               if err := ctx.Req.ParseMultipartForm(setting.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
-                                       ctx.ServerError("ParseMultipartForm", err)
-                                       return
-                               }
-                       }
-
-                       httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
-                       ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
-
-                       ctx.Data["SystemConfig"] = setting.Config()
-                       ctx.Data["CsrfToken"] = ctx.Csrf.GetToken()
-                       ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.Data["CsrfToken"].(string) + `">`)
-
-                       // FIXME: do we really always need these setting? There should be someway to have to avoid having to always set these
-                       ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
-                       ctx.Data["DisableStars"] = setting.Repository.DisableStars
-                       ctx.Data["EnableActions"] = setting.Actions.Enabled
-
-                       ctx.Data["ManifestData"] = setting.ManifestData
-
-                       ctx.Data["UnitWikiGlobalDisabled"] = unit.TypeWiki.UnitGlobalDisabled()
-                       ctx.Data["UnitIssuesGlobalDisabled"] = unit.TypeIssues.UnitGlobalDisabled()
-                       ctx.Data["UnitPullsGlobalDisabled"] = unit.TypePullRequests.UnitGlobalDisabled()
-                       ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
-                       ctx.Data["UnitActionsGlobalDisabled"] = unit.TypeActions.UnitGlobalDisabled()
-
-                       ctx.Data["AllLangs"] = translation.AllLangs()
-
-                       next.ServeHTTP(ctx.Resp, ctx.Req)
-               })
-       }
-}
-
-// HasError returns true if error occurs in form validation.
-// Attention: this function changes ctx.Data and ctx.Flash
-func (ctx *Context) HasError() bool {
-       hasErr, ok := ctx.Data["HasError"]
-       if !ok {
-               return false
-       }
-       ctx.Flash.ErrorMsg = ctx.GetErrMsg()
-       ctx.Data["Flash"] = ctx.Flash
-       return hasErr.(bool)
-}
-
-// GetErrMsg returns error message in form validation.
-func (ctx *Context) GetErrMsg() string {
-       msg, _ := ctx.Data["ErrorMsg"].(string)
-       if msg == "" {
-               msg = "invalid form data"
-       }
-       return msg
-}
-
-func (ctx *Context) JSONRedirect(redirect string) {
-       ctx.JSON(http.StatusOK, map[string]any{"redirect": redirect})
-}
-
-func (ctx *Context) JSONOK() {
-       ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
-}
-
-func (ctx *Context) JSONError(msg any) {
-       switch v := msg.(type) {
-       case string:
-               ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "text"})
-       case template.HTML:
-               ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "html"})
-       default:
-               panic(fmt.Sprintf("unsupported type: %T", msg))
-       }
-}
diff --git a/modules/context/context_cookie.go b/modules/context/context_cookie.go
deleted file mode 100644 (file)
index b6f8dad..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "net/http"
-       "strings"
-
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/web/middleware"
-)
-
-const CookieNameFlash = "gitea_flash"
-
-func removeSessionCookieHeader(w http.ResponseWriter) {
-       cookies := w.Header()["Set-Cookie"]
-       w.Header().Del("Set-Cookie")
-       for _, cookie := range cookies {
-               if strings.HasPrefix(cookie, setting.SessionConfig.CookieName+"=") {
-                       continue
-               }
-               w.Header().Add("Set-Cookie", cookie)
-       }
-}
-
-// SetSiteCookie convenience function to set most cookies consistently
-// CSRF and a few others are the exception here
-func (ctx *Context) SetSiteCookie(name, value string, maxAge int) {
-       middleware.SetSiteCookie(ctx.Resp, name, value, maxAge)
-}
-
-// DeleteSiteCookie convenience function to delete most cookies consistently
-// CSRF and a few others are the exception here
-func (ctx *Context) DeleteSiteCookie(name string) {
-       middleware.SetSiteCookie(ctx.Resp, name, "", -1)
-}
-
-// GetSiteCookie returns given cookie value from request header.
-func (ctx *Context) GetSiteCookie(name string) string {
-       return middleware.GetSiteCookie(ctx.Req, name)
-}
diff --git a/modules/context/context_model.go b/modules/context/context_model.go
deleted file mode 100644 (file)
index 4f70aac..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "code.gitea.io/gitea/models/unit"
-)
-
-// IsUserSiteAdmin returns true if current user is a site admin
-func (ctx *Context) IsUserSiteAdmin() bool {
-       return ctx.IsSigned && ctx.Doer.IsAdmin
-}
-
-// IsUserRepoAdmin returns true if current user is admin in current repo
-func (ctx *Context) IsUserRepoAdmin() bool {
-       return ctx.Repo.IsAdmin()
-}
-
-// IsUserRepoWriter returns true if current user has write privilege in current repo
-func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool {
-       for _, unitType := range unitTypes {
-               if ctx.Repo.CanWrite(unitType) {
-                       return true
-               }
-       }
-
-       return false
-}
diff --git a/modules/context/context_request.go b/modules/context/context_request.go
deleted file mode 100644 (file)
index 984b9ac..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "io"
-       "net/http"
-       "strings"
-)
-
-// UploadStream returns the request body or the first form file
-// Only form files need to get closed.
-func (ctx *Context) UploadStream() (rd io.ReadCloser, needToClose bool, err error) {
-       contentType := strings.ToLower(ctx.Req.Header.Get("Content-Type"))
-       if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") || strings.HasPrefix(contentType, "multipart/form-data") {
-               if err := ctx.Req.ParseMultipartForm(32 << 20); err != nil {
-                       return nil, false, err
-               }
-               if ctx.Req.MultipartForm.File == nil {
-                       return nil, false, http.ErrMissingFile
-               }
-               for _, files := range ctx.Req.MultipartForm.File {
-                       if len(files) > 0 {
-                               r, err := files[0].Open()
-                               return r, true, err
-                       }
-               }
-               return nil, false, http.ErrMissingFile
-       }
-       return ctx.Req.Body, false, nil
-}
diff --git a/modules/context/context_response.go b/modules/context/context_response.go
deleted file mode 100644 (file)
index 829bca1..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "errors"
-       "fmt"
-       "net"
-       "net/http"
-       "net/url"
-       "path"
-       "strconv"
-       "strings"
-       "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"
-       "code.gitea.io/gitea/modules/templates"
-       "code.gitea.io/gitea/modules/web/middleware"
-)
-
-// RedirectToUser redirect to a differently-named user
-func RedirectToUser(ctx *Base, userName string, redirectUserID int64) {
-       user, err := user_model.GetUserByID(ctx, redirectUserID)
-       if err != nil {
-               ctx.Error(http.StatusInternalServerError, "unable to get user")
-               return
-       }
-
-       redirectPath := strings.Replace(
-               ctx.Req.URL.EscapedPath(),
-               url.PathEscape(userName),
-               url.PathEscape(user.Name),
-               1,
-       )
-       if ctx.Req.URL.RawQuery != "" {
-               redirectPath += "?" + ctx.Req.URL.RawQuery
-       }
-       ctx.Redirect(path.Join(setting.AppSubURL, redirectPath), http.StatusTemporaryRedirect)
-}
-
-// RedirectToFirst redirects to first not empty URL
-func (ctx *Context) RedirectToFirst(location ...string) {
-       for _, loc := range location {
-               if len(loc) == 0 {
-                       continue
-               }
-
-               if httplib.IsRiskyRedirectURL(loc) {
-                       continue
-               }
-
-               ctx.Redirect(loc)
-               return
-       }
-
-       ctx.Redirect(setting.AppSubURL + "/")
-}
-
-const tplStatus500 base.TplName = "status/500"
-
-// HTML calls Context.HTML and renders the template to HTTP response
-func (ctx *Context) HTML(status int, name base.TplName) {
-       log.Debug("Template: %s", name)
-
-       tmplStartTime := time.Now()
-       if !setting.IsProd {
-               ctx.Data["TemplateName"] = name
-       }
-       ctx.Data["TemplateLoadTimes"] = func() string {
-               return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
-       }
-
-       err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext)
-       if err == nil {
-               return
-       }
-
-       // if rendering fails, show error page
-       if name != tplStatus500 {
-               err = fmt.Errorf("failed to render template: %s, error: %s", name, templates.HandleTemplateRenderingError(err))
-               ctx.ServerError("Render failed", err) // show the 500 error page
-       } else {
-               ctx.PlainText(http.StatusInternalServerError, "Unable to render status/500 page, the template system is broken, or Gitea can't find your template files.")
-               return
-       }
-}
-
-// 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) {
-       t, err := ctx.Render.TemplateLookup(string(tmpl), nil)
-       if err != nil {
-               ctx.ServerError("unable to find template", err)
-               return
-       }
-       ctx.Resp.Header().Set("Content-Type", "application/json")
-       if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
-               ctx.ServerError("unable to execute template", err)
-       }
-}
-
-// RenderToString renders the template content to a string
-func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
-       var buf strings.Builder
-       err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data, ctx.TemplateContext)
-       return 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) {
-       if form != nil {
-               middleware.AssignForm(form, ctx.Data)
-       }
-       ctx.Flash.Error(msg, true)
-       ctx.HTML(http.StatusOK, tpl)
-}
-
-// NotFound displays a 404 (Not Found) page and prints the given error, if any.
-func (ctx *Context) NotFound(logMsg string, logErr error) {
-       ctx.notFoundInternal(logMsg, logErr)
-}
-
-func (ctx *Context) notFoundInternal(logMsg string, logErr error) {
-       if logErr != nil {
-               log.Log(2, log.DEBUG, "%s: %v", logMsg, logErr)
-               if !setting.IsProd {
-                       ctx.Data["ErrorMsg"] = logErr
-               }
-       }
-
-       // response simple message if Accept isn't text/html
-       showHTML := false
-       for _, part := range ctx.Req.Header["Accept"] {
-               if strings.Contains(part, "text/html") {
-                       showHTML = true
-                       break
-               }
-       }
-
-       if !showHTML {
-               ctx.plainTextInternal(3, http.StatusNotFound, []byte("Not found.\n"))
-               return
-       }
-
-       ctx.Data["IsRepo"] = ctx.Repo.Repository != nil
-       ctx.Data["Title"] = "Page Not Found"
-       ctx.HTML(http.StatusNotFound, base.TplName("status/404"))
-}
-
-// ServerError displays a 500 (Internal Server Error) page and prints the given error, if any.
-func (ctx *Context) ServerError(logMsg string, logErr error) {
-       ctx.serverErrorInternal(logMsg, logErr)
-}
-
-func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
-       if logErr != nil {
-               log.ErrorWithSkip(2, "%s: %v", logMsg, logErr)
-               if _, ok := logErr.(*net.OpError); ok || errors.Is(logErr, &net.OpError{}) {
-                       // This is an error within the underlying connection
-                       // and further rendering will not work so just return
-                       return
-               }
-
-               // it's safe to show internal error to admin users, and it helps
-               if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
-                       ctx.Data["ErrorMsg"] = fmt.Sprintf("%s, %s", logMsg, logErr)
-               }
-       }
-
-       ctx.Data["Title"] = "Internal Server Error"
-       ctx.HTML(http.StatusInternalServerError, tplStatus500)
-}
-
-// NotFoundOrServerError use error check function to determine if the error
-// is about not found. It responds with 404 status code for not found error,
-// or error context description for logging purpose of 500 server error.
-// TODO: remove the "errCheck" and use util.ErrNotFound to check
-func (ctx *Context) NotFoundOrServerError(logMsg string, errCheck func(error) bool, logErr error) {
-       if errCheck(logErr) {
-               ctx.notFoundInternal(logMsg, logErr)
-               return
-       }
-       ctx.serverErrorInternal(logMsg, logErr)
-}
diff --git a/modules/context/context_template.go b/modules/context/context_template.go
deleted file mode 100644 (file)
index 7878d40..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "context"
-       "time"
-)
-
-var _ context.Context = TemplateContext(nil)
-
-func NewTemplateContext(ctx context.Context) TemplateContext {
-       return TemplateContext{"_ctx": ctx}
-}
-
-func (c TemplateContext) parentContext() context.Context {
-       return c["_ctx"].(context.Context)
-}
-
-func (c TemplateContext) Deadline() (deadline time.Time, ok bool) {
-       return c.parentContext().Deadline()
-}
-
-func (c TemplateContext) Done() <-chan struct{} {
-       return c.parentContext().Done()
-}
-
-func (c TemplateContext) Err() error {
-       return c.parentContext().Err()
-}
-
-func (c TemplateContext) Value(key any) any {
-       return c.parentContext().Value(key)
-}
diff --git a/modules/context/context_test.go b/modules/context/context_test.go
deleted file mode 100644 (file)
index 033ce2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "net/http"
-       "net/http/httptest"
-       "testing"
-
-       "code.gitea.io/gitea/modules/setting"
-
-       "github.com/stretchr/testify/assert"
-)
-
-func TestRemoveSessionCookieHeader(t *testing.T) {
-       w := httptest.NewRecorder()
-       w.Header().Add("Set-Cookie", (&http.Cookie{Name: setting.SessionConfig.CookieName, Value: "foo"}).String())
-       w.Header().Add("Set-Cookie", (&http.Cookie{Name: "other", Value: "bar"}).String())
-       assert.Len(t, w.Header().Values("Set-Cookie"), 2)
-       removeSessionCookieHeader(w)
-       assert.Len(t, w.Header().Values("Set-Cookie"), 1)
-       assert.Contains(t, "other=bar", w.Header().Get("Set-Cookie"))
-}
diff --git a/modules/context/csrf.go b/modules/context/csrf.go
deleted file mode 100644 (file)
index 9b0dc29..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright 2013 Martini Authors
-// Copyright 2014 The Macaron Authors
-// Copyright 2021 The Gitea Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License"): you may
-// not use this file except in compliance with the License. You may obtain
-// a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations
-// under the License.
-// SPDX-License-Identifier: Apache-2.0
-
-// a middleware that generates and validates CSRF tokens.
-
-package context
-
-import (
-       "encoding/base32"
-       "fmt"
-       "net/http"
-       "strconv"
-       "time"
-
-       "code.gitea.io/gitea/modules/log"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/util"
-       "code.gitea.io/gitea/modules/web/middleware"
-)
-
-// CSRFProtector represents a CSRF protector and is used to get the current token and validate the token.
-type CSRFProtector interface {
-       // GetHeaderName returns HTTP header to search for token.
-       GetHeaderName() string
-       // GetFormName returns form value to search for token.
-       GetFormName() string
-       // GetToken returns the token.
-       GetToken() string
-       // Validate validates the token in http context.
-       Validate(ctx *Context)
-       // DeleteCookie deletes the cookie
-       DeleteCookie(ctx *Context)
-}
-
-type csrfProtector struct {
-       opt CsrfOptions
-       // Token generated to pass via header, cookie, or hidden form value.
-       Token string
-       // This value must be unique per user.
-       ID string
-}
-
-// GetHeaderName returns the name of the HTTP header for csrf token.
-func (c *csrfProtector) GetHeaderName() string {
-       return c.opt.Header
-}
-
-// GetFormName returns the name of the form value for csrf token.
-func (c *csrfProtector) GetFormName() string {
-       return c.opt.Form
-}
-
-// GetToken returns the current token. This is typically used
-// to populate a hidden form in an HTML template.
-func (c *csrfProtector) GetToken() string {
-       return c.Token
-}
-
-// CsrfOptions maintains options to manage behavior of Generate.
-type CsrfOptions struct {
-       // The global secret value used to generate Tokens.
-       Secret string
-       // HTTP header used to set and get token.
-       Header string
-       // Form value used to set and get token.
-       Form string
-       // Cookie value used to set and get token.
-       Cookie string
-       // Cookie domain.
-       CookieDomain string
-       // Cookie path.
-       CookiePath     string
-       CookieHTTPOnly bool
-       // SameSite set the cookie SameSite type
-       SameSite http.SameSite
-       // Key used for getting the unique ID per user.
-       SessionKey string
-       // oldSessionKey saves old value corresponding to SessionKey.
-       oldSessionKey string
-       // If true, send token via X-Csrf-Token header.
-       SetHeader bool
-       // If true, send token via _csrf cookie.
-       SetCookie bool
-       // Set the Secure flag to true on the cookie.
-       Secure bool
-       // Disallow Origin appear in request header.
-       Origin bool
-       // Cookie lifetime. Default is 0
-       CookieLifeTime int
-}
-
-func prepareDefaultCsrfOptions(opt CsrfOptions) CsrfOptions {
-       if opt.Secret == "" {
-               randBytes, err := util.CryptoRandomBytes(8)
-               if err != nil {
-                       // this panic can be handled by the recover() in http handlers
-                       panic(fmt.Errorf("failed to generate random bytes: %w", err))
-               }
-               opt.Secret = base32.StdEncoding.EncodeToString(randBytes)
-       }
-       if opt.Header == "" {
-               opt.Header = "X-Csrf-Token"
-       }
-       if opt.Form == "" {
-               opt.Form = "_csrf"
-       }
-       if opt.Cookie == "" {
-               opt.Cookie = "_csrf"
-       }
-       if opt.CookiePath == "" {
-               opt.CookiePath = "/"
-       }
-       if opt.SessionKey == "" {
-               opt.SessionKey = "uid"
-       }
-       if opt.CookieLifeTime == 0 {
-               opt.CookieLifeTime = int(CsrfTokenTimeout.Seconds())
-       }
-
-       opt.oldSessionKey = "_old_" + opt.SessionKey
-       return opt
-}
-
-func newCsrfCookie(c *csrfProtector, value string) *http.Cookie {
-       return &http.Cookie{
-               Name:     c.opt.Cookie,
-               Value:    value,
-               Path:     c.opt.CookiePath,
-               Domain:   c.opt.CookieDomain,
-               MaxAge:   c.opt.CookieLifeTime,
-               Secure:   c.opt.Secure,
-               HttpOnly: c.opt.CookieHTTPOnly,
-               SameSite: c.opt.SameSite,
-       }
-}
-
-// PrepareCSRFProtector returns a CSRFProtector to be used for every request.
-// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
-func PrepareCSRFProtector(opt CsrfOptions, ctx *Context) CSRFProtector {
-       opt = prepareDefaultCsrfOptions(opt)
-       x := &csrfProtector{opt: opt}
-
-       if opt.Origin && len(ctx.Req.Header.Get("Origin")) > 0 {
-               return x
-       }
-
-       x.ID = "0"
-       uidAny := ctx.Session.Get(opt.SessionKey)
-       if uidAny != nil {
-               switch uidVal := uidAny.(type) {
-               case string:
-                       x.ID = uidVal
-               case int64:
-                       x.ID = strconv.FormatInt(uidVal, 10)
-               default:
-                       log.Error("invalid uid type in session: %T", uidAny)
-               }
-       }
-
-       oldUID := ctx.Session.Get(opt.oldSessionKey)
-       uidChanged := oldUID == nil || oldUID.(string) != x.ID
-       cookieToken := ctx.GetSiteCookie(opt.Cookie)
-
-       needsNew := true
-       if uidChanged {
-               _ = ctx.Session.Set(opt.oldSessionKey, x.ID)
-       } else if cookieToken != "" {
-               // If cookie token presents, re-use existing unexpired token, else generate a new one.
-               if issueTime, ok := ParseCsrfToken(cookieToken); ok {
-                       dur := time.Since(issueTime) // issueTime is not a monotonic-clock, the server time may change a lot to an early time.
-                       if dur >= -CsrfTokenRegenerationInterval && dur <= CsrfTokenRegenerationInterval {
-                               x.Token = cookieToken
-                               needsNew = false
-                       }
-               }
-       }
-
-       if needsNew {
-               // FIXME: actionId.
-               x.Token = GenerateCsrfToken(x.opt.Secret, x.ID, "POST", time.Now())
-               if opt.SetCookie {
-                       cookie := newCsrfCookie(x, x.Token)
-                       ctx.Resp.Header().Add("Set-Cookie", cookie.String())
-               }
-       }
-
-       if opt.SetHeader {
-               ctx.Resp.Header().Add(opt.Header, x.Token)
-       }
-       return x
-}
-
-func (c *csrfProtector) validateToken(ctx *Context, token string) {
-       if !ValidCsrfToken(token, c.opt.Secret, c.ID, "POST", time.Now()) {
-               c.DeleteCookie(ctx)
-               if middleware.IsAPIPath(ctx.Req) {
-                       // currently, there should be no access to the APIPath with CSRF token. because templates shouldn't use the `/api/` endpoints.
-                       http.Error(ctx.Resp, "Invalid CSRF token.", http.StatusBadRequest)
-               } else {
-                       ctx.Flash.Error(ctx.Tr("error.invalid_csrf"))
-                       ctx.Redirect(setting.AppSubURL + "/")
-               }
-       }
-}
-
-// Validate should be used as a per route middleware. It attempts to get a token from an "X-Csrf-Token"
-// HTTP header and then a "_csrf" form value. If one of these is found, the token will be validated.
-// If this validation fails, custom Error is sent in the reply.
-// If neither a header nor form value is found, http.StatusBadRequest is sent.
-func (c *csrfProtector) Validate(ctx *Context) {
-       if token := ctx.Req.Header.Get(c.GetHeaderName()); token != "" {
-               c.validateToken(ctx, token)
-               return
-       }
-       if token := ctx.Req.FormValue(c.GetFormName()); token != "" {
-               c.validateToken(ctx, token)
-               return
-       }
-       c.validateToken(ctx, "") // no csrf token, use an empty token to respond error
-}
-
-func (c *csrfProtector) DeleteCookie(ctx *Context) {
-       if c.opt.SetCookie {
-               cookie := newCsrfCookie(c, "")
-               cookie.MaxAge = -1
-               ctx.Resp.Header().Add("Set-Cookie", cookie.String())
-       }
-}
diff --git a/modules/context/org.go b/modules/context/org.go
deleted file mode 100644 (file)
index 018b76d..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Copyright 2020 The Gitea Authors.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "strings"
-
-       "code.gitea.io/gitea/models/organization"
-       "code.gitea.io/gitea/models/perm"
-       "code.gitea.io/gitea/models/unit"
-       user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/markup"
-       "code.gitea.io/gitea/modules/markup/markdown"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/structs"
-)
-
-// Organization contains organization context
-type Organization struct {
-       IsOwner          bool
-       IsMember         bool
-       IsTeamMember     bool // Is member of team.
-       IsTeamAdmin      bool // In owner team or team that has admin permission level.
-       Organization     *organization.Organization
-       OrgLink          string
-       CanCreateOrgRepo bool
-       PublicMemberOnly bool // Only display public members
-
-       Team  *organization.Team
-       Teams []*organization.Team
-}
-
-func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool {
-       return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeWrite
-}
-
-func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool {
-       return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeRead
-}
-
-func GetOrganizationByParams(ctx *Context) {
-       orgName := ctx.Params(":org")
-
-       var err error
-
-       ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
-       if err != nil {
-               if organization.IsErrOrgNotExist(err) {
-                       redirectUserID, err := user_model.LookupUserRedirect(ctx, orgName)
-                       if err == nil {
-                               RedirectToUser(ctx.Base, orgName, redirectUserID)
-                       } else if user_model.IsErrUserRedirectNotExist(err) {
-                               ctx.NotFound("GetUserByName", err)
-                       } else {
-                               ctx.ServerError("LookupUserRedirect", err)
-                       }
-               } else {
-                       ctx.ServerError("GetUserByName", err)
-               }
-               return
-       }
-}
-
-// HandleOrgAssignment handles organization assignment
-func HandleOrgAssignment(ctx *Context, args ...bool) {
-       var (
-               requireMember     bool
-               requireOwner      bool
-               requireTeamMember bool
-               requireTeamAdmin  bool
-       )
-       if len(args) >= 1 {
-               requireMember = args[0]
-       }
-       if len(args) >= 2 {
-               requireOwner = args[1]
-       }
-       if len(args) >= 3 {
-               requireTeamMember = args[2]
-       }
-       if len(args) >= 4 {
-               requireTeamAdmin = args[3]
-       }
-
-       var err error
-
-       if ctx.ContextUser == nil {
-               // if Organization is not defined, get it from params
-               if ctx.Org.Organization == nil {
-                       GetOrganizationByParams(ctx)
-                       if ctx.Written() {
-                               return
-                       }
-               }
-       } else if ctx.ContextUser.IsOrganization() {
-               if ctx.Org == nil {
-                       ctx.Org = &Organization{}
-               }
-               ctx.Org.Organization = (*organization.Organization)(ctx.ContextUser)
-       } else {
-               // ContextUser is an individual User
-               return
-       }
-
-       org := ctx.Org.Organization
-
-       // Handle Visibility
-       if org.Visibility != structs.VisibleTypePublic && !ctx.IsSigned {
-               // We must be signed in to see limited or private organizations
-               ctx.NotFound("OrgAssignment", err)
-               return
-       }
-
-       if org.Visibility == structs.VisibleTypePrivate {
-               requireMember = true
-       } else if ctx.IsSigned && ctx.Doer.IsRestricted {
-               requireMember = true
-       }
-
-       ctx.ContextUser = org.AsUser()
-       ctx.Data["Org"] = org
-
-       // Admin has super access.
-       if ctx.IsSigned && ctx.Doer.IsAdmin {
-               ctx.Org.IsOwner = true
-               ctx.Org.IsMember = true
-               ctx.Org.IsTeamMember = true
-               ctx.Org.IsTeamAdmin = true
-               ctx.Org.CanCreateOrgRepo = true
-       } else if ctx.IsSigned {
-               ctx.Org.IsOwner, err = org.IsOwnedBy(ctx, ctx.Doer.ID)
-               if err != nil {
-                       ctx.ServerError("IsOwnedBy", err)
-                       return
-               }
-
-               if ctx.Org.IsOwner {
-                       ctx.Org.IsMember = true
-                       ctx.Org.IsTeamMember = true
-                       ctx.Org.IsTeamAdmin = true
-                       ctx.Org.CanCreateOrgRepo = true
-               } else {
-                       ctx.Org.IsMember, err = org.IsOrgMember(ctx, ctx.Doer.ID)
-                       if err != nil {
-                               ctx.ServerError("IsOrgMember", err)
-                               return
-                       }
-                       ctx.Org.CanCreateOrgRepo, err = org.CanCreateOrgRepo(ctx, ctx.Doer.ID)
-                       if err != nil {
-                               ctx.ServerError("CanCreateOrgRepo", err)
-                               return
-                       }
-               }
-       } else {
-               // Fake data.
-               ctx.Data["SignedUser"] = &user_model.User{}
-       }
-       if (requireMember && !ctx.Org.IsMember) ||
-               (requireOwner && !ctx.Org.IsOwner) {
-               ctx.NotFound("OrgAssignment", err)
-               return
-       }
-       ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
-       ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
-       ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
-       ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
-       ctx.Data["IsPublicMember"] = func(uid int64) bool {
-               is, _ := organization.IsPublicMembership(ctx, ctx.Org.Organization.ID, uid)
-               return is
-       }
-       ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo
-
-       ctx.Org.OrgLink = org.AsUser().OrganisationLink()
-       ctx.Data["OrgLink"] = ctx.Org.OrgLink
-
-       // Member
-       ctx.Org.PublicMemberOnly = ctx.Doer == nil || !ctx.Org.IsMember && !ctx.Doer.IsAdmin
-       opts := &organization.FindOrgMembersOpts{
-               OrgID:      org.ID,
-               PublicOnly: ctx.Org.PublicMemberOnly,
-       }
-       ctx.Data["NumMembers"], err = organization.CountOrgMembers(ctx, opts)
-       if err != nil {
-               ctx.ServerError("CountOrgMembers", err)
-               return
-       }
-
-       // Team.
-       if ctx.Org.IsMember {
-               shouldSeeAllTeams := false
-               if ctx.Org.IsOwner {
-                       shouldSeeAllTeams = true
-               } else {
-                       teams, err := org.GetUserTeams(ctx, ctx.Doer.ID)
-                       if err != nil {
-                               ctx.ServerError("GetUserTeams", err)
-                               return
-                       }
-                       for _, team := range teams {
-                               if team.IncludesAllRepositories && team.AccessMode >= perm.AccessModeAdmin {
-                                       shouldSeeAllTeams = true
-                                       break
-                               }
-                       }
-               }
-               if shouldSeeAllTeams {
-                       ctx.Org.Teams, err = org.LoadTeams(ctx)
-                       if err != nil {
-                               ctx.ServerError("LoadTeams", err)
-                               return
-                       }
-               } else {
-                       ctx.Org.Teams, err = org.GetUserTeams(ctx, ctx.Doer.ID)
-                       if err != nil {
-                               ctx.ServerError("GetUserTeams", err)
-                               return
-                       }
-               }
-               ctx.Data["NumTeams"] = len(ctx.Org.Teams)
-       }
-
-       teamName := ctx.Params(":team")
-       if len(teamName) > 0 {
-               teamExists := false
-               for _, team := range ctx.Org.Teams {
-                       if team.LowerName == strings.ToLower(teamName) {
-                               teamExists = true
-                               ctx.Org.Team = team
-                               ctx.Org.IsTeamMember = true
-                               ctx.Data["Team"] = ctx.Org.Team
-                               break
-                       }
-               }
-
-               if !teamExists {
-                       ctx.NotFound("OrgAssignment", err)
-                       return
-               }
-
-               ctx.Data["IsTeamMember"] = ctx.Org.IsTeamMember
-               if requireTeamMember && !ctx.Org.IsTeamMember {
-                       ctx.NotFound("OrgAssignment", err)
-                       return
-               }
-
-               ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.AccessMode >= perm.AccessModeAdmin
-               ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin
-               if requireTeamAdmin && !ctx.Org.IsTeamAdmin {
-                       ctx.NotFound("OrgAssignment", err)
-                       return
-               }
-       }
-       ctx.Data["ContextUser"] = ctx.ContextUser
-
-       ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
-       ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
-       ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode)
-
-       ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
-       if len(ctx.ContextUser.Description) != 0 {
-               content, err := markdown.RenderString(&markup.RenderContext{
-                       Metas: map[string]string{"mode": "document"},
-                       Ctx:   ctx,
-               }, ctx.ContextUser.Description)
-               if err != nil {
-                       ctx.ServerError("RenderString", err)
-                       return
-               }
-               ctx.Data["RenderedDescription"] = content
-       }
-}
-
-// OrgAssignment returns a middleware to handle organization assignment
-func OrgAssignment(args ...bool) func(ctx *Context) {
-       return func(ctx *Context) {
-               HandleOrgAssignment(ctx, args...)
-       }
-}
diff --git a/modules/context/package.go b/modules/context/package.go
deleted file mode 100644 (file)
index c452c65..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "fmt"
-       "net/http"
-
-       "code.gitea.io/gitea/models/organization"
-       packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/models/perm"
-       "code.gitea.io/gitea/models/unit"
-       user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/structs"
-       "code.gitea.io/gitea/modules/templates"
-)
-
-// Package contains owner, access mode and optional the package descriptor
-type Package struct {
-       Owner      *user_model.User
-       AccessMode perm.AccessMode
-       Descriptor *packages_model.PackageDescriptor
-}
-
-type packageAssignmentCtx struct {
-       *Base
-       Doer        *user_model.User
-       ContextUser *user_model.User
-}
-
-// PackageAssignment returns a middleware to handle Context.Package assignment
-func PackageAssignment() func(ctx *Context) {
-       return func(ctx *Context) {
-               errorFn := func(status int, title string, obj any) {
-                       err, ok := obj.(error)
-                       if !ok {
-                               err = fmt.Errorf("%s", obj)
-                       }
-                       if status == http.StatusNotFound {
-                               ctx.NotFound(title, err)
-                       } else {
-                               ctx.ServerError(title, err)
-                       }
-               }
-               paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser}
-               ctx.Package = packageAssignment(paCtx, errorFn)
-       }
-}
-
-// PackageAssignmentAPI returns a middleware to handle Context.Package assignment
-func PackageAssignmentAPI() func(ctx *APIContext) {
-       return func(ctx *APIContext) {
-               paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser}
-               ctx.Package = packageAssignment(paCtx, ctx.Error)
-       }
-}
-
-func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any)) *Package {
-       pkg := &Package{
-               Owner: ctx.ContextUser,
-       }
-       var err error
-       pkg.AccessMode, err = determineAccessMode(ctx.Base, pkg, ctx.Doer)
-       if err != nil {
-               errCb(http.StatusInternalServerError, "determineAccessMode", err)
-               return pkg
-       }
-
-       packageType := ctx.Params("type")
-       name := ctx.Params("name")
-       version := ctx.Params("version")
-       if packageType != "" && name != "" && version != "" {
-               pv, err := packages_model.GetVersionByNameAndVersion(ctx, pkg.Owner.ID, packages_model.Type(packageType), name, version)
-               if err != nil {
-                       if err == packages_model.ErrPackageNotExist {
-                               errCb(http.StatusNotFound, "GetVersionByNameAndVersion", err)
-                       } else {
-                               errCb(http.StatusInternalServerError, "GetVersionByNameAndVersion", err)
-                       }
-                       return pkg
-               }
-
-               pkg.Descriptor, err = packages_model.GetPackageDescriptor(ctx, pv)
-               if err != nil {
-                       errCb(http.StatusInternalServerError, "GetPackageDescriptor", err)
-                       return pkg
-               }
-       }
-
-       return pkg
-}
-
-func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
-       if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
-               return perm.AccessModeNone, nil
-       }
-
-       if doer != nil && !doer.IsGhost() && (!doer.IsActive || doer.ProhibitLogin) {
-               return perm.AccessModeNone, nil
-       }
-
-       // TODO: ActionUser permission check
-       accessMode := perm.AccessModeNone
-       if pkg.Owner.IsOrganization() {
-               org := organization.OrgFromUser(pkg.Owner)
-
-               if doer != nil && !doer.IsGhost() {
-                       // 1. If user is logged in, check all team packages permissions
-                       var err error
-                       accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx, doer.ID)
-                       if err != nil {
-                               return accessMode, err
-                       }
-                       // If access mode is less than write check every team for more permissions
-                       // The minimum possible access mode is read for org members
-                       if accessMode < perm.AccessModeWrite {
-                               teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
-                               if err != nil {
-                                       return accessMode, err
-                               }
-                               for _, t := range teams {
-                                       perm := t.UnitAccessMode(ctx, unit.TypePackages)
-                                       if accessMode < perm {
-                                               accessMode = perm
-                                       }
-                               }
-                       }
-               }
-               if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, pkg.Owner, doer) {
-                       // 2. If user is unauthorized or no org member, check if org is visible
-                       accessMode = perm.AccessModeRead
-               }
-       } else {
-               if doer != nil && !doer.IsGhost() {
-                       // 1. Check if user is package owner
-                       if doer.ID == pkg.Owner.ID {
-                               accessMode = perm.AccessModeOwner
-                       } else if pkg.Owner.Visibility == structs.VisibleTypePublic || pkg.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
-                               accessMode = perm.AccessModeRead
-                       }
-               } else if pkg.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
-                       accessMode = perm.AccessModeRead
-               }
-       }
-
-       return accessMode, nil
-}
-
-// PackageContexter initializes a package context for a request.
-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()
-
-                       // it is still needed when rendering 500 page in a package handler
-                       ctx := NewWebContext(base, renderer, nil)
-                       ctx.Base.AppendContextValue(WebContextKey, ctx)
-                       next.ServeHTTP(ctx.Resp, ctx.Req)
-               })
-       }
-}
diff --git a/modules/context/pagination.go b/modules/context/pagination.go
deleted file mode 100644 (file)
index 68237c6..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "fmt"
-       "html/template"
-       "net/url"
-       "strings"
-
-       "code.gitea.io/gitea/modules/paginator"
-)
-
-// Pagination provides a pagination via paginator.Paginator and additional configurations for the link params used in rendering
-type Pagination struct {
-       Paginater *paginator.Paginator
-       urlParams []string
-}
-
-// NewPagination creates a new instance of the Pagination struct.
-// "pagingNum" is "page size" or "limit", "current" is "page"
-func NewPagination(total, pagingNum, current, numPages int) *Pagination {
-       p := &Pagination{}
-       p.Paginater = paginator.New(total, pagingNum, current, numPages)
-       return p
-}
-
-// AddParam adds a value from context identified by ctxKey as link param under a given paramKey
-func (p *Pagination) AddParam(ctx *Context, paramKey, ctxKey string) {
-       _, exists := ctx.Data[ctxKey]
-       if !exists {
-               return
-       }
-       paramData := fmt.Sprintf("%v", ctx.Data[ctxKey]) // cast any to string
-       urlParam := fmt.Sprintf("%s=%v", url.QueryEscape(paramKey), url.QueryEscape(paramData))
-       p.urlParams = append(p.urlParams, urlParam)
-}
-
-// AddParamString adds a string parameter directly
-func (p *Pagination) AddParamString(key, value string) {
-       urlParam := fmt.Sprintf("%s=%v", url.QueryEscape(key), url.QueryEscape(value))
-       p.urlParams = append(p.urlParams, urlParam)
-}
-
-// GetParams returns the configured URL params
-func (p *Pagination) GetParams() template.URL {
-       return template.URL(strings.Join(p.urlParams, "&"))
-}
-
-// SetDefaultParams sets common pagination params that are often used
-func (p *Pagination) SetDefaultParams(ctx *Context) {
-       p.AddParam(ctx, "sort", "SortType")
-       p.AddParam(ctx, "q", "Keyword")
-       // do not add any more uncommon params here!
-       p.AddParam(ctx, "t", "queryType")
-}
diff --git a/modules/context/permission.go b/modules/context/permission.go
deleted file mode 100644 (file)
index 14a9801..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2018 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "net/http"
-
-       auth_model "code.gitea.io/gitea/models/auth"
-       repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/log"
-)
-
-// RequireRepoAdmin returns a middleware for requiring repository admin permission
-func RequireRepoAdmin() func(ctx *Context) {
-       return func(ctx *Context) {
-               if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
-                       ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
-                       return
-               }
-       }
-}
-
-// RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
-func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
-       return func(ctx *Context) {
-               if !ctx.Repo.CanWrite(unitType) {
-                       ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
-                       return
-               }
-       }
-}
-
-// CanEnableEditor checks if the user is allowed to write to the branch of the repo
-func CanEnableEditor() func(ctx *Context) {
-       return func(ctx *Context) {
-               if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) {
-                       ctx.NotFound("CanWriteToBranch denies permission", nil)
-                       return
-               }
-       }
-}
-
-// RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
-func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
-       return func(ctx *Context) {
-               for _, unitType := range unitTypes {
-                       if ctx.Repo.CanWrite(unitType) {
-                               return
-                       }
-               }
-               ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
-       }
-}
-
-// RequireRepoReader returns a middleware for requiring repository read to the specify unitType
-func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
-       return func(ctx *Context) {
-               if !ctx.Repo.CanRead(unitType) {
-                       if log.IsTrace() {
-                               if ctx.IsSigned {
-                                       log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
-                                               "User in Repo has Permissions: %-+v",
-                                               ctx.Doer,
-                                               unitType,
-                                               ctx.Repo.Repository,
-                                               ctx.Repo.Permission)
-                               } else {
-                                       log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
-                                               "Anonymous user in Repo has Permissions: %-+v",
-                                               unitType,
-                                               ctx.Repo.Repository,
-                                               ctx.Repo.Permission)
-                               }
-                       }
-                       ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
-                       return
-               }
-       }
-}
-
-// RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
-func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
-       return func(ctx *Context) {
-               for _, unitType := range unitTypes {
-                       if ctx.Repo.CanRead(unitType) {
-                               return
-                       }
-               }
-               if log.IsTrace() {
-                       var format string
-                       var args []any
-                       if ctx.IsSigned {
-                               format = "Permission Denied: User %-v cannot read ["
-                               args = append(args, ctx.Doer)
-                       } else {
-                               format = "Permission Denied: Anonymous user cannot read ["
-                       }
-                       for _, unit := range unitTypes {
-                               format += "%-v, "
-                               args = append(args, unit)
-                       }
-
-                       format = format[:len(format)-2] + "] in Repo %-v\n" +
-                               "User in Repo has Permissions: %-+v"
-                       args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
-                       log.Trace(format, args...)
-               }
-               ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
-       }
-}
-
-// CheckRepoScopedToken check whether personal access token has repo scope
-func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) {
-       if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true {
-               return
-       }
-
-       scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
-       if ok { // it's a personal access token but not oauth2 token
-               var scopeMatched bool
-
-               requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository)
-
-               // check if scope only applies to public resources
-               publicOnly, err := scope.PublicOnly()
-               if err != nil {
-                       ctx.ServerError("HasScope", err)
-                       return
-               }
-
-               if publicOnly && repo.IsPrivate {
-                       ctx.Error(http.StatusForbidden)
-                       return
-               }
-
-               scopeMatched, err = scope.HasScope(requiredScopes...)
-               if err != nil {
-                       ctx.ServerError("HasScope", err)
-                       return
-               }
-
-               if !scopeMatched {
-                       ctx.Error(http.StatusForbidden)
-                       return
-               }
-       }
-}
diff --git a/modules/context/private.go b/modules/context/private.go
deleted file mode 100644 (file)
index 8b41949..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "context"
-       "fmt"
-       "net/http"
-       "time"
-
-       "code.gitea.io/gitea/modules/graceful"
-       "code.gitea.io/gitea/modules/process"
-       "code.gitea.io/gitea/modules/web"
-       web_types "code.gitea.io/gitea/modules/web/types"
-)
-
-// PrivateContext represents a context for private routes
-type PrivateContext struct {
-       *Base
-       Override context.Context
-
-       Repo *Repository
-}
-
-func init() {
-       web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider {
-               return req.Context().Value(privateContextKey).(*PrivateContext)
-       })
-}
-
-// Deadline is part of the interface for context.Context and we pass this to the request context
-func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) {
-       if ctx.Override != nil {
-               return ctx.Override.Deadline()
-       }
-       return ctx.Base.Deadline()
-}
-
-// Done is part of the interface for context.Context and we pass this to the request context
-func (ctx *PrivateContext) Done() <-chan struct{} {
-       if ctx.Override != nil {
-               return ctx.Override.Done()
-       }
-       return ctx.Base.Done()
-}
-
-// Err is part of the interface for context.Context and we pass this to the request context
-func (ctx *PrivateContext) Err() error {
-       if ctx.Override != nil {
-               return ctx.Override.Err()
-       }
-       return ctx.Base.Err()
-}
-
-var privateContextKey any = "default_private_context"
-
-// GetPrivateContext returns a context for Private routes
-func GetPrivateContext(req *http.Request) *PrivateContext {
-       return req.Context().Value(privateContextKey).(*PrivateContext)
-}
-
-// PrivateContexter returns apicontext as middleware
-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)
-                       ctx := &PrivateContext{Base: base}
-                       defer baseCleanUp()
-                       ctx.Base.AppendContextValue(privateContextKey, ctx)
-
-                       next.ServeHTTP(ctx.Resp, ctx.Req)
-               })
-       }
-}
-
-// OverrideContext overrides the underlying request context for Done() etc.
-// 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
-}
diff --git a/modules/context/repo.go b/modules/context/repo.go
deleted file mode 100644 (file)
index a73d09e..0000000
+++ /dev/null
@@ -1,1090 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "context"
-       "errors"
-       "fmt"
-       "html"
-       "net/http"
-       "net/url"
-       "path"
-       "strings"
-
-       "code.gitea.io/gitea/models"
-       "code.gitea.io/gitea/models/db"
-       git_model "code.gitea.io/gitea/models/git"
-       issues_model "code.gitea.io/gitea/models/issues"
-       access_model "code.gitea.io/gitea/models/perm/access"
-       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/cache"
-       "code.gitea.io/gitea/modules/git"
-       "code.gitea.io/gitea/modules/gitrepo"
-       code_indexer "code.gitea.io/gitea/modules/indexer/code"
-       "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/util"
-       asymkey_service "code.gitea.io/gitea/services/asymkey"
-
-       "github.com/editorconfig/editorconfig-core-go/v2"
-)
-
-// PullRequest contains information to make a pull request
-type PullRequest struct {
-       BaseRepo       *repo_model.Repository
-       Allowed        bool
-       SameRepo       bool
-       HeadInfoSubURL string // [<user>:]<branch> url segment
-}
-
-// Repository contains information to operate a repository
-type Repository struct {
-       access_model.Permission
-       IsWatching   bool
-       IsViewBranch bool
-       IsViewTag    bool
-       IsViewCommit bool
-       Repository   *repo_model.Repository
-       Owner        *user_model.User
-       Commit       *git.Commit
-       Tag          *git.Tag
-       GitRepo      *git.Repository
-       RefName      string
-       BranchName   string
-       TagName      string
-       TreePath     string
-       CommitID     string
-       RepoLink     string
-       CloneLink    repo_model.CloneLink
-       CommitsCount int64
-
-       PullRequest *PullRequest
-}
-
-// CanWriteToBranch checks if the branch is writable by the user
-func (r *Repository) CanWriteToBranch(ctx context.Context, user *user_model.User, branch string) bool {
-       return issues_model.CanMaintainerWriteToBranch(ctx, r.Permission, branch, user)
-}
-
-// CanEnableEditor returns true if repository is editable and user has proper access level.
-func (r *Repository) CanEnableEditor(ctx context.Context, user *user_model.User) bool {
-       return r.IsViewBranch && r.CanWriteToBranch(ctx, user, r.BranchName) && r.Repository.CanEnableEditor() && !r.Repository.IsArchived
-}
-
-// CanCreateBranch returns true if repository is editable and user has proper access level.
-func (r *Repository) CanCreateBranch() bool {
-       return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanCreateBranch()
-}
-
-func (r *Repository) GetObjectFormat() git.ObjectFormat {
-       return git.ObjectFormatFromName(r.Repository.ObjectFormatName)
-}
-
-// RepoMustNotBeArchived checks if a repo is archived
-func RepoMustNotBeArchived() func(ctx *Context) {
-       return func(ctx *Context) {
-               if ctx.Repo.Repository.IsArchived {
-                       ctx.NotFound("IsArchived", errors.New(ctx.Locale.TrString("repo.archive.title")))
-               }
-       }
-}
-
-// CanCommitToBranchResults represents the results of CanCommitToBranch
-type CanCommitToBranchResults struct {
-       CanCommitToBranch bool
-       EditorEnabled     bool
-       UserCanPush       bool
-       RequireSigned     bool
-       WillSign          bool
-       SigningKey        string
-       WontSignReason    string
-}
-
-// CanCommitToBranch returns true if repository is editable and user has proper access level
-//
-// and branch is not protected for push
-func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
-       protectedBranch, err := git_model.GetFirstMatchProtectedBranchRule(ctx, r.Repository.ID, r.BranchName)
-       if err != nil {
-               return CanCommitToBranchResults{}, err
-       }
-       userCanPush := true
-       requireSigned := false
-       if protectedBranch != nil {
-               protectedBranch.Repo = r.Repository
-               userCanPush = protectedBranch.CanUserPush(ctx, doer)
-               requireSigned = protectedBranch.RequireSignedCommits
-       }
-
-       sign, keyID, _, err := asymkey_service.SignCRUDAction(ctx, r.Repository.RepoPath(), doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName)
-
-       canCommit := r.CanEnableEditor(ctx, doer) && userCanPush
-       if requireSigned {
-               canCommit = canCommit && sign
-       }
-       wontSignReason := ""
-       if err != nil {
-               if asymkey_service.IsErrWontSign(err) {
-                       wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason)
-                       err = nil
-               } else {
-                       wontSignReason = "error"
-               }
-       }
-
-       return CanCommitToBranchResults{
-               CanCommitToBranch: canCommit,
-               EditorEnabled:     r.CanEnableEditor(ctx, doer),
-               UserCanPush:       userCanPush,
-               RequireSigned:     requireSigned,
-               WillSign:          sign,
-               SigningKey:        keyID,
-               WontSignReason:    wontSignReason,
-       }, err
-}
-
-// CanUseTimetracker returns whether or not a user can use the timetracker.
-func (r *Repository) CanUseTimetracker(ctx context.Context, issue *issues_model.Issue, user *user_model.User) bool {
-       // Checking for following:
-       // 1. Is timetracker enabled
-       // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
-       isAssigned, _ := issues_model.IsUserAssignedToIssue(ctx, issue, user)
-       return r.Repository.IsTimetrackerEnabled(ctx) && (!r.Repository.AllowOnlyContributorsToTrackTime(ctx) ||
-               r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
-}
-
-// CanCreateIssueDependencies returns whether or not a user can create dependencies.
-func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_model.User, isPull bool) bool {
-       return r.Repository.IsDependenciesEnabled(ctx) && r.Permission.CanWriteIssuesOrPulls(isPull)
-}
-
-// GetCommitsCount returns cached commit count for current view
-func (r *Repository) GetCommitsCount() (int64, error) {
-       if r.Commit == nil {
-               return 0, nil
-       }
-       var contextName string
-       if r.IsViewBranch {
-               contextName = r.BranchName
-       } else if r.IsViewTag {
-               contextName = r.TagName
-       } else {
-               contextName = r.CommitID
-       }
-       return cache.GetInt64(r.Repository.GetCommitsCountCacheKey(contextName, r.IsViewBranch || r.IsViewTag), func() (int64, error) {
-               return r.Commit.CommitsCount()
-       })
-}
-
-// GetCommitGraphsCount returns cached commit count for current view
-func (r *Repository) GetCommitGraphsCount(ctx context.Context, hidePRRefs bool, branches, files []string) (int64, error) {
-       cacheKey := fmt.Sprintf("commits-count-%d-graph-%t-%s-%s", r.Repository.ID, hidePRRefs, branches, files)
-
-       return cache.GetInt64(cacheKey, func() (int64, error) {
-               if len(branches) == 0 {
-                       return git.AllCommitsCount(ctx, r.Repository.RepoPath(), hidePRRefs, files...)
-               }
-               return git.CommitsCount(ctx,
-                       git.CommitsCountOptions{
-                               RepoPath: r.Repository.RepoPath(),
-                               Revision: branches,
-                               RelPath:  files,
-                       })
-       })
-}
-
-// BranchNameSubURL sub-URL for the BranchName field
-func (r *Repository) BranchNameSubURL() string {
-       switch {
-       case r.IsViewBranch:
-               return "branch/" + util.PathEscapeSegments(r.BranchName)
-       case r.IsViewTag:
-               return "tag/" + util.PathEscapeSegments(r.TagName)
-       case r.IsViewCommit:
-               return "commit/" + util.PathEscapeSegments(r.CommitID)
-       }
-       log.Error("Unknown view type for repo: %v", r)
-       return ""
-}
-
-// FileExists returns true if a file exists in the given repo branch
-func (r *Repository) FileExists(path, branch string) (bool, error) {
-       if branch == "" {
-               branch = r.Repository.DefaultBranch
-       }
-       commit, err := r.GitRepo.GetBranchCommit(branch)
-       if err != nil {
-               return false, err
-       }
-       if _, err := commit.GetTreeEntryByPath(path); err != nil {
-               return false, err
-       }
-       return true, nil
-}
-
-// GetEditorconfig returns the .editorconfig definition if found in the
-// HEAD of the default repo branch.
-func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (cfg *editorconfig.Editorconfig, warning, err error) {
-       if r.GitRepo == nil {
-               return nil, nil, nil
-       }
-
-       var commit *git.Commit
-
-       if len(optCommit) != 0 {
-               commit = optCommit[0]
-       } else {
-               commit, err = r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
-               if err != nil {
-                       return nil, nil, err
-               }
-       }
-       treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
-       if err != nil {
-               return nil, nil, err
-       }
-       if treeEntry.Blob().Size() >= setting.UI.MaxDisplayFileSize {
-               return nil, nil, git.ErrNotExist{ID: "", RelPath: ".editorconfig"}
-       }
-       reader, err := treeEntry.Blob().DataAsync()
-       if err != nil {
-               return nil, nil, err
-       }
-       defer reader.Close()
-       return editorconfig.ParseGraceful(reader)
-}
-
-// RetrieveBaseRepo retrieves base repository
-func RetrieveBaseRepo(ctx *Context, repo *repo_model.Repository) {
-       // Non-fork repository will not return error in this method.
-       if err := repo.GetBaseRepo(ctx); err != nil {
-               if repo_model.IsErrRepoNotExist(err) {
-                       repo.IsFork = false
-                       repo.ForkID = 0
-                       return
-               }
-               ctx.ServerError("GetBaseRepo", err)
-               return
-       } else if err = repo.BaseRepo.LoadOwner(ctx); err != nil {
-               ctx.ServerError("BaseRepo.LoadOwner", err)
-               return
-       }
-}
-
-// RetrieveTemplateRepo retrieves template repository used to generate this repository
-func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) {
-       // Non-generated repository will not return error in this method.
-       templateRepo, err := repo_model.GetTemplateRepo(ctx, repo)
-       if err != nil {
-               if repo_model.IsErrRepoNotExist(err) {
-                       repo.TemplateID = 0
-                       return
-               }
-               ctx.ServerError("GetTemplateRepo", err)
-               return
-       } else if err = templateRepo.LoadOwner(ctx); err != nil {
-               ctx.ServerError("TemplateRepo.LoadOwner", err)
-               return
-       }
-
-       perm, err := access_model.GetUserRepoPermission(ctx, templateRepo, ctx.Doer)
-       if err != nil {
-               ctx.ServerError("GetUserRepoPermission", err)
-               return
-       }
-
-       if !perm.CanRead(unit_model.TypeCode) {
-               repo.TemplateID = 0
-       }
-}
-
-// ComposeGoGetImport returns go-get-import meta content.
-func ComposeGoGetImport(owner, repo string) string {
-       /// setting.AppUrl is guaranteed to be parse as url
-       appURL, _ := url.Parse(setting.AppURL)
-
-       return path.Join(appURL.Host, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo))
-}
-
-// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
-// if user does not have actual access to the requested repository,
-// or the owner or repository does not exist at all.
-// This is particular a workaround for "go get" command which does not respect
-// .netrc file.
-func EarlyResponseForGoGetMeta(ctx *Context) {
-       username := ctx.Params(":username")
-       reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git")
-       if username == "" || reponame == "" {
-               ctx.PlainText(http.StatusBadRequest, "invalid repository path")
-               return
-       }
-
-       var cloneURL string
-       if setting.Repository.GoGetCloneURLProtocol == "ssh" {
-               cloneURL = repo_model.ComposeSSHCloneURL(username, reponame)
-       } else {
-               cloneURL = repo_model.ComposeHTTPSCloneURL(username, reponame)
-       }
-       goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), cloneURL)
-       htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
-       ctx.PlainText(http.StatusOK, htmlMeta)
-}
-
-// RedirectToRepo redirect to a differently-named repository
-func RedirectToRepo(ctx *Base, redirectRepoID int64) {
-       ownerName := ctx.Params(":username")
-       previousRepoName := ctx.Params(":reponame")
-
-       repo, err := repo_model.GetRepositoryByID(ctx, redirectRepoID)
-       if err != nil {
-               log.Error("GetRepositoryByID: %v", err)
-               ctx.Error(http.StatusInternalServerError, "GetRepositoryByID")
-               return
-       }
-
-       redirectPath := strings.Replace(
-               ctx.Req.URL.EscapedPath(),
-               url.PathEscape(ownerName)+"/"+url.PathEscape(previousRepoName),
-               url.PathEscape(repo.OwnerName)+"/"+url.PathEscape(repo.Name),
-               1,
-       )
-       if ctx.Req.URL.RawQuery != "" {
-               redirectPath += "?" + ctx.Req.URL.RawQuery
-       }
-       ctx.Redirect(path.Join(setting.AppSubURL, redirectPath), http.StatusTemporaryRedirect)
-}
-
-func repoAssignment(ctx *Context, repo *repo_model.Repository) {
-       var err error
-       if err = repo.LoadOwner(ctx); err != nil {
-               ctx.ServerError("LoadOwner", err)
-               return
-       }
-
-       ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
-       if err != nil {
-               ctx.ServerError("GetUserRepoPermission", err)
-               return
-       }
-
-       // Check access.
-       if !ctx.Repo.Permission.HasAccess() {
-               if ctx.FormString("go-get") == "1" {
-                       EarlyResponseForGoGetMeta(ctx)
-                       return
-               }
-               ctx.NotFound("no access right", nil)
-               return
-       }
-       ctx.Data["HasAccess"] = true
-       ctx.Data["Permission"] = &ctx.Repo.Permission
-
-       if repo.IsMirror {
-               pullMirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID)
-               if err == nil {
-                       ctx.Data["PullMirror"] = pullMirror
-               } else if err != repo_model.ErrMirrorNotExist {
-                       ctx.ServerError("GetMirrorByRepoID", err)
-                       return
-               }
-       }
-
-       pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
-       if err != nil {
-               ctx.ServerError("GetPushMirrorsByRepoID", err)
-               return
-       }
-
-       ctx.Repo.Repository = repo
-       ctx.Data["PushMirrors"] = pushMirrors
-       ctx.Data["RepoName"] = ctx.Repo.Repository.Name
-       ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
-}
-
-// RepoIDAssignment returns a handler which assigns the repo to the context.
-func RepoIDAssignment() func(ctx *Context) {
-       return func(ctx *Context) {
-               repoID := ctx.ParamsInt64(":repoid")
-
-               // Get repository.
-               repo, err := repo_model.GetRepositoryByID(ctx, repoID)
-               if err != nil {
-                       if repo_model.IsErrRepoNotExist(err) {
-                               ctx.NotFound("GetRepositoryByID", nil)
-                       } else {
-                               ctx.ServerError("GetRepositoryByID", err)
-                       }
-                       return
-               }
-
-               repoAssignment(ctx, repo)
-       }
-}
-
-// RepoAssignment returns a middleware to handle repository assignment
-func RepoAssignment(ctx *Context) context.CancelFunc {
-       if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
-               log.Trace("RepoAssignment was exec already, skipping second call ...")
-               return nil
-       }
-       ctx.Data["repoAssignmentExecuted"] = true
-
-       var (
-               owner *user_model.User
-               err   error
-       )
-
-       userName := ctx.Params(":username")
-       repoName := ctx.Params(":reponame")
-       repoName = strings.TrimSuffix(repoName, ".git")
-       if setting.Other.EnableFeed {
-               repoName = strings.TrimSuffix(repoName, ".rss")
-               repoName = strings.TrimSuffix(repoName, ".atom")
-       }
-
-       // Check if the user is the same as the repository owner
-       if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) {
-               owner = ctx.Doer
-       } else {
-               owner, err = user_model.GetUserByName(ctx, userName)
-               if err != nil {
-                       if user_model.IsErrUserNotExist(err) {
-                               // go-get does not support redirects
-                               // https://github.com/golang/go/issues/19760
-                               if ctx.FormString("go-get") == "1" {
-                                       EarlyResponseForGoGetMeta(ctx)
-                                       return nil
-                               }
-
-                               if redirectUserID, err := user_model.LookupUserRedirect(ctx, userName); err == nil {
-                                       RedirectToUser(ctx.Base, userName, redirectUserID)
-                               } else if user_model.IsErrUserRedirectNotExist(err) {
-                                       ctx.NotFound("GetUserByName", nil)
-                               } else {
-                                       ctx.ServerError("LookupUserRedirect", err)
-                               }
-                       } else {
-                               ctx.ServerError("GetUserByName", err)
-                       }
-                       return nil
-               }
-       }
-       ctx.Repo.Owner = owner
-       ctx.ContextUser = owner
-       ctx.Data["ContextUser"] = ctx.ContextUser
-       ctx.Data["Username"] = ctx.Repo.Owner.Name
-
-       // redirect link to wiki
-       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.Params(":reponame")
-               redirectRepoName := strings.TrimSuffix(repoName, ".wiki")
-               redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
-               redirectPath := strings.Replace(
-                       ctx.Req.URL.EscapedPath(),
-                       url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
-                       url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
-                       1,
-               )
-               if ctx.Req.URL.RawQuery != "" {
-                       redirectPath += "?" + ctx.Req.URL.RawQuery
-               }
-               ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
-               return nil
-       }
-
-       // Get repository.
-       repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, repoName)
-       if err != nil {
-               if repo_model.IsErrRepoNotExist(err) {
-                       redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, repoName)
-                       if err == nil {
-                               RedirectToRepo(ctx.Base, redirectRepoID)
-                       } else if repo_model.IsErrRedirectNotExist(err) {
-                               if ctx.FormString("go-get") == "1" {
-                                       EarlyResponseForGoGetMeta(ctx)
-                                       return nil
-                               }
-                               ctx.NotFound("GetRepositoryByName", nil)
-                       } else {
-                               ctx.ServerError("LookupRepoRedirect", err)
-                       }
-               } else {
-                       ctx.ServerError("GetRepositoryByName", err)
-               }
-               return nil
-       }
-       repo.Owner = owner
-
-       repoAssignment(ctx, repo)
-       if ctx.Written() {
-               return nil
-       }
-
-       ctx.Repo.RepoLink = repo.Link()
-       ctx.Data["RepoLink"] = ctx.Repo.RepoLink
-       ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
-
-       if setting.Other.EnableFeed {
-               ctx.Data["EnableFeed"] = true
-               ctx.Data["FeedURL"] = ctx.Repo.RepoLink
-       }
-
-       unit, err := ctx.Repo.Repository.GetUnit(ctx, unit_model.TypeExternalTracker)
-       if err == nil {
-               ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL
-       }
-
-       ctx.Data["NumTags"], err = db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{
-               IncludeDrafts: true,
-               IncludeTags:   true,
-               HasSha1:       util.OptionalBoolTrue, // only draft releases which are created with existing tags
-               RepoID:        ctx.Repo.Repository.ID,
-       })
-       if err != nil {
-               ctx.ServerError("GetReleaseCountByRepoID", err)
-               return nil
-       }
-       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.
-               IncludeDrafts: ctx.Repo.CanWrite(unit_model.TypeReleases),
-               RepoID:        ctx.Repo.Repository.ID,
-       })
-       if err != nil {
-               ctx.ServerError("GetReleaseCountByRepoID", err)
-               return nil
-       }
-
-       ctx.Data["Title"] = owner.Name + "/" + repo.Name
-       ctx.Data["Repository"] = repo
-       ctx.Data["Owner"] = ctx.Repo.Repository.Owner
-       ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
-       ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
-       ctx.Data["RepoOwnerIsOrganization"] = repo.Owner.IsOrganization()
-       ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(unit_model.TypeCode)
-       ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
-       ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
-       ctx.Data["CanWriteActions"] = ctx.Repo.CanWrite(unit_model.TypeActions)
-
-       canSignedUserFork, err := repo_module.CanUserForkRepo(ctx, ctx.Doer, ctx.Repo.Repository)
-       if err != nil {
-               ctx.ServerError("CanUserForkRepo", err)
-               return nil
-       }
-       ctx.Data["CanSignedUserFork"] = canSignedUserFork
-
-       userAndOrgForks, err := repo_model.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository)
-       if err != nil {
-               ctx.ServerError("GetForksByUserAndOrgs", err)
-               return nil
-       }
-       ctx.Data["UserAndOrgForks"] = userAndOrgForks
-
-       // canSignedUserFork is true if the current user doesn't have a fork of this repo yet or
-       // if he owns an org that doesn't have a fork of this repo yet
-       // If multiple forks are available or if the user can fork to another account, but there is already a fork: open selection dialog
-       ctx.Data["ShowForkModal"] = len(userAndOrgForks) > 1 || (canSignedUserFork && len(userAndOrgForks) > 0)
-
-       ctx.Data["RepoCloneLink"] = repo.CloneLink()
-
-       cloneButtonShowHTTPS := !setting.Repository.DisableHTTPGit
-       cloneButtonShowSSH := !setting.SSH.Disabled && (ctx.IsSigned || setting.SSH.ExposeAnonymous)
-       if !cloneButtonShowHTTPS && !cloneButtonShowSSH {
-               // We have to show at least one link, so we just show the HTTPS
-               cloneButtonShowHTTPS = true
-       }
-       ctx.Data["CloneButtonShowHTTPS"] = cloneButtonShowHTTPS
-       ctx.Data["CloneButtonShowSSH"] = cloneButtonShowSSH
-       ctx.Data["CloneButtonOriginLink"] = ctx.Data["RepoCloneLink"] // it may be rewritten to the WikiCloneLink by the router middleware
-
-       ctx.Data["RepoSearchEnabled"] = setting.Indexer.RepoIndexerEnabled
-       if setting.Indexer.RepoIndexerEnabled {
-               ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx)
-       }
-
-       if ctx.IsSigned {
-               ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, repo.ID)
-               ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, repo.ID)
-       }
-
-       if repo.IsFork {
-               RetrieveBaseRepo(ctx, repo)
-               if ctx.Written() {
-                       return nil
-               }
-       }
-
-       if repo.IsGenerated() {
-               RetrieveTemplateRepo(ctx, repo)
-               if ctx.Written() {
-                       return nil
-               }
-       }
-
-       isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/")
-
-       // Disable everything when the repo is being created
-       if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
-               ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
-               if !isHomeOrSettings {
-                       ctx.Redirect(ctx.Repo.RepoLink)
-               }
-               return nil
-       }
-
-       gitRepo, err := gitrepo.OpenRepository(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)
-                       ctx.Repo.Repository.MarkAsBrokenEmpty()
-                       ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
-                       // Only allow access to base of repo or settings
-                       if !isHomeOrSettings {
-                               ctx.Redirect(ctx.Repo.RepoLink)
-                       }
-                       return nil
-               }
-               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()
-               }
-       }
-
-       // Stop at this point when the repo is empty.
-       if ctx.Repo.Repository.IsEmpty {
-               ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
-               return cancel
-       }
-
-       branchOpts := git_model.FindBranchOptions{
-               RepoID:          ctx.Repo.Repository.ID,
-               IsDeletedBranch: optional.Some(false),
-               ListOptions:     db.ListOptionsAll,
-       }
-       branchesTotal, err := db.Count[git_model.Branch](ctx, branchOpts)
-       if err != nil {
-               ctx.ServerError("CountBranches", err)
-               return cancel
-       }
-
-       // non-empty repo should have at least 1 branch, so this repository's branches haven't been synced yet
-       if branchesTotal == 0 { // fallback to do a sync immediately
-               branchesTotal, err = repo_module.SyncRepoBranches(ctx, ctx.Repo.Repository.ID, 0)
-               if err != nil {
-                       ctx.ServerError("SyncRepoBranches", err)
-                       return cancel
-               }
-       }
-
-       ctx.Data["BranchesCount"] = branchesTotal
-
-       // 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) {
-                       ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
-               } else {
-                       ctx.Repo.BranchName, _ = gitRepo.GetDefaultBranch()
-                       if ctx.Repo.BranchName == "" {
-                               // If it still can't get a default branch, fall back to default branch from setting.
-                               // Something might be wrong. Either site admin should fix the repo sync or Gitea should fix a potential bug.
-                               ctx.Repo.BranchName = setting.Repository.DefaultBranch
-                       }
-               }
-               ctx.Repo.RefName = ctx.Repo.BranchName
-       }
-       ctx.Data["BranchName"] = ctx.Repo.BranchName
-
-       // People who have push access or have forked repository can propose a new pull request.
-       canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
-               (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID))
-       canCompare := false
-
-       // Pull request is allowed if this is a fork repository
-       // and base repository accepts pull requests.
-       if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls(ctx) {
-               canCompare = true
-               ctx.Data["BaseRepo"] = repo.BaseRepo
-               ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
-               ctx.Repo.PullRequest.Allowed = canPush
-               ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.Repo.Owner.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
-       } else if repo.AllowsPulls(ctx) {
-               // Or, this is repository accepts pull requests between branches.
-               canCompare = true
-               ctx.Data["BaseRepo"] = repo
-               ctx.Repo.PullRequest.BaseRepo = repo
-               ctx.Repo.PullRequest.Allowed = canPush
-               ctx.Repo.PullRequest.SameRepo = true
-               ctx.Repo.PullRequest.HeadInfoSubURL = util.PathEscapeSegments(ctx.Repo.BranchName)
-       }
-       ctx.Data["CanCompareOrPull"] = canCompare
-       ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
-
-       if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
-               repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
-               if err != nil {
-                       ctx.ServerError("GetPendingRepositoryTransfer", err)
-                       return cancel
-               }
-
-               if err := repoTransfer.LoadAttributes(ctx); err != nil {
-                       ctx.ServerError("LoadRecipient", err)
-                       return cancel
-               }
-
-               ctx.Data["RepoTransfer"] = repoTransfer
-               if ctx.Doer != nil {
-                       ctx.Data["CanUserAcceptTransfer"] = repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer)
-               }
-       }
-
-       if ctx.FormString("go-get") == "1" {
-               ctx.Data["GoGetImport"] = ComposeGoGetImport(owner.Name, repo.Name)
-               fullURLPrefix := repo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
-               ctx.Data["GoDocDirectory"] = fullURLPrefix + "{/dir}"
-               ctx.Data["GoDocFile"] = fullURLPrefix + "{/dir}/{file}#L{line}"
-       }
-       return cancel
-}
-
-// RepoRefType type of repo reference
-type RepoRefType int
-
-const (
-       // RepoRefLegacy unknown type, make educated guess and redirect.
-       // for backward compatibility with previous URL scheme
-       RepoRefLegacy RepoRefType = iota
-       // RepoRefAny is for usage where educated guess is needed
-       // but redirect can not be made
-       RepoRefAny
-       // RepoRefBranch branch
-       RepoRefBranch
-       // RepoRefTag tag
-       RepoRefTag
-       // RepoRefCommit commit
-       RepoRefCommit
-       // RepoRefBlob blob
-       RepoRefBlob
-)
-
-const headRefName = "HEAD"
-
-// RepoRef handles repository reference names when the ref name is not
-// explicitly given
-func RepoRef() func(*Context) context.CancelFunc {
-       // since no ref name is explicitly specified, ok to just use branch
-       return RepoRefByType(RepoRefBranch)
-}
-
-// RefTypeIncludesBranches returns true if ref type can be a branch
-func (rt RepoRefType) RefTypeIncludesBranches() bool {
-       if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefBranch {
-               return true
-       }
-       return false
-}
-
-// RefTypeIncludesTags returns true if ref type can be a tag
-func (rt RepoRefType) RefTypeIncludesTags() bool {
-       if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefTag {
-               return true
-       }
-       return false
-}
-
-func getRefNameFromPath(ctx *Base, repo *Repository, path string, isExist func(string) bool) string {
-       refName := ""
-       parts := strings.Split(path, "/")
-       for i, part := range parts {
-               refName = strings.TrimPrefix(refName+"/"+part, "/")
-               if isExist(refName) {
-                       repo.TreePath = strings.Join(parts[i+1:], "/")
-                       return refName
-               }
-       }
-       return ""
-}
-
-func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
-       path := ctx.Params("*")
-       switch pathType {
-       case RepoRefLegacy, RepoRefAny:
-               if refName := getRefName(ctx, repo, RepoRefBranch); len(refName) > 0 {
-                       return refName
-               }
-               if refName := getRefName(ctx, repo, RepoRefTag); len(refName) > 0 {
-                       return refName
-               }
-               // For legacy and API support only full commit sha
-               parts := strings.Split(path, "/")
-
-               if len(parts) > 0 && len(parts[0]) == git.ObjectFormatFromName(repo.Repository.ObjectFormatName).FullLength() {
-                       repo.TreePath = strings.Join(parts[1:], "/")
-                       return parts[0]
-               }
-               if refName := getRefName(ctx, repo, RepoRefBlob); len(refName) > 0 {
-                       return refName
-               }
-               repo.TreePath = path
-               return repo.Repository.DefaultBranch
-       case RepoRefBranch:
-               ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist)
-               if len(ref) == 0 {
-
-                       // check if ref is HEAD
-                       parts := strings.Split(path, "/")
-                       if parts[0] == headRefName {
-                               repo.TreePath = strings.Join(parts[1:], "/")
-                               return repo.Repository.DefaultBranch
-                       }
-
-                       // maybe it's a renamed branch
-                       return getRefNameFromPath(ctx, repo, path, func(s string) bool {
-                               b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s)
-                               if err != nil {
-                                       log.Error("FindRenamedBranch: %v", err)
-                                       return false
-                               }
-
-                               if !exist {
-                                       return false
-                               }
-
-                               ctx.Data["IsRenamedBranch"] = true
-                               ctx.Data["RenamedBranchName"] = b.To
-
-                               return true
-                       })
-               }
-
-               return ref
-       case RepoRefTag:
-               return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
-       case RepoRefCommit:
-               parts := strings.Split(path, "/")
-
-               if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= repo.GetObjectFormat().FullLength() {
-                       repo.TreePath = strings.Join(parts[1:], "/")
-                       return parts[0]
-               }
-
-               if len(parts) > 0 && parts[0] == headRefName {
-                       // HEAD ref points to last default branch commit
-                       commit, err := repo.GitRepo.GetBranchCommit(repo.Repository.DefaultBranch)
-                       if err != nil {
-                               return ""
-                       }
-                       repo.TreePath = strings.Join(parts[1:], "/")
-                       return commit.ID.String()
-               }
-       case RepoRefBlob:
-               _, err := repo.GitRepo.GetBlob(path)
-               if err != nil {
-                       return ""
-               }
-               return path
-       default:
-               log.Error("Unrecognized path type: %v", path)
-       }
-       return ""
-}
-
-// RepoRefByType handles repository reference name for a specific type
-// of repository reference
-func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context) context.CancelFunc {
-       return func(ctx *Context) (cancel context.CancelFunc) {
-               // Empty repository does not have reference information.
-               if ctx.Repo.Repository.IsEmpty {
-                       // assume the user is viewing the (non-existent) default branch
-                       ctx.Repo.IsViewBranch = true
-                       ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
-                       ctx.Data["TreePath"] = ""
-                       return nil
-               }
-
-               var (
-                       refName string
-                       err     error
-               )
-
-               if ctx.Repo.GitRepo == nil {
-                       ctx.Repo.GitRepo, err = gitrepo.OpenRepository(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()
-                               }
-                       }
-               }
-
-               // Get default branch.
-               if len(ctx.Params("*")) == 0 {
-                       refName = ctx.Repo.Repository.DefaultBranch
-                       if !ctx.Repo.GitRepo.IsBranchExist(refName) {
-                               brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 1)
-                               if err == nil && len(brs) != 0 {
-                                       refName = brs[0].Name
-                               } else if len(brs) == 0 {
-                                       log.Error("No branches in non-empty repository %s", ctx.Repo.GitRepo.Path)
-                                       ctx.Repo.Repository.MarkAsBrokenEmpty()
-                               } else {
-                                       log.Error("GetBranches error: %v", err)
-                                       ctx.Repo.Repository.MarkAsBrokenEmpty()
-                               }
-                       }
-                       ctx.Repo.RefName = refName
-                       ctx.Repo.BranchName = refName
-                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
-                       if err == nil {
-                               ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
-                       } else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
-                               // if the repository is broken, we can continue to the handler code, to show "Settings -> Delete Repository" for end users
-                               log.Error("GetBranchCommit: %v", err)
-                               ctx.Repo.Repository.MarkAsBrokenEmpty()
-                       } else {
-                               ctx.ServerError("GetBranchCommit", err)
-                               return cancel
-                       }
-                       ctx.Repo.IsViewBranch = true
-               } else {
-                       refName = getRefName(ctx.Base, ctx.Repo, refType)
-                       ctx.Repo.RefName = refName
-                       isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
-                       if isRenamedBranch && has {
-                               renamedBranchName := ctx.Data["RenamedBranchName"].(string)
-                               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
-                       }
-
-                       if refType.RefTypeIncludesBranches() && ctx.Repo.GitRepo.IsBranchExist(refName) {
-                               ctx.Repo.IsViewBranch = true
-                               ctx.Repo.BranchName = refName
-
-                               ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
-                               if err != nil {
-                                       ctx.ServerError("GetBranchCommit", err)
-                                       return cancel
-                               }
-                               ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
-
-                       } else if refType.RefTypeIncludesTags() && ctx.Repo.GitRepo.IsTagExist(refName) {
-                               ctx.Repo.IsViewTag = true
-                               ctx.Repo.TagName = refName
-
-                               ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
-                               if err != nil {
-                                       if git.IsErrNotExist(err) {
-                                               ctx.NotFound("GetTagCommit", err)
-                                               return cancel
-                                       }
-                                       ctx.ServerError("GetTagCommit", err)
-                                       return cancel
-                               }
-                               ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
-                       } else if len(refName) >= 7 && len(refName) <= ctx.Repo.GetObjectFormat().FullLength() {
-                               ctx.Repo.IsViewCommit = true
-                               ctx.Repo.CommitID = refName
-
-                               ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
-                               if err != nil {
-                                       ctx.NotFound("GetCommit", err)
-                                       return cancel
-                               }
-                               // If short commit ID add canonical link header
-                               if len(refName) < ctx.Repo.GetObjectFormat().FullLength() {
-                                       ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
-                                               util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
-                               }
-                       } else {
-                               if len(ignoreNotExistErr) > 0 && ignoreNotExistErr[0] {
-                                       return cancel
-                               }
-                               ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
-                               return cancel
-                       }
-
-                       if refType == RepoRefLegacy {
-                               // redirect from old URL scheme to new URL scheme
-                               prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*"))), strings.ToLower(ctx.Repo.RepoLink))
-
-                               ctx.Redirect(path.Join(
-                                       ctx.Repo.RepoLink,
-                                       util.PathEscapeSegments(prefix),
-                                       ctx.Repo.BranchNameSubURL(),
-                                       util.PathEscapeSegments(ctx.Repo.TreePath)))
-                               return cancel
-                       }
-               }
-
-               ctx.Data["BranchName"] = ctx.Repo.BranchName
-               ctx.Data["RefName"] = ctx.Repo.RefName
-               ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
-               ctx.Data["TagName"] = ctx.Repo.TagName
-               ctx.Data["CommitID"] = ctx.Repo.CommitID
-               ctx.Data["TreePath"] = ctx.Repo.TreePath
-               ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
-               ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
-               ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
-               ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch()
-
-               ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount()
-               if err != nil {
-                       ctx.ServerError("GetCommitsCount", err)
-                       return cancel
-               }
-               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
-       }
-}
-
-// GitHookService checks if repository Git hooks service has been enabled.
-func GitHookService() func(ctx *Context) {
-       return func(ctx *Context) {
-               if !ctx.Doer.CanEditGitHook() {
-                       ctx.NotFound("GitHookService", nil)
-                       return
-               }
-       }
-}
-
-// UnitTypes returns a middleware to set unit types to context variables.
-func UnitTypes() func(ctx *Context) {
-       return func(ctx *Context) {
-               ctx.Data["UnitTypeCode"] = unit_model.TypeCode
-               ctx.Data["UnitTypeIssues"] = unit_model.TypeIssues
-               ctx.Data["UnitTypePullRequests"] = unit_model.TypePullRequests
-               ctx.Data["UnitTypeReleases"] = unit_model.TypeReleases
-               ctx.Data["UnitTypeWiki"] = unit_model.TypeWiki
-               ctx.Data["UnitTypeExternalWiki"] = unit_model.TypeExternalWiki
-               ctx.Data["UnitTypeExternalTracker"] = unit_model.TypeExternalTracker
-               ctx.Data["UnitTypeProjects"] = unit_model.TypeProjects
-               ctx.Data["UnitTypePackages"] = unit_model.TypePackages
-               ctx.Data["UnitTypeActions"] = unit_model.TypeActions
-       }
-}
diff --git a/modules/context/response.go b/modules/context/response.go
deleted file mode 100644 (file)
index 2f271f2..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "net/http"
-
-       web_types "code.gitea.io/gitea/modules/web/types"
-)
-
-// ResponseWriter represents a response writer for HTTP
-type ResponseWriter interface {
-       http.ResponseWriter
-       http.Flusher
-       web_types.ResponseStatusProvider
-
-       Before(func(ResponseWriter))
-
-       Status() int // used by access logger template
-       Size() int   // used by access logger template
-}
-
-var _ ResponseWriter = &Response{}
-
-// Response represents a response
-type Response struct {
-       http.ResponseWriter
-       written        int
-       status         int
-       befores        []func(ResponseWriter)
-       beforeExecuted bool
-}
-
-// Write writes bytes to HTTP endpoint
-func (r *Response) Write(bs []byte) (int, error) {
-       if !r.beforeExecuted {
-               for _, before := range r.befores {
-                       before(r)
-               }
-               r.beforeExecuted = true
-       }
-       size, err := r.ResponseWriter.Write(bs)
-       r.written += size
-       if err != nil {
-               return size, err
-       }
-       if r.status == 0 {
-               r.status = http.StatusOK
-       }
-       return size, nil
-}
-
-func (r *Response) Status() int {
-       return r.status
-}
-
-func (r *Response) Size() int {
-       return r.written
-}
-
-// WriteHeader write status code
-func (r *Response) WriteHeader(statusCode int) {
-       if !r.beforeExecuted {
-               for _, before := range r.befores {
-                       before(r)
-               }
-               r.beforeExecuted = true
-       }
-       if r.status == 0 {
-               r.status = statusCode
-               r.ResponseWriter.WriteHeader(statusCode)
-       }
-}
-
-// Flush flushes cached data
-func (r *Response) Flush() {
-       if f, ok := r.ResponseWriter.(http.Flusher); ok {
-               f.Flush()
-       }
-}
-
-// WrittenStatus returned status code written
-func (r *Response) WrittenStatus() int {
-       return r.status
-}
-
-// Before allows for a function to be called before the ResponseWriter has been written to. This is
-// useful for setting headers or any other operations that must happen before a response has been written.
-func (r *Response) Before(f func(ResponseWriter)) {
-       r.befores = append(r.befores, f)
-}
-
-func WrapResponseWriter(resp http.ResponseWriter) *Response {
-       if v, ok := resp.(*Response); ok {
-               return v
-       }
-       return &Response{
-               ResponseWriter: resp,
-               status:         0,
-               befores:        make([]func(ResponseWriter), 0),
-       }
-}
diff --git a/modules/context/utils.go b/modules/context/utils.go
deleted file mode 100644 (file)
index 293750f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package context
-
-import (
-       "strings"
-       "time"
-)
-
-// GetQueryBeforeSince return parsed time (unix format) from URL query's before and since
-func GetQueryBeforeSince(ctx *Base) (before, since int64, err error) {
-       before, err = parseFormTime(ctx, "before")
-       if err != nil {
-               return 0, 0, err
-       }
-
-       since, err = parseFormTime(ctx, "since")
-       if err != nil {
-               return 0, 0, err
-       }
-       return before, since, nil
-}
-
-// parseTime parse time and return unix timestamp
-func parseFormTime(ctx *Base, name string) (int64, error) {
-       value := strings.TrimSpace(ctx.FormString(name))
-       if len(value) != 0 {
-               t, err := time.Parse(time.RFC3339, value)
-               if err != nil {
-                       return 0, err
-               }
-               if !t.IsZero() {
-                       return t.Unix(), nil
-               }
-       }
-       return 0, nil
-}
diff --git a/modules/context/xsrf.go b/modules/context/xsrf.go
deleted file mode 100644 (file)
index 15e36d1..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-// Copyright 2014 The Macaron Authors
-// Copyright 2020 The Gitea Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// SPDX-License-Identifier: Apache-2.0
-
-package context
-
-import (
-       "bytes"
-       "crypto/hmac"
-       "crypto/sha1"
-       "crypto/subtle"
-       "encoding/base64"
-       "fmt"
-       "strconv"
-       "strings"
-       "time"
-)
-
-// CsrfTokenTimeout represents the duration that XSRF tokens are valid.
-// It is exported so clients may set cookie timeouts that match generated tokens.
-const CsrfTokenTimeout = 24 * time.Hour
-
-// CsrfTokenRegenerationInterval is the interval between token generations, old tokens are still valid before CsrfTokenTimeout
-var CsrfTokenRegenerationInterval = 10 * time.Minute
-
-var csrfTokenSep = []byte(":")
-
-// GenerateCsrfToken returns a URL-safe secure XSRF token that expires in CsrfTokenTimeout hours.
-// key is a secret key for your application.
-// userID is a unique identifier for the user.
-// actionID is the action the user is taking (e.g. POSTing to a particular path).
-func GenerateCsrfToken(key, userID, actionID string, now time.Time) string {
-       nowUnixNano := now.UnixNano()
-       nowUnixNanoStr := strconv.FormatInt(nowUnixNano, 10)
-       h := hmac.New(sha1.New, []byte(key))
-       h.Write([]byte(strings.ReplaceAll(userID, ":", "_")))
-       h.Write(csrfTokenSep)
-       h.Write([]byte(strings.ReplaceAll(actionID, ":", "_")))
-       h.Write(csrfTokenSep)
-       h.Write([]byte(nowUnixNanoStr))
-       tok := fmt.Sprintf("%s:%s", h.Sum(nil), nowUnixNanoStr)
-       return base64.RawURLEncoding.EncodeToString([]byte(tok))
-}
-
-func ParseCsrfToken(token string) (issueTime time.Time, ok bool) {
-       data, err := base64.RawURLEncoding.DecodeString(token)
-       if err != nil {
-               return time.Time{}, false
-       }
-
-       pos := bytes.LastIndex(data, csrfTokenSep)
-       if pos == -1 {
-               return time.Time{}, false
-       }
-       nanos, err := strconv.ParseInt(string(data[pos+1:]), 10, 64)
-       if err != nil {
-               return time.Time{}, false
-       }
-       return time.Unix(0, nanos), true
-}
-
-// ValidCsrfToken returns true if token is a valid and unexpired token returned by Generate.
-func ValidCsrfToken(token, key, userID, actionID string, now time.Time) bool {
-       issueTime, ok := ParseCsrfToken(token)
-       if !ok {
-               return false
-       }
-
-       // Check that the token is not expired.
-       if now.Sub(issueTime) >= CsrfTokenTimeout {
-               return false
-       }
-
-       // Check that the token is not from the future.
-       // Allow 1-minute grace period in case the token is being verified on a
-       // machine whose clock is behind the machine that issued the token.
-       if issueTime.After(now.Add(1 * time.Minute)) {
-               return false
-       }
-
-       expected := GenerateCsrfToken(key, userID, actionID, issueTime)
-
-       // Check that the token matches the expected value.
-       // Use constant time comparison to avoid timing attacks.
-       return subtle.ConstantTimeCompare([]byte(token), []byte(expected)) == 1
-}
diff --git a/modules/context/xsrf_test.go b/modules/context/xsrf_test.go
deleted file mode 100644 (file)
index 21cda5d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-// Copyright 2014 The Macaron Authors
-// Copyright 2020 The Gitea Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// SPDX-License-Identifier: Apache-2.0
-
-package context
-
-import (
-       "encoding/base64"
-       "testing"
-       "time"
-
-       "github.com/stretchr/testify/assert"
-)
-
-const (
-       key      = "quay"
-       userID   = "12345678"
-       actionID = "POST /form"
-)
-
-var (
-       now              = time.Now()
-       oneMinuteFromNow = now.Add(1 * time.Minute)
-)
-
-func Test_ValidToken(t *testing.T) {
-       t.Run("Validate token", func(t *testing.T) {
-               tok := GenerateCsrfToken(key, userID, actionID, now)
-               assert.True(t, ValidCsrfToken(tok, key, userID, actionID, oneMinuteFromNow))
-               assert.True(t, ValidCsrfToken(tok, key, userID, actionID, now.Add(CsrfTokenTimeout-1*time.Nanosecond)))
-               assert.True(t, ValidCsrfToken(tok, key, userID, actionID, now.Add(-1*time.Minute)))
-       })
-}
-
-// Test_SeparatorReplacement tests that separators are being correctly substituted
-func Test_SeparatorReplacement(t *testing.T) {
-       t.Run("Test two separator replacements", func(t *testing.T) {
-               assert.NotEqual(t, GenerateCsrfToken("foo:bar", "baz", "wah", now),
-                       GenerateCsrfToken("foo", "bar:baz", "wah", now))
-       })
-}
-
-func Test_InvalidToken(t *testing.T) {
-       t.Run("Test invalid tokens", func(t *testing.T) {
-               invalidTokenTests := []struct {
-                       name, key, userID, actionID string
-                       t                           time.Time
-               }{
-                       {"Bad key", "foobar", userID, actionID, oneMinuteFromNow},
-                       {"Bad userID", key, "foobar", actionID, oneMinuteFromNow},
-                       {"Bad actionID", key, userID, "foobar", oneMinuteFromNow},
-                       {"Expired", key, userID, actionID, now.Add(CsrfTokenTimeout)},
-                       {"More than 1 minute from the future", key, userID, actionID, now.Add(-1*time.Nanosecond - 1*time.Minute)},
-               }
-
-               tok := GenerateCsrfToken(key, userID, actionID, now)
-               for _, itt := range invalidTokenTests {
-                       assert.False(t, ValidCsrfToken(tok, itt.key, itt.userID, itt.actionID, itt.t))
-               }
-       })
-}
-
-// Test_ValidateBadData primarily tests that no unexpected panics are triggered during parsing
-func Test_ValidateBadData(t *testing.T) {
-       t.Run("Validate bad data", func(t *testing.T) {
-               badDataTests := []struct {
-                       name, tok string
-               }{
-                       {"Invalid Base64", "ASDab24(@)$*=="},
-                       {"No delimiter", base64.URLEncoding.EncodeToString([]byte("foobar12345678"))},
-                       {"Invalid time", base64.URLEncoding.EncodeToString([]byte("foobar:foobar"))},
-               }
-
-               for _, bdt := range badDataTests {
-                       assert.False(t, ValidCsrfToken(bdt.tok, key, userID, actionID, oneMinuteFromNow))
-               }
-       })
-}
diff --git a/modules/contexttest/context_tests.go b/modules/contexttest/context_tests.go
deleted file mode 100644 (file)
index c9bacf2..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-// Package contexttest provides utilities for testing Web/API contexts with models.
-package contexttest
-
-import (
-       gocontext "context"
-       "io"
-       "net/http"
-       "net/http/httptest"
-       "net/url"
-       "strings"
-       "testing"
-
-       access_model "code.gitea.io/gitea/models/perm/access"
-       repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/models/unittest"
-       user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
-       "code.gitea.io/gitea/modules/gitrepo"
-       "code.gitea.io/gitea/modules/templates"
-       "code.gitea.io/gitea/modules/translation"
-       "code.gitea.io/gitea/modules/web/middleware"
-
-       "github.com/go-chi/chi/v5"
-       "github.com/stretchr/testify/assert"
-)
-
-func mockRequest(t *testing.T, reqPath string) *http.Request {
-       method, path, found := strings.Cut(reqPath, " ")
-       if !found {
-               method = "GET"
-               path = reqPath
-       }
-       requestURL, err := url.Parse(path)
-       assert.NoError(t, err)
-       req := &http.Request{Method: method, URL: requestURL, Form: url.Values{}}
-       req = req.WithContext(middleware.WithContextData(req.Context()))
-       return req
-}
-
-type MockContextOption struct {
-       Render context.Render
-}
-
-// MockContext mock context for unit tests
-func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*context.Context, *httptest.ResponseRecorder) {
-       var opt MockContextOption
-       if len(opts) > 0 {
-               opt = opts[0]
-       }
-       if opt.Render == nil {
-               opt.Render = &MockRender{}
-       }
-       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.Data = middleware.GetContextData(req.Context())
-       base.Locale = &translation.MockLocale{}
-
-       ctx := context.NewWebContext(base, opt.Render, nil)
-
-       chiCtx := chi.NewRouteContext()
-       ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx)
-       return ctx, resp
-}
-
-// MockAPIContext mock context for unit tests
-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.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)
-       return ctx, resp
-}
-
-// LoadRepo load a repo into a test context.
-func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {
-       var doer *user_model.User
-       repo := &context.Repository{}
-       switch ctx := ctx.(type) {
-       case *context.Context:
-               ctx.Repo = repo
-               doer = ctx.Doer
-       case *context.APIContext:
-               ctx.Repo = repo
-               doer = ctx.Doer
-       default:
-               assert.FailNow(t, "context is not *context.Context or *context.APIContext")
-       }
-
-       repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
-       var err error
-       repo.Owner, err = user_model.GetUserByID(ctx, repo.Repository.OwnerID)
-       assert.NoError(t, err)
-       repo.RepoLink = repo.Repository.Link()
-       repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo.Repository, doer)
-       assert.NoError(t, err)
-}
-
-// LoadRepoCommit loads a repo's commit into a test context.
-func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {
-       var repo *context.Repository
-       switch ctx := ctx.(type) {
-       case *context.Context:
-               repo = ctx.Repo
-       case *context.APIContext:
-               repo = ctx.Repo
-       default:
-               assert.FailNow(t, "context is not *context.Context or *context.APIContext")
-       }
-
-       gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository)
-       assert.NoError(t, err)
-       defer gitRepo.Close()
-       branch, err := gitRepo.GetHEADBranch()
-       assert.NoError(t, err)
-       assert.NotNil(t, branch)
-       if branch != nil {
-               repo.Commit, err = gitRepo.GetBranchCommit(branch.Name)
-               assert.NoError(t, err)
-       }
-}
-
-// LoadUser load a user into a test context
-func LoadUser(t *testing.T, ctx gocontext.Context, userID int64) {
-       doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
-       switch ctx := ctx.(type) {
-       case *context.Context:
-               ctx.Doer = doer
-       case *context.APIContext:
-               ctx.Doer = doer
-       default:
-               assert.FailNow(t, "context is not *context.Context or *context.APIContext")
-       }
-}
-
-// LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has
-// already been populated.
-func LoadGitRepo(t *testing.T, ctx *context.Context) {
-       assert.NoError(t, ctx.Repo.Repository.LoadOwner(ctx))
-       var err error
-       ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
-       assert.NoError(t, err)
-}
-
-type MockRender struct{}
-
-func (tr *MockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) {
-       return nil, nil
-}
-
-func (tr *MockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error {
-       if resp, ok := w.(http.ResponseWriter); ok {
-               resp.WriteHeader(status)
-       }
-       return nil
-}
diff --git a/modules/upload/upload.go b/modules/upload/upload.go
deleted file mode 100644 (file)
index cd10715..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package upload
-
-import (
-       "mime"
-       "net/http"
-       "net/url"
-       "path"
-       "regexp"
-       "strings"
-
-       "code.gitea.io/gitea/modules/context"
-       "code.gitea.io/gitea/modules/log"
-       "code.gitea.io/gitea/modules/setting"
-)
-
-// ErrFileTypeForbidden not allowed file type error
-type ErrFileTypeForbidden struct {
-       Type string
-}
-
-// IsErrFileTypeForbidden checks if an error is a ErrFileTypeForbidden.
-func IsErrFileTypeForbidden(err error) bool {
-       _, ok := err.(ErrFileTypeForbidden)
-       return ok
-}
-
-func (err ErrFileTypeForbidden) Error() string {
-       return "This file extension or type is not allowed to be uploaded."
-}
-
-var wildcardTypeRe = regexp.MustCompile(`^[a-z]+/\*$`)
-
-// Verify validates whether a file is allowed to be uploaded.
-func Verify(buf []byte, fileName, allowedTypesStr string) error {
-       allowedTypesStr = strings.ReplaceAll(allowedTypesStr, "|", ",") // compat for old config format
-
-       allowedTypes := []string{}
-       for _, entry := range strings.Split(allowedTypesStr, ",") {
-               entry = strings.ToLower(strings.TrimSpace(entry))
-               if entry != "" {
-                       allowedTypes = append(allowedTypes, entry)
-               }
-       }
-
-       if len(allowedTypes) == 0 {
-               return nil // everything is allowed
-       }
-
-       fullMimeType := http.DetectContentType(buf)
-       mimeType, _, err := mime.ParseMediaType(fullMimeType)
-       if err != nil {
-               log.Warn("Detected attachment type could not be parsed %s", fullMimeType)
-               return ErrFileTypeForbidden{Type: fullMimeType}
-       }
-       extension := strings.ToLower(path.Ext(fileName))
-
-       // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers
-       for _, allowEntry := range allowedTypes {
-               if allowEntry == "*/*" {
-                       return nil // everything allowed
-               } else if strings.HasPrefix(allowEntry, ".") && allowEntry == extension {
-                       return nil // extension is allowed
-               } else if mimeType == allowEntry {
-                       return nil // mime type is allowed
-               } else if wildcardTypeRe.MatchString(allowEntry) && strings.HasPrefix(mimeType, allowEntry[:len(allowEntry)-1]) {
-                       return nil // wildcard match, e.g. image/*
-               }
-       }
-
-       log.Info("Attachment with type %s blocked from upload", fullMimeType)
-       return ErrFileTypeForbidden{Type: fullMimeType}
-}
-
-// AddUploadContext renders template values for dropzone
-func AddUploadContext(ctx *context.Context, uploadType string) {
-       if uploadType == "release" {
-               ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/releases/attachments"
-               ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/releases/attachments/remove"
-               ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/releases/attachments"
-               ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Release.AllowedTypes, "|", ",")
-               ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles
-               ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize
-       } else if uploadType == "comment" {
-               ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
-               ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove"
-               if len(ctx.Params(":index")) > 0 {
-                       ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.Params(":index")) + "/attachments"
-               } else {
-                       ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
-               }
-               ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Attachment.AllowedTypes, "|", ",")
-               ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles
-               ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize
-       } else if uploadType == "repo" {
-               ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/upload-file"
-               ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/upload-remove"
-               ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/upload-file"
-               ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Upload.AllowedTypes, "|", ",")
-               ctx.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles
-               ctx.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize
-       }
-}
diff --git a/modules/upload/upload_test.go b/modules/upload/upload_test.go
deleted file mode 100644 (file)
index f2c3242..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package upload
-
-import (
-       "bytes"
-       "compress/gzip"
-       "testing"
-
-       "github.com/stretchr/testify/assert"
-)
-
-func TestUpload(t *testing.T) {
-       testContent := []byte(`This is a plain text file.`)
-       var b bytes.Buffer
-       w := gzip.NewWriter(&b)
-       w.Write(testContent)
-       w.Close()
-
-       kases := []struct {
-               data         []byte
-               fileName     string
-               allowedTypes string
-               err          error
-       }{
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "dir/test.txt",
-                       allowedTypes: "",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "../../../test.txt",
-                       allowedTypes: "",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: ",",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "|",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "*/*",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "*/*,",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "*/*|",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "text/plain",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "dir/test.txt",
-                       allowedTypes: "text/plain",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "/dir.txt/test.js",
-                       allowedTypes: ".js",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: " text/plain ",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: ".txt",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: " .txt,.js",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: " .txt|.js",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "../../test.txt",
-                       allowedTypes: " .txt|.js",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: " .txt ,.js ",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "text/plain, .txt",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "text/*",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "text/*,.js",
-                       err:          nil,
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "text/**",
-                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: "application/x-gzip",
-                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: ".zip",
-                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: ".zip,.txtx",
-                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
-               },
-               {
-                       data:         testContent,
-                       fileName:     "test.txt",
-                       allowedTypes: ".zip|.txtx",
-                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
-               },
-               {
-                       data:         b.Bytes(),
-                       fileName:     "test.txt",
-                       allowedTypes: "application/x-gzip",
-                       err:          nil,
-               },
-       }
-
-       for _, kase := range kases {
-               assert.Equal(t, kase.err, Verify(kase.data, kase.fileName, kase.allowedTypes))
-       }
-}
index 9fbd3f045d759d37a90796246942c7d3e5e36a52..d530e9cee5693eef3a2a16820381e688a658f1dc 100644 (file)
@@ -71,7 +71,6 @@ import (
 
        "code.gitea.io/gitea/models/actions"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
@@ -80,6 +79,7 @@ import (
        "code.gitea.io/gitea/modules/web"
        web_types "code.gitea.io/gitea/modules/web/types"
        actions_service "code.gitea.io/gitea/services/actions"
+       "code.gitea.io/gitea/services/context"
 )
 
 const artifactRouteBase = "/_apis/pipelines/workflows/{run_id}/artifacts"
index 3fd8288c018c6623e3b3b42e52060be6da929311..dae9c3dfcb2c887aeca97c9c3b7cfc7be29ae6d4 100644 (file)
@@ -14,12 +14,12 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        packages_module "code.gitea.io/gitea/modules/packages"
        alpine_module "code.gitea.io/gitea/modules/packages/alpine"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
        alpine_service "code.gitea.io/gitea/services/packages/alpine"
 )
index d990ebb56a75913351eb2b4c5c77f5b29ed35fc9..5e3cbac8f9cb1928d3e2b7d51933a0cefa7a2bcd 100644 (file)
@@ -10,7 +10,6 @@ import (
 
        auth_model "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/models/perm"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
@@ -36,7 +35,7 @@ import (
        "code.gitea.io/gitea/routers/api/packages/swift"
        "code.gitea.io/gitea/routers/api/packages/vagrant"
        "code.gitea.io/gitea/services/auth"
-       context_service "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
@@ -642,7 +641,7 @@ func CommonRoutes() *web.Route {
                                })
                        })
                }, reqPackageAccess(perm.AccessModeRead))
-       }, context_service.UserAssignmentWeb(), context.PackageAssignment())
+       }, context.UserAssignmentWeb(), context.PackageAssignment())
 
        return r
 }
@@ -812,7 +811,7 @@ func ContainerRoutes() *web.Route {
 
                        ctx.Status(http.StatusNotFound)
                })
-       }, container.ReqContainerAccess, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
+       }, container.ReqContainerAccess, context.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
 
        return r
 }
index 8f1e965c9a399f5045d209d740c4498127074e4a..d01a13d78f67cf9672c712acb6bae122713370d8 100644 (file)
@@ -12,7 +12,6 @@ import (
 
        "code.gitea.io/gitea/models/db"
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
        cargo_module "code.gitea.io/gitea/modules/packages/cargo"
@@ -20,6 +19,7 @@ import (
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        packages_service "code.gitea.io/gitea/services/packages"
        cargo_service "code.gitea.io/gitea/services/packages/cargo"
index f1e9ae12d816cd42233e4aaef21c8ccbd27f2419..720fce0a2a5d7cdc058ae7190ae07c1d600fe428 100644 (file)
@@ -15,12 +15,12 @@ import (
 
        "code.gitea.io/gitea/models/db"
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        chef_module "code.gitea.io/gitea/modules/packages/chef"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 0551093cd19f2326c65cdf69e4815588c3c3a29a..346408d2611ba1ec92f78590481e91fc6b96e64e 100644 (file)
@@ -14,12 +14,12 @@ import (
 
        "code.gitea.io/gitea/models/db"
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        composer_module "code.gitea.io/gitea/modules/packages/composer"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        packages_service "code.gitea.io/gitea/services/packages"
 
index 4bf13222dc793965911dcb271720a13d3e831556..c45e085a4d9f04feecf8fec672c8b021ac57a42a 100644 (file)
@@ -15,13 +15,13 @@ import (
        packages_model "code.gitea.io/gitea/models/packages"
        conan_model "code.gitea.io/gitea/models/packages/conan"
        "code.gitea.io/gitea/modules/container"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
        conan_module "code.gitea.io/gitea/modules/packages/conan"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        notify_service "code.gitea.io/gitea/services/notify"
        packages_service "code.gitea.io/gitea/services/packages"
 )
index 2bcf9df162b9814c5c78ca4354daa3eba8e3ae3a..7370c702cd668ac8538a28e4e8fcf3d53afe56cd 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        conan_model "code.gitea.io/gitea/models/packages/conan"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        conan_module "code.gitea.io/gitea/modules/packages/conan"
+       "code.gitea.io/gitea/services/context"
 )
 
 // SearchResult contains the found recipe names
index 0bee7baa96f76f66fcb18af6ce57075fd83f26d3..30c80fc15e0571278b797d47f83da43f6e2fd693 100644 (file)
@@ -12,13 +12,13 @@ import (
 
        packages_model "code.gitea.io/gitea/models/packages"
        conda_model "code.gitea.io/gitea/models/packages/conda"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
        conda_module "code.gitea.io/gitea/modules/packages/conda"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 
        "github.com/dsnet/compress/bzip2"
index 8621242da4eb3ff1fea3bb8f1565f7a464dc8f41..e5197661423b3256f4c1ea03abd236fbc92497a6 100644 (file)
@@ -17,7 +17,6 @@ import (
        packages_model "code.gitea.io/gitea/models/packages"
        container_model "code.gitea.io/gitea/models/packages/container"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
@@ -25,6 +24,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
        container_service "code.gitea.io/gitea/services/packages/container"
 
index ae43df7c9aa0d0f3697efd23716c2544b4702fc1..2cec75294fec27fb059731e8cf0026a8595774d7 100644 (file)
@@ -13,11 +13,11 @@ import (
 
        packages_model "code.gitea.io/gitea/models/packages"
        cran_model "code.gitea.io/gitea/models/packages/cran"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        cran_module "code.gitea.io/gitea/modules/packages/cran"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 379137e87eb9c269bdc850110e369bba3bb20374..241de3ac5d915cb672d32bec8b06e2f1c342d534 100644 (file)
@@ -13,11 +13,11 @@ import (
 
        "code.gitea.io/gitea/models/db"
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        debian_module "code.gitea.io/gitea/modules/packages/debian"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        notify_service "code.gitea.io/gitea/services/notify"
        packages_service "code.gitea.io/gitea/services/packages"
        debian_service "code.gitea.io/gitea/services/packages/debian"
index 30854335c09362893c5623e80b94acd9ea244b9c..b65870a8d098de4b10f2105dcf7228e0c084585c 100644 (file)
@@ -10,10 +10,10 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 18e0074ab4d0120eb0524e960781f1b8761302b4..9eb515d9a1befd4176ee63f1498cb74b5d00b479 100644 (file)
@@ -12,11 +12,11 @@ import (
        "time"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        goproxy_module "code.gitea.io/gitea/modules/packages/goproxy"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index a8daa69dc3a9d46078b959f10f9d255582dc08d5..e7a346d9ca7beba2f3d7d22af76e0cd49a6cb7e5 100644 (file)
@@ -13,7 +13,6 @@ import (
        "time"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
@@ -21,6 +20,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 
        "gopkg.in/yaml.v3"
index aadb10376c81ee52eed3c5875150f031c763b7c8..cdb64109ade24eb2c5e3e9266fb20f6492b03851 100644 (file)
@@ -10,9 +10,9 @@ import (
        "net/url"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 // LogAndProcessError logs an error and calls a custom callback with the processed error message.
index 5106395eb1a620addd01115ba1bf06c19341ddda..27f0578db70e8273a1dfe3c36b44ed1fbb08303c 100644 (file)
@@ -20,12 +20,12 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
        maven_module "code.gitea.io/gitea/modules/packages/maven"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 170edfbe11cc1d1d87054486a79947810ee3a797..72b43059281116733da43817201a67b6e192d95f 100644 (file)
@@ -17,12 +17,12 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        npm_module "code.gitea.io/gitea/modules/packages/npm"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 
        "github.com/hashicorp/go-version"
index 769c4c1824571559bbf55e9e379b3da3aba0352d..a0273aad5ad3306de4d698c621bb4d065e2dd3b4 100644 (file)
@@ -17,13 +17,13 @@ import (
        "code.gitea.io/gitea/models/db"
        packages_model "code.gitea.io/gitea/models/packages"
        nuget_model "code.gitea.io/gitea/models/packages/nuget"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
        nuget_module "code.gitea.io/gitea/modules/packages/nuget"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 1f605c6c9f432fccae0dde9d9fad443a9f4eff95..f87df52a29aa145e06959c6d1578588905de0a3c 100644 (file)
@@ -14,7 +14,6 @@ import (
        "time"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
@@ -22,6 +21,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 5718b1203b48b48bb846964f4c5383811d6db374..7824db18235d9ce473f4b866c6287e3a595cd886 100644 (file)
@@ -12,12 +12,12 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        pypi_module "code.gitea.io/gitea/modules/packages/pypi"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/validation"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 5d06680552cb57dc5f86c85ad4a3a92f1095f693..4de361c214227ffa9fe84cc5e4c5c37bc18dac77 100644 (file)
@@ -13,13 +13,13 @@ import (
 
        "code.gitea.io/gitea/models/db"
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        packages_module "code.gitea.io/gitea/modules/packages"
        rpm_module "code.gitea.io/gitea/modules/packages/rpm"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        notify_service "code.gitea.io/gitea/services/notify"
        packages_service "code.gitea.io/gitea/services/packages"
        rpm_service "code.gitea.io/gitea/services/packages/rpm"
index 01fd4dad669156e865c2c932d152a7c6d4891d5e..5d05b6d524d51d935a303be9752b8e1eef75d754 100644 (file)
@@ -13,11 +13,11 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        rubygems_module "code.gitea.io/gitea/modules/packages/rubygems"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 )
 
index 6ad289e51e9ea2b88f2602091b86296dfe5e6964..1fc8baeaacd6a574374fa6411436a072504aa9ca 100644 (file)
@@ -13,7 +13,6 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        packages_module "code.gitea.io/gitea/modules/packages"
@@ -21,6 +20,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 
        "github.com/hashicorp/go-version"
index af9cd08a6297ef2b781fabdf91ba507469a31e08..98a81da368ead270907b527cfdd5feb0a36cfa50 100644 (file)
@@ -12,11 +12,11 @@ import (
        "strings"
 
        packages_model "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        packages_module "code.gitea.io/gitea/modules/packages"
        vagrant_module "code.gitea.io/gitea/modules/packages/vagrant"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/routers/api/packages/helper"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
 
        "github.com/hashicorp/go-version"
index cad5032d103c97a45932b6a7016170608fa84200..995a148f0bdb1a67097eebf6fca36cb3706a1e4b 100644 (file)
@@ -9,9 +9,9 @@ import (
        "strings"
 
        "code.gitea.io/gitea/modules/activitypub"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 
        ap "github.com/go-ap/activitypub"
        "github.com/go-ap/jsonld"
index 3f60ed7776a3f7ecb6c98d77541f06e1929edf9e..59ebc74b89ef7cab7d92930aac44f163550a8221 100644 (file)
@@ -13,9 +13,9 @@ import (
        "net/url"
 
        "code.gitea.io/gitea/modules/activitypub"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/httplib"
        "code.gitea.io/gitea/modules/setting"
+       gitea_context "code.gitea.io/gitea/services/context"
 
        ap "github.com/go-ap/activitypub"
        "github.com/go-fed/httpsig"
index bf030eb222bc7cc07667d1297d0be424cc584a17..a4708fe0326e6c550f4a60639d05028244266f28 100644 (file)
@@ -8,9 +8,9 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index cc8c6c9e2391fc935bcc2c4dc044f0adfc55e975..e1ca6048c930bb93062bc7ff06d715b3789849ad 100644 (file)
@@ -6,11 +6,11 @@ package admin
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/cron"
 )
 
index 5914215bc2a128d3ef70eb4710caa5123d325774..ba963e9f69d9a9aa9347539c7fb219df71ef489c 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
 
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 8a095a7defa2ae63bfc0e058f3a56a04f946b637..2217d002a02063dbb83da5a3d76d5309d899ae3a 100644 (file)
@@ -8,12 +8,12 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/models/webhook"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        webhook_service "code.gitea.io/gitea/services/webhook"
 )
 
index bf68942a9cade95ab54535a8a64598f0d06a7ded..a5c299bbf01c8daeec4a06fd529e75299e966301 100644 (file)
@@ -10,10 +10,10 @@ 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/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index a4895f260beca98a3b0eb9549224582a76c31537..c119d5390a2c770da50c78e8c5d9b8bbd17d19a8 100644 (file)
@@ -4,10 +4,10 @@
 package admin
 
 import (
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/repo"
+       "code.gitea.io/gitea/services/context"
 )
 
 // CreateRepo api for creating a repository
index c0d93644350717b78db10cdd1bb43dbf62247548..329242d9f6ee531fdeb5bbd4635a4bac4a20b289 100644 (file)
@@ -4,8 +4,8 @@
 package admin
 
 import (
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/routers/api/v1/shared"
+       "code.gitea.io/gitea/services/context"
 )
 
 // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
index 2ce7651a096bcc4099bc8d1f925989a5ee171eaa..64315108b088c1971de538400cda575f3dfa570e 100644 (file)
@@ -15,7 +15,6 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
@@ -25,6 +24,7 @@ import (
        "code.gitea.io/gitea/routers/api/v1/user"
        "code.gitea.io/gitea/routers/api/v1/utils"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/mailer"
        user_service "code.gitea.io/gitea/services/user"
index e0c72c7ac401c68116dc328c2cf509c84d88346e..0913571c270204da5cae4a9cc4ed141a40602f65 100644 (file)
@@ -79,7 +79,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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
@@ -95,7 +94,7 @@ import (
        "code.gitea.io/gitea/routers/api/v1/user"
        "code.gitea.io/gitea/routers/common"
        "code.gitea.io/gitea/services/auth"
-       context_service "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 
        _ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
@@ -855,11 +854,11 @@ func Routes() *web.Route {
                                m.Group("/user/{username}", func() {
                                        m.Get("", activitypub.Person)
                                        m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
-                               }, context_service.UserAssignmentAPI())
+                               }, context.UserAssignmentAPI())
                                m.Group("/user-id/{user-id}", func() {
                                        m.Get("", activitypub.Person)
                                        m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
-                               }, context_service.UserIDAssignmentAPI())
+                               }, context.UserIDAssignmentAPI())
                        }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub))
                }
 
@@ -915,7 +914,7 @@ func Routes() *web.Route {
                                }, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
 
                                m.Get("/activities/feeds", user.ListUserActivityFeeds)
-                       }, context_service.UserAssignmentAPI(), individualPermsChecker)
+                       }, context.UserAssignmentAPI(), individualPermsChecker)
                }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
 
                // Users (requires user scope)
@@ -933,7 +932,7 @@ func Routes() *web.Route {
                                m.Get("/starred", user.GetStarredRepos)
 
                                m.Get("/subscriptions", user.GetWatchedRepos)
-                       }, context_service.UserAssignmentAPI())
+                       }, context.UserAssignmentAPI())
                }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
 
                // Users (requires user scope)
@@ -968,7 +967,7 @@ func Routes() *web.Route {
                                        m.Get("", user.CheckMyFollowing)
                                        m.Put("", user.Follow)
                                        m.Delete("", user.Unfollow)
-                               }, context_service.UserAssignmentAPI())
+                               }, context.UserAssignmentAPI())
                        })
 
                        // (admin:public_key scope)
@@ -1415,14 +1414,14 @@ func Routes() *web.Route {
                                m.Get("/files", reqToken(), packages.ListPackageFiles)
                        })
                        m.Get("/", reqToken(), packages.ListPackages)
-               }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
+               }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
 
                // Organizations
                m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
                m.Group("/users/{username}/orgs", func() {
                        m.Get("", reqToken(), org.ListUserOrgs)
                        m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
-               }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context_service.UserAssignmentAPI())
+               }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI())
                m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create)
                m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
                m.Group("/orgs/{org}", func() {
@@ -1520,7 +1519,7 @@ func Routes() *web.Route {
                                        m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
                                        m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
                                        m.Post("/rename", bind(api.RenameUserOption{}), admin.RenameUser)
-                               }, context_service.UserAssignmentAPI())
+                               }, context.UserAssignmentAPI())
                        })
                        m.Group("/emails", func() {
                                m.Get("", admin.GetAllEmails)
index 7c7fe4b125fa43461b42545fba75782100514e58..dffd771752e16befe109b90eea0087b019364d78 100644 (file)
@@ -6,11 +6,11 @@ package misc
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/options"
        repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Shows a list of all Gitignore templates
index 0e0ca39fc5d465d88fe96b7a6b1879d663cbc4cd..cc11f376262c521ef9f77ce3560d8a422b62cb87 100644 (file)
@@ -6,9 +6,9 @@ package misc
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 65f63468cfd9fe154c3cc448d7008db35e104212..2a980f5084d36c0dba91968ac2165ec5634e07a2 100644 (file)
@@ -8,12 +8,12 @@ import (
        "net/http"
        "net/url"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/options"
        repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Returns a list of all License templates
index 7b24b353b63d0abcc1f0cd1e2e14cca68d568070..9699c79368a2cecf8e43ab6c95c96632b9e32627 100644 (file)
@@ -6,12 +6,12 @@ package misc
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/markdown"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/common"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Markup render markup document to HTML
index ec8f8f47b70417a55753807f18d0db56005ce736..f499501c2fc9e135a9257a75844dc7a91b0386b4 100644 (file)
@@ -10,11 +10,11 @@ import (
        "strings"
        "testing"
 
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index cc754f64a21a9758f95ef2ca29dec5171e8f7e81..3bd80de5c18e3099f437efd3af3fa28fc83510ac 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 )
 
 const cacheKeyNodeInfoUsage = "API_NodeInfoUsage"
index 2ca9813e15ca00368c986840bc3ef6a4322ce6c8..24a46c1e704ca4990dc23665b9e0ab5609aead55 100644 (file)
@@ -7,8 +7,8 @@ import (
        "fmt"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
 )
 
 // SigningKey returns the public key of the default signing key if it exists
index 83fa35219abe9cab5f9b8b20ccea90c583997e73..e3b43a0e6b6f87033af7455e51fe7b0aa9050f84 100644 (file)
@@ -6,9 +6,9 @@ package misc
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Version shows the version of the Gitea server
index c87da9399f0506a36dbf8dfd8393b1c5b0eb6e86..46b3c7f5e75827767a7ea74e0537630b4802e4d1 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        activities_model "code.gitea.io/gitea/models/activities"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
 )
 
 // NewAvailable check if unread notifications exist
index 55ca6ad1fd57976ca6f9fcb59ecd22179681fda7..8d97e8a3f84337f54531a7f0a46230edfd017ac3 100644 (file)
@@ -10,9 +10,9 @@ import (
 
        activities_model "code.gitea.io/gitea/models/activities"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 919e52952dc5ca542022bf86e9526a7f07a46244..8e12d359cb315e1a2263f368610f57f6dd314b04 100644 (file)
@@ -10,7 +10,7 @@ import (
        activities_model "code.gitea.io/gitea/models/activities"
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 4abdfb2e925a4784707cbe929727767f31020023..879f484cceef7cde9f0d51a53e37f711f5874827 100644 (file)
@@ -9,8 +9,8 @@ import (
 
        activities_model "code.gitea.io/gitea/models/activities"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 7b621a50c319e9f6e4beb9bb7341759aac366f6d..e34c68dfc9da1cf5a55295d10c7b3faf7f6538e4 100644 (file)
@@ -7,9 +7,9 @@ import (
        "encoding/base64"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        user_service "code.gitea.io/gitea/services/user"
 )
 
index 3c3f058b5ddf114cdf613a2831ebb8bf7c4e7613..c1dc0519ea1ebd1c8dd91c271f28f653f16bf762 100644 (file)
@@ -6,10 +6,10 @@ package org
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        webhook_service "code.gitea.io/gitea/services/webhook"
 )
 
index 5a03059deda26ba9e8b29d532681ad14d69a2f06..b5ec54ccf4e2c936212290a3c32d0974fae5edf4 100644 (file)
@@ -9,11 +9,11 @@ import (
        "strings"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/label"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 422b7cecfee14c94847a2ff81f668735d346f20b..fb66d4c3f5b00e2a5c81949230cedbe3074b72bd 100644 (file)
@@ -9,11 +9,11 @@ import (
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/organization"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/user"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 255e28c706469de6e1edf521cdaf7b1c4c2ab812..e848d951810949a93dca9573ceab5e91075bfd44 100644 (file)
@@ -12,12 +12,12 @@ import (
        "code.gitea.io/gitea/models/organization"
        "code.gitea.io/gitea/models/perm"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/optional"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/user"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/org"
        user_service "code.gitea.io/gitea/services/user"
index 05bce8daefbc9dc5bfee83855b5203d3ff8710d7..2a52bd8778f7eac3798d889e57686187ab589a7b 100644 (file)
@@ -4,8 +4,8 @@
 package org
 
 import (
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/routers/api/v1/shared"
+       "code.gitea.io/gitea/services/context"
 )
 
 // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
index ddc74d865b183b055e5382a3acc1b907ecd2b559..abb6bb26c433f7deeb35c06521d4d961e40c56fe 100644 (file)
@@ -9,11 +9,11 @@ import (
 
        "code.gitea.io/gitea/models/db"
        secret_model "code.gitea.io/gitea/models/secret"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        secret_service "code.gitea.io/gitea/services/secrets"
 )
 
index f129c662306c4caad00f85d0132b2a9e5adfd5a0..b62a386fd77ec2424456839a064a4d9c09e573d5 100644 (file)
@@ -15,12 +15,12 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        unit_model "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/user"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        org_service "code.gitea.io/gitea/services/org"
        repo_service "code.gitea.io/gitea/services/repository"
index a79ba315be2fc038d55749659023e929420587df..3be31b13ae100f61a1000c2903bc50abfacd9f7e 100644 (file)
@@ -7,10 +7,10 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/models/packages"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        packages_service "code.gitea.io/gitea/services/packages"
 )
index 039cdadac9c144ef99adee803e2e65c03f93bc13..e0af276c71503d5f3fb06b3f2df6c27173709540 100644 (file)
@@ -7,10 +7,10 @@ import (
        "errors"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        secret_service "code.gitea.io/gitea/services/secrets"
 )
 
index 1b661955f0590c40e1fee5a10a69121b55c39d99..698337ffd2f17b0c8e34fe6991c27facd8aa0491 100644 (file)
@@ -7,9 +7,9 @@ import (
        "encoding/base64"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index 26605bba03c720298f149f8e832043fef1d4de12..3b116666ead786b8a0ff3028cd44cccf3ee4dba9 100644 (file)
@@ -6,7 +6,7 @@ package repo
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        files_service "code.gitea.io/gitea/services/repository/files"
 )
 
index 2cdbcd25a2ef178e7022bc5b6e5deaa62ed0c496..5e6b6a86586bcedd7b990a52d31a5c7451d1299b 100644 (file)
@@ -14,7 +14,6 @@ import (
        git_model "code.gitea.io/gitea/models/git"
        "code.gitea.io/gitea/models/organization"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/optional"
@@ -22,6 +21,7 @@ import (
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        pull_service "code.gitea.io/gitea/services/pull"
        repo_service "code.gitea.io/gitea/services/repository"
index a222e50a5e537d18fddbb7adbc44ec12501ef450..7d48d7151690cc7f1c87e3560ca99319002a9ebd 100644 (file)
@@ -13,11 +13,11 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        repo_module "code.gitea.io/gitea/modules/repository"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        repo_service "code.gitea.io/gitea/services/repository"
 )
index d01cf6b8bcdfd9d72ed90545438465a5a5990cfd..d06a3b4e49a504b06cfab5bba9677847825be3e7 100644 (file)
@@ -12,11 +12,11 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 317213c9466fb1b6923408c9afa79a7a11eff100..907a5b568e6e2ec2d5834df54ba849645e6443f0 100644 (file)
@@ -19,7 +19,6 @@ 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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/httpcache"
@@ -30,6 +29,7 @@ import (
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/common"
+       "code.gitea.io/gitea/services/context"
        archiver_service "code.gitea.io/gitea/services/repository/archiver"
        files_service "code.gitea.io/gitea/services/repository/files"
 )
index 69433bf4cc40175b890260ddfeb5616c6a627664..212cc7a93b54f9d1c87d319ba2aaf97ca8b60933 100644 (file)
@@ -14,11 +14,11 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        repo_service "code.gitea.io/gitea/services/repository"
 )
index 7e471e263b68c282edf3da039cdda541a5deb22d..26ae84d08d3392dd2f8ee9aa4ea66389a96d3bae 100644 (file)
@@ -6,10 +6,10 @@ package repo
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 34d2dcfcc8143266970b682647bca104277753b9..0fa58425b85266987bf541196d03f49f2f7be7c8 100644 (file)
@@ -7,10 +7,10 @@ import (
        "net/http"
        "net/url"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
 )
 
 // GetGitAllRefs get ref or an list all the refs of a repository
index 8859e3ae2369533c237ea018995d3cf32d74c7da..ffd2313591b109353d66686c224323623c6b24d2 100644 (file)
@@ -11,13 +11,13 @@ import (
        "code.gitea.io/gitea/models/perm"
        access_model "code.gitea.io/gitea/models/perm/access"
        "code.gitea.io/gitea/models/webhook"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        webhook_module "code.gitea.io/gitea/modules/webhook"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        webhook_service "code.gitea.io/gitea/services/webhook"
 )
index 94a71e20ad70335ea58f8afac727abd07ed9bdcc..37cf61c1edf2d8ac57edbc9372d232a807b8a000 100644 (file)
@@ -9,7 +9,7 @@ import (
 
        "code.gitea.io/gitea/models/unittest"
        "code.gitea.io/gitea/models/webhook"
-       "code.gitea.io/gitea/modules/contexttest"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index 0f76a4b4ff26d84a8b2e75921636ab55009c7a2f..efc1a08a0501532630b1b8013d3eb2a32ce26773 100644 (file)
@@ -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/context"
        issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
@@ -26,6 +25,7 @@ import (
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        issue_service "code.gitea.io/gitea/services/issue"
        notify_service "code.gitea.io/gitea/services/notify"
index 11d19b21ff5d4e58bd42a3888021d35067f67560..d62e23aa0226082641473ac46ff17f641f687d5f 100644 (file)
@@ -8,12 +8,12 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/services/attachment"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        issue_service "code.gitea.io/gitea/services/issue"
 )
index 2b7a8f7ba1cc30b8322875a8cdb42a72cea7dffc..763419b7a25200b76a031d847047ea7085f1c97e 100644 (file)
@@ -14,11 +14,11 @@ 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/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        issue_service "code.gitea.io/gitea/services/issue"
 )
index 21e2f4dabd6b826482609f35e9dc3bc20cc64330..e7436db7982a751b995bd3bb6fb4462d9580c30e 100644 (file)
@@ -8,12 +8,12 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/services/attachment"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        issue_service "code.gitea.io/gitea/services/issue"
 )
index 62d1057cdf946cd6bcc8a2fd3f202cfd0af24e8b..a42920d4fd333582f98a2a7b21faa85d58328a70 100644 (file)
@@ -11,10 +11,10 @@ import (
        issues_model "code.gitea.io/gitea/models/issues"
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index c2f530956e9b4ff3e8a4a12095e034db568dd98a..7d9f85d2aa2580f327ec6fc49e88715be0aea551 100644 (file)
@@ -8,9 +8,9 @@ import (
        "net/http"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        issue_service "code.gitea.io/gitea/services/issue"
 )
index 61f88de34eb64047db9ea10d613251bcaefd45ea..ff1135862b3f142225112a935cd141ff92468d1d 100644 (file)
@@ -7,8 +7,8 @@ import (
        "net/http"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index c886bd71b7687087515396126ea484e962291f9e..799c687812635afd9e57ca622f1a8f4cd6ebcd32 100644 (file)
@@ -8,10 +8,10 @@ import (
        "net/http"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 52bf8b5c7b8065bb6cb8b562bfd0877088669aad..d9054e8f77573164ae919671c2ab6f99a3ebc1b5 100644 (file)
@@ -8,8 +8,8 @@ import (
        "net/http"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index ece880c03e1a10d161209787854e78f83c654ffd..a535172462e1910dfa0a0fc9f0270dc842230ddf 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index cf03e72aa0c18d78d7a4f3195ea920df292b2843..c6405158819db132aee1db052fbdedbeeb096def 100644 (file)
@@ -12,10 +12,10 @@ import (
        issues_model "code.gitea.io/gitea/models/issues"
        "code.gitea.io/gitea/models/unit"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index af48c40885df515e792285e571420296741f7784..88444a26250c0a7fdf8fa6624634b92c4de7c66d 100644 (file)
@@ -15,12 +15,12 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 420d3ab5b49bccbd6fc219ef45f5fdc8be24bf60..b6eb51fd20a849e1cb05299f34ae974a876720d7 100644 (file)
@@ -9,11 +9,11 @@ import (
        "strconv"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/label"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 12f1761ad08c1e95c5140926dc4db53fa00a8d18..f1d5bbe45fe72b4a7d85ce6ebf5bda47cce13f4c 100644 (file)
@@ -9,8 +9,8 @@ import (
        "strconv"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 type languageResponse []*repo_model.LanguageStat
index 839fbfe8a1a328e521daf2a99d647efe0bc5351e..2caaa130e8d012c78df194a9bf5ab7d263f9047c 100644 (file)
@@ -17,7 +17,6 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/lfs"
        "code.gitea.io/gitea/modules/log"
@@ -26,6 +25,7 @@ import (
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/migrations"
index 9c2ed16d930c1a16887f6f91e28e6a2f4f1645da..d4c828fe8bf1d84bb2e399baec6fbe18c88aa331 100644 (file)
@@ -11,12 +11,12 @@ import (
 
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/timeutil"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 26e0be301c11f34fcc073f141dbbca9599535f9c..864644e1efc83d4880b88b344c73b60520ff5c0c 100644 (file)
@@ -13,12 +13,12 @@ import (
        "code.gitea.io/gitea/models/db"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/migrations"
index e7e00dae418023e0a41c391715633f633922fe01..a4a1d4eab7c8dc1969b4ed80b819f342124cd4dc 100644 (file)
@@ -7,9 +7,9 @@ import (
        "fmt"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 9b5635d245a0c6d683e9933b22caf01f2679f349..0e0601b7d93e77164891108cd8f7ec6533b2dd34 100644 (file)
@@ -10,10 +10,10 @@ import (
        "code.gitea.io/gitea/models"
        git_model "code.gitea.io/gitea/models/git"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/repository/files"
 )
 
index 85f8ec1de566cae08a1298a4f41e1ff665462246..8f9848f71d17cdea4b5b4b0a7f9958708737790b 100644 (file)
@@ -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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/log"
@@ -32,6 +31,7 @@ import (
        "code.gitea.io/gitea/routers/api/v1/utils"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
        "code.gitea.io/gitea/services/automerge"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/gitdiff"
index 6338651aae9921f85a1fc94479aa606c9845bfdb..5128102e61bca61a01819b62897eed1c167b73f2 100644 (file)
@@ -12,11 +12,11 @@ import (
        "code.gitea.io/gitea/models/organization"
        access_model "code.gitea.io/gitea/models/perm/access"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/gitrepo"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        issue_service "code.gitea.io/gitea/services/issue"
        pull_service "code.gitea.io/gitea/services/pull"
index a41c5ba7d8550e801a470c6b3c82012810146291..a47fc1cc598d2637ac80212e8c949a3362467bc8 100644 (file)
@@ -11,10 +11,10 @@ import (
        "code.gitea.io/gitea/models/perm"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        release_service "code.gitea.io/gitea/services/release"
 )
index c36bf12e6d330201c2b76d70c157170f0b1ff48a..a29bce66a4e89dd72b08abf7f2d82081c5805a44 100644 (file)
@@ -7,13 +7,13 @@ import (
        "net/http"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/services/attachment"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/convert"
 )
 
index 9f2098df06642026a29b6e9ecc9ebf8f87343e5b..fec91164a29ac7957fc46eaebe1bebad3fb1ad45 100644 (file)
@@ -8,7 +8,7 @@ import (
 
        "code.gitea.io/gitea/models"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        releaseservice "code.gitea.io/gitea/services/release"
 )
index 40de8853d8352a5d2dffe3f116d8d30963483a85..8685d88913af106c14c487e205c15bf35669c935 100644 (file)
@@ -20,7 +20,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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/label"
@@ -32,6 +31,7 @@ import (
        "code.gitea.io/gitea/modules/validation"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/issue"
        repo_service "code.gitea.io/gitea/services/repository"
index 08ba7fabac4b3e8518559ad659dc2f1f1459569a..8d6ca9e3b54f02771b8134c13bf58a8cc34e3c6d 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index 0a2bbf81176c9775a641ee93561d822220928b73..fe133b311d503e4f036588363f22fc80b696da38 100644 (file)
@@ -4,8 +4,8 @@
 package repo
 
 import (
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/routers/api/v1/shared"
+       "code.gitea.io/gitea/services/context"
 )
 
 // GetRegistrationToken returns the token to register repo runners
index 05227e33a0c612d28a96c35bc6a0c1f32b0771c3..99676de119c1f05928a48d0d42aa7817547fa975 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index b4edf0608cf8f7b2f023f5be21b7670d0d681fb7..53711bedebfc5b6eb4be0634f4b79320a9409ffa 100644 (file)
@@ -9,10 +9,10 @@ import (
 
        "code.gitea.io/gitea/models/db"
        git_model "code.gitea.io/gitea/models/git"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        files_service "code.gitea.io/gitea/services/repository/files"
 )
index 05509fc4435c9b09880087662a29bac536590c02..8584182857825c54ec084f473386b4abb0fb913e 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 2f19f95e66dec58725e48268146123882e8b41df..a6908f361572e5d4afc4b82caa7cc324bd177cb3 100644 (file)
@@ -10,10 +10,10 @@ import (
 
        "code.gitea.io/gitea/models"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        releaseservice "code.gitea.io/gitea/services/release"
 )
index 1bacc7121187b7105eece42118167865b4c8f806..0ecf3a39d8fd672ad807fb2993073d80142e8f89 100644 (file)
@@ -8,7 +8,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/models/organization"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        org_service "code.gitea.io/gitea/services/org"
        repo_service "code.gitea.io/gitea/services/repository"
index d662b9b5832b50739ae3ca04d2950b9d65e74225..1d8e675bde0ffab0788152b256a6eb96743640ae 100644 (file)
@@ -8,11 +8,11 @@ import (
        "strings"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index c0a40ce0620f5dc5500fe77b8410dda9e8c9fdef..4f05c0df518c75158a6e801115c18a321a0bc9be 100644 (file)
@@ -13,10 +13,10 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        repo_service "code.gitea.io/gitea/services/repository"
 )
index f63100b6ea266d7b3dba367d81b884fe09e90cc9..353a996d5b0d13c76719dc78e9b8917c82adba59 100644 (file)
@@ -6,7 +6,7 @@ package repo
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        files_service "code.gitea.io/gitea/services/repository/files"
 )
 
index 4f27500496cd290e4888aa1e51f3018f28876aad..f18ea087c4d75d6cbfa1c6c6714fdfaf766aa6cd 100644 (file)
@@ -10,13 +10,13 @@ import (
        "net/url"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        notify_service "code.gitea.io/gitea/services/notify"
        wiki_service "code.gitea.io/gitea/services/wiki"
index 02bda1309d7297ba5fcc058d75fe93b330682064..0ee81b96d5bb973d26a8e6b676badcf9719eb38b 100644 (file)
@@ -6,9 +6,9 @@ package settings
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 )
 
 // GetGeneralUISettings returns instance's global settings for ui
index a342bd4b63712cec30c6f30b971f5894dd129c6c..c850ad7866a4b0dc225485c8b641bb91c1662d0f 100644 (file)
@@ -8,8 +8,8 @@ import (
        "net/http"
 
        actions_model "code.gitea.io/gitea/models/actions"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 // RegistrationToken is response related to registeration token
index cbe332a7798f7385432bb6e4706b2497f76f2ae4..babb8c0cf7abbc1cd9246c2d92619337c25510bb 100644 (file)
@@ -7,10 +7,10 @@ import (
        "errors"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        secret_service "code.gitea.io/gitea/services/secrets"
 )
 
index f045fb4d5d8c44a18324f690c8af469800a3bc91..88e314ed31ba726c09d2ac09850858004b4775d3 100644 (file)
@@ -13,10 +13,10 @@ import (
 
        auth_model "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 1c1bb6181aad0defa73fd3351ab4b1373311eb68..f912296228e7d64e80dd046723edb8b966c9fda1 100644 (file)
@@ -7,9 +7,9 @@ import (
        "encoding/base64"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        user_service "code.gitea.io/gitea/services/user"
 )
 
index 3dcea9083cd5758e383954bbba7662833554d817..33aa851a807169f0872b427b57e840d4d3b0b58d 100644 (file)
@@ -8,9 +8,9 @@ import (
        "net/http"
 
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        user_service "code.gitea.io/gitea/services/user"
 )
index 5815ed4f0b4454c976f5f91d567331a7a34f76b5..398c6b25673dc301103f9a5115d272ecf562f146 100644 (file)
@@ -8,9 +8,9 @@ import (
        "net/http"
 
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 234da5dfdc490d3e4e77617fc7e9b6a12d2c958c..b8438cd2aafeec8dd5d30f493e0ad68535121e72 100644 (file)
@@ -10,10 +10,10 @@ import (
 
        asymkey_model "code.gitea.io/gitea/models/asymkey"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 392b266ebd8f0b880beb14f721752131ff61d333..8b5c64e291988a833b6744e13c1cfac700150e0d 100644 (file)
@@ -7,7 +7,7 @@ import (
        "net/http"
 
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 // GetUserByParamsName get user by name
index e87385e4a2602fb6bf14da187f683d5e176ec7e6..9d9ca5bf01059ab2588ae7cd8b64f543db6aa33e 100644 (file)
@@ -6,10 +6,10 @@ package user
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        webhook_service "code.gitea.io/gitea/services/webhook"
 )
 
index dd185aa7d623623dbee6c03af0cd9c02cfd508dd..ada6759f8e6c59afcff64eaea828a46ae1b8b7cd 100644 (file)
@@ -11,13 +11,13 @@ import (
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/perm"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/repo"
        "code.gitea.io/gitea/routers/api/v1/utils"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index b8b2d265bf7e9d0ca61d21a0fc450577e8e3642a..81f8e0f3fe9bd61cac5cee058941d16e39327141 100644 (file)
@@ -11,9 +11,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/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 51556ae0fb8c039c45e508740103f5ebbf65040c..899218473ee314171ffc71a92f01053e245ab816 100644 (file)
@@ -4,8 +4,8 @@
 package user
 
 import (
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/routers/api/v1/shared"
+       "code.gitea.io/gitea/services/context"
 )
 
 // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
index 062df1ca43f7b9e54e01e020358e742038d12897..d0a8daaa85ba5ec5562aacec7922a44dccfdf7a2 100644 (file)
@@ -6,10 +6,10 @@ package user
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/optional"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        user_service "code.gitea.io/gitea/services/user"
 )
index 2659789ddd90cae51f8d20e1a23d8a14f41aee1b..e624884db361c1c6b038340ac9f1171d60941bd3 100644 (file)
@@ -12,9 +12,9 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index fb8f67d072226477fe2bc5037ed06364c7312f90..09147cd2ae00b9ea261f5e17856e41261064c8c0 100644 (file)
@@ -9,8 +9,8 @@ import (
 
        activities_model "code.gitea.io/gitea/models/activities"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 7f531eafaa6bedc279f247b432c6081f6048eda8..706f4cc66bc2eae628e244d0209f702470ff57e5 100644 (file)
@@ -11,9 +11,9 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/api/v1/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 5e80190017350e2ad6139874454e9c4ec29541d4..4e25137817e1f8a5fc732dca19ea5cf161c0a0ef 100644 (file)
@@ -8,10 +8,10 @@ import (
        "fmt"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 // ResolveRefOrSha resolve ref to sha if exist
index 28b21ab8db657d83e1b3b7e21eadc6af160e7f60..f1abd49a7d60b5a07fa63906bf77646049235ea2 100644 (file)
@@ -12,12 +12,12 @@ 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/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        webhook_module "code.gitea.io/gitea/modules/webhook"
+       "code.gitea.io/gitea/services/context"
        webhook_service "code.gitea.io/gitea/services/webhook"
 )
 
index 6910b8293196ed54490b49b045339c5a893846ef..024ba7b8d92a390cd4b21c9718a2edeaab1aaff7 100644 (file)
@@ -5,7 +5,7 @@ package utils
 
 import (
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 8904785d51f3766221c0b1b8a14e2f48d1364bf0..115d65ed104a8b2fc40282cbb1982f19e7684f63 100644 (file)
@@ -5,9 +5,9 @@ package common
 
 import (
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
        auth_service "code.gitea.io/gitea/services/auth"
+       "code.gitea.io/gitea/services/context"
 )
 
 type AuthResult struct {
index 923421a29c8943697e074bcc41e6ca4ae1cf77a0..402ca44c12d21a69e85738c34c542140d1d90b64 100644 (file)
@@ -9,13 +9,13 @@ import (
 
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/httpcache"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/templates"
        "code.gitea.io/gitea/modules/web/middleware"
        "code.gitea.io/gitea/modules/web/routing"
+       "code.gitea.io/gitea/services/context"
 )
 
 const tplStatus500 base.TplName = "status/500"
index a1c2c37ac07a48d3396deb6c1b13aa1d219b4447..7819ee72276f797ff3b83db70720049d9790bbe0 100644 (file)
@@ -9,11 +9,11 @@ import (
        "net/http"
        "strings"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/markdown"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 
        "mvdan.cc/xurls/v2"
 )
index 8a39dda179893277e62655b6a6ab54b58244c530..1ee4c629adbc2c1e35771f79d297efb41a7caa52 100644 (file)
@@ -9,11 +9,11 @@ import (
        "strings"
 
        "code.gitea.io/gitea/modules/cache"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/process"
        "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"
 
        "gitea.com/go-chi/session"
        "github.com/chi-middleware/proxy"
index 8a7f8b3332127197ddc8dc0a99fdaad503f503ae..446908db75dc764edad2b5eb04a1c20c7cc86106 100644 (file)
@@ -7,11 +7,11 @@ import (
        "io"
        "time"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/httpcache"
        "code.gitea.io/gitea/modules/httplib"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 // ServeBlob download a git.Blob
index decf74cecb6f0d5eb352a7d55f76b0682be58ff3..9c6a8849b63ffc9ead82145e275230016f794603 100644 (file)
@@ -22,7 +22,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/generate"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/log"
@@ -36,6 +35,7 @@ import (
        "code.gitea.io/gitea/modules/web/middleware"
        "code.gitea.io/gitea/routers/common"
        auth_service "code.gitea.io/gitea/services/auth"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 
        "gitea.com/go-chi/session"
index 886f23b1c245086f9919af23161010abc60ec753..53c2412308f4d29cd04b31c5201e16ea5c9e73c2 100644 (file)
@@ -12,11 +12,11 @@ import (
        actions_model "code.gitea.io/gitea/models/actions"
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 // GenerateActionsRunnerToken generates a new runner token for a given scope
index a23e101e9d1ed29e4ababac29b7f8907d46aca42..2e323129ef0289141bc12a562a9e30e0eb61c61a 100644 (file)
@@ -8,9 +8,9 @@ import (
        "net/http"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/private"
+       gitea_context "code.gitea.io/gitea/services/context"
 )
 
 // SetDefaultBranch updates the default branch
index 5ae03ce294b565009421aab935c8ab9ce031cad1..4eafe3923dfb897ac8fbae070e30ff2732572f4f 100644 (file)
@@ -10,7 +10,6 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        repo_model "code.gitea.io/gitea/models/repo"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
@@ -18,6 +17,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       gitea_context "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index ad52f350845787a2ee107b86d8eeaa8ab8b562c2..32ec3003e265cb9516e07c621eae5f3b0cf49262 100644 (file)
@@ -16,11 +16,11 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        "code.gitea.io/gitea/models/unit"
        user_model "code.gitea.io/gitea/models/user"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/web"
+       gitea_context "code.gitea.io/gitea/services/context"
        pull_service "code.gitea.io/gitea/services/pull"
 )
 
index 5805202bb57da71aa12dd07bc7a1adc57a8c31e6..cee3bbdd121273be61ea6b99d3d37023a939c8e5 100644 (file)
@@ -7,12 +7,12 @@ import (
        "net/http"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/services/agit"
+       gitea_context "code.gitea.io/gitea/services/context"
 )
 
 // HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present
index 407edebeede8a0d2387202c51bbbd3de513a997a..ede310113ca45aa84de22c15ce8093e550f08a86 100644 (file)
@@ -8,11 +8,11 @@ import (
        "net/http"
        "strings"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
        chi_middleware "github.com/go-chi/chi/v5/middleware"
index 615239d479d967aa9cf02c70221d4c11d083c426..e8ee8ba8ac3fc61d106a79cb5d849928a5f63e0b 100644 (file)
@@ -9,10 +9,10 @@ import (
        "net/http"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
+       gitea_context "code.gitea.io/gitea/services/context"
 )
 
 // This file contains common functions relating to setting the Repository for the internal routes
index 0096480d6a668dc3a9a3eab367c0c71a4fbce4c1..5b8f238a83ebcb4bd427ea3770d8a55ff9a84fc3 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
 
        asymkey_model "code.gitea.io/gitea/models/asymkey"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/timeutil"
+       "code.gitea.io/gitea/services/context"
 )
 
 // UpdatePublicKeyInRepo update public key and deploy key updates
index e5e162c8809140260aef58cccabb9def0d4606ff..c19ee67896a49f51c01a88bf536f9f359235cb67 100644 (file)
@@ -11,11 +11,11 @@ import (
 
        "code.gitea.io/gitea/models/db"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/mailer"
 )
 
index 397e6fac7bf50b86bd2ce2c401687c8eb3f95d9f..a6aa03e4ec95483e1f1e0addb33593be31aec831 100644 (file)
@@ -8,7 +8,6 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/graceful/releasereopen"
        "code.gitea.io/gitea/modules/log"
@@ -17,6 +16,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/templates"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
 )
 
 // ReloadTemplates reloads all the templates
index 68e4a21805b2ffdf11beeb602ba8bec67691d054..9a0298a37c60c0254f46815cbd0cc19ff5946782 100644 (file)
@@ -11,10 +11,10 @@ import (
        "runtime"
        "time"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        process_module "code.gitea.io/gitea/modules/process"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Processes prints out the processes
index 09ced33b8d76052ba941ae31b1a35d540188df84..0c63ebc918faebdbc05b4a3894be04bd8c157ebf 100644 (file)
@@ -8,8 +8,8 @@ package private
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/graceful"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Restart causes the server to perform a graceful restart
index bd3c3c30d06a33d7f3b56512a03d8176b25940b5..f1b9365f528e025e3188eb4d812c6ac02028c39e 100644 (file)
@@ -8,9 +8,9 @@ package private
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/private"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Restart is not implemented for Windows based servers as they can't fork
index 7efc22a3d9bec9e6d57b63f82d375d677618442e..4e95d3071db261150eed66c355921faca9b481fa 100644 (file)
@@ -7,9 +7,9 @@ import (
        "io"
        "net/http"
 
-       myCtx "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/private"
+       myCtx "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/migrations"
 )
 
index 3812ccb52b52208fe2b8cf369db51595dccdbd6f..85368a0aed4c1824f77490b46af25b8d979699c2 100644 (file)
@@ -14,11 +14,11 @@ 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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
        wiki_service "code.gitea.io/gitea/services/wiki"
 )
index eacfa18f058bc6c212d6b0278188fd6844255fd0..5bec632ead9070c1052649b52026a2f282406ee4 100644 (file)
@@ -6,11 +6,11 @@ package private
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
 )
 
 // SSHLog hook to response ssh log
index 9fbd429f743253f1e1ad7f546f1369ae1fde9adb..f3f10fd1b828290b421bdc8b508bfaaafb53dc86 100644 (file)
@@ -14,13 +14,13 @@ import (
        activities_model "code.gitea.io/gitea/models/activities"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/updatechecker"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/cron"
        "code.gitea.io/gitea/services/forms"
        release_service "code.gitea.io/gitea/services/release"
index b6f7bcd2a5b2f6a57c8a106ccdea9c7b50e792ec..8583398074627dd7075b7fc41c7dbc00a92227f0 100644 (file)
@@ -10,9 +10,9 @@ import (
        "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        user_setting "code.gitea.io/gitea/routers/web/user/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 var (
index 7fdd18dfae9c0222fed1f3fe007c6c275d6e8d90..ba487d10457d8d92803848e7f8477222c7be177f 100644 (file)
@@ -16,7 +16,6 @@ import (
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/auth/pam"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
@@ -27,6 +26,7 @@ import (
        pam_service "code.gitea.io/gitea/services/auth/source/pam"
        "code.gitea.io/gitea/services/auth/source/smtp"
        "code.gitea.io/gitea/services/auth/source/sspi"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 
        "xorm.io/xorm/convert"
index 47f920150465c1471854df26d7ba1933a8e3e96f..2f5f17e2013f214a3f5e82df717c7a5020ae08ae 100644 (file)
@@ -12,13 +12,13 @@ import (
 
        system_model "code.gitea.io/gitea/models/system"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "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/util"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/mailer"
 
        "gitea.com/go-chi/session"
index 2d550125d550c26ee952c46364c718afce7a3ddf..020554a35a4f3b194ee7251cfc8b3cb7437cf7eb 100644 (file)
@@ -9,8 +9,8 @@ import (
        "runtime/pprof"
        "time"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/httplib"
+       "code.gitea.io/gitea/services/context"
 )
 
 func MonitorDiagnosis(ctx *context.Context) {
index 59f80035d89b6882067538631588e96c63a16b70..4296d70aeee120120b3bdf39d8bf6d0a23c73e55 100644 (file)
@@ -11,10 +11,10 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index cd8cc29cdfbc0d5b7c02dead6697f5c7b78e4199..8d4c66fdb2bef45fd9d02f4cede428a6f0d486f3 100644 (file)
@@ -8,9 +8,9 @@ import (
 
        "code.gitea.io/gitea/models/webhook"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index e1cb578d0525f73f23499e3e7001ef8a020120af..36303cbc06e9a7deaed64d907e4016e728c8817b 100644 (file)
@@ -11,9 +11,9 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 00131c9e2f7f4d3cb5910fe23f3bea8651a37558..c5454db71e39cc50f0c9e6d8d80fb6a69d74d274 100644 (file)
@@ -8,10 +8,10 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/routers/web/explore"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 35ce215be481874ee0635b94c8fc76b80fba2df1..7c16b69a85cf7640aa9343dd45462e745d1613d6 100644 (file)
@@ -11,9 +11,9 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        packages_service "code.gitea.io/gitea/services/packages"
        packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup"
 )
index 18a8d7d3e6834c99ab750da3560fedc9611901e2..d8c50730b144e3accede123913b28399ea618c14 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
        "strconv"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/queue"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 func Queues(ctx *context.Context) {
index 45c280ef7317d81a14ad0283cf88af54703e790f..ddf4440167686c9ed7a1eeef442297ff84b40fce 100644 (file)
@@ -12,11 +12,11 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/web/explore"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index eaa268b4f142a45b6ec910d05aa2a1a4b28ce290..d73290a8dba80cbfbae565c82879f09e46568c2a 100644 (file)
@@ -4,8 +4,8 @@
 package admin
 
 import (
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 func RedirectToDefaultSetting(ctx *context.Context) {
index b603fb59a26d7257b88efe82c1f1bb87a375103d..d6def94bb492a00662fe7730fbc05b0b89fdbc02 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
        "runtime"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/process"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Stacktrace show admin monitor goroutines page
index adb9799c0166e330df7178c46c4a294d483c2567..cbca26eba8c8298c51627acbfe82b6d341d5cb03 100644 (file)
@@ -19,7 +19,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
@@ -27,6 +26,7 @@ import (
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/web/explore"
        user_setting "code.gitea.io/gitea/routers/web/user/setting"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/mailer"
        user_service "code.gitea.io/gitea/services/user"
index 560ee70ea04cb8ae290cf41dadb3032e3ce83e38..f6f92378581e04eb342ae24ade9d6c97d3378cbe 100644 (file)
@@ -8,10 +8,10 @@ import (
 
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/forms"
 
        "github.com/stretchr/testify/assert"
index dc0062ebaa59a000d6d144f5dbd2aae7d24b676f..f93177bf96b8b2325659ff712884d05082762a40 100644 (file)
@@ -10,9 +10,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/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/externalaccount"
        "code.gitea.io/gitea/services/forms"
 )
index a30ee0ce542f87f03d33dad1863e1d9acc898945..fee6a89a99962b769d2f9cd9186ab7e2f94f63d3 100644 (file)
@@ -16,7 +16,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/eventsource"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
@@ -29,6 +28,7 @@ import (
        "code.gitea.io/gitea/routers/utils"
        auth_service "code.gitea.io/gitea/services/auth"
        "code.gitea.io/gitea/services/auth/source/oauth2"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/externalaccount"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/mailer"
index 1d94e52fe3e472f6539de6da7cf477ccc156efe5..f744a57a43f94d73a737be9dcfbab7b9277d37be 100644 (file)
@@ -12,13 +12,13 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        auth_service "code.gitea.io/gitea/services/auth"
        "code.gitea.io/gitea/services/auth/source/oauth2"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/externalaccount"
        "code.gitea.io/gitea/services/forms"
 
index 33a4ae91927f95bcd90313d82794a1be86c35a3f..d5ca7397f06c122fcd7d65b6edc844e34dcc94bc 100644 (file)
@@ -22,7 +22,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
@@ -34,6 +33,7 @@ import (
        auth_service "code.gitea.io/gitea/services/auth"
        source_service "code.gitea.io/gitea/services/auth/source"
        "code.gitea.io/gitea/services/auth/source/oauth2"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/externalaccount"
        "code.gitea.io/gitea/services/forms"
        user_service "code.gitea.io/gitea/services/user"
index 29ef772b1c6bfb600ba17133f7a692825fb55280..2143b8096a0bd800928bc2eab305a5d307a5f2e6 100644 (file)
@@ -11,12 +11,12 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/services/auth"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 1f2d1332820d16bda770e3d6ce487cd45af137e2..c9e03860412e1af18c505ffbf789be3d6d107236 100644 (file)
@@ -12,7 +12,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
@@ -20,6 +19,7 @@ import (
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/modules/web/middleware"
        "code.gitea.io/gitea/routers/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/mailer"
        user_service "code.gitea.io/gitea/services/user"
index 95c8d262a532593945d14c704dca9f04f29d3d21..1079f44a085b34696988cc3641412a1ba3eee979 100644 (file)
@@ -11,9 +11,9 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/externalaccount"
 
        "github.com/go-webauthn/webauthn/protocol"
index 525ca9be53c6388090ee587f97bfe0de4e6549f3..dd20663f94bd70f3534172077923ba8b7156122f 100644 (file)
@@ -10,8 +10,8 @@ import (
        "time"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/templates"
+       "code.gitea.io/gitea/services/context"
 )
 
 // List all devtest templates, they will be used for e2e tests for the UI components
index 1a5a162c1a2e79cce4a4f1b20f11f9f35ab0cc1d..52f20e07dc3e210ad852cde9c132faf974e767c7 100644 (file)
@@ -7,11 +7,11 @@ import (
        "net/http"
        "time"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/eventsource"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/routers/web/auth"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Events listens for events
index d81884ec62deb70d42afd7724958b9426ae7bd06..2cde8b655ee7b2ac41d9515a552802cb7d281771 100644 (file)
@@ -8,9 +8,9 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        code_indexer "code.gitea.io/gitea/modules/indexer/code"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index dc1318beefec0e9c50da18f69849fe474c6678d9..4a468482ae1931290398012b7c9e696e00e46de1 100644 (file)
@@ -6,9 +6,9 @@ package explore
 import (
        "code.gitea.io/gitea/models/db"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Organizations render explore organizations page
index 0446edebe69136b1e8668e9569abf32a2ce7c987..d5a46f6883b383fdbd3682203a63c5bfb19b8b2f 100644 (file)
@@ -10,10 +10,10 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/sitemap"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index bb1be310de777a8fb898f6f8ae7df05098ecc7a4..95fecfe2b81963f0e90a5be736d3c006fb0459bd 100644 (file)
@@ -8,8 +8,8 @@ import (
 
        "code.gitea.io/gitea/models/db"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 09d31f95ef47d5c820d81b29580ffda0592b463a..b67fac2fc133e64fdeefa399a895c446b304b199 100644 (file)
@@ -10,12 +10,12 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/sitemap"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index f13038ff9b42e3ad1ba73715cfaff58a6eac1d9d..80ce2ad198bcd82bd151177584b76bce5bebe5c2 100644 (file)
@@ -9,7 +9,7 @@ import (
        "time"
 
        "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/gorilla/feeds"
 )
index 1e040ed819eb6d0773060cf5db4581d0699101d4..298fe0bb39adeb2c4ca506ef6a5046562775e6a3 100644 (file)
@@ -14,12 +14,12 @@ import (
 
        activities_model "code.gitea.io/gitea/models/activities"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "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/util"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/gorilla/feeds"
 )
index 56a9c54ddcbbe929b2cc536fcaf4dc4cc0b6f18f..1ab768ff27fcbb076bef8e6c8735706ddbe99a99 100644 (file)
@@ -9,9 +9,9 @@ import (
        "time"
 
        "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/gorilla/feeds"
 )
index 3feca68d61a2dd0922a03be220df737fbc575464..2b70aad17b75a86485b7fb46ed3c57b6658c88cc 100644 (file)
@@ -7,9 +7,9 @@ import (
        "time"
 
        activities_model "code.gitea.io/gitea/models/activities"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/markdown"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/gorilla/feeds"
 )
index 558c03dba7494aeda12532afc0bdccc69eace0b7..273f47e3b467f9566f4ee19cc398da9bcc0f721b 100644 (file)
@@ -8,7 +8,7 @@ import (
 
        "code.gitea.io/gitea/models/db"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/gorilla/feeds"
 )
index 8931dae8cce6df98bd6504ef941ce8fe59210d6f..a41808c24ac6758a2548fe9e5a956c50d9f0b49e 100644 (file)
@@ -4,7 +4,7 @@
 package feed
 
 import (
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 // RenderBranchFeed render format for branch or file
index 51c24510c7e5ae8e21d97b83ad5bd2d20cd33d22..bfcc3a37d6a9ef631617aa894039b109417feb1b 100644 (file)
@@ -8,7 +8,7 @@ import (
 
        activities_model "code.gitea.io/gitea/models/activities"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/gorilla/feeds"
 )
index ab74e9a333b35ecb71a6eb0559d08e11d94e5cbb..5f1dedce763a25832b6ff32289874fd23d1cda07 100644 (file)
@@ -6,11 +6,10 @@ package web
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/web/repo"
-       context_service "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 func requireSignIn(ctx *context.Context) {
@@ -39,5 +38,5 @@ func gitHTTPRouters(m *web.Route) {
                m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38,62}}", repo.GetLooseObject)
                m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.pack", repo.GetPackFile)
                m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.idx", repo.GetIdxFile)
-       }, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
+       }, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context.UserAssignmentWeb())
 }
index c5b8b6cbc015dcd7f2b0e08f1e009dc67afbf02d..8d5612ebfe9708086e240157296acbfea7d107b2 100644 (file)
@@ -12,9 +12,9 @@ import (
        "strings"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 func goGet(ctx *context.Context) {
index 2321b00efe7d2ae831d770f3f5afb5f67b63f335..555f94c9835dfd96de134950abdceb9a5cb7edc2 100644 (file)
@@ -12,7 +12,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/sitemap"
@@ -21,6 +20,7 @@ import (
        "code.gitea.io/gitea/modules/web/middleware"
        "code.gitea.io/gitea/routers/web/auth"
        "code.gitea.io/gitea/routers/web/user"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index c91da9a7f1028233ec6a3d670863282284d7ebc0..2dbbd6fc097dca3e9772988ebcc7bf3dbba6131c 100644 (file)
@@ -5,10 +5,10 @@
 package misc
 
 import (
-       "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/common"
+       "code.gitea.io/gitea/services/context"
 )
 
 // Markup render markup document to HTML
index 72c09a3780174fe1e67ea7fc6f01849749bf6763..5fddfa8885f82b853083a4b2a007baac537022b3 100644 (file)
@@ -7,7 +7,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 // tplSwagger swagger page template
index 01b71e7086bdc0b862723da14af32f06c499ae13..f1cc7bf530fef5b4e19fc3bc8d98c5999e78a72e 100644 (file)
@@ -7,8 +7,8 @@ import (
        "fmt"
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 type nodeInfoLinks struct {
index 36f543dc45f7e1bc692ec2b9cbc1328719b5a529..4a7378689adb96c24d250c13f6ab8c4b4dc02816 100644 (file)
@@ -12,7 +12,6 @@ import (
        "code.gitea.io/gitea/models/organization"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/markup"
@@ -20,6 +19,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 15a615c706fe62537c9475a2362921f34f5d0a51..9a3d60e122bafb367700133c589b7b4e5285df17 100644 (file)
@@ -10,10 +10,10 @@ import (
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/models/organization"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 1e4544730e14da197de248ebe40b409b6d9bd873..f94dd16eaef96e11b9354423ce18b562ba07bb9d 100644 (file)
@@ -12,10 +12,10 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index f78bd002742636a9f2d2e29ba248308e32c35d44..02eae8052ea2ae9a06eb758a9db594a5627b91cd 100644 (file)
@@ -8,10 +8,10 @@ import (
 
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/label"
        repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index f062127d24fd3612cf41f964f0ae66d8ee6a544e..338558fa2393b4ad81468135f24e272e4f2ef047 100644 (file)
@@ -17,12 +17,12 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 8053ab4cf93fd9630d971993535c0c961d141462..f4ccfe1c066caefef38d98d5549b8d9837eaa80a 100644 (file)
@@ -7,8 +7,8 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/routers/web/org"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index 47d0063f767d84caa31fa801fffb892c01840e47..494ada4323a667f564626b552477e9ee772a5f72 100644 (file)
@@ -14,7 +14,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        repo_module "code.gitea.io/gitea/modules/repository"
@@ -22,6 +21,7 @@ import (
        "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"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        org_service "code.gitea.io/gitea/services/org"
        repo_service "code.gitea.io/gitea/services/repository"
index c3c771036aad7beea9a06da7fa9227e0d79010e6..fe05709237dfc1188a8f640970b9bc66c647d2af 100644 (file)
@@ -4,7 +4,7 @@
 package setting
 
 import (
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 func RedirectToDefaultSetting(ctx *context.Context) {
index ca4fe09f380cbdd0c89462268c544343ce9a7eed..7f855795d3639ab76a95c5790a6ab837d73e435d 100644 (file)
@@ -10,10 +10,10 @@ import (
        "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        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 (
index 796829d34ef27608417d964f07ebc5679f82498e..af9836e42c2b3a5d31d613e5e4ac7f8230fa0fc4 100644 (file)
@@ -8,10 +8,10 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        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 (
index 71fe99c97c70dd6e5844256a7331cf94d294ca6d..fd7486cacdbc42fe441aa644a9916cfa334b0cbc 100644 (file)
@@ -20,11 +20,11 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        org_service "code.gitea.io/gitea/services/org"
index 95874dfc48d71290ecf975a9d6d528b541da6ec8..0d10a69dfe66a7e834fe990f7bffe4570c50f949 100644 (file)
@@ -6,8 +6,8 @@ package web
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 type passkeyEndpointsType struct {
index 19aca2671170191f59d0a999402dcb99bb4316c1..e7849123779367f11af4007bf544765b34d19ce8 100644 (file)
@@ -15,11 +15,11 @@ import (
        "code.gitea.io/gitea/modules/actions"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/container"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/web/repo"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 
        "github.com/nektos/act/pkg/model"
index 49387362b353707999c5f991c60ca5a234d8aad6..2f26e710cddcf1c8791135b19e0271ceabb962e8 100644 (file)
@@ -21,12 +21,12 @@ import (
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/actions"
        "code.gitea.io/gitea/modules/base"
-       context_module "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/storage"
        "code.gitea.io/gitea/modules/timeutil"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        actions_service "code.gitea.io/gitea/services/actions"
+       context_module "code.gitea.io/gitea/services/context"
 
        "xorm.io/builder"
 )
index af99c4ed986302f0ef728643dcb3da147ef02cc5..6f6641cc65e2ac5e833a9d2241914d771d27cadd 100644 (file)
@@ -10,7 +10,7 @@ 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/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 8c322b45e5ec892b003758869dd4c878f111bde1..f0c5622aec73de2b513397ca791e03d80db4a522 100644 (file)
@@ -9,15 +9,15 @@ import (
 
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/httpcache"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/storage"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/common"
        "code.gitea.io/gitea/services/attachment"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index 7602b30d2b14539dccd58c8a7d1b858cd38b3ccb..b088b8387e7e4bc4f06212bcc01254ca0bcb18e5 100644 (file)
@@ -13,13 +13,13 @@ import (
 
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/charset"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/highlight"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/templates"
        "code.gitea.io/gitea/modules/timeutil"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        files_service "code.gitea.io/gitea/services/repository/files"
 )
 
index c543160f42040cdda4e059c8f405b13bc9eca54e..05f06a3ceb7a9ac220ccd1bd320fac9bf200eedd 100644 (file)
@@ -16,7 +16,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        repo_module "code.gitea.io/gitea/modules/repository"
@@ -24,6 +23,7 @@ import (
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/utils"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        release_service "code.gitea.io/gitea/services/release"
        repo_service "code.gitea.io/gitea/services/repository"
index 8de54d569fd2ae18ea3d018b7080143485ae019c..088f8d889d4ab2cac38ba86aa88a786baf1ca608 100644 (file)
@@ -12,11 +12,11 @@ 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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/repository/files"
 )
index 48ade655b7b68efc9d61302d345fc6f416e8e0b8..c76f492da071edb8d8a24582cd997ef31ef8cbf6 100644 (file)
@@ -8,7 +8,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        contributors_service "code.gitea.io/gitea/services/repository"
 )
 
index 32fa973ef61e54ee91bc44ad2e10d528523b197a..16da917d222c1668300c4d22a706a07a6363a063 100644 (file)
@@ -19,7 +19,6 @@ import (
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/charset"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitgraph"
        "code.gitea.io/gitea/modules/gitrepo"
@@ -27,6 +26,7 @@ import (
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/gitdiff"
        git_service "code.gitea.io/gitea/services/repository"
 )
index 535487d5fdbd05deaf9e3c3c13f61205c21b810a..b0570f97c3b7b5ab849b3262806f2d5c2185cd46 100644 (file)
@@ -25,7 +25,6 @@ import (
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/charset"
-       "code.gitea.io/gitea/modules/context"
        csv_module "code.gitea.io/gitea/modules/csv"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
@@ -35,8 +34,9 @@ import (
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/typesniffer"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/gitdiff"
 )
 
index bcfef7580a6a31ddff3cd19c85867d331890985b..5fda17469e9c0516579c27686a9361fc8003ab51 100644 (file)
@@ -8,7 +8,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        contributors_service "code.gitea.io/gitea/services/repository"
 )
 
index a9e2e2b2fad775f72b8e38d14099fda927382cb0..c4a8baecca352a60a255ce84d9e9feb9d8d74cf8 100644 (file)
@@ -9,7 +9,6 @@ import (
        "time"
 
        git_model "code.gitea.io/gitea/models/git"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/httpcache"
        "code.gitea.io/gitea/modules/lfs"
@@ -17,6 +16,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/storage"
        "code.gitea.io/gitea/routers/common"
+       "code.gitea.io/gitea/services/context"
 )
 
 // ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary
index 28644fbe3d57e4ad208cb55203be0051f64adcd2..8f3d9612eca0b6c8f93b49997068b87f3e67a72a 100644 (file)
@@ -16,17 +16,17 @@ import (
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/charset"
-       "code.gitea.io/gitea/modules/context"
        "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/typesniffer"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/utils"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/forms"
        files_service "code.gitea.io/gitea/services/repository/files"
 )
index c28c3ef1d632dccd4c0bb0f482093c1182f8ee76..313fcfe33a28bb7942f46e20837c1fc80e019d8f 100644 (file)
@@ -7,9 +7,9 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index daefe59c8f2746a56ad7d01f74a8e45e42a9d09a..07b372279882ff95ff89e385fb4fae95c50d8243 100644 (file)
@@ -7,7 +7,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 27c7f4961d2eb91f0e1c418ef34e9c54ecf30455..8fb6d930688f84e72ec1775f4bcd398bbd1a9309 100644 (file)
@@ -24,13 +24,13 @@ import (
        access_model "code.gitea.io/gitea/models/perm/access"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "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/structs"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/go-chi/cors"
index a98abe566f8437699bc6d6bcabd8db7b624bb484..5e1e116018eb5c3684c987c067bdbac443e73c40 100644 (file)
@@ -8,8 +8,8 @@ import (
        "sort"
 
        "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
+       "code.gitea.io/gitea/services/context"
 )
 
 func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
index 46d48c46381a8fb9a4c246cd8d0495200ad04b45..65e74a2d90e3f8bf8da8ab61cea99729bc53c9be 100644 (file)
@@ -31,7 +31,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/emoji"
        "code.gitea.io/gitea/modules/git"
        issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
@@ -44,11 +43,12 @@ import (
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/templates/vars"
        "code.gitea.io/gitea/modules/timeutil"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/utils"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        issue_service "code.gitea.io/gitea/services/issue"
index 0939af487c19156944d18b518ec071eea674c9cd..fce0eccc7ba01bed0fb7e156baac9270df0c5f9d 100644 (file)
@@ -11,11 +11,11 @@ import (
 
        "code.gitea.io/gitea/models/avatars"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/templates"
        "code.gitea.io/gitea/modules/timeutil"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/sergi/go-diff/diffmatchpatch"
 )
index 022ec3ae3e2d113bfa5c1aecdfa3761d840d87d3..e3b85ee638e93ab206cdcbe4a50393c71493cc32 100644 (file)
@@ -8,8 +8,8 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        access_model "code.gitea.io/gitea/models/perm/access"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 // AddDependency adds new dependencies
index dd3e2803b4e43c94b7728dd91635f17fc5ba3918..9dedaefa4beb00149ff8c8c35e9c1c7f82a36b8a 100644 (file)
@@ -10,12 +10,12 @@ import (
        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/context"
        "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/timeutil"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        issue_service "code.gitea.io/gitea/services/issue"
 )
index 742f12114d5900d0027cf316c18dcf36e3fbc5b3..93fc72300b30529b92da7f711d999dbfc71b2613 100644 (file)
@@ -10,10 +10,10 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/test"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/forms"
 
        "github.com/stretchr/testify/assert"
index f83109d9b3f7cfe76d365fb0058a225132a8954f..1d5fc8a5f396c95e51c08fd6eb4ff644af1b450c 100644 (file)
@@ -5,8 +5,8 @@ package repo
 
 import (
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 9f334129f943e311cd6f0541d00614e8fe481e15..365c812681a228189afe0bf9bf5ca44846a22f84 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 // IssuePinOrUnpin pin or unpin a Issue
index ab9fe3e69d9a42dee0687988a041844f50ffec31..70d42b27c0a87827d9a4ae4798c66116438c64e1 100644 (file)
@@ -9,8 +9,8 @@ import (
 
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/eventsource"
+       "code.gitea.io/gitea/services/context"
 )
 
 // IssueStopwatch creates or stops a stopwatch for the given issue.
index c9bf861b844b8b019b6d6adb3809cd1ae67e403c..241e434049900df12953aced45b1724a5961bda4 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 1f51ceba5e47b144aaa0616b999844df5cd875b8..8b033f3b17a807635852099d69a5a2b78f04ad79 100644 (file)
@@ -9,8 +9,8 @@ import (
 
        issues_model "code.gitea.io/gitea/models/issues"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index d70a53030e659ee35827d172469898775f24812b..420931c5fb729d6a4643cae655f4e3d4b5243a78 100644 (file)
@@ -9,9 +9,9 @@ import (
 
        system_model "code.gitea.io/gitea/models/system"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/optional"
+       "code.gitea.io/gitea/services/context"
        user_service "code.gitea.io/gitea/services/user"
 )
 
index b70901d5f28d96e6d047e625fc770cd7effaadce..97b0c425ea3befe6c8a25c439c8d572f344af57a 100644 (file)
@@ -15,13 +15,13 @@ import (
        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/context"
        "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/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/migrations"
        "code.gitea.io/gitea/services/task"
index 400748b963d5dde71cb230a4488e2c60ab9d5a05..49ac94aaf1540342dfb2b7327ec855c772592f14 100644 (file)
@@ -12,13 +12,13 @@ import (
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/markdown"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/timeutil"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/issue"
 
index ac9e64d774e3fe403c3c11c555c4ad1194d7c787..6ed5909dcf6bfd8c902e22c44c4dd367905fd452 100644 (file)
@@ -10,9 +10,9 @@ import (
        "code.gitea.io/gitea/models/packages"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 00bd45aaec14da899363321e288c4c56a5ff9de4..0dee02dd9ca9b1c027536bb55d5c2ee856d5f0b7 100644 (file)
@@ -10,10 +10,10 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/repository/files"
 )
index cc0127e7e173afbb1991035e367ff99771570747..1f9ee727c362ed882d583b8bf2c3995435c074c4 100644 (file)
@@ -17,13 +17,13 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/markdown"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 6698d47028b282d4944cd7482b0e22172ea9aebd..479f8c55a22a66e24cbbbea2a1a8d59bb9886d61 100644 (file)
@@ -7,7 +7,7 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index af626dad303d3b09ca460bda6596389422e60854..b1521a2112a3ec7b07613fd3749b0d7c493ac9ed 100644 (file)
@@ -27,7 +27,6 @@ import (
        "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/context"
        "code.gitea.io/gitea/modules/emoji"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
@@ -36,12 +35,13 @@ import (
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/utils"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
        "code.gitea.io/gitea/services/automerge"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/gitdiff"
        notify_service "code.gitea.io/gitea/services/notify"
index 92665af7e78bfe3f338a776300c109296904b030..64212291e162ed81cd94bfa673badb63234d904e 100644 (file)
@@ -11,12 +11,12 @@ import (
        issues_model "code.gitea.io/gitea/models/issues"
        pull_model "code.gitea.io/gitea/models/pull"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/forms"
        pull_service "code.gitea.io/gitea/services/pull"
 )
index 8fc9cecaf35bf79027e755e4e7121ebdceedcfed..5f035f1eb04cb3210c1a0dd5c64033ecc30030d9 100644 (file)
@@ -10,9 +10,9 @@ import (
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/context"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/templates"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/pull"
 
        "github.com/stretchr/testify/assert"
index 3507cb8752112cd0f81703b115b7c2492b367b1f..c158fb30b641fa934b8761f73f0839fa120f06ae 100644 (file)
@@ -8,7 +8,7 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        contributors_service "code.gitea.io/gitea/services/repository"
 )
 
index b920ffb6dd04e182afa7582e0b86e73113fe2090..f9ab956d4cff3a7383fa2a6621ce43c073b9d8d3 100644 (file)
@@ -17,16 +17,16 @@ import (
        "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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/markup/markdown"
        "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/web/feed"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context/upload"
        "code.gitea.io/gitea/services/forms"
        releaseservice "code.gitea.io/gitea/services/release"
 )
index c4a2c1904e3e0c3b15b1263e2aa2e3c92b969aec..7ebea4c3fbe30c5f0aaf629a89cd782e48f8de0f 100644 (file)
@@ -10,8 +10,8 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/forms"
 
        "github.com/stretchr/testify/assert"
index 7eb5a42aa43c0474220422b085f6d34f17399cc7..10fa21c60e29a882caa59d839c782ca114772cea 100644 (file)
@@ -10,11 +10,11 @@ import (
        "path"
 
        "code.gitea.io/gitea/modules/charset"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/markup"
        "code.gitea.io/gitea/modules/typesniffer"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 // RenderFile renders a file by repos path
index 323413d9766902696cb337a8bd192ba32adb46d8..0fad8752e3482d3680ae31823f6c7b24cbe136ff 100644 (file)
@@ -21,7 +21,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
@@ -31,6 +30,7 @@ import (
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        repo_service "code.gitea.io/gitea/services/repository"
index 3c0fa4bc00ea01273ee5a4a7578e45b311490f35..c53d8fd918a1cf68ecf4bca112bd4087896f5f3e 100644 (file)
@@ -7,9 +7,9 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        code_indexer "code.gitea.io/gitea/modules/indexer/code"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 const tplSearch base.TplName = "repo/search"
index 44468d2666cac9a98b772d7e222b8ed8956e68b0..504f57cfc2b26177a312cc750ae296122e2f59c7 100644 (file)
@@ -8,11 +8,11 @@ import (
        "fmt"
        "io"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/typesniffer"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        repo_service "code.gitea.io/gitea/services/repository"
 )
index c5c2a88c49cf3371429211fddcd054993ada9fb3..6bfd4855667b4cc839077c0b4dec1fa5b8e538cd 100644 (file)
@@ -13,10 +13,10 @@ 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/context"
        "code.gitea.io/gitea/modules/log"
        repo_module "code.gitea.io/gitea/modules/repository"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/mailer"
        org_service "code.gitea.io/gitea/services/org"
        repo_service "code.gitea.io/gitea/services/repository"
index c8a576e57663aeacddac2b86f29719f04ee7066f..881d148afc45c8839c6c7d4653f0f206c081cb4e 100644 (file)
@@ -7,10 +7,10 @@ import (
        "net/http"
 
        git_model "code.gitea.io/gitea/models/git"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/routers/web/repo"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index 3d4420006c47ca8684e0e867d80cf8134d0edd88..abc3eb4af18b676391045c3712feed8456de869c 100644 (file)
@@ -8,11 +8,11 @@ import (
 
        asymkey_model "code.gitea.io/gitea/models/asymkey"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 551327d44b4794a04ef7e5a0fb6aeda0165ab879..217a01c90c1cbdf2096dca3ccbfade8c139f68db 100644 (file)
@@ -6,8 +6,8 @@ package setting
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
+       "code.gitea.io/gitea/services/context"
 )
 
 // GitHooks hooks of a repository
index 76a90a4ac587e4f0ed5c5fbffe6786cc1bf9c9af..32049cf0a423cefd67ed7f1c43f1e066baabbf84 100644 (file)
@@ -18,7 +18,6 @@ import (
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/charset"
        "code.gitea.io/gitea/modules/container"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/git/pipeline"
        "code.gitea.io/gitea/modules/lfs"
@@ -28,6 +27,7 @@ import (
        "code.gitea.io/gitea/modules/storage"
        "code.gitea.io/gitea/modules/typesniffer"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 85068f0ab2a92083f701556f2331428661340c75..b30dc3b0614f2997a235c135cb4db1b9e81fb9a0 100644 (file)
@@ -15,9 +15,9 @@ 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/context"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/web/repo"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        pull_service "code.gitea.io/gitea/services/pull"
        "code.gitea.io/gitea/services/repository"
index 46addb3f0ac02d91cfeba724ac80ad3e5e69692a..2c25b650b977e698f6528346c2d15d7cff89d11e 100644 (file)
@@ -13,9 +13,9 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 8d4112c157b41ce933cb459f3a1601cedec6b265..a47d3b45e2cb54c4979b9cfa555921e4f0d4724c 100644 (file)
@@ -11,10 +11,10 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        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"
 )
 
 const (
index cf427b2c44bd76d1928ee492bdab7849c47a7fd3..d4d56bfc57e314fc767773324e1ca43754b4112b 100644 (file)
@@ -8,10 +8,10 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        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"
 )
 
 const (
index 3b11638a920b0468fa62ea46d598791fa97ce074..b13c4c2ddb1663dd8079fd78ed6196fd5a52a152 100644 (file)
@@ -18,7 +18,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/indexer/code"
        "code.gitea.io/gitea/modules/indexer/stats"
@@ -31,6 +30,7 @@ import (
        "code.gitea.io/gitea/modules/validation"
        "code.gitea.io/gitea/modules/web"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/migrations"
        mirror_service "code.gitea.io/gitea/services/mirror"
index 066d2ef2a9f03dfd8cba0858a98128e7dc9cf493..09586cc68d6dfd04490972c34b54c857217ae4c2 100644 (file)
@@ -14,10 +14,10 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/forms"
        repo_service "code.gitea.io/gitea/services/repository"
 
index 428aa0bd5c4fed5653e303d8dabea519c14adc14..45b6c0f39a64bdc84167ef3b06a33b7c3a1b38b2 100644 (file)
@@ -8,10 +8,10 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        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 (
index c12d7e82a66720e99ee50cc53e530469f1584927..bba4d4df51e41312ae9bfa60a38e7f356ed3ede2 100644 (file)
@@ -18,7 +18,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/setting"
@@ -26,6 +25,7 @@ import (
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        webhook_module "code.gitea.io/gitea/modules/webhook"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
        "code.gitea.io/gitea/services/forms"
        webhook_service "code.gitea.io/gitea/services/webhook"
index d0e706c5bd7aa7a7eb0bfea975adb443dad2ceef..d81a695df97e127d367bc9faec92fb334c77561d 100644 (file)
@@ -8,8 +8,8 @@ import (
        "strings"
 
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 // TopicsPost response for creating repository
index c364e7090f789322437719883479ab54d9d12725..d11af4669f90c371df1147631c1cc081a944339e 100644 (file)
@@ -7,8 +7,8 @@ import (
        "net/http"
 
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/go-enry/go-enry/v2"
 )
index 48a35dd0605f7f83fdef5fffd3f1c1e3de0c5c52..e89739e2fb6d18501141c6acd89b319ce6106817 100644 (file)
@@ -36,7 +36,6 @@ import (
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/charset"
        "code.gitea.io/gitea/modules/container"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/highlight"
        "code.gitea.io/gitea/modules/lfs"
@@ -49,6 +48,7 @@ import (
        "code.gitea.io/gitea/modules/typesniffer"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/web/feed"
+       "code.gitea.io/gitea/services/context"
        issue_service "code.gitea.io/gitea/services/issue"
        files_service "code.gitea.io/gitea/services/repository/files"
 
index 49e95faaba25ce84f61621847506416fee201dd1..91cf727e2c5ce65b74ba011a9d9c54032fe2188c 100644 (file)
@@ -18,7 +18,6 @@ import (
        "code.gitea.io/gitea/models/unit"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/charset"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/log"
@@ -29,6 +28,7 @@ import (
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/common"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        notify_service "code.gitea.io/gitea/services/notify"
        wiki_service "code.gitea.io/gitea/services/wiki"
index d3decdae2deff121380740e87b4ec2d11849c43b..49c83cfef59e7fc2140d1ef823ae261b27505161 100644 (file)
@@ -11,10 +11,10 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/forms"
        wiki_service "code.gitea.io/gitea/services/wiki"
 
index ae9a376724185bb90cd8cc25a25690aaba99232a..34b79694427d3366ce484b4e1b47c87b90fe24ab 100644 (file)
@@ -8,10 +8,10 @@ import (
 
        actions_model "code.gitea.io/gitea/models/actions"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 07a0575207818b9c1ccbda8a91600a926b41a284..0f705399c9705db98016c370dffee403a62993c0 100644 (file)
@@ -10,9 +10,9 @@ import (
 
        actions_model "code.gitea.io/gitea/models/actions"
        "code.gitea.io/gitea/models/db"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        secret_service "code.gitea.io/gitea/services/secrets"
 )
index 30c25374d1b455d5f7778bd69cbd9d0962e81acb..1454396f041dacf54ec31c5969b0cc84419127a4 100644 (file)
@@ -12,10 +12,10 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        cargo_service "code.gitea.io/gitea/services/packages/cargo"
        container_service "code.gitea.io/gitea/services/packages/container"
index c805da734ac0a6fcf2e59b9fa4e3f7f419cdb941..73505ec372d4e310eeec743662b02055b7b974d4 100644 (file)
@@ -6,10 +6,10 @@ package secrets
 import (
        "code.gitea.io/gitea/models/db"
        secret_model "code.gitea.io/gitea/models/secret"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/web/shared/actions"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        secret_service "code.gitea.io/gitea/services/secrets"
 )
index 99b701b4392d1541e29651000ae8d114ab1b0542..eb108268aebd285d473f381b0210b25031d8b6f8 100644 (file)
@@ -13,12 +13,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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
 )
 
 // prepareContextForCommonProfile store some common data into context data for user's profile related pages (including the nav menu)
index 42e9dbe96708c79840de33b56bca9a787dc5c877..fc39b504a920cbd6a55a44672185839bbf4e0db3 100644 (file)
@@ -4,7 +4,7 @@
 package web
 
 import (
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
 )
 
 // SwaggerV1Json render swagger v1 json
index 772cc38bea02722c5f88ed919bc832a9f8e446ad..04f510161db62795e1ab0e8ce758e67ad47feedc 100644 (file)
@@ -9,8 +9,8 @@ import (
 
        "code.gitea.io/gitea/models/avatars"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/httpcache"
+       "code.gitea.io/gitea/services/context"
 )
 
 func cacheableRedirect(ctx *context.Context, location string) {
index ee514a7cfe5355b320c241eceb8a8ccc207827d3..eb711b76ebb0808c65a064508ef7d6040f8268b2 100644 (file)
@@ -8,10 +8,10 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        code_indexer "code.gitea.io/gitea/modules/indexer/code"
        "code.gitea.io/gitea/modules/setting"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index b7abbcbc002812bce2a3ea265a04ac95cacb3ea7..78548e6df7a1b176e6a6f08b8f5027271003aaaf 100644 (file)
@@ -24,7 +24,6 @@ import (
        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/context"
        issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/markup"
@@ -32,7 +31,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/routers/web/feed"
-       context_service "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context"
        issue_service "code.gitea.io/gitea/services/issue"
        pull_service "code.gitea.io/gitea/services/pull"
 
@@ -714,7 +713,7 @@ func UsernameSubRoute(ctx *context.Context) {
        username := ctx.Params("username")
        reloadParam := func(suffix string) (success bool) {
                ctx.SetParams("username", strings.TrimSuffix(username, suffix))
-               context_service.UserAssignmentWeb()(ctx)
+               context.UserAssignmentWeb()(ctx)
                // check view permissions
                if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
                        ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
@@ -741,7 +740,7 @@ func UsernameSubRoute(ctx *context.Context) {
                        return
                }
                if reloadParam(".rss") {
-                       context_service.UserAssignmentWeb()(ctx)
+                       context.UserAssignmentWeb()(ctx)
                        feed.ShowUserFeedRSS(ctx)
                }
        case strings.HasSuffix(username, ".atom"):
@@ -753,7 +752,7 @@ func UsernameSubRoute(ctx *context.Context) {
                        feed.ShowUserFeedAtom(ctx)
                }
        default:
-               context_service.UserAssignmentWeb()(ctx)
+               context.UserAssignmentWeb()(ctx)
                if !ctx.Written() {
                        ctx.Data["EnableFeed"] = setting.Other.EnableFeed
                        OwnerProfile(ctx)
index a32b015cd1d7555ee4d7090e1aa3047eea4ab8f8..3f5fd266895096f240712ae7d6f48db562235f15 100644 (file)
@@ -10,8 +10,8 @@ import (
        "code.gitea.io/gitea/models/db"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index 26f77cfc3a36c02fcfe34a8ce83574e971586605..05034f8efaba4e117cea4c02448343f40e5e1f18 100644 (file)
@@ -16,11 +16,11 @@ import (
        issues_model "code.gitea.io/gitea/models/issues"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        issue_service "code.gitea.io/gitea/services/issue"
        pull_service "code.gitea.io/gitea/services/pull"
 )
index 708af3e43c98a63fc01bf9b2c1fc9dcda665ceb4..d03b28309fd8f68ee6136f7fc9167dabf0bd6bd9 100644 (file)
@@ -15,7 +15,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        alpine_module "code.gitea.io/gitea/modules/packages/alpine"
        debian_module "code.gitea.io/gitea/modules/packages/debian"
@@ -25,6 +24,7 @@ import (
        "code.gitea.io/gitea/modules/web"
        packages_helper "code.gitea.io/gitea/routers/api/packages/helper"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        packages_service "code.gitea.io/gitea/services/packages"
 )
index 4d0ad06cbadda8a9bc15269fd30a00b4565c07df..e7890b7c12090f4bfd23fd6ceda64513683c8545 100644 (file)
@@ -15,7 +15,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/markup"
@@ -25,6 +24,7 @@ import (
        "code.gitea.io/gitea/routers/web/feed"
        "code.gitea.io/gitea/routers/web/org"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 4d090a3784cc7e8f54be78e57d03e06a4770d250..fb7729bbe141965c4236bd55abd2ff6944a418c5 100644 (file)
@@ -8,7 +8,7 @@ import (
 
        "code.gitea.io/gitea/models/db"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 659c3e29c1e25ef5dd73e811e562ac26c9fcb2e0..23d3ca31618be3d2a6e1b16d05be78af3ba46f7a 100644 (file)
@@ -13,13 +13,13 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/timeutil"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/services/auth"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/mailer"
        "code.gitea.io/gitea/services/user"
index 6742c382e97e52c5e972a4d18d1056e7423865f1..9fdc5e4d5325bcd3f0b8a7fa01f1985d885eb7a6 100644 (file)
@@ -8,9 +8,9 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/forms"
 
        "github.com/stretchr/testify/assert"
index decb35c1e1776f142876837b0ef635662674fb09..171c1933d4f49f49d0006594c1ff64d282564bc2 100644 (file)
@@ -8,9 +8,9 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context"
        repo_service "code.gitea.io/gitea/services/repository"
 )
 
index a7e31fd505181ba20cfe5b91895345a6905d7b7f..e3822ca988c529340dd6d46c90722f619fb523be 100644 (file)
@@ -10,9 +10,9 @@ import (
        auth_model "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 16410d06ff02f90ed0462b23d927f3a37d8db998..0a12777e5e8dded9ebcd76b9d8b11bcadbb3b90c 100644 (file)
@@ -10,10 +10,10 @@ import (
        asymkey_model "code.gitea.io/gitea/models/asymkey"
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
        asymkey_service "code.gitea.io/gitea/services/asymkey"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 93142c21fcfc18ec3115dc1f1873a371902711e2..1f485e06c815e8eb7dc63bb39e3d0405a5076db6 100644 (file)
@@ -5,8 +5,8 @@ package setting
 
 import (
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index fecaa4b873eb87b11474f636aa85231c6604a463..85d1e820a5144e19f6fd8c77583072275a64efd1 100644 (file)
@@ -9,10 +9,10 @@ import (
 
        "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        shared_user "code.gitea.io/gitea/routers/web/shared/user"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 34d18f999e23dbb1c208944751b0ed90a196aade..4132659495394457f32c0c3b421c974a28493606 100644 (file)
@@ -9,11 +9,11 @@ import (
 
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        chef_module "code.gitea.io/gitea/modules/packages/chef"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        shared "code.gitea.io/gitea/routers/web/shared/packages"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 24a807d518f4e0b622fa7cf3153fb9d1bf6db8d8..49eb050dcb63e5732eef6aae1c6f52971fa0b295 100644 (file)
@@ -20,7 +20,6 @@ import (
        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/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
@@ -29,6 +28,7 @@ import (
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        user_service "code.gitea.io/gitea/services/user"
 )
index 451fd0ca97afadbca27e86ebd5b1ed6b9959437d..2bb10cceb95548a520eb21f5adce388ef163c08f 100644 (file)
@@ -4,8 +4,8 @@
 package setting
 
 import (
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 func RedirectToDefaultSetting(ctx *context.Context) {
index 7858b634ce3c3a4d018da1d8bf4287e385385cf3..cd0910236986871a7386d60ba30d7f80126600e8 100644 (file)
@@ -13,10 +13,10 @@ import (
        "strings"
 
        "code.gitea.io/gitea/models/auth"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 
        "github.com/pquerna/otp"
index 9a207e149d1df829d354bd380afdb0a29080121d..8f788e17356ca91ca8d9d0597999747ddccdcbd2 100644 (file)
@@ -8,10 +8,10 @@ import (
 
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/auth/openid"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 )
 
index 3647d606eef82dbafc2c79ec25965ffe38b19393..30611dd9f19c81c828f418eca5aab0274f60cfe6 100644 (file)
@@ -12,10 +12,10 @@ 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/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/services/auth/source/oauth2"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index ce103528c57ea4745c589c5bb435b5c07b6336ce..e382c8b9af413c765c56448abd3ed52397372aa6 100644 (file)
@@ -11,10 +11,10 @@ import (
 
        "code.gitea.io/gitea/models/auth"
        wa "code.gitea.io/gitea/modules/auth/webauthn"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
 
        "github.com/go-webauthn/webauthn/protocol"
index 679b72e5011971320923209f05f97d53f9c102f4..4423b627814ab8ff5741006a8ff9950e62cdec7b 100644 (file)
@@ -9,8 +9,8 @@ import (
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/webhook"
        "code.gitea.io/gitea/modules/base"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 const (
index 86f66e64a69696e11b6fb1dcd3c02852abe13986..38f74ea4554548397d131b959b212b4d9bfd983a 100644 (file)
@@ -8,7 +8,7 @@ import (
 
        "code.gitea.io/gitea/models/db"
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index bec68c5f209f46db9d4d966b1b8930fece69ef03..8476767e9e025aee745111d870d294b3f908b43e 100644 (file)
@@ -8,8 +8,8 @@ import (
        "strconv"
 
        admin_model "code.gitea.io/gitea/models/admin"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
+       "code.gitea.io/gitea/services/context"
 )
 
 // TaskStatus returns task's status
index b1fa5cf3550d3c5b83b5693ad8a620a167ed4a2a..452998703a3f129ea0d6149d1febfd6620ce67b2 100644 (file)
@@ -12,7 +12,6 @@ import (
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/perm"
        "code.gitea.io/gitea/models/unit"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/metrics"
        "code.gitea.io/gitea/modules/public"
@@ -42,7 +41,7 @@ import (
        user_setting "code.gitea.io/gitea/routers/web/user/setting"
        "code.gitea.io/gitea/routers/web/user/setting/security"
        auth_service "code.gitea.io/gitea/services/auth"
-       context_service "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/forms"
        "code.gitea.io/gitea/services/lfs"
 
@@ -790,7 +789,7 @@ func registerRoutes(m *web.Route) {
                m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment)
        }, ignSignIn)
 
-       m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action)
+       m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.Action)
 
        reqRepoAdmin := context.RequireRepoAdmin()
        reqRepoCodeWriter := context.RequireRepoWriter(unit.TypeCode)
@@ -1019,7 +1018,7 @@ func registerRoutes(m *web.Route) {
                m.Group("", func() {
                        m.Get("/code", user.CodeSearch)
                }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker)
-       }, ignSignIn, context_service.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code)
+       }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code)
 
        m.Group("/{username}/{reponame}", func() {
                m.Group("/settings", func() {
index faa35b8d2f529eb4547fb4c9b25fef6239f978b7..a87c426b3baa12118514247ef2d2e9bc2743ed88 100644 (file)
@@ -10,9 +10,9 @@ import (
        "strings"
 
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
 )
 
 // https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-webfinger-14#section-4.4
index 967332fd982f160839fd89e656e3b241384b8e23..eab3d0b142a1b62c6b8c820edc238081f250977e 100644 (file)
@@ -12,8 +12,8 @@ import (
        "code.gitea.io/gitea/models/db"
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/modules/storage"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/services/context/upload"
 
        "github.com/google/uuid"
 )
index 7c07dc438e4b80de201b3bc8be14082fd23dc2e7..a2523a2452e9b3de494a85e1d517da5cd3e6b22f 100644 (file)
@@ -12,12 +12,12 @@ import (
 
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/auth/webauthn"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "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/web/middleware"
+       gitea_context "code.gitea.io/gitea/services/context"
        user_service "code.gitea.io/gitea/services/user"
 )
 
index 8c0fc77a96feb0d88d8788bd14f58542f5f6466b..9108a0a668a42ed712b158d8ab9cf73a10ad5de9 100644 (file)
@@ -14,13 +14,13 @@ import (
        "code.gitea.io/gitea/models/db"
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/base"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/optional"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web/middleware"
        "code.gitea.io/gitea/services/auth/source/sspi"
+       gitea_context "code.gitea.io/gitea/services/context"
 
        gouuid "github.com/google/uuid"
 )
diff --git a/services/context/access_log.go b/services/context/access_log.go
new file mode 100644 (file)
index 0000000..0926748
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "bytes"
+       "fmt"
+       "net"
+       "net/http"
+       "strings"
+       "text/template"
+       "time"
+
+       user_model "code.gitea.io/gitea/models/user"
+       "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/web/middleware"
+)
+
+type routerLoggerOptions struct {
+       req            *http.Request
+       Identity       *string
+       Start          *time.Time
+       ResponseWriter http.ResponseWriter
+       Ctx            map[string]any
+       RequestID      *string
+}
+
+const keyOfRequestIDInTemplate = ".RequestID"
+
+// According to:
+// TraceId: A valid trace identifier is a 16-byte array with at least one non-zero byte
+// MD5 output is 16 or 32 bytes: md5-bytes is 16, md5-hex is 32
+// SHA1: similar, SHA1-bytes is 20, SHA1-hex is 40.
+// UUID is 128-bit, 32 hex chars, 36 ASCII chars with 4 dashes
+// So, we accept a Request ID with a maximum character length of 40
+const maxRequestIDByteLength = 40
+
+func parseRequestIDFromRequestHeader(req *http.Request) string {
+       requestID := "-"
+       for _, key := range setting.Log.RequestIDHeaders {
+               if req.Header.Get(key) != "" {
+                       requestID = req.Header.Get(key)
+                       break
+               }
+       }
+       if len(requestID) > maxRequestIDByteLength {
+               requestID = fmt.Sprintf("%s...", requestID[:maxRequestIDByteLength])
+       }
+       return requestID
+}
+
+// AccessLogger returns a middleware to log access logger
+func AccessLogger() func(http.Handler) http.Handler {
+       logger := log.GetLogger("access")
+       needRequestID := len(setting.Log.RequestIDHeaders) > 0 && strings.Contains(setting.Log.AccessLogTemplate, keyOfRequestIDInTemplate)
+       logTemplate, _ := template.New("log").Parse(setting.Log.AccessLogTemplate)
+       return func(next http.Handler) http.Handler {
+               return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+                       start := time.Now()
+
+                       var requestID string
+                       if needRequestID {
+                               requestID = parseRequestIDFromRequestHeader(req)
+                       }
+
+                       reqHost, _, err := net.SplitHostPort(req.RemoteAddr)
+                       if err != nil {
+                               reqHost = req.RemoteAddr
+                       }
+
+                       next.ServeHTTP(w, req)
+                       rw := w.(ResponseWriter)
+
+                       identity := "-"
+                       data := middleware.GetContextData(req.Context())
+                       if signedUser, ok := data[middleware.ContextDataKeySignedUser].(*user_model.User); ok {
+                               identity = signedUser.Name
+                       }
+                       buf := bytes.NewBuffer([]byte{})
+                       err = logTemplate.Execute(buf, routerLoggerOptions{
+                               req:            req,
+                               Identity:       &identity,
+                               Start:          &start,
+                               ResponseWriter: rw,
+                               Ctx: map[string]any{
+                                       "RemoteAddr": req.RemoteAddr,
+                                       "RemoteHost": reqHost,
+                                       "Req":        req,
+                               },
+                               RequestID: &requestID,
+                       })
+                       if err != nil {
+                               log.Error("Could not execute access logger template: %v", err.Error())
+                       }
+
+                       logger.Info("%s", buf.String())
+               })
+       }
+}
diff --git a/services/context/api.go b/services/context/api.go
new file mode 100644 (file)
index 0000000..b18a206
--- /dev/null
@@ -0,0 +1,408 @@
+// Copyright 2016 The Gogs Authors. All rights reserved.
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "context"
+       "fmt"
+       "net/http"
+       "net/url"
+       "strings"
+
+       "code.gitea.io/gitea/models/unit"
+       user_model "code.gitea.io/gitea/models/user"
+       mc "code.gitea.io/gitea/modules/cache"
+       "code.gitea.io/gitea/modules/git"
+       "code.gitea.io/gitea/modules/gitrepo"
+       "code.gitea.io/gitea/modules/httpcache"
+       "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/web"
+       web_types "code.gitea.io/gitea/modules/web/types"
+
+       "gitea.com/go-chi/cache"
+)
+
+// APIContext is a specific context for API service
+type APIContext struct {
+       *Base
+
+       Cache cache.Cache
+
+       Doer        *user_model.User // current signed-in user
+       IsSigned    bool
+       IsBasicAuth bool
+
+       ContextUser *user_model.User // the user which is being visited, in most cases it differs from Doer
+
+       Repo    *Repository
+       Org     *APIOrganization
+       Package *Package
+}
+
+func init() {
+       web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider {
+               return req.Context().Value(apiContextKey).(*APIContext)
+       })
+}
+
+// Currently, we have the following common fields in error response:
+// * message: the message for end users (it shouldn't be used for error type detection)
+//            if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType
+// * url:     the swagger document URL
+
+// APIError is error format response
+// swagger:response error
+type APIError struct {
+       Message string `json:"message"`
+       URL     string `json:"url"`
+}
+
+// APIValidationError is error format response related to input validation
+// swagger:response validationError
+type APIValidationError struct {
+       Message string `json:"message"`
+       URL     string `json:"url"`
+}
+
+// APIInvalidTopicsError is error format response to invalid topics
+// swagger:response invalidTopicsError
+type APIInvalidTopicsError struct {
+       Message       string   `json:"message"`
+       InvalidTopics []string `json:"invalidTopics"`
+}
+
+// APIEmpty is an empty response
+// swagger:response empty
+type APIEmpty struct{}
+
+// APIForbiddenError is a forbidden error response
+// swagger:response forbidden
+type APIForbiddenError struct {
+       APIError
+}
+
+// APINotFound is a not found empty response
+// swagger:response notFound
+type APINotFound struct{}
+
+// APIConflict is a conflict empty response
+// swagger:response conflict
+type APIConflict struct{}
+
+// APIRedirect is a redirect response
+// swagger:response redirect
+type APIRedirect struct{}
+
+// APIString is a string response
+// swagger:response string
+type APIString string
+
+// APIRepoArchivedError is an error that is raised when an archived repo should be modified
+// swagger:response repoArchivedError
+type APIRepoArchivedError struct {
+       APIError
+}
+
+// ServerError responds with error message, status is 500
+func (ctx *APIContext) ServerError(title string, err error) {
+       ctx.Error(http.StatusInternalServerError, title, err)
+}
+
+// Error responds with an error message to client with given obj as the message.
+// If status is 500, also it prints error to log.
+func (ctx *APIContext) Error(status int, title string, obj any) {
+       var message string
+       if err, ok := obj.(error); ok {
+               message = err.Error()
+       } else {
+               message = fmt.Sprintf("%s", obj)
+       }
+
+       if status == http.StatusInternalServerError {
+               log.ErrorWithSkip(1, "%s: %s", title, message)
+
+               if setting.IsProd && !(ctx.Doer != nil && ctx.Doer.IsAdmin) {
+                       message = ""
+               }
+       }
+
+       ctx.JSON(status, APIError{
+               Message: message,
+               URL:     setting.API.SwaggerURL,
+       })
+}
+
+// InternalServerError responds with an error message to the client with the error as a message
+// and the file and line of the caller.
+func (ctx *APIContext) InternalServerError(err error) {
+       log.ErrorWithSkip(1, "InternalServerError: %v", err)
+
+       var message string
+       if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
+               message = err.Error()
+       }
+
+       ctx.JSON(http.StatusInternalServerError, APIError{
+               Message: message,
+               URL:     setting.API.SwaggerURL,
+       })
+}
+
+type apiContextKeyType struct{}
+
+var apiContextKey = apiContextKeyType{}
+
+// GetAPIContext returns a context for API routes
+func GetAPIContext(req *http.Request) *APIContext {
+       return req.Context().Value(apiContextKey).(*APIContext)
+}
+
+func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string {
+       page := NewPagination(total, pageSize, curPage, 0)
+       paginater := page.Paginater
+       links := make([]string, 0, 4)
+
+       if paginater.HasNext() {
+               u := *curURL
+               queries := u.Query()
+               queries.Set("page", fmt.Sprintf("%d", paginater.Next()))
+               u.RawQuery = queries.Encode()
+
+               links = append(links, fmt.Sprintf("<%s%s>; rel=\"next\"", setting.AppURL, u.RequestURI()[1:]))
+       }
+       if !paginater.IsLast() {
+               u := *curURL
+               queries := u.Query()
+               queries.Set("page", fmt.Sprintf("%d", paginater.TotalPages()))
+               u.RawQuery = queries.Encode()
+
+               links = append(links, fmt.Sprintf("<%s%s>; rel=\"last\"", setting.AppURL, u.RequestURI()[1:]))
+       }
+       if !paginater.IsFirst() {
+               u := *curURL
+               queries := u.Query()
+               queries.Set("page", "1")
+               u.RawQuery = queries.Encode()
+
+               links = append(links, fmt.Sprintf("<%s%s>; rel=\"first\"", setting.AppURL, u.RequestURI()[1:]))
+       }
+       if paginater.HasPrevious() {
+               u := *curURL
+               queries := u.Query()
+               queries.Set("page", fmt.Sprintf("%d", paginater.Previous()))
+               u.RawQuery = queries.Encode()
+
+               links = append(links, fmt.Sprintf("<%s%s>; rel=\"prev\"", setting.AppURL, u.RequestURI()[1:]))
+       }
+       return links
+}
+
+// SetLinkHeader sets pagination link header by given total number and page size.
+func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
+       links := genAPILinks(ctx.Req.URL, total, pageSize, ctx.FormInt("page"))
+
+       if len(links) > 0 {
+               ctx.RespHeader().Set("Link", strings.Join(links, ","))
+               ctx.AppendAccessControlExposeHeaders("Link")
+       }
+}
+
+// APIContexter returns apicontext as middleware
+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)
+                       ctx := &APIContext{
+                               Base:  base,
+                               Cache: mc.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 })
+
+                       // 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") {
+                               if err := ctx.Req.ParseMultipartForm(setting.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
+                                       ctx.InternalServerError(err)
+                                       return
+                               }
+                       }
+
+                       httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
+                       ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
+
+                       next.ServeHTTP(ctx.Resp, ctx.Req)
+               })
+       }
+}
+
+// NotFound handles 404s for APIContext
+// String will replace message, errors will be added to a slice
+func (ctx *APIContext) NotFound(objs ...any) {
+       message := ctx.Locale.TrString("error.not_found")
+       var errors []string
+       for _, obj := range objs {
+               // Ignore nil
+               if obj == nil {
+                       continue
+               }
+
+               if err, ok := obj.(error); ok {
+                       errors = append(errors, err.Error())
+               } else {
+                       message = obj.(string)
+               }
+       }
+
+       ctx.JSON(http.StatusNotFound, map[string]any{
+               "message": message,
+               "url":     setting.API.SwaggerURL,
+               "errors":  errors,
+       })
+}
+
+// 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) {
+               // Empty repository does not have reference information.
+               if ctx.Repo.Repository.IsEmpty && !(len(allowEmpty) != 0 && allowEmpty[0]) {
+                       return nil
+               }
+
+               // For API calls.
+               if ctx.Repo.GitRepo == nil {
+                       gitRepo, err := gitrepo.OpenRepository(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 cancel
+       }
+}
+
+// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
+func RepoRefForAPI(next http.Handler) http.Handler {
+       return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+               ctx := GetAPIContext(req)
+
+               if ctx.Repo.GitRepo == nil {
+                       ctx.InternalServerError(fmt.Errorf("no open git repo"))
+                       return
+               }
+
+               if ref := ctx.FormTrim("ref"); len(ref) > 0 {
+                       commit, err := ctx.Repo.GitRepo.GetCommit(ref)
+                       if err != nil {
+                               if git.IsErrNotExist(err) {
+                                       ctx.NotFound()
+                               } else {
+                                       ctx.Error(http.StatusInternalServerError, "GetCommit", err)
+                               }
+                               return
+                       }
+                       ctx.Repo.Commit = commit
+                       ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+                       ctx.Repo.TreePath = ctx.Params("*")
+                       next.ServeHTTP(w, req)
+                       return
+               }
+
+               refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
+               var err error
+
+               if ctx.Repo.GitRepo.IsBranchExist(refName) {
+                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
+                       if err != nil {
+                               ctx.InternalServerError(err)
+                               return
+                       }
+                       ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+               } else if ctx.Repo.GitRepo.IsTagExist(refName) {
+                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
+                       if err != nil {
+                               ctx.InternalServerError(err)
+                               return
+                       }
+                       ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+               } else if len(refName) == ctx.Repo.GetObjectFormat().FullLength() {
+                       ctx.Repo.CommitID = refName
+                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
+                       if err != nil {
+                               ctx.NotFound("GetCommit", err)
+                               return
+                       }
+               } else {
+                       ctx.NotFound(fmt.Errorf("not exist: '%s'", ctx.Params("*")))
+                       return
+               }
+
+               next.ServeHTTP(w, req)
+       })
+}
+
+// HasAPIError returns true if error occurs in form validation.
+func (ctx *APIContext) HasAPIError() bool {
+       hasErr, ok := ctx.Data["HasError"]
+       if !ok {
+               return false
+       }
+       return hasErr.(bool)
+}
+
+// GetErrMsg returns error message in form validation.
+func (ctx *APIContext) GetErrMsg() string {
+       msg, _ := ctx.Data["ErrorMsg"].(string)
+       if msg == "" {
+               msg = "invalid form data"
+       }
+       return msg
+}
+
+// NotFoundOrServerError use error check function to determine if the error
+// is about not found. It responds with 404 status code for not found error,
+// or error context description for logging purpose of 500 server error.
+func (ctx *APIContext) NotFoundOrServerError(logMsg string, errCheck func(error) bool, logErr error) {
+       if errCheck(logErr) {
+               ctx.JSON(http.StatusNotFound, nil)
+               return
+       }
+       ctx.Error(http.StatusInternalServerError, "NotFoundOrServerError", logMsg)
+}
+
+// IsUserSiteAdmin returns true if current user is a site admin
+func (ctx *APIContext) IsUserSiteAdmin() bool {
+       return ctx.IsSigned && ctx.Doer.IsAdmin
+}
+
+// IsUserRepoAdmin returns true if current user is admin in current repo
+func (ctx *APIContext) IsUserRepoAdmin() bool {
+       return ctx.Repo.IsAdmin()
+}
+
+// IsUserRepoWriter returns true if current user has write privilege in current repo
+func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool {
+       for _, unitType := range unitTypes {
+               if ctx.Repo.CanWrite(unitType) {
+                       return true
+               }
+       }
+
+       return false
+}
diff --git a/services/context/api_org.go b/services/context/api_org.go
new file mode 100644 (file)
index 0000000..dad02b1
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2016 The Gogs Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import "code.gitea.io/gitea/models/organization"
+
+// APIOrganization contains organization and team
+type APIOrganization struct {
+       Organization *organization.Organization
+       Team         *organization.Team
+}
diff --git a/services/context/api_test.go b/services/context/api_test.go
new file mode 100644 (file)
index 0000000..911a499
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "net/url"
+       "strconv"
+       "testing"
+
+       "code.gitea.io/gitea/modules/setting"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestGenAPILinks(t *testing.T) {
+       setting.AppURL = "http://localhost:3000/"
+       kases := map[string][]string{
+               "api/v1/repos/jerrykan/example-repo/issues?state=all": {
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=2&state=all>; rel="next"`,
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
+               },
+               "api/v1/repos/jerrykan/example-repo/issues?state=all&page=1": {
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=2&state=all>; rel="next"`,
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
+               },
+               "api/v1/repos/jerrykan/example-repo/issues?state=all&page=2": {
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=3&state=all>; rel="next"`,
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="first"`,
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="prev"`,
+               },
+               "api/v1/repos/jerrykan/example-repo/issues?state=all&page=5": {
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="first"`,
+                       `<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=4&state=all>; rel="prev"`,
+               },
+       }
+
+       for req, response := range kases {
+               u, err := url.Parse(setting.AppURL + req)
+               assert.NoError(t, err)
+
+               p := u.Query().Get("page")
+               curPage, _ := strconv.Atoi(p)
+
+               links := genAPILinks(u, 100, 20, curPage)
+
+               assert.EqualValues(t, links, response)
+       }
+}
diff --git a/services/context/base.go b/services/context/base.go
new file mode 100644 (file)
index 0000000..ddd04f4
--- /dev/null
@@ -0,0 +1,317 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "context"
+       "fmt"
+       "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/translation"
+       "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/modules/web/middleware"
+
+       "github.com/go-chi/chi/v5"
+)
+
+type contextValuePair struct {
+       key     any
+       valueFn func() any
+}
+
+type Base struct {
+       originCtx     context.Context
+       contextValues []contextValuePair
+
+       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
+
+       // 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")
+       if len(val) != 0 {
+               b.RespHeader().Set("Access-Control-Expose-Headers", fmt.Sprintf("%s, %s", val, strings.Join(names, ", ")))
+       } else {
+               b.RespHeader().Set("Access-Control-Expose-Headers", strings.Join(names, ", "))
+       }
+}
+
+// SetTotalCountHeader set "X-Total-Count" header
+func (b *Base) SetTotalCountHeader(total int64) {
+       b.RespHeader().Set("X-Total-Count", fmt.Sprint(total))
+       b.AppendAccessControlExposeHeaders("X-Total-Count")
+}
+
+// Written returns true if there are something sent to web browser
+func (b *Base) Written() bool {
+       return b.Resp.WrittenStatus() != 0
+}
+
+func (b *Base) WrittenStatus() int {
+       return b.Resp.WrittenStatus()
+}
+
+// Status writes status code
+func (b *Base) Status(status int) {
+       b.Resp.WriteHeader(status)
+}
+
+// Write writes data to web browser
+func (b *Base) Write(bs []byte) (int, error) {
+       return b.Resp.Write(bs)
+}
+
+// RespHeader returns the response header
+func (b *Base) RespHeader() http.Header {
+       return b.Resp.Header()
+}
+
+// Error returned an error to web browser
+func (b *Base) Error(status int, contents ...string) {
+       v := http.StatusText(status)
+       if len(contents) > 0 {
+               v = contents[0]
+       }
+       http.Error(b.Resp, v, status)
+}
+
+// JSON render content as JSON
+func (b *Base) JSON(status int, content any) {
+       b.Resp.Header().Set("Content-Type", "application/json;charset=utf-8")
+       b.Resp.WriteHeader(status)
+       if err := json.NewEncoder(b.Resp).Encode(content); err != nil {
+               log.Error("Render JSON failed: %v", err)
+       }
+}
+
+// RemoteAddr returns the client machine ip address
+func (b *Base) RemoteAddr() string {
+       return b.Req.RemoteAddr
+}
+
+// Params returns the param on route
+func (b *Base) Params(p string) string {
+       s, _ := url.PathUnescape(chi.URLParam(b.Req, strings.TrimPrefix(p, ":")))
+       return s
+}
+
+func (b *Base) PathParamRaw(p string) string {
+       return chi.URLParam(b.Req, strings.TrimPrefix(p, ":"))
+}
+
+// ParamsInt64 returns the param on route as int64
+func (b *Base) ParamsInt64(p string) int64 {
+       v, _ := strconv.ParseInt(b.Params(p), 10, 64)
+       return v
+}
+
+// SetParams set params into routes
+func (b *Base) SetParams(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 OptionalBoolTrue or OptionalBoolFalse if the value
+// for the provided key exists in the form else it returns OptionalBoolNone
+func (b *Base) FormOptionalBool(key string) util.OptionalBool {
+       value := b.Req.FormValue(key)
+       if len(value) == 0 {
+               return util.OptionalBoolNone
+       }
+       s := b.Req.FormValue(key)
+       v, _ := strconv.ParseBool(s)
+       v = v || strings.EqualFold(s, "on")
+       return util.OptionalBoolOf(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
+       if statusPrefix == 4 || statusPrefix == 5 {
+               log.Log(skip, log.TRACE, "plainTextInternal (status=%d): %s", status, string(bs))
+       }
+       b.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8")
+       b.Resp.Header().Set("X-Content-Type-Options", "nosniff")
+       b.Resp.WriteHeader(status)
+       if _, err := b.Resp.Write(bs); err != nil {
+               log.ErrorWithSkip(skip, "plainTextInternal (status=%d): write bytes failed: %v", status, err)
+       }
+}
+
+// PlainTextBytes renders bytes as plain text
+func (b *Base) PlainTextBytes(status int, bs []byte) {
+       b.plainTextInternal(2, status, bs)
+}
+
+// PlainText renders content as plain text
+func (b *Base) PlainText(status int, text string) {
+       b.plainTextInternal(2, status, []byte(text))
+}
+
+// Redirect redirects the request
+func (b *Base) Redirect(location string, status ...int) {
+       code := http.StatusSeeOther
+       if len(status) == 1 {
+               code = status[0]
+       }
+
+       if strings.Contains(location, "://") || strings.HasPrefix(location, "//") {
+               // Some browsers (Safari) have buggy behavior for Cookie + Cache + External Redirection, eg: /my-path => https://other/path
+               // 1. the first request to "/my-path" contains cookie
+               // 2. some time later, the request to "/my-path" doesn't contain cookie (caused by Prevent web tracking)
+               // 3. Gitea's Sessioner doesn't see the session cookie, so it generates a new session id, and returns it to browser
+               // 4. then the browser accepts the empty session, then the user is logged out
+               // So in this case, we should remove the session cookie from the response header
+               removeSessionCookieHeader(b.Resp)
+       }
+       // in case the request is made by htmx, have it redirect the browser instead of trying to follow the redirect inside htmx
+       if b.Req.Header.Get("HX-Request") == "true" {
+               b.Resp.Header().Set("HX-Redirect", location)
+               // we have to return a non-redirect status code so XMLHTTPRequest will not immediately follow the redirect
+               // so as to give htmx redirect logic a chance to run
+               b.Status(http.StatusNoContent)
+               return
+       }
+       http.Redirect(b.Resp, b.Req, location, code)
+}
+
+type ServeHeaderOptions httplib.ServeHeaderOptions
+
+func (b *Base) SetServeHeaders(opt *ServeHeaderOptions) {
+       httplib.ServeSetHeaders(b.Resp, (*httplib.ServeHeaderOptions)(opt))
+}
+
+// ServeContent serves content to http request
+func (b *Base) ServeContent(r io.ReadSeeker, opts *ServeHeaderOptions) {
+       httplib.ServeSetHeaders(b.Resp, (*httplib.ServeHeaderOptions)(opts))
+       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...)
+}
+
+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()),
+       }
+       b.AppendContextValue(translation.ContextKey, b.Locale)
+       b.Req = b.Req.WithContext(b)
+       return b, b.cleanUp
+}
diff --git a/services/context/captcha.go b/services/context/captcha.go
new file mode 100644 (file)
index 0000000..a199990
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+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/turnstile"
+
+       "gitea.com/go-chi/captcha"
+)
+
+var (
+       imageCaptchaOnce sync.Once
+       cpt              *captcha.Captcha
+)
+
+// GetImageCaptcha returns global image captcha
+func GetImageCaptcha() *captcha.Captcha {
+       imageCaptchaOnce.Do(func() {
+               cpt = captcha.NewCaptcha(captcha.Options{
+                       SubURL: setting.AppSubURL,
+               })
+               cpt.Store = cache.GetCache()
+       })
+       return cpt
+}
+
+// SetCaptchaData sets common captcha data
+func SetCaptchaData(ctx *Context) {
+       if !setting.Service.EnableCaptcha {
+               return
+       }
+       ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
+       ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
+       ctx.Data["Captcha"] = GetImageCaptcha()
+       ctx.Data["CaptchaType"] = setting.Service.CaptchaType
+       ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
+       ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
+       ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
+       ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
+       ctx.Data["CfTurnstileSitekey"] = setting.Service.CfTurnstileSitekey
+}
+
+const (
+       gRecaptchaResponseField  = "g-recaptcha-response"
+       hCaptchaResponseField    = "h-captcha-response"
+       mCaptchaResponseField    = "m-captcha-response"
+       cfTurnstileResponseField = "cf-turnstile-response"
+)
+
+// VerifyCaptcha verifies Captcha data
+// No-op if captchas are not enabled
+func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) {
+       if !setting.Service.EnableCaptcha {
+               return
+       }
+
+       var valid bool
+       var err error
+       switch setting.Service.CaptchaType {
+       case setting.ImageCaptcha:
+               valid = GetImageCaptcha().VerifyReq(ctx.Req)
+       case setting.ReCaptcha:
+               valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField))
+       case setting.HCaptcha:
+               valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(hCaptchaResponseField))
+       case setting.MCaptcha:
+               valid, err = mcaptcha.Verify(ctx, ctx.Req.Form.Get(mCaptchaResponseField))
+       case setting.CfTurnstile:
+               valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField))
+       default:
+               ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
+               return
+       }
+       if err != nil {
+               log.Debug("%v", err)
+       }
+
+       if !valid {
+               ctx.Data["Err_Captcha"] = true
+               ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, form)
+       }
+}
diff --git a/services/context/context.go b/services/context/context.go
new file mode 100644 (file)
index 0000000..4b318f7
--- /dev/null
@@ -0,0 +1,257 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "context"
+       "encoding/hex"
+       "fmt"
+       "html/template"
+       "io"
+       "net/http"
+       "net/url"
+       "strings"
+       "time"
+
+       "code.gitea.io/gitea/models/unit"
+       user_model "code.gitea.io/gitea/models/user"
+       mc "code.gitea.io/gitea/modules/cache"
+       "code.gitea.io/gitea/modules/gitrepo"
+       "code.gitea.io/gitea/modules/httpcache"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/templates"
+       "code.gitea.io/gitea/modules/translation"
+       "code.gitea.io/gitea/modules/web"
+       "code.gitea.io/gitea/modules/web/middleware"
+       web_types "code.gitea.io/gitea/modules/web/types"
+
+       "gitea.com/go-chi/cache"
+       "gitea.com/go-chi/session"
+)
+
+// 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
+}
+
+// Context represents context of a request.
+type Context struct {
+       *Base
+
+       TemplateContext TemplateContext
+
+       Render   Render
+       PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
+
+       Cache   cache.Cache
+       Csrf    CSRFProtector
+       Flash   *middleware.Flash
+       Session session.Store
+
+       Link string // current request URL (without query string)
+
+       Doer        *user_model.User // current signed-in user
+       IsSigned    bool
+       IsBasicAuth bool
+
+       ContextUser *user_model.User // the user which is being visited, in most cases it differs from Doer
+
+       Repo    *Repository
+       Org     *Organization
+       Package *Package
+}
+
+type TemplateContext map[string]any
+
+func init() {
+       web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider {
+               return req.Context().Value(WebContextKey).(*Context)
+       })
+}
+
+type webContextKeyType struct{}
+
+var WebContextKey = webContextKeyType{}
+
+func GetWebContext(req *http.Request) *Context {
+       ctx, _ := req.Context().Value(WebContextKey).(*Context)
+       return ctx
+}
+
+// ValidateContext is a special context for form validation middleware. It may be different from other contexts.
+type ValidateContext struct {
+       *Base
+}
+
+// GetValidateContext gets a context for middleware form validation
+func GetValidateContext(req *http.Request) (ctx *ValidateContext) {
+       if ctxAPI, ok := req.Context().Value(apiContextKey).(*APIContext); ok {
+               ctx = &ValidateContext{Base: ctxAPI.Base}
+       } else if ctxWeb, ok := req.Context().Value(WebContextKey).(*Context); ok {
+               ctx = &ValidateContext{Base: ctxWeb.Base}
+       } else {
+               panic("invalid context, expect either APIContext or Context")
+       }
+       return ctx
+}
+
+func NewTemplateContextForWeb(ctx *Context) TemplateContext {
+       tmplCtx := NewTemplateContext(ctx)
+       tmplCtx["Locale"] = ctx.Base.Locale
+       tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx)
+       return tmplCtx
+}
+
+func NewWebContext(base *Base, render Render, session session.Store) *Context {
+       ctx := &Context{
+               Base:    base,
+               Render:  render,
+               Session: session,
+
+               Cache: mc.GetCache(),
+               Link:  setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
+               Repo:  &Repository{PullRequest: &PullRequest{}},
+               Org:   &Organization{},
+       }
+       ctx.TemplateContext = NewTemplateContextForWeb(ctx)
+       ctx.Flash = &middleware.Flash{DataStore: ctx, Values: url.Values{}}
+       return ctx
+}
+
+// Contexter initializes a classic context for a request.
+func Contexter() func(next http.Handler) http.Handler {
+       rnd := templates.HTMLRenderer()
+       csrfOpts := CsrfOptions{
+               Secret:         hex.EncodeToString(setting.GetGeneralTokenSigningSecret()),
+               Cookie:         setting.CSRFCookieName,
+               SetCookie:      true,
+               Secure:         setting.SessionConfig.Secure,
+               CookieHTTPOnly: setting.CSRFCookieHTTPOnly,
+               Header:         "X-Csrf-Token",
+               CookieDomain:   setting.SessionConfig.Domain,
+               CookiePath:     setting.SessionConfig.CookiePath,
+               SameSite:       setting.SessionConfig.SameSite,
+       }
+       if !setting.IsProd {
+               CsrfTokenRegenerationInterval = 5 * time.Second // in dev, re-generate the tokens more aggressively for debug purpose
+       }
+       return func(next http.Handler) http.Handler {
+               return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+                       base, baseCleanUp := NewBaseContext(resp, req)
+                       defer baseCleanUp()
+                       ctx := NewWebContext(base, rnd, session.GetSession(req))
+
+                       ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
+                       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
+
+                       // PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules
+                       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.Csrf = PrepareCSRFProtector(csrfOpts, ctx)
+
+                       // Get the last flash message from cookie
+                       lastFlashCookie := middleware.GetSiteCookie(ctx.Req, CookieNameFlash)
+                       if vals, _ := url.ParseQuery(lastFlashCookie); len(vals) > 0 {
+                               // store last Flash message into the template data, to render it
+                               ctx.Data["Flash"] = &middleware.Flash{
+                                       DataStore:  ctx,
+                                       Values:     vals,
+                                       ErrorMsg:   vals.Get("error"),
+                                       SuccessMsg: vals.Get("success"),
+                                       InfoMsg:    vals.Get("info"),
+                                       WarningMsg: vals.Get("warning"),
+                               }
+                       }
+
+                       // if there are new messages in the ctx.Flash, write them into cookie
+                       ctx.Resp.Before(func(resp ResponseWriter) {
+                               if val := ctx.Flash.Encode(); val != "" {
+                                       middleware.SetSiteCookie(ctx.Resp, CookieNameFlash, val, 0)
+                               } else if lastFlashCookie != "" {
+                                       middleware.SetSiteCookie(ctx.Resp, CookieNameFlash, "", -1)
+                               }
+                       })
+
+                       // 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") {
+                               if err := ctx.Req.ParseMultipartForm(setting.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
+                                       ctx.ServerError("ParseMultipartForm", err)
+                                       return
+                               }
+                       }
+
+                       httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
+                       ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
+
+                       ctx.Data["SystemConfig"] = setting.Config()
+                       ctx.Data["CsrfToken"] = ctx.Csrf.GetToken()
+                       ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.Data["CsrfToken"].(string) + `">`)
+
+                       // FIXME: do we really always need these setting? There should be someway to have to avoid having to always set these
+                       ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
+                       ctx.Data["DisableStars"] = setting.Repository.DisableStars
+                       ctx.Data["EnableActions"] = setting.Actions.Enabled
+
+                       ctx.Data["ManifestData"] = setting.ManifestData
+
+                       ctx.Data["UnitWikiGlobalDisabled"] = unit.TypeWiki.UnitGlobalDisabled()
+                       ctx.Data["UnitIssuesGlobalDisabled"] = unit.TypeIssues.UnitGlobalDisabled()
+                       ctx.Data["UnitPullsGlobalDisabled"] = unit.TypePullRequests.UnitGlobalDisabled()
+                       ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
+                       ctx.Data["UnitActionsGlobalDisabled"] = unit.TypeActions.UnitGlobalDisabled()
+
+                       ctx.Data["AllLangs"] = translation.AllLangs()
+
+                       next.ServeHTTP(ctx.Resp, ctx.Req)
+               })
+       }
+}
+
+// HasError returns true if error occurs in form validation.
+// Attention: this function changes ctx.Data and ctx.Flash
+func (ctx *Context) HasError() bool {
+       hasErr, ok := ctx.Data["HasError"]
+       if !ok {
+               return false
+       }
+       ctx.Flash.ErrorMsg = ctx.GetErrMsg()
+       ctx.Data["Flash"] = ctx.Flash
+       return hasErr.(bool)
+}
+
+// GetErrMsg returns error message in form validation.
+func (ctx *Context) GetErrMsg() string {
+       msg, _ := ctx.Data["ErrorMsg"].(string)
+       if msg == "" {
+               msg = "invalid form data"
+       }
+       return msg
+}
+
+func (ctx *Context) JSONRedirect(redirect string) {
+       ctx.JSON(http.StatusOK, map[string]any{"redirect": redirect})
+}
+
+func (ctx *Context) JSONOK() {
+       ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
+}
+
+func (ctx *Context) JSONError(msg any) {
+       switch v := msg.(type) {
+       case string:
+               ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "text"})
+       case template.HTML:
+               ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "html"})
+       default:
+               panic(fmt.Sprintf("unsupported type: %T", msg))
+       }
+}
diff --git a/services/context/context_cookie.go b/services/context/context_cookie.go
new file mode 100644 (file)
index 0000000..b6f8dad
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "net/http"
+       "strings"
+
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/web/middleware"
+)
+
+const CookieNameFlash = "gitea_flash"
+
+func removeSessionCookieHeader(w http.ResponseWriter) {
+       cookies := w.Header()["Set-Cookie"]
+       w.Header().Del("Set-Cookie")
+       for _, cookie := range cookies {
+               if strings.HasPrefix(cookie, setting.SessionConfig.CookieName+"=") {
+                       continue
+               }
+               w.Header().Add("Set-Cookie", cookie)
+       }
+}
+
+// SetSiteCookie convenience function to set most cookies consistently
+// CSRF and a few others are the exception here
+func (ctx *Context) SetSiteCookie(name, value string, maxAge int) {
+       middleware.SetSiteCookie(ctx.Resp, name, value, maxAge)
+}
+
+// DeleteSiteCookie convenience function to delete most cookies consistently
+// CSRF and a few others are the exception here
+func (ctx *Context) DeleteSiteCookie(name string) {
+       middleware.SetSiteCookie(ctx.Resp, name, "", -1)
+}
+
+// GetSiteCookie returns given cookie value from request header.
+func (ctx *Context) GetSiteCookie(name string) string {
+       return middleware.GetSiteCookie(ctx.Req, name)
+}
diff --git a/services/context/context_model.go b/services/context/context_model.go
new file mode 100644 (file)
index 0000000..4f70aac
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "code.gitea.io/gitea/models/unit"
+)
+
+// IsUserSiteAdmin returns true if current user is a site admin
+func (ctx *Context) IsUserSiteAdmin() bool {
+       return ctx.IsSigned && ctx.Doer.IsAdmin
+}
+
+// IsUserRepoAdmin returns true if current user is admin in current repo
+func (ctx *Context) IsUserRepoAdmin() bool {
+       return ctx.Repo.IsAdmin()
+}
+
+// IsUserRepoWriter returns true if current user has write privilege in current repo
+func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool {
+       for _, unitType := range unitTypes {
+               if ctx.Repo.CanWrite(unitType) {
+                       return true
+               }
+       }
+
+       return false
+}
diff --git a/services/context/context_request.go b/services/context/context_request.go
new file mode 100644 (file)
index 0000000..984b9ac
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "io"
+       "net/http"
+       "strings"
+)
+
+// UploadStream returns the request body or the first form file
+// Only form files need to get closed.
+func (ctx *Context) UploadStream() (rd io.ReadCloser, needToClose bool, err error) {
+       contentType := strings.ToLower(ctx.Req.Header.Get("Content-Type"))
+       if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") || strings.HasPrefix(contentType, "multipart/form-data") {
+               if err := ctx.Req.ParseMultipartForm(32 << 20); err != nil {
+                       return nil, false, err
+               }
+               if ctx.Req.MultipartForm.File == nil {
+                       return nil, false, http.ErrMissingFile
+               }
+               for _, files := range ctx.Req.MultipartForm.File {
+                       if len(files) > 0 {
+                               r, err := files[0].Open()
+                               return r, true, err
+                       }
+               }
+               return nil, false, http.ErrMissingFile
+       }
+       return ctx.Req.Body, false, nil
+}
diff --git a/services/context/context_response.go b/services/context/context_response.go
new file mode 100644 (file)
index 0000000..829bca1
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "errors"
+       "fmt"
+       "net"
+       "net/http"
+       "net/url"
+       "path"
+       "strconv"
+       "strings"
+       "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"
+       "code.gitea.io/gitea/modules/templates"
+       "code.gitea.io/gitea/modules/web/middleware"
+)
+
+// RedirectToUser redirect to a differently-named user
+func RedirectToUser(ctx *Base, userName string, redirectUserID int64) {
+       user, err := user_model.GetUserByID(ctx, redirectUserID)
+       if err != nil {
+               ctx.Error(http.StatusInternalServerError, "unable to get user")
+               return
+       }
+
+       redirectPath := strings.Replace(
+               ctx.Req.URL.EscapedPath(),
+               url.PathEscape(userName),
+               url.PathEscape(user.Name),
+               1,
+       )
+       if ctx.Req.URL.RawQuery != "" {
+               redirectPath += "?" + ctx.Req.URL.RawQuery
+       }
+       ctx.Redirect(path.Join(setting.AppSubURL, redirectPath), http.StatusTemporaryRedirect)
+}
+
+// RedirectToFirst redirects to first not empty URL
+func (ctx *Context) RedirectToFirst(location ...string) {
+       for _, loc := range location {
+               if len(loc) == 0 {
+                       continue
+               }
+
+               if httplib.IsRiskyRedirectURL(loc) {
+                       continue
+               }
+
+               ctx.Redirect(loc)
+               return
+       }
+
+       ctx.Redirect(setting.AppSubURL + "/")
+}
+
+const tplStatus500 base.TplName = "status/500"
+
+// HTML calls Context.HTML and renders the template to HTTP response
+func (ctx *Context) HTML(status int, name base.TplName) {
+       log.Debug("Template: %s", name)
+
+       tmplStartTime := time.Now()
+       if !setting.IsProd {
+               ctx.Data["TemplateName"] = name
+       }
+       ctx.Data["TemplateLoadTimes"] = func() string {
+               return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
+       }
+
+       err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext)
+       if err == nil {
+               return
+       }
+
+       // if rendering fails, show error page
+       if name != tplStatus500 {
+               err = fmt.Errorf("failed to render template: %s, error: %s", name, templates.HandleTemplateRenderingError(err))
+               ctx.ServerError("Render failed", err) // show the 500 error page
+       } else {
+               ctx.PlainText(http.StatusInternalServerError, "Unable to render status/500 page, the template system is broken, or Gitea can't find your template files.")
+               return
+       }
+}
+
+// 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) {
+       t, err := ctx.Render.TemplateLookup(string(tmpl), nil)
+       if err != nil {
+               ctx.ServerError("unable to find template", err)
+               return
+       }
+       ctx.Resp.Header().Set("Content-Type", "application/json")
+       if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
+               ctx.ServerError("unable to execute template", err)
+       }
+}
+
+// RenderToString renders the template content to a string
+func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
+       var buf strings.Builder
+       err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data, ctx.TemplateContext)
+       return 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) {
+       if form != nil {
+               middleware.AssignForm(form, ctx.Data)
+       }
+       ctx.Flash.Error(msg, true)
+       ctx.HTML(http.StatusOK, tpl)
+}
+
+// NotFound displays a 404 (Not Found) page and prints the given error, if any.
+func (ctx *Context) NotFound(logMsg string, logErr error) {
+       ctx.notFoundInternal(logMsg, logErr)
+}
+
+func (ctx *Context) notFoundInternal(logMsg string, logErr error) {
+       if logErr != nil {
+               log.Log(2, log.DEBUG, "%s: %v", logMsg, logErr)
+               if !setting.IsProd {
+                       ctx.Data["ErrorMsg"] = logErr
+               }
+       }
+
+       // response simple message if Accept isn't text/html
+       showHTML := false
+       for _, part := range ctx.Req.Header["Accept"] {
+               if strings.Contains(part, "text/html") {
+                       showHTML = true
+                       break
+               }
+       }
+
+       if !showHTML {
+               ctx.plainTextInternal(3, http.StatusNotFound, []byte("Not found.\n"))
+               return
+       }
+
+       ctx.Data["IsRepo"] = ctx.Repo.Repository != nil
+       ctx.Data["Title"] = "Page Not Found"
+       ctx.HTML(http.StatusNotFound, base.TplName("status/404"))
+}
+
+// ServerError displays a 500 (Internal Server Error) page and prints the given error, if any.
+func (ctx *Context) ServerError(logMsg string, logErr error) {
+       ctx.serverErrorInternal(logMsg, logErr)
+}
+
+func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
+       if logErr != nil {
+               log.ErrorWithSkip(2, "%s: %v", logMsg, logErr)
+               if _, ok := logErr.(*net.OpError); ok || errors.Is(logErr, &net.OpError{}) {
+                       // This is an error within the underlying connection
+                       // and further rendering will not work so just return
+                       return
+               }
+
+               // it's safe to show internal error to admin users, and it helps
+               if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
+                       ctx.Data["ErrorMsg"] = fmt.Sprintf("%s, %s", logMsg, logErr)
+               }
+       }
+
+       ctx.Data["Title"] = "Internal Server Error"
+       ctx.HTML(http.StatusInternalServerError, tplStatus500)
+}
+
+// NotFoundOrServerError use error check function to determine if the error
+// is about not found. It responds with 404 status code for not found error,
+// or error context description for logging purpose of 500 server error.
+// TODO: remove the "errCheck" and use util.ErrNotFound to check
+func (ctx *Context) NotFoundOrServerError(logMsg string, errCheck func(error) bool, logErr error) {
+       if errCheck(logErr) {
+               ctx.notFoundInternal(logMsg, logErr)
+               return
+       }
+       ctx.serverErrorInternal(logMsg, logErr)
+}
diff --git a/services/context/context_template.go b/services/context/context_template.go
new file mode 100644 (file)
index 0000000..7878d40
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "context"
+       "time"
+)
+
+var _ context.Context = TemplateContext(nil)
+
+func NewTemplateContext(ctx context.Context) TemplateContext {
+       return TemplateContext{"_ctx": ctx}
+}
+
+func (c TemplateContext) parentContext() context.Context {
+       return c["_ctx"].(context.Context)
+}
+
+func (c TemplateContext) Deadline() (deadline time.Time, ok bool) {
+       return c.parentContext().Deadline()
+}
+
+func (c TemplateContext) Done() <-chan struct{} {
+       return c.parentContext().Done()
+}
+
+func (c TemplateContext) Err() error {
+       return c.parentContext().Err()
+}
+
+func (c TemplateContext) Value(key any) any {
+       return c.parentContext().Value(key)
+}
diff --git a/services/context/context_test.go b/services/context/context_test.go
new file mode 100644 (file)
index 0000000..033ce2e
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "net/http"
+       "net/http/httptest"
+       "testing"
+
+       "code.gitea.io/gitea/modules/setting"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestRemoveSessionCookieHeader(t *testing.T) {
+       w := httptest.NewRecorder()
+       w.Header().Add("Set-Cookie", (&http.Cookie{Name: setting.SessionConfig.CookieName, Value: "foo"}).String())
+       w.Header().Add("Set-Cookie", (&http.Cookie{Name: "other", Value: "bar"}).String())
+       assert.Len(t, w.Header().Values("Set-Cookie"), 2)
+       removeSessionCookieHeader(w)
+       assert.Len(t, w.Header().Values("Set-Cookie"), 1)
+       assert.Contains(t, "other=bar", w.Header().Get("Set-Cookie"))
+}
diff --git a/services/context/csrf.go b/services/context/csrf.go
new file mode 100644 (file)
index 0000000..9b0dc29
--- /dev/null
@@ -0,0 +1,242 @@
+// Copyright 2013 Martini Authors
+// Copyright 2014 The Macaron Authors
+// Copyright 2021 The Gitea Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+// a middleware that generates and validates CSRF tokens.
+
+package context
+
+import (
+       "encoding/base32"
+       "fmt"
+       "net/http"
+       "strconv"
+       "time"
+
+       "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/util"
+       "code.gitea.io/gitea/modules/web/middleware"
+)
+
+// CSRFProtector represents a CSRF protector and is used to get the current token and validate the token.
+type CSRFProtector interface {
+       // GetHeaderName returns HTTP header to search for token.
+       GetHeaderName() string
+       // GetFormName returns form value to search for token.
+       GetFormName() string
+       // GetToken returns the token.
+       GetToken() string
+       // Validate validates the token in http context.
+       Validate(ctx *Context)
+       // DeleteCookie deletes the cookie
+       DeleteCookie(ctx *Context)
+}
+
+type csrfProtector struct {
+       opt CsrfOptions
+       // Token generated to pass via header, cookie, or hidden form value.
+       Token string
+       // This value must be unique per user.
+       ID string
+}
+
+// GetHeaderName returns the name of the HTTP header for csrf token.
+func (c *csrfProtector) GetHeaderName() string {
+       return c.opt.Header
+}
+
+// GetFormName returns the name of the form value for csrf token.
+func (c *csrfProtector) GetFormName() string {
+       return c.opt.Form
+}
+
+// GetToken returns the current token. This is typically used
+// to populate a hidden form in an HTML template.
+func (c *csrfProtector) GetToken() string {
+       return c.Token
+}
+
+// CsrfOptions maintains options to manage behavior of Generate.
+type CsrfOptions struct {
+       // The global secret value used to generate Tokens.
+       Secret string
+       // HTTP header used to set and get token.
+       Header string
+       // Form value used to set and get token.
+       Form string
+       // Cookie value used to set and get token.
+       Cookie string
+       // Cookie domain.
+       CookieDomain string
+       // Cookie path.
+       CookiePath     string
+       CookieHTTPOnly bool
+       // SameSite set the cookie SameSite type
+       SameSite http.SameSite
+       // Key used for getting the unique ID per user.
+       SessionKey string
+       // oldSessionKey saves old value corresponding to SessionKey.
+       oldSessionKey string
+       // If true, send token via X-Csrf-Token header.
+       SetHeader bool
+       // If true, send token via _csrf cookie.
+       SetCookie bool
+       // Set the Secure flag to true on the cookie.
+       Secure bool
+       // Disallow Origin appear in request header.
+       Origin bool
+       // Cookie lifetime. Default is 0
+       CookieLifeTime int
+}
+
+func prepareDefaultCsrfOptions(opt CsrfOptions) CsrfOptions {
+       if opt.Secret == "" {
+               randBytes, err := util.CryptoRandomBytes(8)
+               if err != nil {
+                       // this panic can be handled by the recover() in http handlers
+                       panic(fmt.Errorf("failed to generate random bytes: %w", err))
+               }
+               opt.Secret = base32.StdEncoding.EncodeToString(randBytes)
+       }
+       if opt.Header == "" {
+               opt.Header = "X-Csrf-Token"
+       }
+       if opt.Form == "" {
+               opt.Form = "_csrf"
+       }
+       if opt.Cookie == "" {
+               opt.Cookie = "_csrf"
+       }
+       if opt.CookiePath == "" {
+               opt.CookiePath = "/"
+       }
+       if opt.SessionKey == "" {
+               opt.SessionKey = "uid"
+       }
+       if opt.CookieLifeTime == 0 {
+               opt.CookieLifeTime = int(CsrfTokenTimeout.Seconds())
+       }
+
+       opt.oldSessionKey = "_old_" + opt.SessionKey
+       return opt
+}
+
+func newCsrfCookie(c *csrfProtector, value string) *http.Cookie {
+       return &http.Cookie{
+               Name:     c.opt.Cookie,
+               Value:    value,
+               Path:     c.opt.CookiePath,
+               Domain:   c.opt.CookieDomain,
+               MaxAge:   c.opt.CookieLifeTime,
+               Secure:   c.opt.Secure,
+               HttpOnly: c.opt.CookieHTTPOnly,
+               SameSite: c.opt.SameSite,
+       }
+}
+
+// PrepareCSRFProtector returns a CSRFProtector to be used for every request.
+// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
+func PrepareCSRFProtector(opt CsrfOptions, ctx *Context) CSRFProtector {
+       opt = prepareDefaultCsrfOptions(opt)
+       x := &csrfProtector{opt: opt}
+
+       if opt.Origin && len(ctx.Req.Header.Get("Origin")) > 0 {
+               return x
+       }
+
+       x.ID = "0"
+       uidAny := ctx.Session.Get(opt.SessionKey)
+       if uidAny != nil {
+               switch uidVal := uidAny.(type) {
+               case string:
+                       x.ID = uidVal
+               case int64:
+                       x.ID = strconv.FormatInt(uidVal, 10)
+               default:
+                       log.Error("invalid uid type in session: %T", uidAny)
+               }
+       }
+
+       oldUID := ctx.Session.Get(opt.oldSessionKey)
+       uidChanged := oldUID == nil || oldUID.(string) != x.ID
+       cookieToken := ctx.GetSiteCookie(opt.Cookie)
+
+       needsNew := true
+       if uidChanged {
+               _ = ctx.Session.Set(opt.oldSessionKey, x.ID)
+       } else if cookieToken != "" {
+               // If cookie token presents, re-use existing unexpired token, else generate a new one.
+               if issueTime, ok := ParseCsrfToken(cookieToken); ok {
+                       dur := time.Since(issueTime) // issueTime is not a monotonic-clock, the server time may change a lot to an early time.
+                       if dur >= -CsrfTokenRegenerationInterval && dur <= CsrfTokenRegenerationInterval {
+                               x.Token = cookieToken
+                               needsNew = false
+                       }
+               }
+       }
+
+       if needsNew {
+               // FIXME: actionId.
+               x.Token = GenerateCsrfToken(x.opt.Secret, x.ID, "POST", time.Now())
+               if opt.SetCookie {
+                       cookie := newCsrfCookie(x, x.Token)
+                       ctx.Resp.Header().Add("Set-Cookie", cookie.String())
+               }
+       }
+
+       if opt.SetHeader {
+               ctx.Resp.Header().Add(opt.Header, x.Token)
+       }
+       return x
+}
+
+func (c *csrfProtector) validateToken(ctx *Context, token string) {
+       if !ValidCsrfToken(token, c.opt.Secret, c.ID, "POST", time.Now()) {
+               c.DeleteCookie(ctx)
+               if middleware.IsAPIPath(ctx.Req) {
+                       // currently, there should be no access to the APIPath with CSRF token. because templates shouldn't use the `/api/` endpoints.
+                       http.Error(ctx.Resp, "Invalid CSRF token.", http.StatusBadRequest)
+               } else {
+                       ctx.Flash.Error(ctx.Tr("error.invalid_csrf"))
+                       ctx.Redirect(setting.AppSubURL + "/")
+               }
+       }
+}
+
+// Validate should be used as a per route middleware. It attempts to get a token from an "X-Csrf-Token"
+// HTTP header and then a "_csrf" form value. If one of these is found, the token will be validated.
+// If this validation fails, custom Error is sent in the reply.
+// If neither a header nor form value is found, http.StatusBadRequest is sent.
+func (c *csrfProtector) Validate(ctx *Context) {
+       if token := ctx.Req.Header.Get(c.GetHeaderName()); token != "" {
+               c.validateToken(ctx, token)
+               return
+       }
+       if token := ctx.Req.FormValue(c.GetFormName()); token != "" {
+               c.validateToken(ctx, token)
+               return
+       }
+       c.validateToken(ctx, "") // no csrf token, use an empty token to respond error
+}
+
+func (c *csrfProtector) DeleteCookie(ctx *Context) {
+       if c.opt.SetCookie {
+               cookie := newCsrfCookie(c, "")
+               cookie.MaxAge = -1
+               ctx.Resp.Header().Add("Set-Cookie", cookie.String())
+       }
+}
diff --git a/services/context/org.go b/services/context/org.go
new file mode 100644 (file)
index 0000000..018b76d
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2020 The Gitea Authors.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "strings"
+
+       "code.gitea.io/gitea/models/organization"
+       "code.gitea.io/gitea/models/perm"
+       "code.gitea.io/gitea/models/unit"
+       user_model "code.gitea.io/gitea/models/user"
+       "code.gitea.io/gitea/modules/markup"
+       "code.gitea.io/gitea/modules/markup/markdown"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/structs"
+)
+
+// Organization contains organization context
+type Organization struct {
+       IsOwner          bool
+       IsMember         bool
+       IsTeamMember     bool // Is member of team.
+       IsTeamAdmin      bool // In owner team or team that has admin permission level.
+       Organization     *organization.Organization
+       OrgLink          string
+       CanCreateOrgRepo bool
+       PublicMemberOnly bool // Only display public members
+
+       Team  *organization.Team
+       Teams []*organization.Team
+}
+
+func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool {
+       return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeWrite
+}
+
+func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool {
+       return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeRead
+}
+
+func GetOrganizationByParams(ctx *Context) {
+       orgName := ctx.Params(":org")
+
+       var err error
+
+       ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
+       if err != nil {
+               if organization.IsErrOrgNotExist(err) {
+                       redirectUserID, err := user_model.LookupUserRedirect(ctx, orgName)
+                       if err == nil {
+                               RedirectToUser(ctx.Base, orgName, redirectUserID)
+                       } else if user_model.IsErrUserRedirectNotExist(err) {
+                               ctx.NotFound("GetUserByName", err)
+                       } else {
+                               ctx.ServerError("LookupUserRedirect", err)
+                       }
+               } else {
+                       ctx.ServerError("GetUserByName", err)
+               }
+               return
+       }
+}
+
+// HandleOrgAssignment handles organization assignment
+func HandleOrgAssignment(ctx *Context, args ...bool) {
+       var (
+               requireMember     bool
+               requireOwner      bool
+               requireTeamMember bool
+               requireTeamAdmin  bool
+       )
+       if len(args) >= 1 {
+               requireMember = args[0]
+       }
+       if len(args) >= 2 {
+               requireOwner = args[1]
+       }
+       if len(args) >= 3 {
+               requireTeamMember = args[2]
+       }
+       if len(args) >= 4 {
+               requireTeamAdmin = args[3]
+       }
+
+       var err error
+
+       if ctx.ContextUser == nil {
+               // if Organization is not defined, get it from params
+               if ctx.Org.Organization == nil {
+                       GetOrganizationByParams(ctx)
+                       if ctx.Written() {
+                               return
+                       }
+               }
+       } else if ctx.ContextUser.IsOrganization() {
+               if ctx.Org == nil {
+                       ctx.Org = &Organization{}
+               }
+               ctx.Org.Organization = (*organization.Organization)(ctx.ContextUser)
+       } else {
+               // ContextUser is an individual User
+               return
+       }
+
+       org := ctx.Org.Organization
+
+       // Handle Visibility
+       if org.Visibility != structs.VisibleTypePublic && !ctx.IsSigned {
+               // We must be signed in to see limited or private organizations
+               ctx.NotFound("OrgAssignment", err)
+               return
+       }
+
+       if org.Visibility == structs.VisibleTypePrivate {
+               requireMember = true
+       } else if ctx.IsSigned && ctx.Doer.IsRestricted {
+               requireMember = true
+       }
+
+       ctx.ContextUser = org.AsUser()
+       ctx.Data["Org"] = org
+
+       // Admin has super access.
+       if ctx.IsSigned && ctx.Doer.IsAdmin {
+               ctx.Org.IsOwner = true
+               ctx.Org.IsMember = true
+               ctx.Org.IsTeamMember = true
+               ctx.Org.IsTeamAdmin = true
+               ctx.Org.CanCreateOrgRepo = true
+       } else if ctx.IsSigned {
+               ctx.Org.IsOwner, err = org.IsOwnedBy(ctx, ctx.Doer.ID)
+               if err != nil {
+                       ctx.ServerError("IsOwnedBy", err)
+                       return
+               }
+
+               if ctx.Org.IsOwner {
+                       ctx.Org.IsMember = true
+                       ctx.Org.IsTeamMember = true
+                       ctx.Org.IsTeamAdmin = true
+                       ctx.Org.CanCreateOrgRepo = true
+               } else {
+                       ctx.Org.IsMember, err = org.IsOrgMember(ctx, ctx.Doer.ID)
+                       if err != nil {
+                               ctx.ServerError("IsOrgMember", err)
+                               return
+                       }
+                       ctx.Org.CanCreateOrgRepo, err = org.CanCreateOrgRepo(ctx, ctx.Doer.ID)
+                       if err != nil {
+                               ctx.ServerError("CanCreateOrgRepo", err)
+                               return
+                       }
+               }
+       } else {
+               // Fake data.
+               ctx.Data["SignedUser"] = &user_model.User{}
+       }
+       if (requireMember && !ctx.Org.IsMember) ||
+               (requireOwner && !ctx.Org.IsOwner) {
+               ctx.NotFound("OrgAssignment", err)
+               return
+       }
+       ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
+       ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
+       ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
+       ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
+       ctx.Data["IsPublicMember"] = func(uid int64) bool {
+               is, _ := organization.IsPublicMembership(ctx, ctx.Org.Organization.ID, uid)
+               return is
+       }
+       ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo
+
+       ctx.Org.OrgLink = org.AsUser().OrganisationLink()
+       ctx.Data["OrgLink"] = ctx.Org.OrgLink
+
+       // Member
+       ctx.Org.PublicMemberOnly = ctx.Doer == nil || !ctx.Org.IsMember && !ctx.Doer.IsAdmin
+       opts := &organization.FindOrgMembersOpts{
+               OrgID:      org.ID,
+               PublicOnly: ctx.Org.PublicMemberOnly,
+       }
+       ctx.Data["NumMembers"], err = organization.CountOrgMembers(ctx, opts)
+       if err != nil {
+               ctx.ServerError("CountOrgMembers", err)
+               return
+       }
+
+       // Team.
+       if ctx.Org.IsMember {
+               shouldSeeAllTeams := false
+               if ctx.Org.IsOwner {
+                       shouldSeeAllTeams = true
+               } else {
+                       teams, err := org.GetUserTeams(ctx, ctx.Doer.ID)
+                       if err != nil {
+                               ctx.ServerError("GetUserTeams", err)
+                               return
+                       }
+                       for _, team := range teams {
+                               if team.IncludesAllRepositories && team.AccessMode >= perm.AccessModeAdmin {
+                                       shouldSeeAllTeams = true
+                                       break
+                               }
+                       }
+               }
+               if shouldSeeAllTeams {
+                       ctx.Org.Teams, err = org.LoadTeams(ctx)
+                       if err != nil {
+                               ctx.ServerError("LoadTeams", err)
+                               return
+                       }
+               } else {
+                       ctx.Org.Teams, err = org.GetUserTeams(ctx, ctx.Doer.ID)
+                       if err != nil {
+                               ctx.ServerError("GetUserTeams", err)
+                               return
+                       }
+               }
+               ctx.Data["NumTeams"] = len(ctx.Org.Teams)
+       }
+
+       teamName := ctx.Params(":team")
+       if len(teamName) > 0 {
+               teamExists := false
+               for _, team := range ctx.Org.Teams {
+                       if team.LowerName == strings.ToLower(teamName) {
+                               teamExists = true
+                               ctx.Org.Team = team
+                               ctx.Org.IsTeamMember = true
+                               ctx.Data["Team"] = ctx.Org.Team
+                               break
+                       }
+               }
+
+               if !teamExists {
+                       ctx.NotFound("OrgAssignment", err)
+                       return
+               }
+
+               ctx.Data["IsTeamMember"] = ctx.Org.IsTeamMember
+               if requireTeamMember && !ctx.Org.IsTeamMember {
+                       ctx.NotFound("OrgAssignment", err)
+                       return
+               }
+
+               ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.AccessMode >= perm.AccessModeAdmin
+               ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin
+               if requireTeamAdmin && !ctx.Org.IsTeamAdmin {
+                       ctx.NotFound("OrgAssignment", err)
+                       return
+               }
+       }
+       ctx.Data["ContextUser"] = ctx.ContextUser
+
+       ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
+       ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
+       ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode)
+
+       ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
+       if len(ctx.ContextUser.Description) != 0 {
+               content, err := markdown.RenderString(&markup.RenderContext{
+                       Metas: map[string]string{"mode": "document"},
+                       Ctx:   ctx,
+               }, ctx.ContextUser.Description)
+               if err != nil {
+                       ctx.ServerError("RenderString", err)
+                       return
+               }
+               ctx.Data["RenderedDescription"] = content
+       }
+}
+
+// OrgAssignment returns a middleware to handle organization assignment
+func OrgAssignment(args ...bool) func(ctx *Context) {
+       return func(ctx *Context) {
+               HandleOrgAssignment(ctx, args...)
+       }
+}
diff --git a/services/context/package.go b/services/context/package.go
new file mode 100644 (file)
index 0000000..c452c65
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "fmt"
+       "net/http"
+
+       "code.gitea.io/gitea/models/organization"
+       packages_model "code.gitea.io/gitea/models/packages"
+       "code.gitea.io/gitea/models/perm"
+       "code.gitea.io/gitea/models/unit"
+       user_model "code.gitea.io/gitea/models/user"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/modules/templates"
+)
+
+// Package contains owner, access mode and optional the package descriptor
+type Package struct {
+       Owner      *user_model.User
+       AccessMode perm.AccessMode
+       Descriptor *packages_model.PackageDescriptor
+}
+
+type packageAssignmentCtx struct {
+       *Base
+       Doer        *user_model.User
+       ContextUser *user_model.User
+}
+
+// PackageAssignment returns a middleware to handle Context.Package assignment
+func PackageAssignment() func(ctx *Context) {
+       return func(ctx *Context) {
+               errorFn := func(status int, title string, obj any) {
+                       err, ok := obj.(error)
+                       if !ok {
+                               err = fmt.Errorf("%s", obj)
+                       }
+                       if status == http.StatusNotFound {
+                               ctx.NotFound(title, err)
+                       } else {
+                               ctx.ServerError(title, err)
+                       }
+               }
+               paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser}
+               ctx.Package = packageAssignment(paCtx, errorFn)
+       }
+}
+
+// PackageAssignmentAPI returns a middleware to handle Context.Package assignment
+func PackageAssignmentAPI() func(ctx *APIContext) {
+       return func(ctx *APIContext) {
+               paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser}
+               ctx.Package = packageAssignment(paCtx, ctx.Error)
+       }
+}
+
+func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any)) *Package {
+       pkg := &Package{
+               Owner: ctx.ContextUser,
+       }
+       var err error
+       pkg.AccessMode, err = determineAccessMode(ctx.Base, pkg, ctx.Doer)
+       if err != nil {
+               errCb(http.StatusInternalServerError, "determineAccessMode", err)
+               return pkg
+       }
+
+       packageType := ctx.Params("type")
+       name := ctx.Params("name")
+       version := ctx.Params("version")
+       if packageType != "" && name != "" && version != "" {
+               pv, err := packages_model.GetVersionByNameAndVersion(ctx, pkg.Owner.ID, packages_model.Type(packageType), name, version)
+               if err != nil {
+                       if err == packages_model.ErrPackageNotExist {
+                               errCb(http.StatusNotFound, "GetVersionByNameAndVersion", err)
+                       } else {
+                               errCb(http.StatusInternalServerError, "GetVersionByNameAndVersion", err)
+                       }
+                       return pkg
+               }
+
+               pkg.Descriptor, err = packages_model.GetPackageDescriptor(ctx, pv)
+               if err != nil {
+                       errCb(http.StatusInternalServerError, "GetPackageDescriptor", err)
+                       return pkg
+               }
+       }
+
+       return pkg
+}
+
+func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
+       if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
+               return perm.AccessModeNone, nil
+       }
+
+       if doer != nil && !doer.IsGhost() && (!doer.IsActive || doer.ProhibitLogin) {
+               return perm.AccessModeNone, nil
+       }
+
+       // TODO: ActionUser permission check
+       accessMode := perm.AccessModeNone
+       if pkg.Owner.IsOrganization() {
+               org := organization.OrgFromUser(pkg.Owner)
+
+               if doer != nil && !doer.IsGhost() {
+                       // 1. If user is logged in, check all team packages permissions
+                       var err error
+                       accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx, doer.ID)
+                       if err != nil {
+                               return accessMode, err
+                       }
+                       // If access mode is less than write check every team for more permissions
+                       // The minimum possible access mode is read for org members
+                       if accessMode < perm.AccessModeWrite {
+                               teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
+                               if err != nil {
+                                       return accessMode, err
+                               }
+                               for _, t := range teams {
+                                       perm := t.UnitAccessMode(ctx, unit.TypePackages)
+                                       if accessMode < perm {
+                                               accessMode = perm
+                                       }
+                               }
+                       }
+               }
+               if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, pkg.Owner, doer) {
+                       // 2. If user is unauthorized or no org member, check if org is visible
+                       accessMode = perm.AccessModeRead
+               }
+       } else {
+               if doer != nil && !doer.IsGhost() {
+                       // 1. Check if user is package owner
+                       if doer.ID == pkg.Owner.ID {
+                               accessMode = perm.AccessModeOwner
+                       } else if pkg.Owner.Visibility == structs.VisibleTypePublic || pkg.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
+                               accessMode = perm.AccessModeRead
+                       }
+               } else if pkg.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
+                       accessMode = perm.AccessModeRead
+               }
+       }
+
+       return accessMode, nil
+}
+
+// PackageContexter initializes a package context for a request.
+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()
+
+                       // it is still needed when rendering 500 page in a package handler
+                       ctx := NewWebContext(base, renderer, nil)
+                       ctx.Base.AppendContextValue(WebContextKey, ctx)
+                       next.ServeHTTP(ctx.Resp, ctx.Req)
+               })
+       }
+}
diff --git a/services/context/pagination.go b/services/context/pagination.go
new file mode 100644 (file)
index 0000000..68237c6
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "fmt"
+       "html/template"
+       "net/url"
+       "strings"
+
+       "code.gitea.io/gitea/modules/paginator"
+)
+
+// Pagination provides a pagination via paginator.Paginator and additional configurations for the link params used in rendering
+type Pagination struct {
+       Paginater *paginator.Paginator
+       urlParams []string
+}
+
+// NewPagination creates a new instance of the Pagination struct.
+// "pagingNum" is "page size" or "limit", "current" is "page"
+func NewPagination(total, pagingNum, current, numPages int) *Pagination {
+       p := &Pagination{}
+       p.Paginater = paginator.New(total, pagingNum, current, numPages)
+       return p
+}
+
+// AddParam adds a value from context identified by ctxKey as link param under a given paramKey
+func (p *Pagination) AddParam(ctx *Context, paramKey, ctxKey string) {
+       _, exists := ctx.Data[ctxKey]
+       if !exists {
+               return
+       }
+       paramData := fmt.Sprintf("%v", ctx.Data[ctxKey]) // cast any to string
+       urlParam := fmt.Sprintf("%s=%v", url.QueryEscape(paramKey), url.QueryEscape(paramData))
+       p.urlParams = append(p.urlParams, urlParam)
+}
+
+// AddParamString adds a string parameter directly
+func (p *Pagination) AddParamString(key, value string) {
+       urlParam := fmt.Sprintf("%s=%v", url.QueryEscape(key), url.QueryEscape(value))
+       p.urlParams = append(p.urlParams, urlParam)
+}
+
+// GetParams returns the configured URL params
+func (p *Pagination) GetParams() template.URL {
+       return template.URL(strings.Join(p.urlParams, "&"))
+}
+
+// SetDefaultParams sets common pagination params that are often used
+func (p *Pagination) SetDefaultParams(ctx *Context) {
+       p.AddParam(ctx, "sort", "SortType")
+       p.AddParam(ctx, "q", "Keyword")
+       // do not add any more uncommon params here!
+       p.AddParam(ctx, "t", "queryType")
+}
diff --git a/services/context/permission.go b/services/context/permission.go
new file mode 100644 (file)
index 0000000..14a9801
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "net/http"
+
+       auth_model "code.gitea.io/gitea/models/auth"
+       repo_model "code.gitea.io/gitea/models/repo"
+       "code.gitea.io/gitea/models/unit"
+       "code.gitea.io/gitea/modules/log"
+)
+
+// RequireRepoAdmin returns a middleware for requiring repository admin permission
+func RequireRepoAdmin() func(ctx *Context) {
+       return func(ctx *Context) {
+               if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
+                       ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+                       return
+               }
+       }
+}
+
+// RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
+func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
+       return func(ctx *Context) {
+               if !ctx.Repo.CanWrite(unitType) {
+                       ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+                       return
+               }
+       }
+}
+
+// CanEnableEditor checks if the user is allowed to write to the branch of the repo
+func CanEnableEditor() func(ctx *Context) {
+       return func(ctx *Context) {
+               if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) {
+                       ctx.NotFound("CanWriteToBranch denies permission", nil)
+                       return
+               }
+       }
+}
+
+// RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
+func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
+       return func(ctx *Context) {
+               for _, unitType := range unitTypes {
+                       if ctx.Repo.CanWrite(unitType) {
+                               return
+                       }
+               }
+               ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+       }
+}
+
+// RequireRepoReader returns a middleware for requiring repository read to the specify unitType
+func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
+       return func(ctx *Context) {
+               if !ctx.Repo.CanRead(unitType) {
+                       if log.IsTrace() {
+                               if ctx.IsSigned {
+                                       log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
+                                               "User in Repo has Permissions: %-+v",
+                                               ctx.Doer,
+                                               unitType,
+                                               ctx.Repo.Repository,
+                                               ctx.Repo.Permission)
+                               } else {
+                                       log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
+                                               "Anonymous user in Repo has Permissions: %-+v",
+                                               unitType,
+                                               ctx.Repo.Repository,
+                                               ctx.Repo.Permission)
+                               }
+                       }
+                       ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+                       return
+               }
+       }
+}
+
+// RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
+func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
+       return func(ctx *Context) {
+               for _, unitType := range unitTypes {
+                       if ctx.Repo.CanRead(unitType) {
+                               return
+                       }
+               }
+               if log.IsTrace() {
+                       var format string
+                       var args []any
+                       if ctx.IsSigned {
+                               format = "Permission Denied: User %-v cannot read ["
+                               args = append(args, ctx.Doer)
+                       } else {
+                               format = "Permission Denied: Anonymous user cannot read ["
+                       }
+                       for _, unit := range unitTypes {
+                               format += "%-v, "
+                               args = append(args, unit)
+                       }
+
+                       format = format[:len(format)-2] + "] in Repo %-v\n" +
+                               "User in Repo has Permissions: %-+v"
+                       args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
+                       log.Trace(format, args...)
+               }
+               ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+       }
+}
+
+// CheckRepoScopedToken check whether personal access token has repo scope
+func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) {
+       if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true {
+               return
+       }
+
+       scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
+       if ok { // it's a personal access token but not oauth2 token
+               var scopeMatched bool
+
+               requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository)
+
+               // check if scope only applies to public resources
+               publicOnly, err := scope.PublicOnly()
+               if err != nil {
+                       ctx.ServerError("HasScope", err)
+                       return
+               }
+
+               if publicOnly && repo.IsPrivate {
+                       ctx.Error(http.StatusForbidden)
+                       return
+               }
+
+               scopeMatched, err = scope.HasScope(requiredScopes...)
+               if err != nil {
+                       ctx.ServerError("HasScope", err)
+                       return
+               }
+
+               if !scopeMatched {
+                       ctx.Error(http.StatusForbidden)
+                       return
+               }
+       }
+}
diff --git a/services/context/private.go b/services/context/private.go
new file mode 100644 (file)
index 0000000..8b41949
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "context"
+       "fmt"
+       "net/http"
+       "time"
+
+       "code.gitea.io/gitea/modules/graceful"
+       "code.gitea.io/gitea/modules/process"
+       "code.gitea.io/gitea/modules/web"
+       web_types "code.gitea.io/gitea/modules/web/types"
+)
+
+// PrivateContext represents a context for private routes
+type PrivateContext struct {
+       *Base
+       Override context.Context
+
+       Repo *Repository
+}
+
+func init() {
+       web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider {
+               return req.Context().Value(privateContextKey).(*PrivateContext)
+       })
+}
+
+// Deadline is part of the interface for context.Context and we pass this to the request context
+func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) {
+       if ctx.Override != nil {
+               return ctx.Override.Deadline()
+       }
+       return ctx.Base.Deadline()
+}
+
+// Done is part of the interface for context.Context and we pass this to the request context
+func (ctx *PrivateContext) Done() <-chan struct{} {
+       if ctx.Override != nil {
+               return ctx.Override.Done()
+       }
+       return ctx.Base.Done()
+}
+
+// Err is part of the interface for context.Context and we pass this to the request context
+func (ctx *PrivateContext) Err() error {
+       if ctx.Override != nil {
+               return ctx.Override.Err()
+       }
+       return ctx.Base.Err()
+}
+
+var privateContextKey any = "default_private_context"
+
+// GetPrivateContext returns a context for Private routes
+func GetPrivateContext(req *http.Request) *PrivateContext {
+       return req.Context().Value(privateContextKey).(*PrivateContext)
+}
+
+// PrivateContexter returns apicontext as middleware
+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)
+                       ctx := &PrivateContext{Base: base}
+                       defer baseCleanUp()
+                       ctx.Base.AppendContextValue(privateContextKey, ctx)
+
+                       next.ServeHTTP(ctx.Resp, ctx.Req)
+               })
+       }
+}
+
+// OverrideContext overrides the underlying request context for Done() etc.
+// 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
+}
diff --git a/services/context/repo.go b/services/context/repo.go
new file mode 100644 (file)
index 0000000..a73d09e
--- /dev/null
@@ -0,0 +1,1090 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "context"
+       "errors"
+       "fmt"
+       "html"
+       "net/http"
+       "net/url"
+       "path"
+       "strings"
+
+       "code.gitea.io/gitea/models"
+       "code.gitea.io/gitea/models/db"
+       git_model "code.gitea.io/gitea/models/git"
+       issues_model "code.gitea.io/gitea/models/issues"
+       access_model "code.gitea.io/gitea/models/perm/access"
+       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/cache"
+       "code.gitea.io/gitea/modules/git"
+       "code.gitea.io/gitea/modules/gitrepo"
+       code_indexer "code.gitea.io/gitea/modules/indexer/code"
+       "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/util"
+       asymkey_service "code.gitea.io/gitea/services/asymkey"
+
+       "github.com/editorconfig/editorconfig-core-go/v2"
+)
+
+// PullRequest contains information to make a pull request
+type PullRequest struct {
+       BaseRepo       *repo_model.Repository
+       Allowed        bool
+       SameRepo       bool
+       HeadInfoSubURL string // [<user>:]<branch> url segment
+}
+
+// Repository contains information to operate a repository
+type Repository struct {
+       access_model.Permission
+       IsWatching   bool
+       IsViewBranch bool
+       IsViewTag    bool
+       IsViewCommit bool
+       Repository   *repo_model.Repository
+       Owner        *user_model.User
+       Commit       *git.Commit
+       Tag          *git.Tag
+       GitRepo      *git.Repository
+       RefName      string
+       BranchName   string
+       TagName      string
+       TreePath     string
+       CommitID     string
+       RepoLink     string
+       CloneLink    repo_model.CloneLink
+       CommitsCount int64
+
+       PullRequest *PullRequest
+}
+
+// CanWriteToBranch checks if the branch is writable by the user
+func (r *Repository) CanWriteToBranch(ctx context.Context, user *user_model.User, branch string) bool {
+       return issues_model.CanMaintainerWriteToBranch(ctx, r.Permission, branch, user)
+}
+
+// CanEnableEditor returns true if repository is editable and user has proper access level.
+func (r *Repository) CanEnableEditor(ctx context.Context, user *user_model.User) bool {
+       return r.IsViewBranch && r.CanWriteToBranch(ctx, user, r.BranchName) && r.Repository.CanEnableEditor() && !r.Repository.IsArchived
+}
+
+// CanCreateBranch returns true if repository is editable and user has proper access level.
+func (r *Repository) CanCreateBranch() bool {
+       return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanCreateBranch()
+}
+
+func (r *Repository) GetObjectFormat() git.ObjectFormat {
+       return git.ObjectFormatFromName(r.Repository.ObjectFormatName)
+}
+
+// RepoMustNotBeArchived checks if a repo is archived
+func RepoMustNotBeArchived() func(ctx *Context) {
+       return func(ctx *Context) {
+               if ctx.Repo.Repository.IsArchived {
+                       ctx.NotFound("IsArchived", errors.New(ctx.Locale.TrString("repo.archive.title")))
+               }
+       }
+}
+
+// CanCommitToBranchResults represents the results of CanCommitToBranch
+type CanCommitToBranchResults struct {
+       CanCommitToBranch bool
+       EditorEnabled     bool
+       UserCanPush       bool
+       RequireSigned     bool
+       WillSign          bool
+       SigningKey        string
+       WontSignReason    string
+}
+
+// CanCommitToBranch returns true if repository is editable and user has proper access level
+//
+// and branch is not protected for push
+func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
+       protectedBranch, err := git_model.GetFirstMatchProtectedBranchRule(ctx, r.Repository.ID, r.BranchName)
+       if err != nil {
+               return CanCommitToBranchResults{}, err
+       }
+       userCanPush := true
+       requireSigned := false
+       if protectedBranch != nil {
+               protectedBranch.Repo = r.Repository
+               userCanPush = protectedBranch.CanUserPush(ctx, doer)
+               requireSigned = protectedBranch.RequireSignedCommits
+       }
+
+       sign, keyID, _, err := asymkey_service.SignCRUDAction(ctx, r.Repository.RepoPath(), doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName)
+
+       canCommit := r.CanEnableEditor(ctx, doer) && userCanPush
+       if requireSigned {
+               canCommit = canCommit && sign
+       }
+       wontSignReason := ""
+       if err != nil {
+               if asymkey_service.IsErrWontSign(err) {
+                       wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason)
+                       err = nil
+               } else {
+                       wontSignReason = "error"
+               }
+       }
+
+       return CanCommitToBranchResults{
+               CanCommitToBranch: canCommit,
+               EditorEnabled:     r.CanEnableEditor(ctx, doer),
+               UserCanPush:       userCanPush,
+               RequireSigned:     requireSigned,
+               WillSign:          sign,
+               SigningKey:        keyID,
+               WontSignReason:    wontSignReason,
+       }, err
+}
+
+// CanUseTimetracker returns whether or not a user can use the timetracker.
+func (r *Repository) CanUseTimetracker(ctx context.Context, issue *issues_model.Issue, user *user_model.User) bool {
+       // Checking for following:
+       // 1. Is timetracker enabled
+       // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
+       isAssigned, _ := issues_model.IsUserAssignedToIssue(ctx, issue, user)
+       return r.Repository.IsTimetrackerEnabled(ctx) && (!r.Repository.AllowOnlyContributorsToTrackTime(ctx) ||
+               r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
+}
+
+// CanCreateIssueDependencies returns whether or not a user can create dependencies.
+func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_model.User, isPull bool) bool {
+       return r.Repository.IsDependenciesEnabled(ctx) && r.Permission.CanWriteIssuesOrPulls(isPull)
+}
+
+// GetCommitsCount returns cached commit count for current view
+func (r *Repository) GetCommitsCount() (int64, error) {
+       if r.Commit == nil {
+               return 0, nil
+       }
+       var contextName string
+       if r.IsViewBranch {
+               contextName = r.BranchName
+       } else if r.IsViewTag {
+               contextName = r.TagName
+       } else {
+               contextName = r.CommitID
+       }
+       return cache.GetInt64(r.Repository.GetCommitsCountCacheKey(contextName, r.IsViewBranch || r.IsViewTag), func() (int64, error) {
+               return r.Commit.CommitsCount()
+       })
+}
+
+// GetCommitGraphsCount returns cached commit count for current view
+func (r *Repository) GetCommitGraphsCount(ctx context.Context, hidePRRefs bool, branches, files []string) (int64, error) {
+       cacheKey := fmt.Sprintf("commits-count-%d-graph-%t-%s-%s", r.Repository.ID, hidePRRefs, branches, files)
+
+       return cache.GetInt64(cacheKey, func() (int64, error) {
+               if len(branches) == 0 {
+                       return git.AllCommitsCount(ctx, r.Repository.RepoPath(), hidePRRefs, files...)
+               }
+               return git.CommitsCount(ctx,
+                       git.CommitsCountOptions{
+                               RepoPath: r.Repository.RepoPath(),
+                               Revision: branches,
+                               RelPath:  files,
+                       })
+       })
+}
+
+// BranchNameSubURL sub-URL for the BranchName field
+func (r *Repository) BranchNameSubURL() string {
+       switch {
+       case r.IsViewBranch:
+               return "branch/" + util.PathEscapeSegments(r.BranchName)
+       case r.IsViewTag:
+               return "tag/" + util.PathEscapeSegments(r.TagName)
+       case r.IsViewCommit:
+               return "commit/" + util.PathEscapeSegments(r.CommitID)
+       }
+       log.Error("Unknown view type for repo: %v", r)
+       return ""
+}
+
+// FileExists returns true if a file exists in the given repo branch
+func (r *Repository) FileExists(path, branch string) (bool, error) {
+       if branch == "" {
+               branch = r.Repository.DefaultBranch
+       }
+       commit, err := r.GitRepo.GetBranchCommit(branch)
+       if err != nil {
+               return false, err
+       }
+       if _, err := commit.GetTreeEntryByPath(path); err != nil {
+               return false, err
+       }
+       return true, nil
+}
+
+// GetEditorconfig returns the .editorconfig definition if found in the
+// HEAD of the default repo branch.
+func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (cfg *editorconfig.Editorconfig, warning, err error) {
+       if r.GitRepo == nil {
+               return nil, nil, nil
+       }
+
+       var commit *git.Commit
+
+       if len(optCommit) != 0 {
+               commit = optCommit[0]
+       } else {
+               commit, err = r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
+               if err != nil {
+                       return nil, nil, err
+               }
+       }
+       treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
+       if err != nil {
+               return nil, nil, err
+       }
+       if treeEntry.Blob().Size() >= setting.UI.MaxDisplayFileSize {
+               return nil, nil, git.ErrNotExist{ID: "", RelPath: ".editorconfig"}
+       }
+       reader, err := treeEntry.Blob().DataAsync()
+       if err != nil {
+               return nil, nil, err
+       }
+       defer reader.Close()
+       return editorconfig.ParseGraceful(reader)
+}
+
+// RetrieveBaseRepo retrieves base repository
+func RetrieveBaseRepo(ctx *Context, repo *repo_model.Repository) {
+       // Non-fork repository will not return error in this method.
+       if err := repo.GetBaseRepo(ctx); err != nil {
+               if repo_model.IsErrRepoNotExist(err) {
+                       repo.IsFork = false
+                       repo.ForkID = 0
+                       return
+               }
+               ctx.ServerError("GetBaseRepo", err)
+               return
+       } else if err = repo.BaseRepo.LoadOwner(ctx); err != nil {
+               ctx.ServerError("BaseRepo.LoadOwner", err)
+               return
+       }
+}
+
+// RetrieveTemplateRepo retrieves template repository used to generate this repository
+func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) {
+       // Non-generated repository will not return error in this method.
+       templateRepo, err := repo_model.GetTemplateRepo(ctx, repo)
+       if err != nil {
+               if repo_model.IsErrRepoNotExist(err) {
+                       repo.TemplateID = 0
+                       return
+               }
+               ctx.ServerError("GetTemplateRepo", err)
+               return
+       } else if err = templateRepo.LoadOwner(ctx); err != nil {
+               ctx.ServerError("TemplateRepo.LoadOwner", err)
+               return
+       }
+
+       perm, err := access_model.GetUserRepoPermission(ctx, templateRepo, ctx.Doer)
+       if err != nil {
+               ctx.ServerError("GetUserRepoPermission", err)
+               return
+       }
+
+       if !perm.CanRead(unit_model.TypeCode) {
+               repo.TemplateID = 0
+       }
+}
+
+// ComposeGoGetImport returns go-get-import meta content.
+func ComposeGoGetImport(owner, repo string) string {
+       /// setting.AppUrl is guaranteed to be parse as url
+       appURL, _ := url.Parse(setting.AppURL)
+
+       return path.Join(appURL.Host, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo))
+}
+
+// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
+// if user does not have actual access to the requested repository,
+// or the owner or repository does not exist at all.
+// This is particular a workaround for "go get" command which does not respect
+// .netrc file.
+func EarlyResponseForGoGetMeta(ctx *Context) {
+       username := ctx.Params(":username")
+       reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git")
+       if username == "" || reponame == "" {
+               ctx.PlainText(http.StatusBadRequest, "invalid repository path")
+               return
+       }
+
+       var cloneURL string
+       if setting.Repository.GoGetCloneURLProtocol == "ssh" {
+               cloneURL = repo_model.ComposeSSHCloneURL(username, reponame)
+       } else {
+               cloneURL = repo_model.ComposeHTTPSCloneURL(username, reponame)
+       }
+       goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), cloneURL)
+       htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
+       ctx.PlainText(http.StatusOK, htmlMeta)
+}
+
+// RedirectToRepo redirect to a differently-named repository
+func RedirectToRepo(ctx *Base, redirectRepoID int64) {
+       ownerName := ctx.Params(":username")
+       previousRepoName := ctx.Params(":reponame")
+
+       repo, err := repo_model.GetRepositoryByID(ctx, redirectRepoID)
+       if err != nil {
+               log.Error("GetRepositoryByID: %v", err)
+               ctx.Error(http.StatusInternalServerError, "GetRepositoryByID")
+               return
+       }
+
+       redirectPath := strings.Replace(
+               ctx.Req.URL.EscapedPath(),
+               url.PathEscape(ownerName)+"/"+url.PathEscape(previousRepoName),
+               url.PathEscape(repo.OwnerName)+"/"+url.PathEscape(repo.Name),
+               1,
+       )
+       if ctx.Req.URL.RawQuery != "" {
+               redirectPath += "?" + ctx.Req.URL.RawQuery
+       }
+       ctx.Redirect(path.Join(setting.AppSubURL, redirectPath), http.StatusTemporaryRedirect)
+}
+
+func repoAssignment(ctx *Context, repo *repo_model.Repository) {
+       var err error
+       if err = repo.LoadOwner(ctx); err != nil {
+               ctx.ServerError("LoadOwner", err)
+               return
+       }
+
+       ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
+       if err != nil {
+               ctx.ServerError("GetUserRepoPermission", err)
+               return
+       }
+
+       // Check access.
+       if !ctx.Repo.Permission.HasAccess() {
+               if ctx.FormString("go-get") == "1" {
+                       EarlyResponseForGoGetMeta(ctx)
+                       return
+               }
+               ctx.NotFound("no access right", nil)
+               return
+       }
+       ctx.Data["HasAccess"] = true
+       ctx.Data["Permission"] = &ctx.Repo.Permission
+
+       if repo.IsMirror {
+               pullMirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID)
+               if err == nil {
+                       ctx.Data["PullMirror"] = pullMirror
+               } else if err != repo_model.ErrMirrorNotExist {
+                       ctx.ServerError("GetMirrorByRepoID", err)
+                       return
+               }
+       }
+
+       pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
+       if err != nil {
+               ctx.ServerError("GetPushMirrorsByRepoID", err)
+               return
+       }
+
+       ctx.Repo.Repository = repo
+       ctx.Data["PushMirrors"] = pushMirrors
+       ctx.Data["RepoName"] = ctx.Repo.Repository.Name
+       ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
+}
+
+// RepoIDAssignment returns a handler which assigns the repo to the context.
+func RepoIDAssignment() func(ctx *Context) {
+       return func(ctx *Context) {
+               repoID := ctx.ParamsInt64(":repoid")
+
+               // Get repository.
+               repo, err := repo_model.GetRepositoryByID(ctx, repoID)
+               if err != nil {
+                       if repo_model.IsErrRepoNotExist(err) {
+                               ctx.NotFound("GetRepositoryByID", nil)
+                       } else {
+                               ctx.ServerError("GetRepositoryByID", err)
+                       }
+                       return
+               }
+
+               repoAssignment(ctx, repo)
+       }
+}
+
+// RepoAssignment returns a middleware to handle repository assignment
+func RepoAssignment(ctx *Context) context.CancelFunc {
+       if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
+               log.Trace("RepoAssignment was exec already, skipping second call ...")
+               return nil
+       }
+       ctx.Data["repoAssignmentExecuted"] = true
+
+       var (
+               owner *user_model.User
+               err   error
+       )
+
+       userName := ctx.Params(":username")
+       repoName := ctx.Params(":reponame")
+       repoName = strings.TrimSuffix(repoName, ".git")
+       if setting.Other.EnableFeed {
+               repoName = strings.TrimSuffix(repoName, ".rss")
+               repoName = strings.TrimSuffix(repoName, ".atom")
+       }
+
+       // Check if the user is the same as the repository owner
+       if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) {
+               owner = ctx.Doer
+       } else {
+               owner, err = user_model.GetUserByName(ctx, userName)
+               if err != nil {
+                       if user_model.IsErrUserNotExist(err) {
+                               // go-get does not support redirects
+                               // https://github.com/golang/go/issues/19760
+                               if ctx.FormString("go-get") == "1" {
+                                       EarlyResponseForGoGetMeta(ctx)
+                                       return nil
+                               }
+
+                               if redirectUserID, err := user_model.LookupUserRedirect(ctx, userName); err == nil {
+                                       RedirectToUser(ctx.Base, userName, redirectUserID)
+                               } else if user_model.IsErrUserRedirectNotExist(err) {
+                                       ctx.NotFound("GetUserByName", nil)
+                               } else {
+                                       ctx.ServerError("LookupUserRedirect", err)
+                               }
+                       } else {
+                               ctx.ServerError("GetUserByName", err)
+                       }
+                       return nil
+               }
+       }
+       ctx.Repo.Owner = owner
+       ctx.ContextUser = owner
+       ctx.Data["ContextUser"] = ctx.ContextUser
+       ctx.Data["Username"] = ctx.Repo.Owner.Name
+
+       // redirect link to wiki
+       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.Params(":reponame")
+               redirectRepoName := strings.TrimSuffix(repoName, ".wiki")
+               redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
+               redirectPath := strings.Replace(
+                       ctx.Req.URL.EscapedPath(),
+                       url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
+                       url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
+                       1,
+               )
+               if ctx.Req.URL.RawQuery != "" {
+                       redirectPath += "?" + ctx.Req.URL.RawQuery
+               }
+               ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
+               return nil
+       }
+
+       // Get repository.
+       repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, repoName)
+       if err != nil {
+               if repo_model.IsErrRepoNotExist(err) {
+                       redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, repoName)
+                       if err == nil {
+                               RedirectToRepo(ctx.Base, redirectRepoID)
+                       } else if repo_model.IsErrRedirectNotExist(err) {
+                               if ctx.FormString("go-get") == "1" {
+                                       EarlyResponseForGoGetMeta(ctx)
+                                       return nil
+                               }
+                               ctx.NotFound("GetRepositoryByName", nil)
+                       } else {
+                               ctx.ServerError("LookupRepoRedirect", err)
+                       }
+               } else {
+                       ctx.ServerError("GetRepositoryByName", err)
+               }
+               return nil
+       }
+       repo.Owner = owner
+
+       repoAssignment(ctx, repo)
+       if ctx.Written() {
+               return nil
+       }
+
+       ctx.Repo.RepoLink = repo.Link()
+       ctx.Data["RepoLink"] = ctx.Repo.RepoLink
+       ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
+
+       if setting.Other.EnableFeed {
+               ctx.Data["EnableFeed"] = true
+               ctx.Data["FeedURL"] = ctx.Repo.RepoLink
+       }
+
+       unit, err := ctx.Repo.Repository.GetUnit(ctx, unit_model.TypeExternalTracker)
+       if err == nil {
+               ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL
+       }
+
+       ctx.Data["NumTags"], err = db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{
+               IncludeDrafts: true,
+               IncludeTags:   true,
+               HasSha1:       util.OptionalBoolTrue, // only draft releases which are created with existing tags
+               RepoID:        ctx.Repo.Repository.ID,
+       })
+       if err != nil {
+               ctx.ServerError("GetReleaseCountByRepoID", err)
+               return nil
+       }
+       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.
+               IncludeDrafts: ctx.Repo.CanWrite(unit_model.TypeReleases),
+               RepoID:        ctx.Repo.Repository.ID,
+       })
+       if err != nil {
+               ctx.ServerError("GetReleaseCountByRepoID", err)
+               return nil
+       }
+
+       ctx.Data["Title"] = owner.Name + "/" + repo.Name
+       ctx.Data["Repository"] = repo
+       ctx.Data["Owner"] = ctx.Repo.Repository.Owner
+       ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
+       ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
+       ctx.Data["RepoOwnerIsOrganization"] = repo.Owner.IsOrganization()
+       ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(unit_model.TypeCode)
+       ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
+       ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
+       ctx.Data["CanWriteActions"] = ctx.Repo.CanWrite(unit_model.TypeActions)
+
+       canSignedUserFork, err := repo_module.CanUserForkRepo(ctx, ctx.Doer, ctx.Repo.Repository)
+       if err != nil {
+               ctx.ServerError("CanUserForkRepo", err)
+               return nil
+       }
+       ctx.Data["CanSignedUserFork"] = canSignedUserFork
+
+       userAndOrgForks, err := repo_model.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository)
+       if err != nil {
+               ctx.ServerError("GetForksByUserAndOrgs", err)
+               return nil
+       }
+       ctx.Data["UserAndOrgForks"] = userAndOrgForks
+
+       // canSignedUserFork is true if the current user doesn't have a fork of this repo yet or
+       // if he owns an org that doesn't have a fork of this repo yet
+       // If multiple forks are available or if the user can fork to another account, but there is already a fork: open selection dialog
+       ctx.Data["ShowForkModal"] = len(userAndOrgForks) > 1 || (canSignedUserFork && len(userAndOrgForks) > 0)
+
+       ctx.Data["RepoCloneLink"] = repo.CloneLink()
+
+       cloneButtonShowHTTPS := !setting.Repository.DisableHTTPGit
+       cloneButtonShowSSH := !setting.SSH.Disabled && (ctx.IsSigned || setting.SSH.ExposeAnonymous)
+       if !cloneButtonShowHTTPS && !cloneButtonShowSSH {
+               // We have to show at least one link, so we just show the HTTPS
+               cloneButtonShowHTTPS = true
+       }
+       ctx.Data["CloneButtonShowHTTPS"] = cloneButtonShowHTTPS
+       ctx.Data["CloneButtonShowSSH"] = cloneButtonShowSSH
+       ctx.Data["CloneButtonOriginLink"] = ctx.Data["RepoCloneLink"] // it may be rewritten to the WikiCloneLink by the router middleware
+
+       ctx.Data["RepoSearchEnabled"] = setting.Indexer.RepoIndexerEnabled
+       if setting.Indexer.RepoIndexerEnabled {
+               ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx)
+       }
+
+       if ctx.IsSigned {
+               ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, repo.ID)
+               ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, repo.ID)
+       }
+
+       if repo.IsFork {
+               RetrieveBaseRepo(ctx, repo)
+               if ctx.Written() {
+                       return nil
+               }
+       }
+
+       if repo.IsGenerated() {
+               RetrieveTemplateRepo(ctx, repo)
+               if ctx.Written() {
+                       return nil
+               }
+       }
+
+       isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/")
+
+       // Disable everything when the repo is being created
+       if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
+               ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
+               if !isHomeOrSettings {
+                       ctx.Redirect(ctx.Repo.RepoLink)
+               }
+               return nil
+       }
+
+       gitRepo, err := gitrepo.OpenRepository(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)
+                       ctx.Repo.Repository.MarkAsBrokenEmpty()
+                       ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
+                       // Only allow access to base of repo or settings
+                       if !isHomeOrSettings {
+                               ctx.Redirect(ctx.Repo.RepoLink)
+                       }
+                       return nil
+               }
+               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()
+               }
+       }
+
+       // Stop at this point when the repo is empty.
+       if ctx.Repo.Repository.IsEmpty {
+               ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
+               return cancel
+       }
+
+       branchOpts := git_model.FindBranchOptions{
+               RepoID:          ctx.Repo.Repository.ID,
+               IsDeletedBranch: optional.Some(false),
+               ListOptions:     db.ListOptionsAll,
+       }
+       branchesTotal, err := db.Count[git_model.Branch](ctx, branchOpts)
+       if err != nil {
+               ctx.ServerError("CountBranches", err)
+               return cancel
+       }
+
+       // non-empty repo should have at least 1 branch, so this repository's branches haven't been synced yet
+       if branchesTotal == 0 { // fallback to do a sync immediately
+               branchesTotal, err = repo_module.SyncRepoBranches(ctx, ctx.Repo.Repository.ID, 0)
+               if err != nil {
+                       ctx.ServerError("SyncRepoBranches", err)
+                       return cancel
+               }
+       }
+
+       ctx.Data["BranchesCount"] = branchesTotal
+
+       // 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) {
+                       ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
+               } else {
+                       ctx.Repo.BranchName, _ = gitRepo.GetDefaultBranch()
+                       if ctx.Repo.BranchName == "" {
+                               // If it still can't get a default branch, fall back to default branch from setting.
+                               // Something might be wrong. Either site admin should fix the repo sync or Gitea should fix a potential bug.
+                               ctx.Repo.BranchName = setting.Repository.DefaultBranch
+                       }
+               }
+               ctx.Repo.RefName = ctx.Repo.BranchName
+       }
+       ctx.Data["BranchName"] = ctx.Repo.BranchName
+
+       // People who have push access or have forked repository can propose a new pull request.
+       canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
+               (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID))
+       canCompare := false
+
+       // Pull request is allowed if this is a fork repository
+       // and base repository accepts pull requests.
+       if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls(ctx) {
+               canCompare = true
+               ctx.Data["BaseRepo"] = repo.BaseRepo
+               ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
+               ctx.Repo.PullRequest.Allowed = canPush
+               ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.Repo.Owner.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
+       } else if repo.AllowsPulls(ctx) {
+               // Or, this is repository accepts pull requests between branches.
+               canCompare = true
+               ctx.Data["BaseRepo"] = repo
+               ctx.Repo.PullRequest.BaseRepo = repo
+               ctx.Repo.PullRequest.Allowed = canPush
+               ctx.Repo.PullRequest.SameRepo = true
+               ctx.Repo.PullRequest.HeadInfoSubURL = util.PathEscapeSegments(ctx.Repo.BranchName)
+       }
+       ctx.Data["CanCompareOrPull"] = canCompare
+       ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
+
+       if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
+               repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
+               if err != nil {
+                       ctx.ServerError("GetPendingRepositoryTransfer", err)
+                       return cancel
+               }
+
+               if err := repoTransfer.LoadAttributes(ctx); err != nil {
+                       ctx.ServerError("LoadRecipient", err)
+                       return cancel
+               }
+
+               ctx.Data["RepoTransfer"] = repoTransfer
+               if ctx.Doer != nil {
+                       ctx.Data["CanUserAcceptTransfer"] = repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer)
+               }
+       }
+
+       if ctx.FormString("go-get") == "1" {
+               ctx.Data["GoGetImport"] = ComposeGoGetImport(owner.Name, repo.Name)
+               fullURLPrefix := repo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
+               ctx.Data["GoDocDirectory"] = fullURLPrefix + "{/dir}"
+               ctx.Data["GoDocFile"] = fullURLPrefix + "{/dir}/{file}#L{line}"
+       }
+       return cancel
+}
+
+// RepoRefType type of repo reference
+type RepoRefType int
+
+const (
+       // RepoRefLegacy unknown type, make educated guess and redirect.
+       // for backward compatibility with previous URL scheme
+       RepoRefLegacy RepoRefType = iota
+       // RepoRefAny is for usage where educated guess is needed
+       // but redirect can not be made
+       RepoRefAny
+       // RepoRefBranch branch
+       RepoRefBranch
+       // RepoRefTag tag
+       RepoRefTag
+       // RepoRefCommit commit
+       RepoRefCommit
+       // RepoRefBlob blob
+       RepoRefBlob
+)
+
+const headRefName = "HEAD"
+
+// RepoRef handles repository reference names when the ref name is not
+// explicitly given
+func RepoRef() func(*Context) context.CancelFunc {
+       // since no ref name is explicitly specified, ok to just use branch
+       return RepoRefByType(RepoRefBranch)
+}
+
+// RefTypeIncludesBranches returns true if ref type can be a branch
+func (rt RepoRefType) RefTypeIncludesBranches() bool {
+       if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefBranch {
+               return true
+       }
+       return false
+}
+
+// RefTypeIncludesTags returns true if ref type can be a tag
+func (rt RepoRefType) RefTypeIncludesTags() bool {
+       if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefTag {
+               return true
+       }
+       return false
+}
+
+func getRefNameFromPath(ctx *Base, repo *Repository, path string, isExist func(string) bool) string {
+       refName := ""
+       parts := strings.Split(path, "/")
+       for i, part := range parts {
+               refName = strings.TrimPrefix(refName+"/"+part, "/")
+               if isExist(refName) {
+                       repo.TreePath = strings.Join(parts[i+1:], "/")
+                       return refName
+               }
+       }
+       return ""
+}
+
+func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
+       path := ctx.Params("*")
+       switch pathType {
+       case RepoRefLegacy, RepoRefAny:
+               if refName := getRefName(ctx, repo, RepoRefBranch); len(refName) > 0 {
+                       return refName
+               }
+               if refName := getRefName(ctx, repo, RepoRefTag); len(refName) > 0 {
+                       return refName
+               }
+               // For legacy and API support only full commit sha
+               parts := strings.Split(path, "/")
+
+               if len(parts) > 0 && len(parts[0]) == git.ObjectFormatFromName(repo.Repository.ObjectFormatName).FullLength() {
+                       repo.TreePath = strings.Join(parts[1:], "/")
+                       return parts[0]
+               }
+               if refName := getRefName(ctx, repo, RepoRefBlob); len(refName) > 0 {
+                       return refName
+               }
+               repo.TreePath = path
+               return repo.Repository.DefaultBranch
+       case RepoRefBranch:
+               ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist)
+               if len(ref) == 0 {
+
+                       // check if ref is HEAD
+                       parts := strings.Split(path, "/")
+                       if parts[0] == headRefName {
+                               repo.TreePath = strings.Join(parts[1:], "/")
+                               return repo.Repository.DefaultBranch
+                       }
+
+                       // maybe it's a renamed branch
+                       return getRefNameFromPath(ctx, repo, path, func(s string) bool {
+                               b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s)
+                               if err != nil {
+                                       log.Error("FindRenamedBranch: %v", err)
+                                       return false
+                               }
+
+                               if !exist {
+                                       return false
+                               }
+
+                               ctx.Data["IsRenamedBranch"] = true
+                               ctx.Data["RenamedBranchName"] = b.To
+
+                               return true
+                       })
+               }
+
+               return ref
+       case RepoRefTag:
+               return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
+       case RepoRefCommit:
+               parts := strings.Split(path, "/")
+
+               if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= repo.GetObjectFormat().FullLength() {
+                       repo.TreePath = strings.Join(parts[1:], "/")
+                       return parts[0]
+               }
+
+               if len(parts) > 0 && parts[0] == headRefName {
+                       // HEAD ref points to last default branch commit
+                       commit, err := repo.GitRepo.GetBranchCommit(repo.Repository.DefaultBranch)
+                       if err != nil {
+                               return ""
+                       }
+                       repo.TreePath = strings.Join(parts[1:], "/")
+                       return commit.ID.String()
+               }
+       case RepoRefBlob:
+               _, err := repo.GitRepo.GetBlob(path)
+               if err != nil {
+                       return ""
+               }
+               return path
+       default:
+               log.Error("Unrecognized path type: %v", path)
+       }
+       return ""
+}
+
+// RepoRefByType handles repository reference name for a specific type
+// of repository reference
+func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context) context.CancelFunc {
+       return func(ctx *Context) (cancel context.CancelFunc) {
+               // Empty repository does not have reference information.
+               if ctx.Repo.Repository.IsEmpty {
+                       // assume the user is viewing the (non-existent) default branch
+                       ctx.Repo.IsViewBranch = true
+                       ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
+                       ctx.Data["TreePath"] = ""
+                       return nil
+               }
+
+               var (
+                       refName string
+                       err     error
+               )
+
+               if ctx.Repo.GitRepo == nil {
+                       ctx.Repo.GitRepo, err = gitrepo.OpenRepository(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()
+                               }
+                       }
+               }
+
+               // Get default branch.
+               if len(ctx.Params("*")) == 0 {
+                       refName = ctx.Repo.Repository.DefaultBranch
+                       if !ctx.Repo.GitRepo.IsBranchExist(refName) {
+                               brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 1)
+                               if err == nil && len(brs) != 0 {
+                                       refName = brs[0].Name
+                               } else if len(brs) == 0 {
+                                       log.Error("No branches in non-empty repository %s", ctx.Repo.GitRepo.Path)
+                                       ctx.Repo.Repository.MarkAsBrokenEmpty()
+                               } else {
+                                       log.Error("GetBranches error: %v", err)
+                                       ctx.Repo.Repository.MarkAsBrokenEmpty()
+                               }
+                       }
+                       ctx.Repo.RefName = refName
+                       ctx.Repo.BranchName = refName
+                       ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
+                       if err == nil {
+                               ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+                       } else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
+                               // if the repository is broken, we can continue to the handler code, to show "Settings -> Delete Repository" for end users
+                               log.Error("GetBranchCommit: %v", err)
+                               ctx.Repo.Repository.MarkAsBrokenEmpty()
+                       } else {
+                               ctx.ServerError("GetBranchCommit", err)
+                               return cancel
+                       }
+                       ctx.Repo.IsViewBranch = true
+               } else {
+                       refName = getRefName(ctx.Base, ctx.Repo, refType)
+                       ctx.Repo.RefName = refName
+                       isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
+                       if isRenamedBranch && has {
+                               renamedBranchName := ctx.Data["RenamedBranchName"].(string)
+                               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
+                       }
+
+                       if refType.RefTypeIncludesBranches() && ctx.Repo.GitRepo.IsBranchExist(refName) {
+                               ctx.Repo.IsViewBranch = true
+                               ctx.Repo.BranchName = refName
+
+                               ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
+                               if err != nil {
+                                       ctx.ServerError("GetBranchCommit", err)
+                                       return cancel
+                               }
+                               ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+
+                       } else if refType.RefTypeIncludesTags() && ctx.Repo.GitRepo.IsTagExist(refName) {
+                               ctx.Repo.IsViewTag = true
+                               ctx.Repo.TagName = refName
+
+                               ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
+                               if err != nil {
+                                       if git.IsErrNotExist(err) {
+                                               ctx.NotFound("GetTagCommit", err)
+                                               return cancel
+                                       }
+                                       ctx.ServerError("GetTagCommit", err)
+                                       return cancel
+                               }
+                               ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
+                       } else if len(refName) >= 7 && len(refName) <= ctx.Repo.GetObjectFormat().FullLength() {
+                               ctx.Repo.IsViewCommit = true
+                               ctx.Repo.CommitID = refName
+
+                               ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
+                               if err != nil {
+                                       ctx.NotFound("GetCommit", err)
+                                       return cancel
+                               }
+                               // If short commit ID add canonical link header
+                               if len(refName) < ctx.Repo.GetObjectFormat().FullLength() {
+                                       ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
+                                               util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
+                               }
+                       } else {
+                               if len(ignoreNotExistErr) > 0 && ignoreNotExistErr[0] {
+                                       return cancel
+                               }
+                               ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
+                               return cancel
+                       }
+
+                       if refType == RepoRefLegacy {
+                               // redirect from old URL scheme to new URL scheme
+                               prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*"))), strings.ToLower(ctx.Repo.RepoLink))
+
+                               ctx.Redirect(path.Join(
+                                       ctx.Repo.RepoLink,
+                                       util.PathEscapeSegments(prefix),
+                                       ctx.Repo.BranchNameSubURL(),
+                                       util.PathEscapeSegments(ctx.Repo.TreePath)))
+                               return cancel
+                       }
+               }
+
+               ctx.Data["BranchName"] = ctx.Repo.BranchName
+               ctx.Data["RefName"] = ctx.Repo.RefName
+               ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
+               ctx.Data["TagName"] = ctx.Repo.TagName
+               ctx.Data["CommitID"] = ctx.Repo.CommitID
+               ctx.Data["TreePath"] = ctx.Repo.TreePath
+               ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
+               ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
+               ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
+               ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch()
+
+               ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount()
+               if err != nil {
+                       ctx.ServerError("GetCommitsCount", err)
+                       return cancel
+               }
+               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
+       }
+}
+
+// GitHookService checks if repository Git hooks service has been enabled.
+func GitHookService() func(ctx *Context) {
+       return func(ctx *Context) {
+               if !ctx.Doer.CanEditGitHook() {
+                       ctx.NotFound("GitHookService", nil)
+                       return
+               }
+       }
+}
+
+// UnitTypes returns a middleware to set unit types to context variables.
+func UnitTypes() func(ctx *Context) {
+       return func(ctx *Context) {
+               ctx.Data["UnitTypeCode"] = unit_model.TypeCode
+               ctx.Data["UnitTypeIssues"] = unit_model.TypeIssues
+               ctx.Data["UnitTypePullRequests"] = unit_model.TypePullRequests
+               ctx.Data["UnitTypeReleases"] = unit_model.TypeReleases
+               ctx.Data["UnitTypeWiki"] = unit_model.TypeWiki
+               ctx.Data["UnitTypeExternalWiki"] = unit_model.TypeExternalWiki
+               ctx.Data["UnitTypeExternalTracker"] = unit_model.TypeExternalTracker
+               ctx.Data["UnitTypeProjects"] = unit_model.TypeProjects
+               ctx.Data["UnitTypePackages"] = unit_model.TypePackages
+               ctx.Data["UnitTypeActions"] = unit_model.TypeActions
+       }
+}
diff --git a/services/context/response.go b/services/context/response.go
new file mode 100644 (file)
index 0000000..2f271f2
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "net/http"
+
+       web_types "code.gitea.io/gitea/modules/web/types"
+)
+
+// ResponseWriter represents a response writer for HTTP
+type ResponseWriter interface {
+       http.ResponseWriter
+       http.Flusher
+       web_types.ResponseStatusProvider
+
+       Before(func(ResponseWriter))
+
+       Status() int // used by access logger template
+       Size() int   // used by access logger template
+}
+
+var _ ResponseWriter = &Response{}
+
+// Response represents a response
+type Response struct {
+       http.ResponseWriter
+       written        int
+       status         int
+       befores        []func(ResponseWriter)
+       beforeExecuted bool
+}
+
+// Write writes bytes to HTTP endpoint
+func (r *Response) Write(bs []byte) (int, error) {
+       if !r.beforeExecuted {
+               for _, before := range r.befores {
+                       before(r)
+               }
+               r.beforeExecuted = true
+       }
+       size, err := r.ResponseWriter.Write(bs)
+       r.written += size
+       if err != nil {
+               return size, err
+       }
+       if r.status == 0 {
+               r.status = http.StatusOK
+       }
+       return size, nil
+}
+
+func (r *Response) Status() int {
+       return r.status
+}
+
+func (r *Response) Size() int {
+       return r.written
+}
+
+// WriteHeader write status code
+func (r *Response) WriteHeader(statusCode int) {
+       if !r.beforeExecuted {
+               for _, before := range r.befores {
+                       before(r)
+               }
+               r.beforeExecuted = true
+       }
+       if r.status == 0 {
+               r.status = statusCode
+               r.ResponseWriter.WriteHeader(statusCode)
+       }
+}
+
+// Flush flushes cached data
+func (r *Response) Flush() {
+       if f, ok := r.ResponseWriter.(http.Flusher); ok {
+               f.Flush()
+       }
+}
+
+// WrittenStatus returned status code written
+func (r *Response) WrittenStatus() int {
+       return r.status
+}
+
+// Before allows for a function to be called before the ResponseWriter has been written to. This is
+// useful for setting headers or any other operations that must happen before a response has been written.
+func (r *Response) Before(f func(ResponseWriter)) {
+       r.befores = append(r.befores, f)
+}
+
+func WrapResponseWriter(resp http.ResponseWriter) *Response {
+       if v, ok := resp.(*Response); ok {
+               return v
+       }
+       return &Response{
+               ResponseWriter: resp,
+               status:         0,
+               befores:        make([]func(ResponseWriter), 0),
+       }
+}
diff --git a/services/context/upload/upload.go b/services/context/upload/upload.go
new file mode 100644 (file)
index 0000000..77a7eb9
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package upload
+
+import (
+       "mime"
+       "net/http"
+       "net/url"
+       "path"
+       "regexp"
+       "strings"
+
+       "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/setting"
+       "code.gitea.io/gitea/services/context"
+)
+
+// ErrFileTypeForbidden not allowed file type error
+type ErrFileTypeForbidden struct {
+       Type string
+}
+
+// IsErrFileTypeForbidden checks if an error is a ErrFileTypeForbidden.
+func IsErrFileTypeForbidden(err error) bool {
+       _, ok := err.(ErrFileTypeForbidden)
+       return ok
+}
+
+func (err ErrFileTypeForbidden) Error() string {
+       return "This file extension or type is not allowed to be uploaded."
+}
+
+var wildcardTypeRe = regexp.MustCompile(`^[a-z]+/\*$`)
+
+// Verify validates whether a file is allowed to be uploaded.
+func Verify(buf []byte, fileName, allowedTypesStr string) error {
+       allowedTypesStr = strings.ReplaceAll(allowedTypesStr, "|", ",") // compat for old config format
+
+       allowedTypes := []string{}
+       for _, entry := range strings.Split(allowedTypesStr, ",") {
+               entry = strings.ToLower(strings.TrimSpace(entry))
+               if entry != "" {
+                       allowedTypes = append(allowedTypes, entry)
+               }
+       }
+
+       if len(allowedTypes) == 0 {
+               return nil // everything is allowed
+       }
+
+       fullMimeType := http.DetectContentType(buf)
+       mimeType, _, err := mime.ParseMediaType(fullMimeType)
+       if err != nil {
+               log.Warn("Detected attachment type could not be parsed %s", fullMimeType)
+               return ErrFileTypeForbidden{Type: fullMimeType}
+       }
+       extension := strings.ToLower(path.Ext(fileName))
+
+       // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers
+       for _, allowEntry := range allowedTypes {
+               if allowEntry == "*/*" {
+                       return nil // everything allowed
+               } else if strings.HasPrefix(allowEntry, ".") && allowEntry == extension {
+                       return nil // extension is allowed
+               } else if mimeType == allowEntry {
+                       return nil // mime type is allowed
+               } else if wildcardTypeRe.MatchString(allowEntry) && strings.HasPrefix(mimeType, allowEntry[:len(allowEntry)-1]) {
+                       return nil // wildcard match, e.g. image/*
+               }
+       }
+
+       log.Info("Attachment with type %s blocked from upload", fullMimeType)
+       return ErrFileTypeForbidden{Type: fullMimeType}
+}
+
+// AddUploadContext renders template values for dropzone
+func AddUploadContext(ctx *context.Context, uploadType string) {
+       if uploadType == "release" {
+               ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/releases/attachments"
+               ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/releases/attachments/remove"
+               ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/releases/attachments"
+               ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Release.AllowedTypes, "|", ",")
+               ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles
+               ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize
+       } else if uploadType == "comment" {
+               ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
+               ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove"
+               if len(ctx.Params(":index")) > 0 {
+                       ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.Params(":index")) + "/attachments"
+               } else {
+                       ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
+               }
+               ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Attachment.AllowedTypes, "|", ",")
+               ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles
+               ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize
+       } else if uploadType == "repo" {
+               ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/upload-file"
+               ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/upload-remove"
+               ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/upload-file"
+               ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Upload.AllowedTypes, "|", ",")
+               ctx.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles
+               ctx.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize
+       }
+}
diff --git a/services/context/upload/upload_test.go b/services/context/upload/upload_test.go
new file mode 100644 (file)
index 0000000..f2c3242
--- /dev/null
@@ -0,0 +1,194 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package upload
+
+import (
+       "bytes"
+       "compress/gzip"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestUpload(t *testing.T) {
+       testContent := []byte(`This is a plain text file.`)
+       var b bytes.Buffer
+       w := gzip.NewWriter(&b)
+       w.Write(testContent)
+       w.Close()
+
+       kases := []struct {
+               data         []byte
+               fileName     string
+               allowedTypes string
+               err          error
+       }{
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "dir/test.txt",
+                       allowedTypes: "",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "../../../test.txt",
+                       allowedTypes: "",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: ",",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "|",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "*/*",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "*/*,",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "*/*|",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "text/plain",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "dir/test.txt",
+                       allowedTypes: "text/plain",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "/dir.txt/test.js",
+                       allowedTypes: ".js",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: " text/plain ",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: ".txt",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: " .txt,.js",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: " .txt|.js",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "../../test.txt",
+                       allowedTypes: " .txt|.js",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: " .txt ,.js ",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "text/plain, .txt",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "text/*",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "text/*,.js",
+                       err:          nil,
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "text/**",
+                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: "application/x-gzip",
+                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: ".zip",
+                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: ".zip,.txtx",
+                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
+               },
+               {
+                       data:         testContent,
+                       fileName:     "test.txt",
+                       allowedTypes: ".zip|.txtx",
+                       err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
+               },
+               {
+                       data:         b.Bytes(),
+                       fileName:     "test.txt",
+                       allowedTypes: "application/x-gzip",
+                       err:          nil,
+               },
+       }
+
+       for _, kase := range kases {
+               assert.Equal(t, kase.err, Verify(kase.data, kase.fileName, kase.allowedTypes))
+       }
+}
index 8b2faf33691c11f52be3340ed1035671408b42da..4c9cd2928b94d8490a5cef8b3bf69fce08dfbda8 100644 (file)
@@ -9,12 +9,11 @@ import (
        "strings"
 
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
 )
 
 // UserAssignmentWeb returns a middleware to handle context-user assignment for web routes
-func UserAssignmentWeb() func(ctx *context.Context) {
-       return func(ctx *context.Context) {
+func UserAssignmentWeb() func(ctx *Context) {
+       return func(ctx *Context) {
                errorFn := func(status int, title string, obj any) {
                        err, ok := obj.(error)
                        if !ok {
@@ -32,8 +31,8 @@ func UserAssignmentWeb() func(ctx *context.Context) {
 }
 
 // UserIDAssignmentAPI returns a middleware to handle context-user assignment for api routes
-func UserIDAssignmentAPI() func(ctx *context.APIContext) {
-       return func(ctx *context.APIContext) {
+func UserIDAssignmentAPI() func(ctx *APIContext) {
+       return func(ctx *APIContext) {
                userID := ctx.ParamsInt64(":user-id")
 
                if ctx.IsSigned && ctx.Doer.ID == userID {
@@ -53,13 +52,13 @@ func UserIDAssignmentAPI() func(ctx *context.APIContext) {
 }
 
 // UserAssignmentAPI returns a middleware to handle context-user assignment for api routes
-func UserAssignmentAPI() func(ctx *context.APIContext) {
-       return func(ctx *context.APIContext) {
+func UserAssignmentAPI() func(ctx *APIContext) {
+       return func(ctx *APIContext) {
                ctx.ContextUser = userAssignment(ctx.Base, ctx.Doer, ctx.Error)
        }
 }
 
-func userAssignment(ctx *context.Base, doer *user_model.User, errCb func(int, string, any)) (contextUser *user_model.User) {
+func userAssignment(ctx *Base, doer *user_model.User, errCb func(int, string, any)) (contextUser *user_model.User) {
        username := ctx.Params(":username")
 
        if doer != nil && doer.LowerName == strings.ToLower(username) {
@@ -70,7 +69,7 @@ func userAssignment(ctx *context.Base, doer *user_model.User, errCb func(int, st
                if err != nil {
                        if user_model.IsErrUserNotExist(err) {
                                if redirectUserID, err := user_model.LookupUserRedirect(ctx, username); err == nil {
-                                       context.RedirectToUser(ctx, username, redirectUserID)
+                                       RedirectToUser(ctx, username, redirectUserID)
                                } else if user_model.IsErrUserRedirectNotExist(err) {
                                        errCb(http.StatusNotFound, "GetUserByName", err)
                                } else {
diff --git a/services/context/utils.go b/services/context/utils.go
new file mode 100644 (file)
index 0000000..293750f
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+       "strings"
+       "time"
+)
+
+// GetQueryBeforeSince return parsed time (unix format) from URL query's before and since
+func GetQueryBeforeSince(ctx *Base) (before, since int64, err error) {
+       before, err = parseFormTime(ctx, "before")
+       if err != nil {
+               return 0, 0, err
+       }
+
+       since, err = parseFormTime(ctx, "since")
+       if err != nil {
+               return 0, 0, err
+       }
+       return before, since, nil
+}
+
+// parseTime parse time and return unix timestamp
+func parseFormTime(ctx *Base, name string) (int64, error) {
+       value := strings.TrimSpace(ctx.FormString(name))
+       if len(value) != 0 {
+               t, err := time.Parse(time.RFC3339, value)
+               if err != nil {
+                       return 0, err
+               }
+               if !t.IsZero() {
+                       return t.Unix(), nil
+               }
+       }
+       return 0, nil
+}
diff --git a/services/context/xsrf.go b/services/context/xsrf.go
new file mode 100644 (file)
index 0000000..15e36d1
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Copyright 2014 The Macaron Authors
+// Copyright 2020 The Gitea Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+package context
+
+import (
+       "bytes"
+       "crypto/hmac"
+       "crypto/sha1"
+       "crypto/subtle"
+       "encoding/base64"
+       "fmt"
+       "strconv"
+       "strings"
+       "time"
+)
+
+// CsrfTokenTimeout represents the duration that XSRF tokens are valid.
+// It is exported so clients may set cookie timeouts that match generated tokens.
+const CsrfTokenTimeout = 24 * time.Hour
+
+// CsrfTokenRegenerationInterval is the interval between token generations, old tokens are still valid before CsrfTokenTimeout
+var CsrfTokenRegenerationInterval = 10 * time.Minute
+
+var csrfTokenSep = []byte(":")
+
+// GenerateCsrfToken returns a URL-safe secure XSRF token that expires in CsrfTokenTimeout hours.
+// key is a secret key for your application.
+// userID is a unique identifier for the user.
+// actionID is the action the user is taking (e.g. POSTing to a particular path).
+func GenerateCsrfToken(key, userID, actionID string, now time.Time) string {
+       nowUnixNano := now.UnixNano()
+       nowUnixNanoStr := strconv.FormatInt(nowUnixNano, 10)
+       h := hmac.New(sha1.New, []byte(key))
+       h.Write([]byte(strings.ReplaceAll(userID, ":", "_")))
+       h.Write(csrfTokenSep)
+       h.Write([]byte(strings.ReplaceAll(actionID, ":", "_")))
+       h.Write(csrfTokenSep)
+       h.Write([]byte(nowUnixNanoStr))
+       tok := fmt.Sprintf("%s:%s", h.Sum(nil), nowUnixNanoStr)
+       return base64.RawURLEncoding.EncodeToString([]byte(tok))
+}
+
+func ParseCsrfToken(token string) (issueTime time.Time, ok bool) {
+       data, err := base64.RawURLEncoding.DecodeString(token)
+       if err != nil {
+               return time.Time{}, false
+       }
+
+       pos := bytes.LastIndex(data, csrfTokenSep)
+       if pos == -1 {
+               return time.Time{}, false
+       }
+       nanos, err := strconv.ParseInt(string(data[pos+1:]), 10, 64)
+       if err != nil {
+               return time.Time{}, false
+       }
+       return time.Unix(0, nanos), true
+}
+
+// ValidCsrfToken returns true if token is a valid and unexpired token returned by Generate.
+func ValidCsrfToken(token, key, userID, actionID string, now time.Time) bool {
+       issueTime, ok := ParseCsrfToken(token)
+       if !ok {
+               return false
+       }
+
+       // Check that the token is not expired.
+       if now.Sub(issueTime) >= CsrfTokenTimeout {
+               return false
+       }
+
+       // Check that the token is not from the future.
+       // Allow 1-minute grace period in case the token is being verified on a
+       // machine whose clock is behind the machine that issued the token.
+       if issueTime.After(now.Add(1 * time.Minute)) {
+               return false
+       }
+
+       expected := GenerateCsrfToken(key, userID, actionID, issueTime)
+
+       // Check that the token matches the expected value.
+       // Use constant time comparison to avoid timing attacks.
+       return subtle.ConstantTimeCompare([]byte(token), []byte(expected)) == 1
+}
diff --git a/services/context/xsrf_test.go b/services/context/xsrf_test.go
new file mode 100644 (file)
index 0000000..21cda5d
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Copyright 2014 The Macaron Authors
+// Copyright 2020 The Gitea Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+package context
+
+import (
+       "encoding/base64"
+       "testing"
+       "time"
+
+       "github.com/stretchr/testify/assert"
+)
+
+const (
+       key      = "quay"
+       userID   = "12345678"
+       actionID = "POST /form"
+)
+
+var (
+       now              = time.Now()
+       oneMinuteFromNow = now.Add(1 * time.Minute)
+)
+
+func Test_ValidToken(t *testing.T) {
+       t.Run("Validate token", func(t *testing.T) {
+               tok := GenerateCsrfToken(key, userID, actionID, now)
+               assert.True(t, ValidCsrfToken(tok, key, userID, actionID, oneMinuteFromNow))
+               assert.True(t, ValidCsrfToken(tok, key, userID, actionID, now.Add(CsrfTokenTimeout-1*time.Nanosecond)))
+               assert.True(t, ValidCsrfToken(tok, key, userID, actionID, now.Add(-1*time.Minute)))
+       })
+}
+
+// Test_SeparatorReplacement tests that separators are being correctly substituted
+func Test_SeparatorReplacement(t *testing.T) {
+       t.Run("Test two separator replacements", func(t *testing.T) {
+               assert.NotEqual(t, GenerateCsrfToken("foo:bar", "baz", "wah", now),
+                       GenerateCsrfToken("foo", "bar:baz", "wah", now))
+       })
+}
+
+func Test_InvalidToken(t *testing.T) {
+       t.Run("Test invalid tokens", func(t *testing.T) {
+               invalidTokenTests := []struct {
+                       name, key, userID, actionID string
+                       t                           time.Time
+               }{
+                       {"Bad key", "foobar", userID, actionID, oneMinuteFromNow},
+                       {"Bad userID", key, "foobar", actionID, oneMinuteFromNow},
+                       {"Bad actionID", key, userID, "foobar", oneMinuteFromNow},
+                       {"Expired", key, userID, actionID, now.Add(CsrfTokenTimeout)},
+                       {"More than 1 minute from the future", key, userID, actionID, now.Add(-1*time.Nanosecond - 1*time.Minute)},
+               }
+
+               tok := GenerateCsrfToken(key, userID, actionID, now)
+               for _, itt := range invalidTokenTests {
+                       assert.False(t, ValidCsrfToken(tok, itt.key, itt.userID, itt.actionID, itt.t))
+               }
+       })
+}
+
+// Test_ValidateBadData primarily tests that no unexpected panics are triggered during parsing
+func Test_ValidateBadData(t *testing.T) {
+       t.Run("Validate bad data", func(t *testing.T) {
+               badDataTests := []struct {
+                       name, tok string
+               }{
+                       {"Invalid Base64", "ASDab24(@)$*=="},
+                       {"No delimiter", base64.URLEncoding.EncodeToString([]byte("foobar12345678"))},
+                       {"Invalid time", base64.URLEncoding.EncodeToString([]byte("foobar:foobar"))},
+               }
+
+               for _, bdt := range badDataTests {
+                       assert.False(t, ValidCsrfToken(bdt.tok, key, userID, actionID, oneMinuteFromNow))
+               }
+       })
+}
diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go
new file mode 100644 (file)
index 0000000..8a7dd69
--- /dev/null
@@ -0,0 +1,166 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+// Package contexttest provides utilities for testing Web/API contexts with models.
+package contexttest
+
+import (
+       gocontext "context"
+       "io"
+       "net/http"
+       "net/http/httptest"
+       "net/url"
+       "strings"
+       "testing"
+
+       access_model "code.gitea.io/gitea/models/perm/access"
+       repo_model "code.gitea.io/gitea/models/repo"
+       "code.gitea.io/gitea/models/unittest"
+       user_model "code.gitea.io/gitea/models/user"
+       "code.gitea.io/gitea/modules/gitrepo"
+       "code.gitea.io/gitea/modules/templates"
+       "code.gitea.io/gitea/modules/translation"
+       "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
+
+       "github.com/go-chi/chi/v5"
+       "github.com/stretchr/testify/assert"
+)
+
+func mockRequest(t *testing.T, reqPath string) *http.Request {
+       method, path, found := strings.Cut(reqPath, " ")
+       if !found {
+               method = "GET"
+               path = reqPath
+       }
+       requestURL, err := url.Parse(path)
+       assert.NoError(t, err)
+       req := &http.Request{Method: method, URL: requestURL, Form: url.Values{}}
+       req = req.WithContext(middleware.WithContextData(req.Context()))
+       return req
+}
+
+type MockContextOption struct {
+       Render context.Render
+}
+
+// MockContext mock context for unit tests
+func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*context.Context, *httptest.ResponseRecorder) {
+       var opt MockContextOption
+       if len(opts) > 0 {
+               opt = opts[0]
+       }
+       if opt.Render == nil {
+               opt.Render = &MockRender{}
+       }
+       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.Data = middleware.GetContextData(req.Context())
+       base.Locale = &translation.MockLocale{}
+
+       ctx := context.NewWebContext(base, opt.Render, nil)
+
+       chiCtx := chi.NewRouteContext()
+       ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx)
+       return ctx, resp
+}
+
+// MockAPIContext mock context for unit tests
+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.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)
+       return ctx, resp
+}
+
+// LoadRepo load a repo into a test context.
+func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {
+       var doer *user_model.User
+       repo := &context.Repository{}
+       switch ctx := ctx.(type) {
+       case *context.Context:
+               ctx.Repo = repo
+               doer = ctx.Doer
+       case *context.APIContext:
+               ctx.Repo = repo
+               doer = ctx.Doer
+       default:
+               assert.FailNow(t, "context is not *context.Context or *context.APIContext")
+       }
+
+       repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
+       var err error
+       repo.Owner, err = user_model.GetUserByID(ctx, repo.Repository.OwnerID)
+       assert.NoError(t, err)
+       repo.RepoLink = repo.Repository.Link()
+       repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo.Repository, doer)
+       assert.NoError(t, err)
+}
+
+// LoadRepoCommit loads a repo's commit into a test context.
+func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {
+       var repo *context.Repository
+       switch ctx := ctx.(type) {
+       case *context.Context:
+               repo = ctx.Repo
+       case *context.APIContext:
+               repo = ctx.Repo
+       default:
+               assert.FailNow(t, "context is not *context.Context or *context.APIContext")
+       }
+
+       gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository)
+       assert.NoError(t, err)
+       defer gitRepo.Close()
+       branch, err := gitRepo.GetHEADBranch()
+       assert.NoError(t, err)
+       assert.NotNil(t, branch)
+       if branch != nil {
+               repo.Commit, err = gitRepo.GetBranchCommit(branch.Name)
+               assert.NoError(t, err)
+       }
+}
+
+// LoadUser load a user into a test context
+func LoadUser(t *testing.T, ctx gocontext.Context, userID int64) {
+       doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
+       switch ctx := ctx.(type) {
+       case *context.Context:
+               ctx.Doer = doer
+       case *context.APIContext:
+               ctx.Doer = doer
+       default:
+               assert.FailNow(t, "context is not *context.Context or *context.APIContext")
+       }
+}
+
+// LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has
+// already been populated.
+func LoadGitRepo(t *testing.T, ctx *context.Context) {
+       assert.NoError(t, ctx.Repo.Repository.LoadOwner(ctx))
+       var err error
+       ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
+       assert.NoError(t, err)
+}
+
+type MockRender struct{}
+
+func (tr *MockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) {
+       return nil, nil
+}
+
+func (tr *MockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error {
+       if resp, ok := w.(http.ResponseWriter); ok {
+               resp.WriteHeader(status)
+       }
+       return nil
+}
index ed08691c8b1b4b473db8cdef6403d242d969a1a8..e0efcddbcb0c77adc2bdb427003a9564a78ace3a 100644 (file)
@@ -10,11 +10,11 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        user_model "code.gitea.io/gitea/models/user"
-       ctx "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        api "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/util"
+       ctx "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/gitdiff"
 )
 
index 4b3cacc606f7db4350ec4d2f5d2dc643438709ed..f112013060708fabaaf368571d5cff98b428e7a8 100644 (file)
@@ -6,9 +6,9 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 25acbbb99e877fa6676d0b902d0c0c4a3c1cc312..c9f3182b3a06883de88819cd05530176b6e0c354 100644 (file)
@@ -6,8 +6,8 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 6e2d787516d26132727f86601b37a8eb6a6f41f3..3677fcf429b555f57788fea698d620e98cb81103 100644 (file)
@@ -7,9 +7,9 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 2f08dfe9f4864de24af75cc35930e31627fd5779..cc940d42d34df62c227aba6cf5d2f9c03597aab1 100644 (file)
@@ -6,8 +6,8 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 5deb0ae463a033c5abaaafcaa8db628d65f19988..42e6c85c371a83dbeb0bf8f65974af53f3d1b284 100644 (file)
@@ -6,8 +6,8 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 98b8d610d0abd07eb22a65f5d3b47f8c3ec26df4..e40bcf4eea8e316efda79fc259c6f557ed185f13 100644 (file)
@@ -12,10 +12,10 @@ import (
        "code.gitea.io/gitea/models"
        issues_model "code.gitea.io/gitea/models/issues"
        project_model "code.gitea.io/gitea/models/project"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/webhook"
 
        "gitea.com/go-chi/binding"
index 4dd99f9e32feeee022a80f8593179ea5a39f411a..0135684737c7eef1d98b474362033b45e39291ff 100644 (file)
@@ -6,8 +6,8 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 6d16cfce49b180b9359879daf84aaac83b219f81..6abfc66fc27ea30629c3ac9729024d7c8cb4b0b1 100644 (file)
@@ -6,8 +6,8 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index cbab2742388994e88c4f04d460105fef2105bb85..186aa4a8782ad7ef0207f5b31704b2ee40bf9144 100644 (file)
@@ -10,11 +10,11 @@ import (
        "strings"
 
        auth_model "code.gitea.io/gitea/models/auth"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/structs"
        "code.gitea.io/gitea/modules/validation"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index d8137a8d134fe257483957737d374524591b7305..ca1c77e320871755096028df2c61000c01f5f672 100644 (file)
@@ -6,8 +6,8 @@ package forms
 import (
        "net/http"
 
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/web/middleware"
+       "code.gitea.io/gitea/services/context"
 
        "gitea.com/go-chi/binding"
 )
index 03e629a553ac05734005a57cd33c9473c7c4ea2e..c21fddf47864fac6e4071ee14ab88ac883773d7f 100644 (file)
@@ -7,8 +7,8 @@ import (
        "math/big"
 
        issues_model "code.gitea.io/gitea/models/issues"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/services/context"
 )
 
 type hiddenCommentTypeGroupsType map[string][]issues_model.CommentType
index 08d74326567b3aa2a85237f7bad4c927287831b5..2a362b1c0d4c7f1f6c6134ac3d484d86d1277229 100644 (file)
@@ -11,12 +11,12 @@ import (
        auth_model "code.gitea.io/gitea/models/auth"
        git_model "code.gitea.io/gitea/models/git"
        repo_model "code.gitea.io/gitea/models/repo"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
        lfs_module "code.gitea.io/gitea/modules/lfs"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
index 56714120ad09af4c3fb976830950c86f2b74cc40..706be0d080ebc644b8182d2991332027f8d01734 100644 (file)
@@ -26,12 +26,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/context"
        "code.gitea.io/gitea/modules/json"
        lfs_module "code.gitea.io/gitea/modules/lfs"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/storage"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/golang-jwt/jwt/v5"
 )
index 5ce2cd5fd578a339bdd707afb7b70094caf9cd81..dc0b53982216ddbd90224559d8f643722c9e3860 100644 (file)
@@ -14,9 +14,9 @@ import (
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/upload"
        "code.gitea.io/gitea/modules/util"
        attachment_service "code.gitea.io/gitea/services/attachment"
+       "code.gitea.io/gitea/services/context/upload"
        issue_service "code.gitea.io/gitea/services/issue"
        incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload"
        "code.gitea.io/gitea/services/mailer/token"
index 3551f85c4668cd1b209bb929012c2bf5c37fdd55..a4378678a08b59bfd78f7777268a1a9570f6e792 100644 (file)
@@ -7,8 +7,8 @@ import (
        "context"
 
        "code.gitea.io/gitea/models/user"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/markup"
+       gitea_context "code.gitea.io/gitea/services/context"
 )
 
 func ProcessorHelper() *markup.ProcessorHelper {
index ef8f56224517c53fa7456d21531c8eba87c5976c..170edae0e0beb29b4e119afb3e95f52963810329 100644 (file)
@@ -12,8 +12,8 @@ import (
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/unittest"
        "code.gitea.io/gitea/models/user"
-       gitea_context "code.gitea.io/gitea/modules/context"
-       "code.gitea.io/gitea/modules/contexttest"
+       gitea_context "code.gitea.io/gitea/services/context"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index e1ea4357fc5d22f4ed75950371e50ecac478ae17..42363f886d7d07f0d406f99502c7c9f648c9f14d 100644 (file)
@@ -21,7 +21,6 @@ import (
        user_model "code.gitea.io/gitea/models/user"
        "code.gitea.io/gitea/modules/base"
        "code.gitea.io/gitea/modules/container"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/graceful"
@@ -31,6 +30,7 @@ import (
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/sync"
        "code.gitea.io/gitea/modules/util"
+       gitea_context "code.gitea.io/gitea/services/context"
        issue_service "code.gitea.io/gitea/services/issue"
        notify_service "code.gitea.io/gitea/services/notify"
 )
index 5deec259da5e2774bf08a9c2648f6d051a16a5e4..ec6e9dfac3c8a19993de4c1f38bb3758860d7694 100644 (file)
@@ -10,7 +10,7 @@ import (
 
        "code.gitea.io/gitea/models/db"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
+       "code.gitea.io/gitea/services/contexttest"
 
        _ "code.gitea.io/gitea/models/actions"
 
index 2497910a838d7683f5eb69e0e72839319e4f108c..e8c0262ef41c7805ca5426f3d6156c70e4d0c8fc 100644 (file)
@@ -7,8 +7,8 @@ import (
        "context"
        "fmt"
 
-       gitea_ctx "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/util"
+       gitea_ctx "code.gitea.io/gitea/services/context"
 )
 
 type ContainedLinks struct { // TODO: better name?
index d50847789ace1816447c901807d95254acf4b123..4811f9d327a131d7456f738a6980d30696ca2786 100644 (file)
@@ -7,9 +7,9 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/gitrepo"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/contexttest"
 
        _ "code.gitea.io/gitea/models/actions"
 
index 91c878e50532c0e53bb061c125fe8a565a6aa5af..63aff9b0e309990b8379fdff7804b50b6d561065 100644 (file)
@@ -8,8 +8,8 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/json"
+       "code.gitea.io/gitea/services/contexttest"
        "code.gitea.io/gitea/services/gitdiff"
 
        "github.com/stretchr/testify/assert"
index 675ddbddb3e8e29e10078871eb6da79821547bd9..a5b3aad91e32b0ae68522a0e1b015e13b74d564c 100644 (file)
@@ -7,10 +7,10 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index 528ef500df24a7f3fb641dbc27c7688d97462082..508f20090ddc60da7a3498d65b630a636ee5d002 100644 (file)
@@ -7,8 +7,8 @@ import (
        "testing"
 
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/contexttest"
 
        "github.com/stretchr/testify/assert"
 )
index 0d192a1fe84acccc9bfd0ccedfac911d2d48ee81..41ad7211ff87b656c0ca416f22888649ceb4dde6 100644 (file)
@@ -17,10 +17,10 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/stretchr/testify/assert"
 )
index 195a1090c7c03f656bd42e526ecbe31517680586..ac28e0c0a26652b97c3f8278f93d310efa112061 100644 (file)
@@ -16,10 +16,10 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/stretchr/testify/assert"
 )
index ab5cf19a9c88ddceb1d8839ed888d52469fd64e2..fb3ae5e4ddb3ee91b9832ffb4fcf5dc712dc10cb 100644 (file)
@@ -15,10 +15,10 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/context"
 
        "github.com/stretchr/testify/assert"
 )
index de2a9d7d23be9e2e39010d57bf5c96935b0b019b..045567ce77c4d53a5db2a684d17b001ccc365248 100644 (file)
@@ -10,8 +10,8 @@ import (
        "path"
        "testing"
 
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/json"
+       gitea_context "code.gitea.io/gitea/services/context"
 
        "github.com/stretchr/testify/assert"
 )
index 95350d79caa45fd753e2f968a17525ebc59903bb..818e1fa65350ac5eea43320a738b5c5a530c9da1 100644 (file)
@@ -24,12 +24,12 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/lfs"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       gitea_context "code.gitea.io/gitea/services/context"
        files_service "code.gitea.io/gitea/services/repository/files"
        "code.gitea.io/gitea/tests"
 
index 1127de1afcdd4bc803b71a190cdeaf17855fec5a..f9bd352b6221c803445279632c4be5e4aad320cf 100644 (file)
@@ -24,7 +24,6 @@ import (
 
        "code.gitea.io/gitea/models/auth"
        "code.gitea.io/gitea/models/unittest"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/graceful"
        "code.gitea.io/gitea/modules/json"
        "code.gitea.io/gitea/modules/log"
@@ -33,6 +32,7 @@ import (
        "code.gitea.io/gitea/modules/util"
        "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers"
+       gitea_context "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/tests"
 
        "github.com/PuerkitoBio/goquery"
index 3dc719593c3069d73d8bd11967c967280d01362c..1c262b334967b512829d04ae8304ce52a173d6ae 100644 (file)
@@ -15,10 +15,10 @@ import (
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
        user_model "code.gitea.io/gitea/models/user"
-       gitea_context "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
+       gitea_context "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/migrations"
        mirror_service "code.gitea.io/gitea/services/mirror"
        repo_service "code.gitea.io/gitea/services/repository"
index 19fbd1754cc2f9010496b7b3f407e97d98163a4e..49abeb83fb127af6ce3b875b46633fca10912ca8 100644 (file)
@@ -12,11 +12,11 @@ import (
 
        repo_model "code.gitea.io/gitea/models/repo"
        "code.gitea.io/gitea/models/unittest"
-       "code.gitea.io/gitea/modules/contexttest"
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/gitrepo"
        "code.gitea.io/gitea/modules/setting"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/services/contexttest"
        files_service "code.gitea.io/gitea/services/repository/files"
 
        "github.com/stretchr/testify/assert"