A journey to fix `ValidationError` in Pocket imports turned service layer refactoring :D
90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
# -*- 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
|