Skip to content

Commit

Permalink
Move some errors to their own sub packages (#32880)
Browse files Browse the repository at this point in the history
  • Loading branch information
lunny authored Dec 20, 2024
1 parent 4774151 commit 751fe8b
Show file tree
Hide file tree
Showing 52 changed files with 728 additions and 781 deletions.
510 changes: 0 additions & 510 deletions models/error.go

This file was deleted.

15 changes: 15 additions & 0 deletions models/organization/org_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ func init() {
db.RegisterModel(new(OrgUser))
}

// ErrUserHasOrgs represents a "UserHasOrgs" kind of error.
type ErrUserHasOrgs struct {
UID int64
}

// IsErrUserHasOrgs checks if an error is a ErrUserHasOrgs.
func IsErrUserHasOrgs(err error) bool {
_, ok := err.(ErrUserHasOrgs)
return ok
}

func (err ErrUserHasOrgs) Error() string {
return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID)
}

// GetOrganizationCount returns count of membership of organization of the user.
func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) {
return db.GetEngine(ctx).
Expand Down
15 changes: 15 additions & 0 deletions models/packages/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,21 @@ func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
Find(&ps)
}

// ErrUserOwnPackages notifies that the user (still) owns the packages.
type ErrUserOwnPackages struct {
UID int64
}

// IsErrUserOwnPackages checks if an error is an ErrUserOwnPackages.
func IsErrUserOwnPackages(err error) bool {
_, ok := err.(ErrUserOwnPackages)
return ok
}

func (err ErrUserOwnPackages) Error() string {
return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID)
}

// HasOwnerPackages tests if a user/org has accessible packages
func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
return db.GetEngine(ctx).
Expand Down
17 changes: 16 additions & 1 deletion models/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type ErrUserDoesNotHaveAccessToRepo struct {
RepoName string
}

// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExists.
// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrUserDoesNotHaveAccessToRepo.
func IsErrUserDoesNotHaveAccessToRepo(err error) bool {
_, ok := err.(ErrUserDoesNotHaveAccessToRepo)
return ok
Expand Down Expand Up @@ -866,6 +866,21 @@ func (repo *Repository) TemplateRepo(ctx context.Context) *Repository {
return repo
}

// ErrUserOwnRepos represents a "UserOwnRepos" kind of error.
type ErrUserOwnRepos struct {
UID int64
}

// IsErrUserOwnRepos checks if an error is a ErrUserOwnRepos.
func IsErrUserOwnRepos(err error) bool {
_, ok := err.(ErrUserOwnRepos)
return ok
}

func (err ErrUserOwnRepos) Error() string {
return fmt.Sprintf("user still has ownership of repositories [uid: %d]", err.UID)
}

type CountRepositoryOptions struct {
OwnerID int64
Private optional.Option[bool]
Expand Down
15 changes: 15 additions & 0 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,21 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o
return committer.Commit()
}

// ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error.
type ErrDeleteLastAdminUser struct {
UID int64
}

// IsErrDeleteLastAdminUser checks if an error is a ErrDeleteLastAdminUser.
func IsErrDeleteLastAdminUser(err error) bool {
_, ok := err.(ErrDeleteLastAdminUser)
return ok
}

func (err ErrDeleteLastAdminUser) Error() string {
return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID)
}

// IsLastAdminUser check whether user is the last admin
func IsLastAdminUser(ctx context.Context, user *User) bool {
if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: optional.Some(true)}) <= 1 {
Expand Down
62 changes: 62 additions & 0 deletions modules/git/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ package git

import (
"context"
"fmt"
"net/url"
"strings"

giturl "code.gitea.io/gitea/modules/git/url"
"code.gitea.io/gitea/modules/util"
)

// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
Expand Down Expand Up @@ -37,3 +41,61 @@ func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (*giturl.Git
}
return giturl.Parse(addr)
}

// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
type ErrInvalidCloneAddr struct {
Host string
IsURLError bool
IsInvalidPath bool
IsProtocolInvalid bool
IsPermissionDenied bool
LocalPath bool
}

// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr.
func IsErrInvalidCloneAddr(err error) bool {
_, ok := err.(*ErrInvalidCloneAddr)
return ok
}

func (err *ErrInvalidCloneAddr) Error() string {
if err.IsInvalidPath {
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host)
}
if err.IsProtocolInvalid {
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url protocol is not allowed", err.Host)
}
if err.IsPermissionDenied {
return fmt.Sprintf("migration/cloning from '%s' is not allowed.", err.Host)
}
if err.IsURLError {
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url is invalid", err.Host)
}

