Files
b2b/app/utils/responseErrors/responseErrors.go
2026-04-14 15:42:30 +02:00

330 lines
14 KiB
Go

package responseErrors
import (
"errors"
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
"github.com/gofiber/fiber/v3"
)
var (
// Typed errors for request validation and authentication
ErrForbidden = errors.New("forbidden")
ErrInvalidBody = errors.New("invalid request body")
ErrNotAuthenticated = errors.New("not authenticated")
ErrUserNotFound = errors.New("user not found")
ErrUserInactive = errors.New("user account is inactive")
ErrInvalidToken = errors.New("invalid token")
ErrTokenExpired = errors.New("token has expired")
ErrTokenRequired = errors.New("token is required")
ErrAdminAccessRequired = errors.New("admin access required")
// Typed errors for logging in and registering
ErrInvalidCredentials = errors.New("invalid email or password")
ErrEmailNotVerified = errors.New("email not verified")
ErrEmailExists = errors.New("email already exists")
ErrFirstLastNameRequired = errors.New("first and last name is required")
ErrEmailRequired = errors.New("email is required")
ErrEmailPasswordRequired = errors.New("email and password are required")
ErrRefreshTokenRequired = errors.New("refresh token is required")
ErrBadLangID = errors.New("bad language id")
ErrBadCountryID = errors.New("bad country id")
// Typed errors for password reset
ErrInvalidResetToken = errors.New("invalid reset token")
ErrResetTokenExpired = errors.New("reset token has expired")
ErrPasswordsDoNotMatch = errors.New("passwords do not match")
ErrInvalidPassword = errors.New("password must be at least 8 characters long and contain at least one lowercase letter, one uppercase letter, and one digit")
ErrTokenPasswordRequired = errors.New("token and password are required")
// Typed errors for verification
ErrInvalidVerificationToken = errors.New("invalid verification token")
ErrVerificationTokenExpired = errors.New("verification token has expired")
// Typed errors for product description handler
ErrBadAttribute = errors.New("bad or missing attribute value in header")
ErrBadField = errors.New("this field can not be updated")
ErrInvalidURLSlug = errors.New("URL slug does not obey the industry standard")
ErrInvalidXHTML = errors.New("text is not in xhtml format")
ErrAIResponseFail = errors.New("AI responded with failure")
ErrAIBadOutput = errors.New("AI response does not obey the format")
// Typed errors for product handler
ErrBadPaging = errors.New("bad or missing paging attribute value in header")
ErrProductNotFound = errors.New("product with provided id does not exist")
ErrAlreadyInFavorites = errors.New("the product already is in your favorites")
ErrNotInFavorites = errors.New("the product already is not in your favorites")
// Typed errors for menu handler
ErrNoRootFound = errors.New("no root found in categories table")
ErrCircularDependency = errors.New("circular dependency structure in tree (could be caused by improper root id)")
ErrStartCategoryNotFound = errors.New("the start category has not been found")
ErrRootNeverReached = errors.New("the root category is not an ancestor of start category")
// Typed errors for carts handler
ErrMaxAmtOfCartsReached = errors.New("maximal amount of carts reached")
ErrUserHasNoSuchCart = errors.New("user does not have cart with given id")
ErrProductOrItsVariationDoesNotExist = errors.New("product or its variation with given ids does not exist")
ErrAmountMustBePositive = errors.New("amount must be positive")
ErrAmountMustBeReasonable = errors.New("amount must be reasonable")
// Typed errors for orders handler
ErrEmptyCart = errors.New("the cart is empty")
ErrUserHasNoSuchOrder = errors.New("user does not have order with given id")
// Typed errors for price reduction handler
ErrInvalidReductionType = errors.New("invalid reduction type: must be 'amount' or 'percentage'")
ErrPercentageRequired = errors.New("percentage_reduction required when reduction_type is percentage")
ErrPriceRequired = errors.New("price required when reduction_type is amount")
ErrSpecificPriceNotFound = errors.New("price reduction not found")
// Typed errors for storage
ErrAccessDenied = errors.New("access denied!")
ErrFolderDoesNotExist = errors.New("folder does not exist")
ErrFileDoesNotExist = errors.New("file does not exist")
ErrNameTaken = errors.New("name taken")
ErrMissingFileFieldDocument = errors.New("missing file field 'document'")
// Typed errors for data parsing
ErrJSONBody = errors.New("invalid JSON body")
// Typed errors for addresses
ErrMaxAmtOfAddressesReached = errors.New("maximal amount of addresses per user reached")
ErrUserHasNoSuchAddress = errors.New("user has no such address")
ErrInvalidCountryID = errors.New("invalid country id")
ErrInvalidAddressJSON = errors.New("invalid address json")
)
// Error represents an error with HTTP status code
type Error struct {
Err error
Status int
}
func (e *Error) Error() string {
return e.Err.Error()
}
func (e *Error) Unwrap() error {
return e.Err
}
// NewError creates a new typed error
func NewError(err error, status int) *Error {
return &Error{Err: err, Status: status}
}
// GetErrorCode returns the error code string for HTTP response mapping
func GetErrorCode(c fiber.Ctx, err error) string {
switch {
case errors.Is(err, ErrForbidden):
return i18n.T_(c, "error.err_forbidden")
case errors.Is(err, ErrInvalidBody):
return i18n.T_(c, "error.err_invalid_body")
case errors.Is(err, ErrInvalidCredentials):
return i18n.T_(c, "error.err_invalid_credentials")
case errors.Is(err, ErrNotAuthenticated):
return i18n.T_(c, "error.err_not_authenticated")
case errors.Is(err, ErrUserNotFound):
return i18n.T_(c, "error.err_user_not_found")
case errors.Is(err, ErrUserInactive):
return i18n.T_(c, "error.err_user_inactive")
case errors.Is(err, ErrEmailNotVerified):
return i18n.T_(c, "error.err_email_not_verified")
case errors.Is(err, ErrEmailExists):
return i18n.T_(c, "error.err_email_exists")
case errors.Is(err, ErrInvalidToken):
return i18n.T_(c, "error.err_invalid_token")
case errors.Is(err, ErrTokenExpired):
return i18n.T_(c, "error.err_token_expired")
case errors.Is(err, ErrFirstLastNameRequired):
return i18n.T_(c, "error.err_first_last_name_required")
case errors.Is(err, ErrEmailRequired):
return i18n.T_(c, "error.err_email_required")
case errors.Is(err, ErrEmailPasswordRequired):
return i18n.T_(c, "error.err_email_password_required")
case errors.Is(err, ErrTokenRequired):
return i18n.T_(c, "error.err_token_required")
case errors.Is(err, ErrRefreshTokenRequired):
return i18n.T_(c, "error.err_refresh_token_required")
case errors.Is(err, ErrAdminAccessRequired):
return i18n.T_(c, "error.err_admin_access_required")
case errors.Is(err, ErrBadLangID):
return i18n.T_(c, "error.err_bad_lang_id")
case errors.Is(err, ErrBadCountryID):
return i18n.T_(c, "error.err_bad_country_id")
case errors.Is(err, ErrInvalidResetToken):
return i18n.T_(c, "error.err_invalid_reset_token")
case errors.Is(err, ErrResetTokenExpired):
return i18n.T_(c, "error.err_reset_token_expired")
case errors.Is(err, ErrPasswordsDoNotMatch):
return i18n.T_(c, "error.err_passwords_do_not_match")
case errors.Is(err, ErrInvalidPassword):
return i18n.T_(c, "error.err_invalid_password")
case errors.Is(err, ErrTokenPasswordRequired):
return i18n.T_(c, "error.err_token_password_required")
case errors.Is(err, ErrInvalidVerificationToken):
return i18n.T_(c, "error.err_invalid_verification_token")
case errors.Is(err, ErrVerificationTokenExpired):
return i18n.T_(c, "error.err_verification_token_expired")
case errors.Is(err, ErrBadAttribute):
return i18n.T_(c, "error.err_bad_attribute")
case errors.Is(err, ErrBadField):
return i18n.T_(c, "error.err_bad_field")
case errors.Is(err, ErrInvalidURLSlug):
return i18n.T_(c, "error.err_invalid_url_slug")
case errors.Is(err, ErrInvalidXHTML):
return i18n.T_(c, "error.err_invalid_html")
case errors.Is(err, ErrAIResponseFail):
return i18n.T_(c, "error.err_ai_response_fail")
case errors.Is(err, ErrAIBadOutput):
return i18n.T_(c, "error.err_ai_bad_output")
case errors.Is(err, ErrBadPaging):
return i18n.T_(c, "error.err_bad_paging")
case errors.Is(err, ErrProductNotFound):
return i18n.T_(c, "error.err_product_not_found")
case errors.Is(err, ErrAlreadyInFavorites):
return i18n.T_(c, "error.err_already_in_favorites")
case errors.Is(err, ErrNotInFavorites):
return i18n.T_(c, "error.err_already_not_in_favorites")
case errors.Is(err, ErrNoRootFound):
return i18n.T_(c, "error.err_no_root_found")
case errors.Is(err, ErrCircularDependency):
return i18n.T_(c, "error.err_circular_dependency")
case errors.Is(err, ErrStartCategoryNotFound):
return i18n.T_(c, "error.err_start_category_not_found")
case errors.Is(err, ErrRootNeverReached):
return i18n.T_(c, "error.err_root_never_reached")
case errors.Is(err, ErrMaxAmtOfCartsReached):
return i18n.T_(c, "error.err_max_amt_of_carts_reached")
case errors.Is(err, ErrUserHasNoSuchCart):
return i18n.T_(c, "error.err_user_has_no_such_cart")
case errors.Is(err, ErrProductOrItsVariationDoesNotExist):
return i18n.T_(c, "error.err_product_or_its_variation_does_not_exist")
case errors.Is(err, ErrAmountMustBePositive):
return i18n.T_(c, "error.err_amount_must_be_positive")
case errors.Is(err, ErrAmountMustBeReasonable):
return i18n.T_(c, "error.err_amount_must_be_reasonable")
case errors.Is(err, ErrEmptyCart):
return i18n.T_(c, "error.err_cart_is_empty")
case errors.Is(err, ErrUserHasNoSuchOrder):
return i18n.T_(c, "error.err_user_has_no_such_order")
case errors.Is(err, ErrAccessDenied):
return i18n.T_(c, "error.err_access_denied")
case errors.Is(err, ErrFolderDoesNotExist):
return i18n.T_(c, "error.err_folder_does_not_exist")
case errors.Is(err, ErrFileDoesNotExist):
return i18n.T_(c, "error.err_file_does_not_exist")
case errors.Is(err, ErrNameTaken):
return i18n.T_(c, "error.err_name_taken")
case errors.Is(err, ErrMissingFileFieldDocument):
return i18n.T_(c, "error.err_missing_file_field_document")
case errors.Is(err, ErrInvalidReductionType):
return i18n.T_(c, "error.invalid_reduction_type")
case errors.Is(err, ErrPercentageRequired):
return i18n.T_(c, "error.percentage_required")
case errors.Is(err, ErrPriceRequired):
return i18n.T_(c, "error.price_required")
case errors.Is(err, ErrSpecificPriceNotFound):
return i18n.T_(c, "error.price_reduction_not_found")
case errors.Is(err, ErrJSONBody):
return i18n.T_(c, "error.err_json_body")
case errors.Is(err, ErrMaxAmtOfAddressesReached):
return i18n.T_(c, "error.err_max_amt_of_addresses_reached")
case errors.Is(err, ErrUserHasNoSuchAddress):
return i18n.T_(c, "error.err_user_has_no_such_address")
case errors.Is(err, ErrInvalidCountryID):
return i18n.T_(c, "error.err_invalid_country_id")
case errors.Is(err, ErrInvalidAddressJSON):
return i18n.T_(c, "error.err_invalid_address_json")
default:
return i18n.T_(c, "error.err_internal_server_error")
}
}
// GetErrorStatus returns the HTTP status code for the given error
func GetErrorStatus(err error) int {
switch {
case errors.Is(err, ErrForbidden):
return fiber.StatusForbidden
case errors.Is(err, ErrInvalidCredentials),
errors.Is(err, ErrNotAuthenticated),
errors.Is(err, ErrInvalidToken),
errors.Is(err, ErrTokenExpired):
return fiber.StatusUnauthorized
case errors.Is(err, ErrInvalidBody),
errors.Is(err, ErrUserNotFound),
errors.Is(err, ErrUserInactive),
errors.Is(err, ErrEmailNotVerified),
errors.Is(err, ErrFirstLastNameRequired),
errors.Is(err, ErrEmailRequired),
errors.Is(err, ErrEmailPasswordRequired),
errors.Is(err, ErrTokenRequired),
errors.Is(err, ErrRefreshTokenRequired),
errors.Is(err, ErrAdminAccessRequired),
errors.Is(err, ErrBadLangID),
errors.Is(err, ErrBadCountryID),
errors.Is(err, ErrPasswordsDoNotMatch),
errors.Is(err, ErrTokenPasswordRequired),
errors.Is(err, ErrInvalidResetToken),
errors.Is(err, ErrResetTokenExpired),
errors.Is(err, ErrInvalidVerificationToken),
errors.Is(err, ErrVerificationTokenExpired),
errors.Is(err, ErrInvalidPassword),
errors.Is(err, ErrBadAttribute),
errors.Is(err, ErrBadField),
errors.Is(err, ErrInvalidURLSlug),
errors.Is(err, ErrInvalidXHTML),
errors.Is(err, ErrBadPaging),
errors.Is(err, ErrProductNotFound),
errors.Is(err, ErrAlreadyInFavorites),
errors.Is(err, ErrNotInFavorites),
errors.Is(err, ErrNoRootFound),
errors.Is(err, ErrCircularDependency),
errors.Is(err, ErrStartCategoryNotFound),
errors.Is(err, ErrRootNeverReached),
errors.Is(err, ErrMaxAmtOfCartsReached),
errors.Is(err, ErrUserHasNoSuchCart),
errors.Is(err, ErrProductOrItsVariationDoesNotExist),
errors.Is(err, ErrAmountMustBePositive),
errors.Is(err, ErrAmountMustBeReasonable),
errors.Is(err, ErrEmptyCart),
errors.Is(err, ErrUserHasNoSuchOrder),
errors.Is(err, ErrInvalidReductionType),
errors.Is(err, ErrPercentageRequired),
errors.Is(err, ErrPriceRequired),
errors.Is(err, ErrAccessDenied),
errors.Is(err, ErrFolderDoesNotExist),
errors.Is(err, ErrFileDoesNotExist),
errors.Is(err, ErrNameTaken),
errors.Is(err, ErrMissingFileFieldDocument),
errors.Is(err, ErrJSONBody),
errors.Is(err, ErrMaxAmtOfAddressesReached),
errors.Is(err, ErrUserHasNoSuchAddress),
errors.Is(err, ErrInvalidCountryID),
errors.Is(err, ErrInvalidAddressJSON):
return fiber.StatusBadRequest
case errors.Is(err, ErrSpecificPriceNotFound):
return fiber.StatusNotFound
case errors.Is(err, ErrEmailExists):
return fiber.StatusConflict
case errors.Is(err, ErrAIResponseFail),
errors.Is(err, ErrAIBadOutput):
return fiber.StatusServiceUnavailable
default:
return fiber.StatusInternalServerError
}
}