diff --git a/src/api/tests/test_available.py b/src/api/tests/test_available.py index 524fd689a..9de152b06 100644 --- a/src/api/tests/test_available.py +++ b/src/api/tests/test_available.py @@ -8,6 +8,7 @@ from django.test import RequestFactory from ..views import available, check_domain_available from .common import less_console_noise from registrar.tests.common import MockEppLib +from registrar.utility.errors import GenericError, GenericErrorCodes from unittest.mock import call from epplibwrapper import ( @@ -100,16 +101,25 @@ class AvailableViewTest(MockEppLib): response = available(request, domain="igorville") self.assertTrue(json.loads(response.content)["available"]) - def test_error_handling(self): - """Calling with bad strings raises an error.""" + def test_bad_string_handling(self): + """Calling with bad strings returns unavailable.""" bad_string = "blah!;" request = self.factory.get(API_BASE_PATH + bad_string) request.user = self.user response = available(request, domain=bad_string) self.assertFalse(json.loads(response.content)["available"]) - # domain set to raise error returns false for availability - error_domain_available = available(request, "errordomain.gov") - self.assertFalse(json.loads(error_domain_available.content)["available"]) + + def test_error_handling(self): + """Error thrown while calling availabilityAPI returns error.""" + request = self.factory.get(API_BASE_PATH + "errordomain.gov") + request.user = self.user + # domain set to raise error returns false for availability and error message + error_domain_response = available(request, domain="errordomain.gov") + self.assertFalse(json.loads(error_domain_response.content)["available"]) + self.assertEqual( + GenericError.get_error_message(GenericErrorCodes.CANNOT_CONTACT_REGISTRY), + json.loads(error_domain_response.content)["message"], + ) class AvailableAPITest(MockEppLib): diff --git a/src/api/views.py b/src/api/views.py index a9f8d7692..85ae021c9 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -5,6 +5,7 @@ from django.http import JsonResponse from django.utils.safestring import mark_safe from registrar.templatetags.url_helpers import public_site_url +from registrar.utility.errors import GenericError, GenericErrorCodes import requests @@ -30,7 +31,7 @@ DOMAIN_API_MESSAGES = { ), "invalid": "Enter a domain using only letters, numbers, or hyphens (though we don't recommend using hyphens).", "success": "That domain is available!", - "error": "Error finding domain availability.", + "error": GenericError.get_error_message(GenericErrorCodes.CANNOT_CONTACT_REGISTRY), } @@ -63,17 +64,14 @@ def check_domain_available(domain): The given domain is lowercased to match against the domains list. If the given domain doesn't end with .gov, ".gov" is added when looking for - a match. + a match. If check fails, throws a RegistryError. """ Domain = apps.get_model("registrar.Domain") - try: - if domain.endswith(".gov"): - return Domain.available(domain) - else: - # domain search string doesn't end with .gov, add it on here - return Domain.available(domain + ".gov") - except Exception: - return False + if domain.endswith(".gov"): + return Domain.available(domain) + else: + # domain search string doesn't end with .gov, add it on here + return Domain.available(domain + ".gov") @require_http_methods(["GET"]) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index a70c23e52..03207087f 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -399,6 +399,8 @@ class AlternativeDomainForm(RegistrarForm): 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") return validated @@ -484,6 +486,8 @@ class DotGovDomainForm(RegistrarForm): 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") return validated diff --git a/src/registrar/models/utility/domain_helper.py b/src/registrar/models/utility/domain_helper.py index 49badd5d7..e43661b1d 100644 --- a/src/registrar/models/utility/domain_helper.py +++ b/src/registrar/models/utility/domain_helper.py @@ -2,6 +2,7 @@ import re from api.views import check_domain_available from registrar.utility import errors +from epplibwrapper.errors import RegistryError class DomainHelper: @@ -29,19 +30,19 @@ class DomainHelper: if not isinstance(domain, str): raise ValueError("Domain name must be a string") domain = domain.lower().strip() - if domain == "": - if blank_ok: - return domain - else: - raise errors.BlankValueError() + 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() - if not check_domain_available(domain): - raise errors.DomainUnavailableError() + try: + if not check_domain_available(domain): + raise errors.DomainUnavailableError() + except RegistryError as err: + raise errors.RegistrySystemError() from err return domain @classmethod diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 52b1ea1d3..9463c1387 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -13,6 +13,10 @@ class DomainUnavailableError(ValueError): pass +class RegistrySystemError(ValueError): + pass + + class ActionNotAllowed(Exception): """User accessed an action that is not allowed by the current state""" @@ -42,7 +46,7 @@ class GenericError(Exception): GenericErrorCodes.CANNOT_CONTACT_REGISTRY: """ We’re experiencing a system connection error. Please wait a few minutes and try again. If you continue to receive this error after a few tries, -contact help@get.gov +contact help@get.gov. """, GenericErrorCodes.GENERIC_ERROR: ("Value entered was wrong."), } @@ -56,6 +60,10 @@ contact help@get.gov def __str__(self): return f"{self.message}" + @classmethod + def get_error_message(self, code=None): + return self._error_mapping.get(code) + class NameserverErrorCodes(IntEnum): """Used in the NameserverError class for