BTHLABS-61: Service layer refactoring

A journey to fix `ValidationError` in Pocket imports turned service
layer refactoring :D
This commit is contained in:
2025-10-12 18:37:32 +00:00
parent ac7a8dd90e
commit 8b86145519
45 changed files with 1023 additions and 337 deletions

View File

@@ -0,0 +1,89 @@
# -*- 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