aboutsummaryrefslogtreecommitdiffstats
path: root/modules/context/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/context/api.go')
-rw-r--r--modules/context/api.go115
1 files changed, 83 insertions, 32 deletions
diff --git a/modules/context/api.go b/modules/context/api.go
index e263dcbe8d..092ad73f31 100644
--- a/modules/context/api.go
+++ b/modules/context/api.go
@@ -13,18 +13,32 @@ import (
"code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/modules/cache"
+ "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/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/web/middleware"
+
+ "gitea.com/go-chi/cache"
)
// APIContext is a specific context for API service
type APIContext struct {
- *Context
- Org *APIOrganization
+ *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
}
// Currently, we have the following common fields in error response:
@@ -128,11 +142,6 @@ type apiContextKeyType struct{}
var apiContextKey = apiContextKeyType{}
-// WithAPIContext set up api context in request
-func WithAPIContext(req *http.Request, ctx *APIContext) *http.Request {
- return req.WithContext(context.WithValue(req.Context(), apiContextKey, ctx))
-}
-
// GetAPIContext returns a context for API routes
func GetAPIContext(req *http.Request) *APIContext {
return req.Context().Value(apiContextKey).(*APIContext)
@@ -195,21 +204,21 @@ func (ctx *APIContext) CheckForOTP() {
}
otpHeader := ctx.Req.Header.Get("X-Gitea-OTP")
- twofa, err := auth.GetTwoFactorByUID(ctx.Context.Doer.ID)
+ twofa, err := auth.GetTwoFactorByUID(ctx.Doer.ID)
if err != nil {
if auth.IsErrTwoFactorNotEnrolled(err) {
return // No 2FA enrollment for this user
}
- ctx.Context.Error(http.StatusInternalServerError)
+ ctx.Error(http.StatusInternalServerError, "GetTwoFactorByUID", err)
return
}
ok, err := twofa.ValidateTOTP(otpHeader)
if err != nil {
- ctx.Context.Error(http.StatusInternalServerError)
+ ctx.Error(http.StatusInternalServerError, "ValidateTOTP", err)
return
}
if !ok {
- ctx.Context.Error(http.StatusUnauthorized)
+ ctx.Error(http.StatusUnauthorized, "", nil)
return
}
}
@@ -218,23 +227,17 @@ func (ctx *APIContext) CheckForOTP() {
func APIContexter() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- locale := middleware.Locale(w, req)
- ctx := APIContext{
- Context: &Context{
- Resp: NewResponse(w),
- Data: middleware.GetContextData(req.Context()),
- Locale: locale,
- Cache: cache.GetCache(),
- Repo: &Repository{
- PullRequest: &PullRequest{},
- },
- Org: &Organization{},
- },
- Org: &APIOrganization{},
+ base, baseCleanUp := NewBaseContext(w, req)
+ ctx := &APIContext{
+ Base: base,
+ Cache: mc.GetCache(),
+ Repo: &Repository{PullRequest: &PullRequest{}},
+ Org: &APIOrganization{},
}
- defer ctx.Close()
+ defer baseCleanUp()
- ctx.Req = WithAPIContext(WithContext(req, ctx.Context), &ctx)
+ ctx.Base.AppendContextValue(apiContextKey, ctx)
+ ctx.Base.AppendContextValueFunc(git.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") {
@@ -247,8 +250,6 @@ func APIContexter() func(http.Handler) http.Handler {
httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
- ctx.Data["Context"] = &ctx
-
next.ServeHTTP(ctx.Resp, ctx.Req)
})
}
@@ -301,7 +302,7 @@ func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context
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()
+ _ = ctx.Repo.GitRepo.Close()
}
}
}
@@ -337,7 +338,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
}
var err error
- refName := getRefName(ctx.Context, RepoRefAny)
+ refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
if ctx.Repo.GitRepo.IsBranchExist(refName) {
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
@@ -368,3 +369,53 @@ func RepoRefForAPI(next http.Handler) http.Handler {
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
+}