diff --git a/src/api/views.py b/src/api/views.py index e40924708..4bec29b80 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,7 +1,7 @@ """Internal API views""" from django.apps import apps from django.views.decorators.http import require_http_methods -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse from django.utils.safestring import mark_safe from registrar.templatetags.url_helpers import public_site_url @@ -71,6 +71,7 @@ def check_domain_available(domain): a match. If check fails, throws a RegistryError. """ Domain = apps.get_model("registrar.Domain") + if domain.endswith(".gov"): return Domain.available(domain) else: @@ -86,29 +87,15 @@ def available(request, domain=""): Response is a JSON dictionary with the key "available" and value true or false. """ + Domain = apps.get_model("registrar.Domain") domain = request.GET.get("domain", "") - DraftDomain = apps.get_model("registrar.DraftDomain") - if domain is None or domain.strip() == "": - # TODO - change this... should it be the regular required? - return JsonResponse({"available": False, "code": "invalid", "message": "This field is required"}) - # validate that the given domain could be a domain name and fail early if - # not. - if not (DraftDomain.string_could_be_domain(domain) or DraftDomain.string_could_be_domain(domain + ".gov")): - print(f"What is the domain at this point? {domain}") - if "." in domain: - return JsonResponse({"available": False, "code": "invalid", "message": DOMAIN_API_MESSAGES["extra_dots"]}) - else: - return JsonResponse({"available": False, "code": "invalid", "message": DOMAIN_API_MESSAGES["invalid"]}) - # a domain is available if it is NOT in the list of current domains - try: - if check_domain_available(domain): - return JsonResponse({"available": True, "code": "success", "message": DOMAIN_API_MESSAGES["success"]}) - else: - return JsonResponse( - {"available": False, "code": "unavailable", "message": DOMAIN_API_MESSAGES["unavailable"]} - ) - except Exception: - return JsonResponse({"available": False, "code": "error", "message": DOMAIN_API_MESSAGES["error"]}) + + json_response = Domain.validate_and_handle_errors( + domain=domain, + error_return_type="JSON_RESPONSE", + display_success=True, + ) + return json_response @require_http_methods(["GET"]) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index fcf6bda7a..00f832d59 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -384,17 +384,8 @@ CurrentSitesFormSet = forms.formset_factory( class AlternativeDomainForm(RegistrarForm): def clean_alternative_domain(self): """Validation code for domain names.""" - try: - requested = self.cleaned_data.get("alternative_domain", None) - validated = DraftDomain.validate(requested, blank_ok=True) - except errors.ExtraDotsError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots") - except errors.DomainUnavailableError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["unavailable"], code="unavailable") - except errors.RegistrySystemError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["error"], code="error") - except ValueError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["invalid"], code="invalid") + requested = self.cleaned_data.get("alternative_domain", None) + validated = DraftDomain.validate_and_handle_errors(requested, "FORM_VALIDATION_ERROR") return validated alternative_domain = forms.CharField( @@ -469,19 +460,8 @@ class DotGovDomainForm(RegistrarForm): def clean_requested_domain(self): """Validation code for domain names.""" - try: - requested = self.cleaned_data.get("requested_domain", None) - validated = DraftDomain.validate(requested) - except errors.BlankValueError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["required"], code="required") - except errors.ExtraDotsError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots") - except errors.DomainUnavailableError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["unavailable"], code="unavailable") - except errors.RegistrySystemError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["error"], code="error") - except ValueError: - raise forms.ValidationError(DOMAIN_API_MESSAGES["invalid"], code="invalid") + requested = self.cleaned_data.get("requested_domain", None) + validated = DraftDomain.validate_and_handle_errors(requested, "FORM_VALIDATION_ERROR") return validated requested_domain = forms.CharField(label="What .gov domain do you want?") diff --git a/src/registrar/models/utility/domain_helper.py b/src/registrar/models/utility/domain_helper.py index e43661b1d..7993d0f90 100644 --- a/src/registrar/models/utility/domain_helper.py +++ b/src/registrar/models/utility/domain_helper.py @@ -1,9 +1,16 @@ +from enum import Enum import re -from api.views import check_domain_available +from django import forms +from django.http import JsonResponse + +from api.views import DOMAIN_API_MESSAGES, check_domain_available from registrar.utility import errors from epplibwrapper.errors import RegistryError +class ValidationErrorReturnType(Enum): + JSON_RESPONSE = "JSON_RESPONSE" + FORM_VALIDATION_ERROR = "FORM_VALIDATION_ERROR" class DomainHelper: """Utility functions and constants for domain names.""" @@ -28,16 +35,10 @@ class DomainHelper: if domain is None: raise errors.BlankValueError() if not isinstance(domain, str): - raise ValueError("Domain name must be a string") - domain = domain.lower().strip() - if domain == "" and not blank_ok: - raise errors.BlankValueError() - if domain.endswith(".gov"): - domain = domain[:-4] - if "." in domain: - raise errors.ExtraDotsError() - if not DomainHelper.string_could_be_domain(domain + ".gov"): - raise ValueError() + raise errors.InvalidDomainError("Domain name must be a string") + + domain = DomainHelper._parse_domain_string(domain, blank_ok) + try: if not check_domain_available(domain): raise errors.DomainUnavailableError() @@ -45,6 +46,85 @@ class DomainHelper: raise errors.RegistrySystemError() from err return domain + @staticmethod + def _parse_domain_string(domain: str, blank_ok) -> str: + """Parses '.gov' out of the domain_name string, and does some validation on it""" + domain = domain.lower().strip() + + if domain == "" and not blank_ok: + raise errors.BlankValueError() + + if domain.endswith(".gov"): + domain = domain[:-4] + + if "." in domain: + raise errors.ExtraDotsError() + + if not DomainHelper.string_could_be_domain(domain + ".gov"): + raise errors.InvalidDomainError() + + @classmethod + def validate_and_handle_errors(cls, domain: str, error_return_type: str, display_success: bool = False): + """Runs validate() and catches possible exceptions.""" + try: + validated = cls.validate(domain) + except errors.BlankValueError: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="required" + ) + except errors.ExtraDotsError: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="extra_dots" + ) + except errors.DomainUnavailableError: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="unavailable" + ) + except errors.RegistrySystemError: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="error" + ) + except errors.InvalidDomainError: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="invalid" + ) + except Exception: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="error" + ) + else: + if display_success: + return DomainHelper._return_form_error_or_json_response( + error_return_type, code="success", available=True + ) + else: + return validated + + @staticmethod + def _return_form_error_or_json_response(return_type, code, available=False): + print(f"What is the code? {code}") + if return_type == "JSON_RESPONSE": + print("in the return context") + return JsonResponse( + {"available": available, "code": code, "message": DOMAIN_API_MESSAGES[code]} + ) + + if return_type == "FORM_VALIDATION_ERROR": + raise forms.ValidationError(DOMAIN_API_MESSAGES[code], code=code) + + # Why is this not working?? + """ + match return_type: + case ValidationErrorReturnType.FORM_VALIDATION_ERROR: + raise forms.ValidationError(DOMAIN_API_MESSAGES[code], code=code) + case ValidationErrorReturnType.JSON_RESPONSE: + return JsonResponse( + {"available": available, "code": code, "message": DOMAIN_API_MESSAGES[code]} + ) + case _: + raise ValueError("Invalid return type specified") + """ + @classmethod def sld(cls, domain: str): """ diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 455419236..199997cc2 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -16,6 +16,8 @@ class DomainUnavailableError(ValueError): class RegistrySystemError(ValueError): pass +class InvalidDomainError(ValueError): + pass class ActionNotAllowed(Exception): """User accessed an action that is not