diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2024-12-20 10:05:29 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-20 18:05:29 +0000 |
commit | 751fe8b714f8ebd5fa915e893402776c4856d6c2 (patch) | |
tree | 04c16b9574ef8ea394ac2565ed2efb18728ce85c /routers/api/v1 | |
parent | 4774151e5339431dcd7fde70f084e7a0ff0b6cf6 (diff) | |
download | gitea-751fe8b714f8ebd5fa915e893402776c4856d6c2.tar.gz gitea-751fe8b714f8ebd5fa915e893402776c4856d6c2.zip |
Move some errors to their own sub packages (#32880)
Diffstat (limited to 'routers/api/v1')
-rw-r--r-- | routers/api/v1/admin/user.go | 14 | ||||
-rw-r--r-- | routers/api/v1/repo/branch.go | 4 | ||||
-rw-r--r-- | routers/api/v1/repo/file.go | 20 | ||||
-rw-r--r-- | routers/api/v1/repo/migrate.go | 11 | ||||
-rw-r--r-- | routers/api/v1/repo/mirror.go | 9 | ||||
-rw-r--r-- | routers/api/v1/repo/patch.go | 8 | ||||
-rw-r--r-- | routers/api/v1/repo/pull.go | 27 | ||||
-rw-r--r-- | routers/api/v1/repo/release.go | 5 | ||||
-rw-r--r-- | routers/api/v1/repo/release_tags.go | 7 | ||||
-rw-r--r-- | routers/api/v1/repo/tag.go | 13 |
10 files changed, 57 insertions, 61 deletions
diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index b0f40084da..3f4a73dcad 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -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" @@ -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) @@ -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) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 946203e97e..9a31aec314 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -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" @@ -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" ) @@ -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.") diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 959a4b952a..83848b7add 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -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" @@ -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" ) @@ -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 } @@ -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 } diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index dcbd8f3dd5..452825c0a3 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -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" @@ -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" @@ -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) } @@ -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) @@ -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) diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 310b82881e..047203501e 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -9,10 +9,10 @@ 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" @@ -20,7 +20,6 @@ import ( "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" ) @@ -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) } @@ -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") diff --git a/routers/api/v1/repo/patch.go b/routers/api/v1/repo/patch.go index 0e0601b7d9..5e24dcf891 100644 --- a/routers/api/v1/repo/patch.go +++ b/routers/api/v1/repo/patch.go @@ -7,13 +7,13 @@ import ( "net/http" "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/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" + pull_service "code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/repository/files" ) @@ -92,12 +92,12 @@ func ApplyDiffPatch(ctx *context.APIContext) { fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, opts) if err != nil { - if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) { + if files.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.IsErrFilenameInvalid(err) || pull_service.IsErrSHADoesNotMatch(err) || + files.IsErrFilePathInvalid(err) || files.IsErrRepoFileAlreadyExists(err) { ctx.Error(http.StatusUnprocessableEntity, "Invalid", err) return } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 6f4f3efaa1..71c4c81b67 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -12,7 +12,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" activities_model "code.gitea.io/gitea/models/activities" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -765,7 +764,7 @@ func EditPullRequest(ctx *context.APIContext) { } else if issues_model.IsErrIssueIsClosed(err) { ctx.Error(http.StatusUnprocessableEntity, "IsErrIssueIsClosed", err) return - } else if models.IsErrPullRequestHasMerged(err) { + } else if pull_service.IsErrPullRequestHasMerged(err) { ctx.Error(http.StatusConflict, "IsErrPullRequestHasMerged", err) return } @@ -941,7 +940,7 @@ func MergePullRequest(ctx *context.APIContext) { ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged") } else if errors.Is(err, pull_service.ErrNotMergeableState) { ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later") - } else if models.IsErrDisallowedToMerge(err) { + } else if pull_service.IsErrDisallowedToMerge(err) { ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err) } else if asymkey_service.IsErrWontSign(err) { ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err) @@ -954,7 +953,7 @@ func MergePullRequest(ctx *context.APIContext) { // handle manually-merged mark if manuallyMerged { if err := pull_service.MergedManually(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { - if models.IsErrInvalidMergeStyle(err) { + if pull_service.IsErrInvalidMergeStyle(err) { ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) return } @@ -1004,20 +1003,20 @@ func MergePullRequest(ctx *context.APIContext) { } if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil { - if models.IsErrInvalidMergeStyle(err) { + if pull_service.IsErrInvalidMergeStyle(err) { ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) - } else if models.IsErrMergeConflicts(err) { - conflictError := err.(models.ErrMergeConflicts) + } else if pull_service.IsErrMergeConflicts(err) { + conflictError := err.(pull_service.ErrMergeConflicts) ctx.JSON(http.StatusConflict, conflictError) - } else if models.IsErrRebaseConflicts(err) { - conflictError := err.(models.ErrRebaseConflicts) + } else if pull_service.IsErrRebaseConflicts(err) { + conflictError := err.(pull_service.ErrRebaseConflicts) ctx.JSON(http.StatusConflict, conflictError) - } else if models.IsErrMergeUnrelatedHistories(err) { - conflictError := err.(models.ErrMergeUnrelatedHistories) + } else if pull_service.IsErrMergeUnrelatedHistories(err) { + conflictError := err.(pull_service.ErrMergeUnrelatedHistories) ctx.JSON(http.StatusConflict, conflictError) } else if git.IsErrPushOutOfDate(err) { ctx.Error(http.StatusConflict, "Merge", "merge push out of date") - } else if models.IsErrSHADoesNotMatch(err) { + } else if pull_service.IsErrSHADoesNotMatch(err) { ctx.Error(http.StatusConflict, "Merge", "head out of date") } else if git.IsErrPushRejected(err) { errPushRej := err.(*git.ErrPushRejected) @@ -1308,10 +1307,10 @@ func UpdatePullRequest(ctx *context.APIContext) { message := fmt.Sprintf("Merge branch '%s' into %s", pr.BaseBranch, pr.HeadBranch) if err = pull_service.Update(ctx, pr, ctx.Doer, message, rebase); err != nil { - if models.IsErrMergeConflicts(err) { + if pull_service.IsErrMergeConflicts(err) { ctx.Error(http.StatusConflict, "Update", "merge failed because of conflict") return - } else if models.IsErrRebaseConflicts(err) { + } else if pull_service.IsErrRebaseConflicts(err) { ctx.Error(http.StatusConflict, "Update", "rebase failed because of conflict") return } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 478bdbd797..141f812172 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -250,7 +249,7 @@ func CreateRelease(ctx *context.APIContext) { if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil { if repo_model.IsErrReleaseAlreadyExist(err) { ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err) - } else if models.IsErrProtectedTagName(err) { + } else if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err) } else if git.IsErrNotExist(err) { ctx.Error(http.StatusNotFound, "ErrNotExist", fmt.Errorf("target \"%v\" not found: %w", rel.Target, err)) @@ -408,7 +407,7 @@ func DeleteRelease(ctx *context.APIContext) { return } if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil { - if models.IsErrProtectedTagName(err) { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 6df47af8d9..99f7a8cbf2 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -6,11 +6,10 @@ package repo import ( "net/http" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" - releaseservice "code.gitea.io/gitea/services/release" + release_service "code.gitea.io/gitea/services/release" ) // GetReleaseByTag get a single release of a repository by tag name @@ -112,8 +111,8 @@ func DeleteReleaseByTag(ctx *context.APIContext) { return } - if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil { - if models.IsErrProtectedTagName(err) { + if err = release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index a72df78666..fe0910c735 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -9,7 +9,6 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -19,7 +18,7 @@ import ( "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" + release_service "code.gitea.io/gitea/services/release" ) // ListTags list all the tags of a repository @@ -205,12 +204,12 @@ func CreateTag(ctx *context.APIContext) { return } - if err := releaseservice.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, commit.ID.String(), form.TagName, form.Message); err != nil { - if models.IsErrTagAlreadyExists(err) { + if err := release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, commit.ID.String(), form.TagName, form.Message); err != nil { + if release_service.IsErrTagAlreadyExists(err) { ctx.Error(http.StatusConflict, "tag exist", err) return } - if models.IsErrProtectedTagName(err) { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "CreateNewTag", "user not allowed to create protected tag") return } @@ -280,8 +279,8 @@ func DeleteTag(ctx *context.APIContext) { return } - if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil { - if models.IsErrProtectedTagName(err) { + if err = release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } |