Merge pull request #1420 from cisagov/es/1378-availability-bugfix

#1378 Display error message when availability API fails
This commit is contained in:
Erin Song 2023-12-01 16:20:54 -08:00 committed by GitHub
commit c569db24f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 23 deletions

View file

@ -8,6 +8,7 @@ from django.test import RequestFactory
from ..views import available, check_domain_available from ..views import available, check_domain_available
from .common import less_console_noise from .common import less_console_noise
from registrar.tests.common import MockEppLib from registrar.tests.common import MockEppLib
from registrar.utility.errors import GenericError, GenericErrorCodes
from unittest.mock import call from unittest.mock import call
from epplibwrapper import ( from epplibwrapper import (
@ -100,16 +101,25 @@ class AvailableViewTest(MockEppLib):
response = available(request, domain="igorville") response = available(request, domain="igorville")
self.assertTrue(json.loads(response.content)["available"]) self.assertTrue(json.loads(response.content)["available"])
def test_error_handling(self): def test_bad_string_handling(self):
"""Calling with bad strings raises an error.""" """Calling with bad strings returns unavailable."""
bad_string = "blah!;" bad_string = "blah!;"
request = self.factory.get(API_BASE_PATH + bad_string) request = self.factory.get(API_BASE_PATH + bad_string)
request.user = self.user request.user = self.user
response = available(request, domain=bad_string) response = available(request, domain=bad_string)
self.assertFalse(json.loads(response.content)["available"]) self.assertFalse(json.loads(response.content)["available"])
# domain set to raise error returns false for availability
error_domain_available = available(request, "errordomain.gov") def test_error_handling(self):
self.assertFalse(json.loads(error_domain_available.content)["available"]) """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): class AvailableAPITest(MockEppLib):

View file

@ -5,6 +5,7 @@ from django.http import JsonResponse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from registrar.templatetags.url_helpers import public_site_url from registrar.templatetags.url_helpers import public_site_url
from registrar.utility.errors import GenericError, GenericErrorCodes
import requests 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).", "invalid": "Enter a domain using only letters, numbers, or hyphens (though we don't recommend using hyphens).",
"success": "That domain is available!", "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 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 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") Domain = apps.get_model("registrar.Domain")
try: if domain.endswith(".gov"):
if domain.endswith(".gov"): return Domain.available(domain)
return Domain.available(domain) else:
else: # domain search string doesn't end with .gov, add it on here
# domain search string doesn't end with .gov, add it on here return Domain.available(domain + ".gov")
return Domain.available(domain + ".gov")
except Exception:
return False
@require_http_methods(["GET"]) @require_http_methods(["GET"])

View file

@ -399,6 +399,8 @@ class AlternativeDomainForm(RegistrarForm):
raise forms.ValidationError(DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots") raise forms.ValidationError(DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots")
except errors.DomainUnavailableError: except errors.DomainUnavailableError:
raise forms.ValidationError(DOMAIN_API_MESSAGES["unavailable"], code="unavailable") raise forms.ValidationError(DOMAIN_API_MESSAGES["unavailable"], code="unavailable")
except errors.RegistrySystemError:
raise forms.ValidationError(DOMAIN_API_MESSAGES["error"], code="error")
except ValueError: except ValueError:
raise forms.ValidationError(DOMAIN_API_MESSAGES["invalid"], code="invalid") raise forms.ValidationError(DOMAIN_API_MESSAGES["invalid"], code="invalid")
return validated return validated
@ -484,6 +486,8 @@ class DotGovDomainForm(RegistrarForm):
raise forms.ValidationError(DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots") raise forms.ValidationError(DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots")
except errors.DomainUnavailableError: except errors.DomainUnavailableError:
raise forms.ValidationError(DOMAIN_API_MESSAGES["unavailable"], code="unavailable") raise forms.ValidationError(DOMAIN_API_MESSAGES["unavailable"], code="unavailable")
except errors.RegistrySystemError:
raise forms.ValidationError(DOMAIN_API_MESSAGES["error"], code="error")
except ValueError: except ValueError:
raise forms.ValidationError(DOMAIN_API_MESSAGES["invalid"], code="invalid") raise forms.ValidationError(DOMAIN_API_MESSAGES["invalid"], code="invalid")
return validated return validated

View file

@ -2,6 +2,7 @@ import re
from api.views import check_domain_available from api.views import check_domain_available
from registrar.utility import errors from registrar.utility import errors
from epplibwrapper.errors import RegistryError
class DomainHelper: class DomainHelper:
@ -29,19 +30,19 @@ class DomainHelper:
if not isinstance(domain, str): if not isinstance(domain, str):
raise ValueError("Domain name must be a string") raise ValueError("Domain name must be a string")
domain = domain.lower().strip() domain = domain.lower().strip()
if domain == "": if domain == "" and not blank_ok:
if blank_ok: raise errors.BlankValueError()
return domain
else:
raise errors.BlankValueError()
if domain.endswith(".gov"): if domain.endswith(".gov"):
domain = domain[:-4] domain = domain[:-4]
if "." in domain: if "." in domain:
raise errors.ExtraDotsError() raise errors.ExtraDotsError()
if not DomainHelper.string_could_be_domain(domain + ".gov"): if not DomainHelper.string_could_be_domain(domain + ".gov"):
raise ValueError() raise ValueError()
if not check_domain_available(domain): try:
raise errors.DomainUnavailableError() if not check_domain_available(domain):
raise errors.DomainUnavailableError()
except RegistryError as err:
raise errors.RegistrySystemError() from err
return domain return domain
@classmethod @classmethod

View file

@ -13,6 +13,10 @@ class DomainUnavailableError(ValueError):
pass pass
class RegistrySystemError(ValueError):
pass
class ActionNotAllowed(Exception): class ActionNotAllowed(Exception):
"""User accessed an action that is not """User accessed an action that is not
allowed by the current state""" allowed by the current state"""
@ -42,7 +46,7 @@ class GenericError(Exception):
GenericErrorCodes.CANNOT_CONTACT_REGISTRY: """ GenericErrorCodes.CANNOT_CONTACT_REGISTRY: """
Were experiencing a system connection error. Please wait a few minutes Were experiencing a system connection error. Please wait a few minutes
and try again. If you continue to receive this error after a few tries, 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."), GenericErrorCodes.GENERIC_ERROR: ("Value entered was wrong."),
} }
@ -56,6 +60,10 @@ contact help@get.gov
def __str__(self): def __str__(self):
return f"{self.message}" return f"{self.message}"
@classmethod
def get_error_message(self, code=None):
return self._error_mapping.get(code)
class NameserverErrorCodes(IntEnum): class NameserverErrorCodes(IntEnum):
"""Used in the NameserverError class for """Used in the NameserverError class for