You've already forked hotpocket
BTHLABS-61: Service layer refactoring
A journey to fix `ValidationError` in Pocket imports turned service layer refactoring :D
This commit is contained in:
11
services/packages/soa/hotpocket_soa/constants.py
Normal file
11
services/packages/soa/hotpocket_soa/constants.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
|
||||
|
||||
class BackendServiceErrorCode(enum.Enum):
|
||||
INTERNAL = -32000
|
||||
NOT_FOUND = -32001
|
||||
ACCESS_DENIED = -32002
|
||||
INVALID = -32003
|
||||
89
services/packages/soa/hotpocket_soa/exceptions/backend.py
Normal file
89
services/packages/soa/hotpocket_soa/exceptions/backend.py
Normal 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
|
||||
28
services/packages/soa/hotpocket_soa/exceptions/frontend.py
Normal file
28
services/packages/soa/hotpocket_soa/exceptions/frontend.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import typing
|
||||
|
||||
from .backend import BackendServiceError
|
||||
|
||||
|
||||
class SOAError(Exception):
|
||||
def __init__(self, code: int, message: str, *args):
|
||||
super().__init__(code, message, *args)
|
||||
self.code = code
|
||||
self.message = message
|
||||
|
||||
self.data: typing.Any = None
|
||||
if len(args) > 0:
|
||||
self.data = args[0]
|
||||
|
||||
@classmethod
|
||||
def from_backend_error(cls: type[typing.Self], exception: BackendServiceError) -> typing.Self:
|
||||
result = cls(
|
||||
exception.CODE.value,
|
||||
exception.message,
|
||||
exception.data,
|
||||
)
|
||||
result.__cause__ = exception
|
||||
|
||||
return result
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import http
|
||||
import uuid
|
||||
|
||||
from hotpocket_backend.apps.accounts.services import (
|
||||
@@ -11,6 +12,7 @@ from hotpocket_soa.dto.accounts import (
|
||||
AccessTokenOut,
|
||||
AccessTokensQuery,
|
||||
)
|
||||
from hotpocket_soa.exceptions.backend import NotFound
|
||||
|
||||
from .base import ProxyService, SOAError
|
||||
|
||||
@@ -19,22 +21,18 @@ class AccessTokensService(ProxyService):
|
||||
class AccessTokensServiceError(SOAError):
|
||||
pass
|
||||
|
||||
class AccessTokenNotFound(AccessTokensServiceError):
|
||||
class NotFound(AccessTokensServiceError):
|
||||
pass
|
||||
|
||||
class AccessTokenAccessDenied(AccessTokensServiceError):
|
||||
class AccessDenied(AccessTokensServiceError):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.backend_access_tokens_service = BackendAccessTokensService()
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.AccessTokensServiceError(*new_exception_args)
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return self.AccessTokensServiceError
|
||||
|
||||
def create(self,
|
||||
*,
|
||||
@@ -69,16 +67,14 @@ class AccessTokensService(ProxyService):
|
||||
)
|
||||
|
||||
if result.account_uuid != account_uuid:
|
||||
raise self.AccessTokenAccessDenied(
|
||||
raise self.AccessDenied(
|
||||
http.HTTPStatus.FORBIDDEN.value,
|
||||
f'account_uuid=`{account_uuid}` pk=`{pk}`',
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendAccessTokensService.AccessTokenNotFound) is True:
|
||||
raise self.AccessTokenNotFound(*exception.args) from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def get_by_key(self,
|
||||
*,
|
||||
@@ -96,16 +92,14 @@ class AccessTokensService(ProxyService):
|
||||
)
|
||||
|
||||
if result.account_uuid != account_uuid:
|
||||
raise self.AccessTokenAccessDenied(
|
||||
raise self.AccessDenied(
|
||||
http.HTTPStatus.FORBIDDEN.value,
|
||||
f'account_uuid=`{account_uuid}` key=`{key}`',
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendAccessTokensService.AccessTokenNotFound) is True:
|
||||
raise self.AccessTokenNotFound(f'account_uuid=`{account_uuid}` pk=`{key}`') from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def search(self,
|
||||
*,
|
||||
@@ -124,23 +118,29 @@ class AccessTokensService(ProxyService):
|
||||
]
|
||||
|
||||
def delete(self, *, access_token: AccessTokenOut) -> bool:
|
||||
return self.call(
|
||||
self.backend_access_tokens_service,
|
||||
'delete',
|
||||
pk=access_token.pk,
|
||||
)
|
||||
try:
|
||||
return self.call(
|
||||
self.backend_access_tokens_service,
|
||||
'delete',
|
||||
pk=access_token.pk,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def update_meta(self,
|
||||
*,
|
||||
access_token: AccessTokenOut,
|
||||
update: AccessTokenMetaUpdateIn,
|
||||
) -> AccessTokenOut:
|
||||
return AccessTokenOut.model_validate(
|
||||
self.call(
|
||||
self.backend_access_tokens_service,
|
||||
'update_meta',
|
||||
pk=access_token.pk,
|
||||
update=update,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
try:
|
||||
return AccessTokenOut.model_validate(
|
||||
self.call(
|
||||
self.backend_access_tokens_service,
|
||||
'update_meta',
|
||||
pk=access_token.pk,
|
||||
update=update,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
@@ -7,6 +7,7 @@ from hotpocket_backend.apps.accounts.services import (
|
||||
AccountsService as BackendAccountsService,
|
||||
)
|
||||
from hotpocket_soa.dto.accounts import AccountOut
|
||||
from hotpocket_soa.exceptions.backend import NotFound
|
||||
|
||||
from .base import ProxyService, SOAError
|
||||
|
||||
@@ -15,19 +16,15 @@ class AccountsService(ProxyService):
|
||||
class AccountsServiceError(SOAError):
|
||||
pass
|
||||
|
||||
class AccountNotFound(AccountsServiceError):
|
||||
class NotFound(AccountsServiceError):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.backend_accounts_service = BackendAccountsService()
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.AccountsServiceError(*new_exception_args)
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return self.AccountsServiceError
|
||||
|
||||
def get(self, *, pk: uuid.UUID) -> AccountOut:
|
||||
try:
|
||||
@@ -41,8 +38,5 @@ class AccountsService(ProxyService):
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendAccountsService.AccountNotFound) is True:
|
||||
raise self.AccountNotFound(*exception.args) from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import http
|
||||
import uuid
|
||||
|
||||
from hotpocket_backend.apps.saves.services import (
|
||||
@@ -14,6 +15,7 @@ from hotpocket_soa.dto.associations import (
|
||||
AssociationWithTargetOut,
|
||||
)
|
||||
from hotpocket_soa.dto.saves import SaveOut
|
||||
from hotpocket_soa.exceptions.backend import NotFound
|
||||
|
||||
from .base import ProxyService, SOAError
|
||||
|
||||
@@ -22,22 +24,18 @@ class AssociationsService(ProxyService):
|
||||
class AssociationsServiceError(SOAError):
|
||||
pass
|
||||
|
||||
class AssociationNotFound(AssociationsServiceError):
|
||||
class NotFound(AssociationsServiceError):
|
||||
pass
|
||||
|
||||
class AssociationAccessDenied(AssociationsServiceError):
|
||||
class AccessDenied(AssociationsServiceError):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.backend_associations_service = BackendAssociationsService()
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.AssociationsServiceError(*new_exception_args)
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return self.AssociationsServiceError
|
||||
|
||||
def create(self,
|
||||
*,
|
||||
@@ -81,19 +79,19 @@ class AssociationsService(ProxyService):
|
||||
)
|
||||
|
||||
if allow_archived is False and result.archived_at is not None:
|
||||
raise self.AssociationNotFound(f'pk=`{pk}`')
|
||||
raise self.NotFound(
|
||||
http.HTTPStatus.NOT_FOUND.value, f'pk=`{pk}`',
|
||||
)
|
||||
|
||||
if account_uuid is not None and result.account_uuid != account_uuid:
|
||||
raise self.AssociationAccessDenied(
|
||||
raise self.AccessDenied(
|
||||
http.HTTPStatus.FORBIDDEN.value,
|
||||
f'account_uuid=`{account_uuid}` pk=`{pk}`',
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendAssociationsService.AssociationNotFound) is True:
|
||||
raise self.AssociationNotFound(*exception.args) from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def search(self,
|
||||
*,
|
||||
@@ -112,50 +110,65 @@ class AssociationsService(ProxyService):
|
||||
]
|
||||
|
||||
def archive(self, *, association: AssociationOut) -> bool:
|
||||
return self.call(
|
||||
self.backend_associations_service,
|
||||
'archive',
|
||||
pk=association.pk,
|
||||
)
|
||||
try:
|
||||
return self.call(
|
||||
self.backend_associations_service,
|
||||
'archive',
|
||||
pk=association.pk,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def star(self, *, association: AssociationOut) -> AssociationOut:
|
||||
return AssociationOut.model_validate(
|
||||
self.call(
|
||||
self.backend_associations_service,
|
||||
'star',
|
||||
pk=association.pk,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
try:
|
||||
return AssociationOut.model_validate(
|
||||
self.call(
|
||||
self.backend_associations_service,
|
||||
'star',
|
||||
pk=association.pk,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def unstar(self, *, association: AssociationOut) -> AssociationOut:
|
||||
return AssociationOut.model_validate(
|
||||
self.call(
|
||||
self.backend_associations_service,
|
||||
'unstar',
|
||||
pk=association.pk,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
try:
|
||||
return AssociationOut.model_validate(
|
||||
self.call(
|
||||
self.backend_associations_service,
|
||||
'unstar',
|
||||
pk=association.pk,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def update(self,
|
||||
*,
|
||||
association: AssociationOut,
|
||||
update: AssociationUpdateIn,
|
||||
) -> AssociationOut:
|
||||
return AssociationOut.model_validate(
|
||||
self.call(
|
||||
self.backend_associations_service,
|
||||
'update',
|
||||
pk=association.pk,
|
||||
update=update,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
try:
|
||||
return AssociationOut.model_validate(
|
||||
self.call(
|
||||
self.backend_associations_service,
|
||||
'update',
|
||||
pk=association.pk,
|
||||
update=update,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def delete(self, *, association: AssociationOut) -> bool:
|
||||
return self.call(
|
||||
self.backend_associations_service,
|
||||
'delete',
|
||||
pk=association.pk,
|
||||
)
|
||||
try:
|
||||
return self.call(
|
||||
self.backend_associations_service,
|
||||
'delete',
|
||||
pk=association.pk,
|
||||
)
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import http
|
||||
import uuid
|
||||
|
||||
from hotpocket_backend.apps.accounts.services import (
|
||||
AuthKeysService as BackendAuthKeysService,
|
||||
)
|
||||
from hotpocket_soa.dto.accounts import AuthKeyOut
|
||||
from hotpocket_soa.exceptions.backend import NotFound
|
||||
|
||||
from .base import ProxyService, SOAError
|
||||
|
||||
@@ -15,23 +17,16 @@ class AuthKeysService(ProxyService):
|
||||
class AuthKeysServiceError(SOAError):
|
||||
pass
|
||||
|
||||
class AuthKeyNotFound(AuthKeysServiceError):
|
||||
class NotFound(AuthKeysServiceError):
|
||||
pass
|
||||
|
||||
class AuthKeyAccessDenied(AuthKeysServiceError):
|
||||
class AccessDenied(AuthKeysServiceError):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.backend_auth_keys_service = BackendAuthKeysService()
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.AuthKeysServiceError(*new_exception_args)
|
||||
|
||||
def _check_auth_key_access(self,
|
||||
auth_key: AuthKeyOut,
|
||||
account_uuid: uuid.UUID | None,
|
||||
@@ -70,16 +65,14 @@ class AuthKeysService(ProxyService):
|
||||
)
|
||||
|
||||
if self._check_auth_key_access(result, account_uuid) is False:
|
||||
raise self.AuthKeyAccessDenied(
|
||||
raise self.AccessDenied(
|
||||
http.HTTPStatus.FORBIDDEN.value,
|
||||
f'account_uuid=`{account_uuid}` pk=`{pk}`',
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendAuthKeysService.AuthKeyNotFound) is True:
|
||||
raise self.AuthKeyNotFound(*exception.args) from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
def get_by_key(self,
|
||||
*,
|
||||
@@ -97,13 +90,11 @@ class AuthKeysService(ProxyService):
|
||||
)
|
||||
|
||||
if self._check_auth_key_access(result, account_uuid) is False:
|
||||
raise self.AuthKeyAccessDenied(
|
||||
raise self.AccessDenied(
|
||||
http.HTTPStatus.FORBIDDEN.value,
|
||||
f'account_uuid=`{account_uuid}` key=`{key}`',
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendAuthKeysService.AuthKeyNotFound) is True:
|
||||
raise self.AuthKeyNotFound(*exception.args) from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
@@ -1,16 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import http
|
||||
import types
|
||||
import typing
|
||||
|
||||
|
||||
class SOAError(Exception):
|
||||
pass
|
||||
from hotpocket_soa.exceptions.backend import BackendServiceError
|
||||
from hotpocket_soa.exceptions.frontend import SOAError
|
||||
|
||||
|
||||
class Service:
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
return SOAError(exception.args[0])
|
||||
def __getattribute__(self, name: str) -> typing.Any:
|
||||
result = super().__getattribute__(name)
|
||||
|
||||
is_service_method = all((
|
||||
name.startswith('_') is False,
|
||||
hasattr(Service, name) is False,
|
||||
isinstance(result, types.MethodType),
|
||||
getattr(result, '__self__', None) is self,
|
||||
))
|
||||
if is_service_method is True:
|
||||
@functools.wraps(result)
|
||||
def wrapped_result(*args, **kwargs):
|
||||
try:
|
||||
return result(*args, **kwargs)
|
||||
except Exception as exception:
|
||||
raise self.wrap_exception(exception) from exception
|
||||
|
||||
return wrapped_result
|
||||
|
||||
return result
|
||||
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return SOAError
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> SOAError:
|
||||
error_class = self.get_error_class()
|
||||
|
||||
if isinstance(exception, error_class) is True:
|
||||
return typing.cast(SOAError, exception)
|
||||
|
||||
result = error_class(
|
||||
http.HTTPStatus.IM_A_TEAPOT.value,
|
||||
'SOA Error',
|
||||
*exception.args,
|
||||
)
|
||||
|
||||
if isinstance(exception, BackendServiceError) is True:
|
||||
baskend_error = typing.cast(BackendServiceError, exception)
|
||||
result = error_class(
|
||||
baskend_error.CODE.value,
|
||||
baskend_error.message,
|
||||
baskend_error.data,
|
||||
*baskend_error.args,
|
||||
)
|
||||
|
||||
result.__cause__ = exception
|
||||
return result
|
||||
|
||||
def call(self, *args, **kwargs) -> typing.Any:
|
||||
raise NotImplementedError('TODO')
|
||||
|
||||
|
||||
class ProxyService(Service):
|
||||
@@ -18,7 +68,4 @@ class ProxyService(Service):
|
||||
handler = getattr(service, method, None)
|
||||
assert handler is not None, f'Unknown method: method=`{method}`'
|
||||
|
||||
try:
|
||||
return handler(*args, **kwargs)
|
||||
except Exception as exception:
|
||||
raise self.wrap_exception(exception) from exception
|
||||
return handler(*args, **kwargs)
|
||||
|
||||
@@ -15,12 +15,8 @@ class BotService(ProxyService):
|
||||
super().__init__()
|
||||
self.backend_associations_service = BackendBotService()
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.BotServiceError(*new_exception_args)
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return self.BotServiceError
|
||||
|
||||
def is_netloc_banned(self, *, url: str) -> bool:
|
||||
return self.call(
|
||||
|
||||
@@ -18,17 +18,13 @@ class SaveProcessorService(ProxyService):
|
||||
class SaveProcessorServiceError(SOAError):
|
||||
pass
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.SaveProcessorServiceError(*new_exception_args)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.backend_save_processor_service = BackendSaveProcessorService()
|
||||
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return self.SaveProcessorServiceError
|
||||
|
||||
def schedule_process_save(self, *, save: SaveOut) -> AsyncResultOut:
|
||||
result = AsyncResultOut.model_validate(
|
||||
self.call(
|
||||
|
||||
@@ -7,6 +7,7 @@ from hotpocket_backend.apps.saves.services import (
|
||||
SavesService as BackendSavesService,
|
||||
)
|
||||
from hotpocket_soa.dto.saves import SaveIn, SaveOut
|
||||
from hotpocket_soa.exceptions.backend import Invalid, NotFound
|
||||
|
||||
from .base import ProxyService, SOAError
|
||||
|
||||
@@ -15,30 +16,34 @@ class SavesService(ProxyService):
|
||||
class SavesServiceError(SOAError):
|
||||
pass
|
||||
|
||||
class SaveNotFound(SavesServiceError):
|
||||
class NotFound(SavesServiceError):
|
||||
pass
|
||||
|
||||
def wrap_exception(self, exception: Exception) -> Exception:
|
||||
new_exception_args = []
|
||||
if len(exception.args) > 0:
|
||||
new_exception_args = [exception.args[0]]
|
||||
|
||||
return self.SavesServiceError(*new_exception_args)
|
||||
class Invalid(SavesServiceError):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.backend_saves_service = BackendSavesService()
|
||||
|
||||
def get_error_class(self) -> type[SOAError]:
|
||||
return self.SavesServiceError
|
||||
|
||||
def create(self, *, account_uuid: uuid.UUID, save: SaveIn) -> SaveOut:
|
||||
return SaveOut.model_validate(
|
||||
self.call(
|
||||
self.backend_saves_service,
|
||||
'create',
|
||||
account_uuid=account_uuid,
|
||||
save=save,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
try:
|
||||
return SaveOut.model_validate(
|
||||
self.call(
|
||||
self.backend_saves_service,
|
||||
'create',
|
||||
account_uuid=account_uuid,
|
||||
save=save,
|
||||
),
|
||||
from_attributes=True,
|
||||
)
|
||||
except Invalid as exception:
|
||||
raise self.Invalid(
|
||||
exception.CODE.value, exception.message, exception.data,
|
||||
)
|
||||
|
||||
def get(self, *, pk: uuid.UUID) -> SaveOut:
|
||||
try:
|
||||
@@ -52,8 +57,5 @@ class SavesService(ProxyService):
|
||||
)
|
||||
|
||||
return result
|
||||
except SOAError as exception:
|
||||
if isinstance(exception.__cause__, BackendSavesService.SaveNotFound) is True:
|
||||
raise self.SaveNotFound(*exception.args) from exception
|
||||
else:
|
||||
raise
|
||||
except NotFound as exception:
|
||||
raise self.NotFound.from_backend_error(exception)
|
||||
|
||||
Reference in New Issue
Block a user