# -*- coding: utf-8 -*- from __future__ import annotations import typing from hotpocket_soa.constants import BackendServiceErrorCode if typing.TYPE_CHECKING: from django.core.exceptions import ValidationError VALIDATION_CODE_INVALID = 'invalid' def get_validation_error_data(validation_error: typing.Any) -> typing.Any: # Heh if hasattr(validation_error, 'error_dict') is True: return { field: [ get_validation_error_data(inner_error) for inner_error in inner_errors ] for field, inner_errors in validation_error.error_dict.items() } elif hasattr(validation_error, 'error_list') is True and len(validation_error.error_list) > 1: return [ get_validation_error_data(inner_error) for inner_error in validation_error.error_list ] elif hasattr(validation_error, 'code') is True: return validation_error.code elif isinstance(validation_error, (tuple, list)) is True: return [ get_validation_error_data(inner_error) for inner_error in validation_error ] elif isinstance(validation_error, dict) is True: return { field: [ get_validation_error_data(inner_error) for inner_error in inner_errors ] for field, inner_errors in validation_error.items() } else: return VALIDATION_CODE_INVALID class BackendServiceError(Exception): CODE = BackendServiceErrorCode.INTERNAL def __init__(self, message: str, *args): super().__init__(message, *args) self.message = message self.data: typing.Any = None if len(args) > 0: self.data = args[0] class InternalError(BackendServiceError): pass class NotFound(BackendServiceError): CODE = BackendServiceErrorCode.NOT_FOUND class AccessDenied(BackendServiceError): CODE = BackendServiceErrorCode.ACCESS_DENIED class Invalid(BackendServiceError): CODE = BackendServiceErrorCode.INVALID @classmethod def from_django_validation_error(cls: type[typing.Self], exception: ValidationError, message: str | None = None, ) -> typing.Self: data = get_validation_error_data(exception) result = cls(message or 'Invalid', data) result.__cause__ = exception return result