diff --git a/solution/api/v1/business/views.py b/solution/api/v1/business/views.py index d39daf4..4cf5e70 100644 --- a/solution/api/v1/business/views.py +++ b/solution/api/v1/business/views.py @@ -23,7 +23,7 @@ router = Router(tags=["business"]) response={ status.OK: schemas.BusinessSignUpOut, status.BAD_REQUEST: global_schemas.BadRequestError, - status.CONFLICT: global_schemas.UniqueConstraintError, + status.CONFLICT: global_schemas.ConflictError, }, ) def signup( @@ -135,6 +135,7 @@ def create_promocode( response={ status.OK: list[schemas.PromocodeViewOut], status.BAD_REQUEST: global_schemas.BadRequestError, + status.UNAUTHORIZED: global_schemas.UnauthorizedError, }, exclude_none=True, ) @@ -188,7 +189,8 @@ def list_promocode( auth=BusinessAuth(), response={ status.OK: schemas.PromocodeViewOut, - status.NOT_FOUND: global_schemas.NotFoundError, + status.BAD_REQUEST: global_schemas.BadRequestError, + status.UNAUTHORIZED: global_schemas.UnauthorizedError, }, exclude_none=True, ) @@ -228,7 +230,8 @@ def get_promocode( auth=BusinessAuth(), response={ status.OK: schemas.PromocodeViewOut, - status.NOT_FOUND: global_schemas.NotFoundError, + status.BAD_REQUEST: global_schemas.BadRequestError, + status.UNAUTHORIZED: global_schemas.UnauthorizedError, }, exclude_none=True, ) @@ -286,7 +289,8 @@ def patch_promocode( auth=BusinessAuth(), response={ status.OK: schemas.PromocodeStats, - status.NOT_FOUND: global_schemas.NotFoundError, + status.BAD_REQUEST: global_schemas.BadRequestError, + status.UNAUTHORIZED: global_schemas.UnauthorizedError, }, exclude_none=True, ) diff --git a/solution/api/v1/handlers.py b/solution/api/v1/handlers.py index ecf07f2..337fe9e 100644 --- a/solution/api/v1/handlers.py +++ b/solution/api/v1/handlers.py @@ -7,14 +7,14 @@ import ninja.errors from django.http import HttpRequest, HttpResponse from ninja import NinjaAPI -from config.errors import UniqueConstraintError +from config.errors import ConflictError logger = logging.getLogger("django") -def handle_unique_constraint_error( +def handle_conflict_error( request: HttpRequest, - exc: UniqueConstraintError, + exc: ConflictError, router: NinjaAPI, ) -> HttpResponse: detail = list(exc.validation_error) @@ -97,7 +97,7 @@ def handle_unknown_exception( exception_handlers = [ - (UniqueConstraintError, handle_unique_constraint_error), + (ConflictError, handle_conflict_error), (django.core.exceptions.ValidationError, handle_django_validation_error), (ninja.errors.AuthenticationError, handle_authentication_error), (ninja.errors.ValidationError, handle_validation_error), diff --git a/solution/api/v1/schemas.py b/solution/api/v1/schemas.py index aab5ba9..c58b291 100644 --- a/solution/api/v1/schemas.py +++ b/solution/api/v1/schemas.py @@ -4,17 +4,21 @@ from typing import Any from ninja import Schema +class BadRequestError(Schema): + detail: Any + + class UnauthorizedError(Schema): detail: str = status.UNAUTHORIZED.phrase +class ForbiddenError(Schema): + detail: str = status.FORBIDDEN.phrase + + class NotFoundError(Schema): detail: str = status.NOT_FOUND.phrase -class BadRequestError(Schema): - detail: Any - - -class UniqueConstraintError(Schema): +class ConflictError(Schema): detail: Any diff --git a/solution/api/v1/user/views.py b/solution/api/v1/user/views.py index b8035aa..2d6d570 100644 --- a/solution/api/v1/user/views.py +++ b/solution/api/v1/user/views.py @@ -16,7 +16,7 @@ from apps.promo.models import ( PromocodeLike, ) from apps.user.models import User -from config.errors import UniqueConstraintError +from config.errors import ConflictError from config.integrations.antifraud.interactor import AntifraudServiceInteractor router = Router(tags=["user"]) @@ -27,7 +27,7 @@ router = Router(tags=["user"]) response={ status.OK: schemas.UserSignUpOut, status.BAD_REQUEST: global_schemas.BadRequestError, - status.CONFLICT: global_schemas.UniqueConstraintError, + status.CONFLICT: global_schemas.ConflictError, }, ) def signup( @@ -216,16 +216,20 @@ def get_activations_history( .order_by("-timestamp") ) - result = [] + promocodes = [] for activation in activations: promocode = activation.promocode promocode.like_count = activation.like_count promocode.comment_count = activation.comment_count promocode.is_liked_by_user = activation.is_liked_by_user promocode.is_activated_by_user = True - result.append(utils.map_promocode_to_schema(promocode)) + promocodes.append(utils.map_promocode_to_schema(promocode)) - return status.OK, result + response["X-Total-Count"] = len(promocodes) + + promocodes = promocodes[filters.offset : filters.offset + filters.limit] + + return status.OK, promocodes @router.get( @@ -292,7 +296,7 @@ def add_like( if not promocodes.exists(): raise HttpError(status.NOT_FOUND, status.NOT_FOUND.phrase) - with contextlib.suppress(UniqueConstraintError): + with contextlib.suppress(ConflictError): PromocodeLike.objects.create(promocode=promocodes.first(), user=user) return status.OK, schemas.PromocodeLikeOut() diff --git a/solution/apps/core/models.py b/solution/apps/core/models.py index 1c522f9..27daed8 100644 --- a/solution/apps/core/models.py +++ b/solution/apps/core/models.py @@ -4,7 +4,7 @@ from typing import Any from django.core.exceptions import ValidationError from django.db import models -from config.errors import UniqueConstraintError +from config.errors import ConflictError class BaseModel(models.Model): @@ -39,10 +39,10 @@ class BaseModel(models.Model): try: self.validate_unique() except ValidationError as e: - raise UniqueConstraintError(e) from None + raise ConflictError(e) from None if validate_constraints: try: self.validate_constraints() except ValidationError as e: - raise UniqueConstraintError(e) from None + raise ConflictError(e) from None diff --git a/solution/config/errors.py b/solution/config/errors.py index 784ea17..afdd2ca 100644 --- a/solution/config/errors.py +++ b/solution/config/errors.py @@ -1,6 +1,6 @@ from django.core.exceptions import ValidationError -class UniqueConstraintError(Exception): +class ConflictError(Exception): def __init__(self, validation_error: ValidationError) -> None: self.validation_error = validation_error diff --git a/solution/config/integrations/antifraud/healthcheck.py b/solution/config/integrations/antifraud/healthcheck.py index 5e63256..4eb84e8 100644 --- a/solution/config/integrations/antifraud/healthcheck.py +++ b/solution/config/integrations/antifraud/healthcheck.py @@ -10,7 +10,9 @@ class AntifraudHealthCheck(BaseHealthCheckBackend): def check_status(self) -> None: try: - response = httpx.get(f"{settings.ANTIFRAUD_ADDRESS}/api/ping") + response = httpx.get( + f"{settings.ANTIFRAUD_ADDRESS}/api/ping", timeout=1 + ) if response.status_code >= status.INTERNAL_SERVER_ERROR: self.add_error("Antifraud service is unaccessible") except httpx.HTTPError: diff --git a/solution/config/integrations/antifraud/interactor.py b/solution/config/integrations/antifraud/interactor.py index 35047ed..131e4f3 100644 --- a/solution/config/integrations/antifraud/interactor.py +++ b/solution/config/integrations/antifraud/interactor.py @@ -100,11 +100,9 @@ class AntifraudServiceInteractor: cache.set(cache_key, result) return result - - except Exception as e: + except Exception: logger.exception( - "Unexpected error during antifraud validation: %s", - e, # noqa: TRY401 + "Unexpected error during antifraud validation", ) return {"ok": False}