08c0b7a2fd
* Refactor error usage from the store level up and add API helpers * Complete API tests * Fix merge errorResponse calls * Remove ensure helpers to allow for custom messages on permission errors * Fix bad import and call * Remove bad user check on auth that was added as part of the main merge * Fix empty list test * Replace deprecated proxy calls to ioutil.ReadAll with io.ReadAll * Add information to the NotFound errors * Add context to all remaining errors and address review comments * Fix linter * Adapt the new card API endpoints to the error refactor * Remove almost all customErrorResponse calls * Add request entity too large to errorResponse and remove customErrorResponse * Fix linter
316 lines
7.1 KiB
Go
316 lines
7.1 KiB
Go
package model
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
|
|
|
pluginapi "github.com/mattermost/mattermost-plugin-api"
|
|
)
|
|
|
|
var (
|
|
ErrViewsLimitReached = errors.New("views limit reached for board")
|
|
ErrPatchUpdatesLimitedCards = errors.New("patch updates cards that are limited")
|
|
|
|
ErrInsufficientLicense = errors.New("appropriate license required")
|
|
|
|
ErrCategoryPermissionDenied = errors.New("category doesn't belong to user")
|
|
ErrCategoryDeleted = errors.New("category is deleted")
|
|
|
|
ErrBoardMemberIsLastAdmin = errors.New("cannot leave a board with no admins")
|
|
|
|
ErrRequestEntityTooLarge = errors.New("request entity too large")
|
|
)
|
|
|
|
// ErrNotFound is an error type that can be returned by store APIs
|
|
// when a query unexpectedly fetches no records.
|
|
type ErrNotFound struct {
|
|
entity string
|
|
}
|
|
|
|
// NewErrNotFound creates a new ErrNotFound instance.
|
|
func NewErrNotFound(entity string) *ErrNotFound {
|
|
return &ErrNotFound{
|
|
entity: entity,
|
|
}
|
|
}
|
|
|
|
func (nf *ErrNotFound) Error() string {
|
|
return fmt.Sprintf("{%s} not found", nf.entity)
|
|
}
|
|
|
|
// ErrNotAllFound is an error type that can be returned by store APIs
|
|
// when a query that should fetch a certain amount of records
|
|
// unexpectedly fetches less.
|
|
type ErrNotAllFound struct {
|
|
entity string
|
|
resources []string
|
|
}
|
|
|
|
func NewErrNotAllFound(entity string, resources []string) *ErrNotAllFound {
|
|
return &ErrNotAllFound{
|
|
entity: entity,
|
|
resources: resources,
|
|
}
|
|
}
|
|
|
|
func (naf *ErrNotAllFound) Error() string {
|
|
return fmt.Sprintf("not all instances of {%s} in {%s} found", naf.entity, strings.Join(naf.resources, ", "))
|
|
}
|
|
|
|
// ErrBadRequest can be returned when the API handler receives a
|
|
// malformed request.
|
|
type ErrBadRequest struct {
|
|
reason string
|
|
}
|
|
|
|
// NewErrNotFound creates a new ErrNotFound instance.
|
|
func NewErrBadRequest(reason string) *ErrBadRequest {
|
|
return &ErrBadRequest{
|
|
reason: reason,
|
|
}
|
|
}
|
|
|
|
func (br *ErrBadRequest) Error() string {
|
|
return br.reason
|
|
}
|
|
|
|
// ErrUnauthorized can be returned when requester has provided an
|
|
// invalid authorization for a given resource or has not provided any.
|
|
type ErrUnauthorized struct {
|
|
reason string
|
|
}
|
|
|
|
// NewErrUnauthorized creates a new ErrUnauthorized instance.
|
|
func NewErrUnauthorized(reason string) *ErrUnauthorized {
|
|
return &ErrUnauthorized{
|
|
reason: reason,
|
|
}
|
|
}
|
|
|
|
func (br *ErrUnauthorized) Error() string {
|
|
return br.reason
|
|
}
|
|
|
|
// ErrPermission can be returned when requester lacks a permission for
|
|
// a given resource.
|
|
type ErrPermission struct {
|
|
reason string
|
|
}
|
|
|
|
// NewErrPermission creates a new ErrPermission instance.
|
|
func NewErrPermission(reason string) *ErrPermission {
|
|
return &ErrPermission{
|
|
reason: reason,
|
|
}
|
|
}
|
|
|
|
func (br *ErrPermission) Error() string {
|
|
return br.reason
|
|
}
|
|
|
|
// ErrForbidden can be returned when requester doesn't have access to
|
|
// a given resource.
|
|
type ErrForbidden struct {
|
|
reason string
|
|
}
|
|
|
|
// NewErrForbidden creates a new ErrForbidden instance.
|
|
func NewErrForbidden(reason string) *ErrForbidden {
|
|
return &ErrForbidden{
|
|
reason: reason,
|
|
}
|
|
}
|
|
|
|
func (br *ErrForbidden) Error() string {
|
|
return br.reason
|
|
}
|
|
|
|
type ErrInvalidCategory struct {
|
|
msg string
|
|
}
|
|
|
|
func NewErrInvalidCategory(msg string) *ErrInvalidCategory {
|
|
return &ErrInvalidCategory{
|
|
msg: msg,
|
|
}
|
|
}
|
|
|
|
func (e *ErrInvalidCategory) Error() string {
|
|
return e.msg
|
|
}
|
|
|
|
type ErrNotImplemented struct {
|
|
msg string
|
|
}
|
|
|
|
func NewErrNotImplemented(msg string) *ErrNotImplemented {
|
|
return &ErrNotImplemented{
|
|
msg: msg,
|
|
}
|
|
}
|
|
|
|
func (ni *ErrNotImplemented) Error() string {
|
|
return ni.msg
|
|
}
|
|
|
|
// IsErrBadRequest returns true if `err` is or wraps one of:
|
|
// - model.ErrBadRequest
|
|
// - model.ErrViewsLimitReached
|
|
// - model.ErrAuthParam
|
|
// - model.ErrInvalidCategory
|
|
// - model.ErrBoardMemberIsLastAdmin
|
|
// - model.ErrBoardIDMismatch.
|
|
func IsErrBadRequest(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
|
|
// check if this is a model.ErrBadRequest
|
|
var br *ErrBadRequest
|
|
if errors.As(err, &br) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrAuthParam
|
|
var ap *ErrAuthParam
|
|
if errors.As(err, &ap) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrViewsLimitReached
|
|
if errors.Is(err, ErrViewsLimitReached) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrInvalidCategory
|
|
var ic *ErrInvalidCategory
|
|
if errors.As(err, &ic) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrBoardIDMismatch
|
|
if errors.Is(err, ErrBoardMemberIsLastAdmin) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrBoardMemberIsLastAdmin
|
|
return errors.Is(err, ErrBoardIDMismatch)
|
|
}
|
|
|
|
// IsErrUnauthorized returns true if `err` is or wraps one of:
|
|
// - model.ErrUnauthorized.
|
|
func IsErrUnauthorized(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
|
|
// check if this is a model.ErrUnauthorized
|
|
var u *ErrUnauthorized
|
|
return errors.As(err, &u)
|
|
}
|
|
|
|
// IsErrForbidden returns true if `err` is or wraps one of:
|
|
// - model.ErrForbidden
|
|
// - model.ErrPermission
|
|
// - model.ErrPatchUpdatesLimitedCards
|
|
// - model.ErrorCategoryPermissionDenied.
|
|
func IsErrForbidden(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
|
|
// check if this is a model.ErrForbidden
|
|
var f *ErrForbidden
|
|
if errors.As(err, &f) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrPermission
|
|
var p *ErrPermission
|
|
if errors.As(err, &p) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrPatchUpdatesLimitedCards
|
|
if errors.Is(err, ErrPatchUpdatesLimitedCards) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrCategoryPermissionDenied
|
|
return errors.Is(err, ErrCategoryPermissionDenied)
|
|
}
|
|
|
|
// IsErrNotFound returns true if `err` is or wraps one of:
|
|
// - model.ErrNotFound
|
|
// - model.ErrNotAllFound
|
|
// - sql.ErrNoRows
|
|
// - mattermost-plugin-api/ErrNotFound.
|
|
// - model.ErrCategoryDeleted.
|
|
func IsErrNotFound(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
|
|
// check if this is a model.ErrNotFound
|
|
var nf *ErrNotFound
|
|
if errors.As(err, &nf) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrNotAllFound
|
|
var naf *ErrNotAllFound
|
|
if errors.As(err, &naf) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a sql.ErrNotFound
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a plugin API error
|
|
if errors.Is(err, pluginapi.ErrNotFound) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a Mattermost AppError with a Not Found status
|
|
var appErr *mmModel.AppError
|
|
if errors.As(err, &appErr) {
|
|
if appErr.StatusCode == http.StatusNotFound {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// check if this is a model.ErrCategoryDeleted
|
|
return errors.Is(err, ErrCategoryDeleted)
|
|
}
|
|
|
|
// IsErrRequestEntityTooLarge returns true if `err` is or wraps one of:
|
|
// - model.ErrRequestEntityTooLarge.
|
|
func IsErrRequestEntityTooLarge(err error) bool {
|
|
// check if this is a model.ErrRequestEntityTooLarge
|
|
return errors.Is(err, ErrRequestEntityTooLarge)
|
|
}
|
|
|
|
// IsErrNotImplemented returns true if `err` is or wraps one of:
|
|
// - model.ErrNotImplemented
|
|
// - model.ErrInsufficientLicense.
|
|
func IsErrNotImplemented(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
|
|
// check if this is a model.ErrNotImplemented
|
|
var eni *ErrNotImplemented
|
|
if errors.As(err, &eni) {
|
|
return true
|
|
}
|
|
|
|
// check if this is a model.ErrInsufficientLicense
|
|
return errors.Is(err, ErrInsufficientLicense)
|
|
}
|