diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2025-02-17 14:13:17 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-16 22:13:17 -0800 |
commit | f35850f48ed0bd40ec288e2547ac687a7bf1746c (patch) | |
tree | 27191daf6a2ca9e216710090bba303e26dafb157 /services | |
parent | 69de5a65c25b08b501ed1e8123fcdad43f382213 (diff) | |
download | gitea-f35850f48ed0bd40ec288e2547ac687a7bf1746c.tar.gz gitea-f35850f48ed0bd40ec288e2547ac687a7bf1746c.zip |
Refactor error system (#33610)
Diffstat (limited to 'services')
-rw-r--r-- | services/actions/workflow.go | 4 | ||||
-rw-r--r-- | services/context/api.go | 62 | ||||
-rw-r--r-- | services/context/base.go | 4 | ||||
-rw-r--r-- | services/context/context_response.go | 6 | ||||
-rw-r--r-- | services/context/org.go | 12 | ||||
-rw-r--r-- | services/context/package.go | 18 | ||||
-rw-r--r-- | services/context/permission.go | 12 | ||||
-rw-r--r-- | services/context/repo.go | 18 | ||||
-rw-r--r-- | services/context/user.go | 20 |
9 files changed, 75 insertions, 81 deletions
diff --git a/services/actions/workflow.go b/services/actions/workflow.go index 4470b60c64..ab320aa453 100644 --- a/services/actions/workflow.go +++ b/services/actions/workflow.go @@ -104,13 +104,13 @@ func EnableOrDisableWorkflow(ctx *context.APIContext, workflowID string, isEnabl func ListActionWorkflows(ctx *context.APIContext) ([]*api.ActionWorkflow, error) { defaultBranchCommit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) if err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowDefaultBranchError", err.Error()) + ctx.APIError(http.StatusInternalServerError, err.Error()) return nil, err } entries, err := actions.ListWorkflows(defaultBranchCommit) if err != nil { - ctx.Error(http.StatusNotFound, "WorkflowListNotFound", err.Error()) + ctx.APIError(http.StatusNotFound, err.Error()) return nil, err } diff --git a/services/context/api.go b/services/context/api.go index baf4131edc..9c3ee2a4ac 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -106,14 +106,24 @@ 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) +// APIErrorInternal responds with error message, status is 500 +func (ctx *APIContext) APIErrorInternal(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, + }) } -// Error responds with an error message to client with given obj as the message. +// APIError 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) { +func (ctx *APIContext) APIError(status int, obj any) { var message string if err, ok := obj.(error); ok { message = err.Error() @@ -122,7 +132,7 @@ func (ctx *APIContext) Error(status int, title string, obj any) { } if status == http.StatusInternalServerError { - log.ErrorWithSkip(1, "%s: %s", title, message) + log.ErrorWithSkip(1, "APIError: %s", message) if setting.IsProd && !(ctx.Doer != nil && ctx.Doer.IsAdmin) { message = "" @@ -135,22 +145,6 @@ func (ctx *APIContext) Error(status int, title string, obj any) { }) } -// 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{} @@ -210,7 +204,7 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) { } } -// APIContexter returns apicontext as middleware +// APIContexter returns APIContext 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) { @@ -227,7 +221,7 @@ func APIContexter() func(http.Handler) http.Handler { // 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) + ctx.APIErrorInternal(err) return } } @@ -240,9 +234,9 @@ func APIContexter() func(http.Handler) http.Handler { } } -// NotFound handles 404s for APIContext +// APIErrorNotFound handles 404s for APIContext // String will replace message, errors will be added to a slice -func (ctx *APIContext) NotFound(objs ...any) { +func (ctx *APIContext) APIErrorNotFound(objs ...any) { message := ctx.Locale.TrString("error.not_found") var errors []string for _, obj := range objs { @@ -279,7 +273,7 @@ func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) { var err error ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx.Repo.Repository) if err != nil { - ctx.Error(http.StatusInternalServerError, fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err) + ctx.APIError(http.StatusInternalServerError, err) return } } @@ -292,7 +286,7 @@ func RepoRefForAPI(next http.Handler) http.Handler { ctx := GetAPIContext(req) if ctx.Repo.GitRepo == nil { - ctx.InternalServerError(fmt.Errorf("no open git repo")) + ctx.APIErrorInternal(fmt.Errorf("no open git repo")) return } @@ -302,14 +296,14 @@ func RepoRefForAPI(next http.Handler) http.Handler { if ctx.Repo.GitRepo.IsBranchExist(refName) { ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName) if err != nil { - ctx.InternalServerError(err) + ctx.APIErrorInternal(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) + ctx.APIErrorInternal(err) return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() @@ -317,11 +311,11 @@ func RepoRefForAPI(next http.Handler) http.Handler { ctx.Repo.CommitID = refName ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { - ctx.NotFound("GetCommit", err) + ctx.APIErrorNotFound("GetCommit", err) return } } else { - ctx.NotFound(fmt.Errorf("not exist: '%s'", ctx.PathParam("*"))) + ctx.APIErrorNotFound(fmt.Errorf("not exist: '%s'", ctx.PathParam("*"))) return } @@ -355,7 +349,7 @@ func (ctx *APIContext) NotFoundOrServerError(logMsg string, errCheck func(error) ctx.JSON(http.StatusNotFound, nil) return } - ctx.Error(http.StatusInternalServerError, "NotFoundOrServerError", logMsg) + ctx.APIError(http.StatusInternalServerError, logMsg) } // IsUserSiteAdmin returns true if current user is a site admin @@ -368,7 +362,7 @@ func (ctx *APIContext) IsUserRepoAdmin() bool { return ctx.Repo.IsAdmin() } -// IsUserRepoWriter returns true if current user has write privilege in current repo +// 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) { diff --git a/services/context/base.go b/services/context/base.go index 4d1c3659a2..3701668bf6 100644 --- a/services/context/base.go +++ b/services/context/base.go @@ -81,8 +81,8 @@ 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) { +// HTTPError returned an error to web browser +func (b *Base) HTTPError(status int, contents ...string) { v := http.StatusText(status) if len(contents) > 0 { v = contents[0] diff --git a/services/context/context_response.go b/services/context/context_response.go index c7044791eb..61b432395a 100644 --- a/services/context/context_response.go +++ b/services/context/context_response.go @@ -28,7 +28,7 @@ import ( 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") + ctx.HTTPError(http.StatusInternalServerError, "unable to get user") return } @@ -122,8 +122,8 @@ func (ctx *Context) RenderWithErr(msg any, tpl templates.TplName, form any) { } // 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) NotFound(logErr error) { + ctx.notFoundInternal("", logErr) } func (ctx *Context) notFoundInternal(logMsg string, logErr error) { diff --git a/services/context/org.go b/services/context/org.go index 3f73165076..992a48afa0 100644 --- a/services/context/org.go +++ b/services/context/org.go @@ -51,7 +51,7 @@ func GetOrganizationByParams(ctx *Context) { if err == nil { RedirectToUser(ctx.Base, orgName, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { - ctx.NotFound("GetUserByName", err) + ctx.NotFound(err) } else { ctx.ServerError("LookupUserRedirect", err) } @@ -93,7 +93,7 @@ func OrgAssignment(opts OrgAssignmentOptions) func(ctx *Context) { // Handle Visibility if org.Visibility != structs.VisibleTypePublic && !ctx.IsSigned { // We must be signed in to see limited or private organizations - ctx.NotFound("OrgAssignment", err) + ctx.NotFound(err) return } @@ -142,7 +142,7 @@ func OrgAssignment(opts OrgAssignmentOptions) func(ctx *Context) { ctx.Data["SignedUser"] = &user_model.User{} } if (opts.RequireMember && !ctx.Org.IsMember) || (opts.RequireOwner && !ctx.Org.IsOwner) { - ctx.NotFound("OrgAssignment", err) + ctx.NotFound(err) return } ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner @@ -218,20 +218,20 @@ func OrgAssignment(opts OrgAssignmentOptions) func(ctx *Context) { } if !teamExists { - ctx.NotFound("OrgAssignment", err) + ctx.NotFound(err) return } ctx.Data["IsTeamMember"] = ctx.Org.IsTeamMember if opts.RequireTeamMember && !ctx.Org.IsTeamMember { - ctx.NotFound("OrgAssignment", err) + ctx.NotFound(err) return } ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.AccessMode >= perm.AccessModeAdmin ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin if opts.RequireTeamAdmin && !ctx.Org.IsTeamAdmin { - ctx.NotFound("OrgAssignment", err) + ctx.NotFound(err) return } } diff --git a/services/context/package.go b/services/context/package.go index e32ba3b481..64bb4f3ecd 100644 --- a/services/context/package.go +++ b/services/context/package.go @@ -33,15 +33,15 @@ type packageAssignmentCtx struct { // 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) { + errorFn := func(status int, obj any) { err, ok := obj.(error) if !ok { err = fmt.Errorf("%s", obj) } if status == http.StatusNotFound { - ctx.NotFound(title, err) + ctx.NotFound(err) } else { - ctx.ServerError(title, err) + ctx.ServerError("PackageAssignment", err) } } paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser} @@ -53,18 +53,18 @@ func PackageAssignment() func(ctx *Context) { 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) + ctx.Package = packageAssignment(paCtx, ctx.APIError) } } -func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any)) *Package { +func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, 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) + errCb(http.StatusInternalServerError, fmt.Errorf("determineAccessMode: %w", err)) return pkg } @@ -75,16 +75,16 @@ func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any)) 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) + errCb(http.StatusNotFound, fmt.Errorf("GetVersionByNameAndVersion: %w", err)) } else { - errCb(http.StatusInternalServerError, "GetVersionByNameAndVersion", err) + errCb(http.StatusInternalServerError, fmt.Errorf("GetVersionByNameAndVersion: %w", err)) } return pkg } pkg.Descriptor, err = packages_model.GetPackageDescriptor(ctx, pv) if err != nil { - errCb(http.StatusInternalServerError, "GetPackageDescriptor", err) + errCb(http.StatusInternalServerError, fmt.Errorf("GetPackageDescriptor: %w", err)) return pkg } } diff --git a/services/context/permission.go b/services/context/permission.go index 0d69ccc4a4..7055f798da 100644 --- a/services/context/permission.go +++ b/services/context/permission.go @@ -15,7 +15,7 @@ import ( func RequireRepoAdmin() func(ctx *Context) { return func(ctx *Context) { if !ctx.IsSigned || !ctx.Repo.IsAdmin() { - ctx.NotFound("RequireRepoAdmin denies the request", nil) + ctx.NotFound(nil) return } } @@ -25,7 +25,7 @@ func RequireRepoAdmin() func(ctx *Context) { func CanWriteToBranch() func(ctx *Context) { return func(ctx *Context) { if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) { - ctx.NotFound("CanWriteToBranch denies permission", nil) + ctx.NotFound(nil) return } } @@ -39,7 +39,7 @@ func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) { return } } - ctx.NotFound("RequireUnitWriter denies the request", nil) + ctx.NotFound(nil) } } @@ -54,7 +54,7 @@ func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) { return } } - ctx.NotFound("RequireUnitReader denies the request", nil) + ctx.NotFound(nil) } } @@ -78,7 +78,7 @@ func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_ } if publicOnly && repo.IsPrivate { - ctx.Error(http.StatusForbidden) + ctx.HTTPError(http.StatusForbidden) return } @@ -89,7 +89,7 @@ func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_ } if !scopeMatched { - ctx.Error(http.StatusForbidden) + ctx.HTTPError(http.StatusForbidden) return } } diff --git a/services/context/repo.go b/services/context/repo.go index 1cb35b9b83..e63e3e5317 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -89,7 +89,7 @@ func (r *Repository) GetObjectFormat() git.ObjectFormat { 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"))) + ctx.NotFound(errors.New(ctx.Locale.TrString("repo.archive.title"))) } } } @@ -315,7 +315,7 @@ func RedirectToRepo(ctx *Base, redirectRepoID int64) { repo, err := repo_model.GetRepositoryByID(ctx, redirectRepoID) if err != nil { log.Error("GetRepositoryByID: %v", err) - ctx.Error(http.StatusInternalServerError, "GetRepositoryByID") + ctx.HTTPError(http.StatusInternalServerError, "GetRepositoryByID") return } @@ -349,7 +349,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { EarlyResponseForGoGetMeta(ctx) return } - ctx.NotFound("no access right", nil) + ctx.NotFound(nil) return } ctx.Data["Permission"] = &ctx.Repo.Permission @@ -402,7 +402,7 @@ func RepoAssignment(ctx *Context) { 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) + ctx.NotFound(nil) } else { ctx.ServerError("LookupUserRedirect", err) } @@ -447,7 +447,7 @@ func RepoAssignment(ctx *Context) { EarlyResponseForGoGetMeta(ctx) return } - ctx.NotFound("GetRepositoryByName", nil) + ctx.NotFound(nil) } else { ctx.ServerError("LookupRepoRedirect", err) } @@ -870,7 +870,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) { ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refShortName) if err != nil { if git.IsErrNotExist(err) { - ctx.NotFound("GetTagCommit", err) + ctx.NotFound(err) return } ctx.ServerError("GetTagCommit", err) @@ -883,7 +883,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) { ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refShortName) if err != nil { - ctx.NotFound("GetCommit", err) + ctx.NotFound(err) return } // If short commit ID add canonical link header @@ -892,7 +892,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) { ctx.RespHeader().Set("Link", fmt.Sprintf(`<%s>; rel="canonical"`, canonicalURL)) } } else { - ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refShortName)) + ctx.NotFound(fmt.Errorf("branch or tag not exist: %s", refShortName)) return } @@ -945,7 +945,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) { func GitHookService() func(ctx *Context) { return func(ctx *Context) { if !ctx.Doer.CanEditGitHook() { - ctx.NotFound("GitHookService", nil) + ctx.NotFound(nil) return } } diff --git a/services/context/user.go b/services/context/user.go index dbc35e198d..4037354955 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -14,15 +14,15 @@ import ( // UserAssignmentWeb returns a middleware to handle context-user assignment for web routes func UserAssignmentWeb() func(ctx *Context) { return func(ctx *Context) { - errorFn := func(status int, title string, obj any) { + errorFn := func(status int, obj any) { err, ok := obj.(error) if !ok { err = fmt.Errorf("%s", obj) } if status == http.StatusNotFound { - ctx.NotFound(title, err) + ctx.NotFound(err) } else { - ctx.ServerError(title, err) + ctx.ServerError("UserAssignmentWeb", err) } } ctx.ContextUser = userAssignment(ctx.Base, ctx.Doer, errorFn) @@ -42,9 +42,9 @@ func UserIDAssignmentAPI() func(ctx *APIContext) { ctx.ContextUser, err = user_model.GetUserByID(ctx, userID) if err != nil { if user_model.IsErrUserNotExist(err) { - ctx.Error(http.StatusNotFound, "GetUserByID", err) + ctx.APIError(http.StatusNotFound, err) } else { - ctx.Error(http.StatusInternalServerError, "GetUserByID", err) + ctx.APIError(http.StatusInternalServerError, err) } } } @@ -54,11 +54,11 @@ func UserIDAssignmentAPI() func(ctx *APIContext) { // UserAssignmentAPI returns a middleware to handle context-user assignment for api routes func UserAssignmentAPI() func(ctx *APIContext) { return func(ctx *APIContext) { - ctx.ContextUser = userAssignment(ctx.Base, ctx.Doer, ctx.Error) + ctx.ContextUser = userAssignment(ctx.Base, ctx.Doer, ctx.APIError) } } -func userAssignment(ctx *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, any)) (contextUser *user_model.User) { username := ctx.PathParam("username") if doer != nil && doer.LowerName == strings.ToLower(username) { @@ -71,12 +71,12 @@ func userAssignment(ctx *Base, doer *user_model.User, errCb func(int, string, an if redirectUserID, err := user_model.LookupUserRedirect(ctx, username); err == nil { RedirectToUser(ctx, username, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { - errCb(http.StatusNotFound, "GetUserByName", err) + errCb(http.StatusNotFound, err) } else { - errCb(http.StatusInternalServerError, "LookupUserRedirect", err) + errCb(http.StatusInternalServerError, fmt.Errorf("LookupUserRedirect: %w", err)) } } else { - errCb(http.StatusInternalServerError, "GetUserByName", err) + errCb(http.StatusInternalServerError, fmt.Errorf("GetUserByName: %w", err)) } } } |