From 98214393a63d07a0ed564da8c185ec9913eda7b6 Mon Sep 17 00:00:00 2001 From: straitz Date: Wed, 3 Jun 2026 05:55:39 +0900 Subject: [PATCH] fix APIError signature and DELETE body for dmr 0.6.0 --- stratoflights_api/pagination.py | 2 +- stratoflights_api/views.py | 39 ++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/stratoflights_api/pagination.py b/stratoflights_api/pagination.py index 797ac58..6f1fbaf 100644 --- a/stratoflights_api/pagination.py +++ b/stratoflights_api/pagination.py @@ -81,7 +81,7 @@ def page_number_paginate(request, queryset, page_size: int = PAGE_SIZE): try: page = paginator.page(page_number) except InvalidPage: - raise APIError(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Invalid page.'}) + raise APIError({'detail': 'Invalid page.'}, status_code=HTTPStatus.NOT_FOUND) url = request.build_absolute_uri() diff --git a/stratoflights_api/views.py b/stratoflights_api/views.py index 6f1d8b8..7de0cf3 100644 --- a/stratoflights_api/views.py +++ b/stratoflights_api/views.py @@ -56,6 +56,15 @@ from .validators import base64_to_curve User = get_user_model() +def _api_error(status_code, body, headers=None): + """Adapter for DMR's APIError(raw_data, *, status_code, ...) signature. + + Lets call sites keep the (status_code=, body=) style; the body is DMR's + first positional ``raw_data`` argument. + """ + return APIError(body, status_code=status_code, headers=headers) + + def _resolve_related(model, pk, field_name): """Resolve a related object by PK (was PrimaryKeyRelatedField(queryset=...)). @@ -66,7 +75,7 @@ def _resolve_related(model, pk, field_name): return None obj = model.objects.filter(pk=pk).first() if obj is None: - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={field_name: [f'Invalid pk "{pk}" - object does not exist.']}, ) @@ -92,7 +101,7 @@ class PredictionCollectionController(Controller[PydanticSerializer]): try: prediction_result = TawhiriClient.get_prediction(parsed_body.model_dump()) except requests.RequestException as exc: - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_GATEWAY, body={'error': f'Tawhiri error: {str(exc)}'}, ) @@ -135,7 +144,7 @@ class PredictionListUserController(Controller[PydanticSerializer]): filters['created_at__lte'] = parse_datetime(parsed_query.created_till) if parsed_query.satellite_id: if not user.satellites.filter(id=parsed_query.satellite_id).exists(): - raise APIError(status_code=HTTPStatus.FORBIDDEN, body={'detail': 'Access denied'}) + raise _api_error(status_code=HTTPStatus.FORBIDDEN, body={'detail': 'Access denied'}) filters['satellite_id'] = parsed_query.satellite_id queryset = Prediction.objects.filter(**filters) @@ -157,7 +166,7 @@ class PredictionDetailController(Controller[PydanticSerializer]): prediction = Prediction.objects.filter( user=self.request.user, pk=parsed_path.pk).first() if prediction is None: - raise APIError(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found'}) + raise _api_error(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found'}) return PredictionDetailOut.model_validate(prediction) @@ -169,7 +178,7 @@ class PredictionDeleteController(Controller[PydanticSerializer]): prediction = Prediction.objects.filter( user=self.request.user, pk=parsed_path.pk).first() if prediction is None: - raise APIError(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found'}) + raise _api_error(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found'}) prediction.delete() @@ -260,14 +269,14 @@ class LoginController(Controller[PydanticSerializer]): password = data.get('password') if username is None or password is None: - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={'detail': 'Please provide username and password.'}, ) user = authenticate(username=username, password=password) if user is None: - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={'detail': 'Invalid credentials.'}, ) @@ -284,7 +293,7 @@ class LogoutController(Controller[PydanticSerializer]): @modify(status_code=HTTPStatus.OK) def post(self) -> DetailResponse: if not self.request.user.is_authenticated: - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={'detail': "You're not logged in."}, ) @@ -302,7 +311,7 @@ def _check_saved_point_unique(user, name, exclude_pk=None): if exclude_pk is not None: qs = qs.exclude(pk=exclude_pk) if qs.exists(): - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={'non_field_errors': [_SAVED_POINT_DUPLICATE]}, ) @@ -330,7 +339,7 @@ class SavedPointDetailController(Controller[PydanticSerializer]): # matching DRF's get_object() over a user-scoped queryset. obj = SavedPoint.objects.filter(user=self.request.user, pk=pk).first() if obj is None: - raise APIError(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found.'}) + raise _api_error(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found.'}) return obj def get(self, parsed_path: Path[PkPath]) -> SavedPointOut: @@ -383,7 +392,7 @@ class PredictionTemplateDetailController(Controller[PydanticSerializer]): def _get_object(self, pk: int): obj = PreditctionTemplate.objects.filter(user=self.request.user, pk=pk).first() if obj is None: - raise APIError(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found.'}) + raise _api_error(status_code=HTTPStatus.NOT_FOUND, body={'detail': 'Not found.'}) return obj def get(self, parsed_path: Path[PkPath]) -> PredictionTemplateOut: @@ -432,7 +441,7 @@ class ChangePasswordController(Controller[PydanticSerializer]): user = self.request.user if not user.check_password(parsed_body.old_password): - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={'detail': 'Old password is incorrect'}, ) @@ -454,12 +463,12 @@ class DeleteAccountController(Controller[PydanticSerializer]): try: parsed_body = DeleteAccountIn(**json.loads(self.request.body or b'{}')) except ValidationError as exc: - raise APIError(status_code=HTTPStatus.BAD_REQUEST, body=json.loads(exc.json())) + raise _api_error(status_code=HTTPStatus.BAD_REQUEST, body=json.loads(exc.json())) except ValueError: - raise APIError(status_code=HTTPStatus.BAD_REQUEST, body={'detail': 'Invalid request body.'}) + raise _api_error(status_code=HTTPStatus.BAD_REQUEST, body={'detail': 'Invalid request body.'}) if not user.check_password(parsed_body.password): - raise APIError( + raise _api_error( status_code=HTTPStatus.BAD_REQUEST, body={'detail': 'Incorrect password'}, )