diff --git a/.flake8 b/.flake8 index 370d558..a3a7fb2 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,6 @@ [flake8] max-line-length = 79 -application_import_names = promo_code, user +application_import_names = promo_code, user, core import-order-style = google exclude = */migrations/, venv/, verdict.py, .venv/, env/, venv, .git, __pycache__ max-complexity = 10 diff --git a/.isort.cfg b/.isort.cfg index 4d10ca4..6bc408b 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,7 +1,7 @@ [settings] profile = black skip = migrations, venv/, venv -known_first_party = promo_code, user +known_first_party = promo_code, user, core default_section = THIRDPARTY force_sort_within_sections = true line_length = 79 \ No newline at end of file diff --git a/promo_code/core/urls.py b/promo_code/core/urls.py index fae4a95..33d8796 100644 --- a/promo_code/core/urls.py +++ b/promo_code/core/urls.py @@ -1,6 +1,7 @@ -import core.views import django.urls +import core.views + app_name = 'api-core' diff --git a/promo_code/user/validators.py b/promo_code/user/validators.py index feda79a..bc0a0eb 100644 --- a/promo_code/user/validators.py +++ b/promo_code/user/validators.py @@ -1,5 +1,6 @@ import pycountry import rest_framework.exceptions +import rest_framework.serializers import user.models @@ -25,47 +26,67 @@ def __call__(self, value): raise exc -class OtherFieldValidator: +class OtherFieldValidator(rest_framework.serializers.Serializer): """ - Validator for JSON fields containing: - - age (required, integer between 0 and 100) - - country (required, string with an ISO 3166-1 alpha-2 country code) + Validates JSON fields: + - age (required, 0-100) + - country (required, valid ISO 3166-1 alpha-2) """ - error_messages = { - 'invalid_type': 'Must be a JSON object.', - 'missing_field': 'This field is required.', - 'age_type': 'Must be an integer.', - 'age_range': 'Must be between 0 and 100.', - 'country_format': 'Must be a 2-letter ISO code.', - 'country_invalid': 'Invalid ISO 3166-1 alpha-2 country code.', - } + country_codes = {c.alpha_2 for c in pycountry.countries} + + age = rest_framework.serializers.IntegerField( + required=True, + min_value=0, + max_value=100, + error_messages={ + 'required': 'This field is required.', + 'invalid': 'Must be an integer.', + 'min_value': 'Must be between 0 and 100.', + 'max_value': 'Must be between 0 and 100.', + }, + ) + + country = rest_framework.serializers.CharField( + required=True, + max_length=2, + min_length=2, + error_messages={ + 'required': 'This field is required.', + 'blank': 'Must be a 2-letter ISO code.', + 'max_length': 'Must be a 2-letter ISO code.', + 'min_length': 'Must be a 2-letter ISO code.', + }, + ) + + def validate_country(self, value): + country = value.upper() + if country not in self.country_codes: + raise rest_framework.serializers.ValidationError( + 'Invalid ISO 3166-1 alpha-2 country code.', + ) + + return country def __call__(self, value): if not isinstance(value, dict): - raise rest_framework.exceptions.ValidationError( - self.error_messages['invalid_type'], + raise rest_framework.serializers.ValidationError( + {'non_field_errors': ['Must be a JSON object']}, ) - errors = {} - - # Validate the 'age' field - age = value.get('age') - if age is None: - errors['age'] = self.error_messages['missing_field'] - elif not isinstance(age, int): - errors['age'] = self.error_messages['age_type'] - elif not (0 <= age <= 100): - errors['age'] = self.error_messages['age_range'] - - # Validate the 'country' field - country_code = value.get('country') - if country_code is None: - errors['country'] = self.error_messages['missing_field'] - elif not (isinstance(country_code, str) and len(country_code) == 2): - errors['country'] = self.error_messages['country_format'] - elif not pycountry.countries.get(alpha_2=country_code.upper()): - errors['country'] = self.error_messages['country_invalid'] - - if errors: - raise rest_framework.exceptions.ValidationError(errors) + missing_fields = [ + field + for field in self.fields + if field not in value or value.get(field) in (None, '') + ] + + if missing_fields: + raise rest_framework.serializers.ValidationError( + {field: 'This field is required.' for field in missing_fields}, + ) + + serializer = self.__class__(data=value) + if not serializer.is_valid(): + raise rest_framework.serializers.ValidationError(serializer.errors) + + return value