return fmt.Sprintf("migration/cloning from '%s' is not allowed", err.Host)
}

func (err *ErrInvalidCloneAddr) Unwrap() error {
return util.ErrInvalidArgument
}

// ParseRemoteAddr checks if given remote address is valid,
// and returns composed URL with needed username and password.
func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) {
remoteAddr = strings.TrimSpace(remoteAddr)
// Remote address can be HTTP/HTTPS/Git URL or local path.
if strings.HasPrefix(remoteAddr, "http://") ||
strings.HasPrefix(remoteAddr, "https://") ||
strings.HasPrefix(remoteAddr, "git://") {
u, err := url.Parse(remoteAddr)
if err != nil {
return "", &ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr}
}
if len(authUsername)+len(authPassword) > 0 {
u.User = url.UserPassword(authUsername, authPassword)
}
remoteAddr = u.String()
}

return remoteAddr, nil
}
14 changes: 8 additions & 6 deletions routers/api/v1/admin/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import (
"fmt"
"net/http"

"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
org_model "code.gitea.io/gitea/models/organization"
packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/log"
Expand Down Expand Up @@ -247,7 +249,7 @@ func EditUser(ctx *context.APIContext) {
}

if err := user_service.UpdateUser(ctx, ctx.ContextUser, opts); err != nil {
if models.IsErrDeleteLastAdminUser(err) {
if user_model.IsErrDeleteLastAdminUser(err) {
ctx.Error(http.StatusBadRequest, "LastAdmin", err)
} else {
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
Expand Down Expand Up @@ -299,10 +301,10 @@ func DeleteUser(ctx *context.APIContext) {
}

if err := user_service.DeleteUser(ctx, ctx.ContextUser, ctx.FormBool("purge")); err != nil {
if models.IsErrUserOwnRepos(err) ||
models.IsErrUserHasOrgs(err) ||
models.IsErrUserOwnPackages(err) ||
models.IsErrDeleteLastAdminUser(err) {
if repo_model.IsErrUserOwnRepos(err) ||
org_model.IsErrUserHasOrgs(err) ||
packages_model.IsErrUserOwnPackages(err) ||
user_model.IsErrDeleteLastAdminUser(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "DeleteUser", err)
Expand Down
4 changes: 2 additions & 2 deletions routers/api/v1/repo/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"fmt"
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/organization"
Expand All @@ -24,6 +23,7 @@ import (
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
pull_service "code.gitea.io/gitea/services/pull"
release_service "code.gitea.io/gitea/services/release"
repo_service "code.gitea.io/gitea/services/repository"
)

Expand Down Expand Up @@ -247,7 +247,7 @@ func CreateBranch(ctx *context.APIContext) {
if err != nil {
if git_model.IsErrBranchNotExist(err) {
ctx.Error(http.StatusNotFound, "", "The old branch does not exist")
} else if models.IsErrTagAlreadyExists(err) {
} else if release_service.IsErrTagAlreadyExists(err) {
ctx.Error(http.StatusConflict, "", "The branch with the same tag already exists.")
} else if git_model.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) {
ctx.Error(http.StatusConflict, "", "The branch already exists.")
Expand Down
20 changes: 10 additions & 10 deletions routers/api/v1/repo/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"strings"
"time"

"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/models/unit"
Expand All @@ -30,6 +29,7 @@ import (
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/services/context"
pull_service "code.gitea.io/gitea/services/pull"
archiver_service "code.gitea.io/gitea/services/repository/archiver"
files_service "code.gitea.io/gitea/services/repository/files"
)
Expand Down Expand Up @@ -736,12 +736,12 @@ func UpdateFile(ctx *context.APIContext) {
}

func handleCreateOrUpdateFileError(ctx *context.APIContext, err error) {
if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) {
if files_service.IsErrUserCannotCommit(err) || pull_service.IsErrFilePathProtected(err) {
ctx.Error(http.StatusForbidden, "Access", err)
return
}
if git_model.IsErrBranchAlreadyExists(err) || models.IsErrFilenameInvalid(err) || models.IsErrSHADoesNotMatch(err) ||
models.IsErrFilePathInvalid(err) || models.IsErrRepoFileAlreadyExists(err) {
if git_model.IsErrBranchAlreadyExists(err) || files_service.IsErrFilenameInvalid(err) || pull_service.IsErrSHADoesNotMatch(err) ||
files_service.IsErrFilePathInvalid(err) || files_service.IsErrRepoFileAlreadyExists(err) {
ctx.Error(http.StatusUnprocessableEntity, "Invalid", err)
return
}
Expand Down Expand Up @@ -887,17 +887,17 @@ func DeleteFile(ctx *context.APIContext) {
}

if filesResponse, err := files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, opts); err != nil {
if git.IsErrBranchNotExist(err) || models.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) {
if git.IsErrBranchNotExist(err) || files_service.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) {
ctx.Error(http.StatusNotFound, "DeleteFile", err)
return
} else if git_model.IsErrBranchAlreadyExists(err) ||
models.IsErrFilenameInvalid(err) ||
models.IsErrSHADoesNotMatch(err) ||
models.IsErrCommitIDDoesNotMatch(err) ||
models.IsErrSHAOrCommitIDNotProvided(err) {
files_service.IsErrFilenameInvalid(err) ||
pull_service.IsErrSHADoesNotMatch(err) ||
files_service.IsErrCommitIDDoesNotMatch(err) ||
files_service.IsErrSHAOrCommitIDNotProvided(err) {
ctx.Error(http.StatusBadRequest, "DeleteFile", err)
return
} else if models.IsErrUserCannotCommit(err) {
} else if files_service.IsErrUserCannotCommit(err) {
ctx.Error(http.StatusForbidden, "DeleteFile", err)
return
}
Expand Down
11 changes: 5 additions & 6 deletions routers/api/v1/repo/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
"net/http"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
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/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
Expand All @@ -27,7 +27,6 @@ import (
"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"
notify_service "code.gitea.io/gitea/services/notify"
repo_service "code.gitea.io/gitea/services/repository"
Expand Down Expand Up @@ -104,7 +103,7 @@ func Migrate(ctx *context.APIContext) {
}
}

remoteAddr, err := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
remoteAddr, err := git.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
if err == nil {
err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.Doer)
}
Expand Down Expand Up @@ -237,7 +236,7 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' contains invalid characters.", err.(db.ErrNameCharsNotAllowed).Name))
case db.IsErrNamePatternNotAllowed(err):
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(db.ErrNamePatternNotAllowed).Pattern))
case models.IsErrInvalidCloneAddr(err):
case git.IsErrInvalidCloneAddr(err):
ctx.Error(http.StatusUnprocessableEntity, "", err)
case base.IsErrNotSupported(err):
ctx.Error(http.StatusUnprocessableEntity, "", err)
Expand All @@ -256,8 +255,8 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err
}

func handleRemoteAddrError(ctx *context.APIContext, err error) {
if models.IsErrInvalidCloneAddr(err) {
addrErr := err.(*models.ErrInvalidCloneAddr)
if git.IsErrInvalidCloneAddr(err) {
addrErr := err.(*git.ErrInvalidCloneAddr)
switch {
case addrErr.IsURLError:
ctx.Error(http.StatusUnprocessableEntity, "", err)
Expand Down
9 changes: 4 additions & 5 deletions routers/api/v1/repo/mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@ import (
"net/http"
"time"

"code.gitea.io/gitea/models"
"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/git"
"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"
mirror_service "code.gitea.io/gitea/services/mirror"
)
Expand Down Expand Up @@ -344,7 +343,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
return
}

address, err := forms.ParseRemoteAddr(mirrorOption.RemoteAddress, mirrorOption.RemoteUsername, mirrorOption.RemotePassword)
address, err := git.ParseRemoteAddr(mirrorOption.RemoteAddress, mirrorOption.RemoteUsername, mirrorOption.RemotePassword)
if err == nil {
err = migrations.IsMigrateURLAllowed(address, ctx.ContextUser)
}
Expand Down Expand Up @@ -397,8 +396,8 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
}

func HandleRemoteAddressError(ctx *context.APIContext, err error) {
if models.IsErrInvalidCloneAddr(err) {
addrErr := err.(*models.ErrInvalidCloneAddr)
if git.IsErrInvalidCloneAddr(err) {
addrErr := err.(*git.ErrInvalidCloneAddr)
switch {
case addrErr.IsProtocolInvalid:
ctx.Error(http.StatusBadRequest, "CreatePushMirror", "Invalid mirror protocol")
Expand Down
Loading

0 comments on commit 751fe8b

Please sign in to comment.