Merge pull request #1186 from cisagov/es/domain-availability-quickfix

Issue#1180 Fix domain availability API and make available API public
This commit is contained in:
Erin Song 2023-10-30 08:48:45 -07:00 committed by GitHub
commit dcb358a015
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 47 deletions

View file

@ -5,14 +5,13 @@ import json
from django.contrib.auth import get_user_model
from django.test import RequestFactory
from ..views import available, in_domains
from ..views import available, check_domain_available
from .common import less_console_noise
from registrar.tests.common import MockEppLib
from unittest.mock import call
from epplibwrapper import (
commands,
RegistryError,
)
API_BASE_PATH = "/api/v1/available/"
@ -37,10 +36,10 @@ class AvailableViewTest(MockEppLib):
response_object = json.loads(response.content)
self.assertIn("available", response_object)
def test_in_domains_makes_calls_(self):
def test_domain_available_makes_calls_(self):
"""Domain searches successfully make correct mock EPP calls"""
gsa_available = in_domains("gsa.gov")
igorville_available = in_domains("igorvilleremixed.gov")
gsa_available = check_domain_available("gsa.gov")
igorville_available = check_domain_available("igorville.gov")
"""Domain searches successfully make mock EPP calls"""
self.mockedSendFunction.assert_has_calls(
@ -53,29 +52,32 @@ class AvailableViewTest(MockEppLib):
),
call(
commands.CheckDomain(
["igorvilleremixed.gov"],
["igorville.gov"],
),
cleaned=True,
),
]
)
"""Domain searches return correct availability results"""
self.assertTrue(gsa_available)
self.assertFalse(igorville_available)
self.assertFalse(gsa_available)
self.assertTrue(igorville_available)
def test_in_domains_capitalized(self):
def test_domain_available_capitalized(self):
"""Domain searches work without case sensitivity"""
self.assertTrue(in_domains("gsa.gov"))
# input is lowercased so GSA.GOV should be found
self.assertTrue(in_domains("GSA.gov"))
self.assertFalse(check_domain_available("gsa.gov"))
self.assertTrue(check_domain_available("igorville.gov"))
# input is lowercased so GSA.GOV should also not be available
self.assertFalse(check_domain_available("GSA.gov"))
# input is lowercased so IGORVILLE.GOV should also not be available
self.assertFalse(check_domain_available("IGORVILLE.gov"))
def test_in_domains_dotgov(self):
def test_domain_available_dotgov(self):
"""Domain searches work without trailing .gov"""
self.assertTrue(in_domains("gsa"))
self.assertFalse(check_domain_available("gsa"))
# input is lowercased so GSA.GOV should be found
self.assertTrue(in_domains("GSA"))
# This domain should not have been registered
self.assertFalse(in_domains("igorvilleremixed"))
self.assertFalse(check_domain_available("GSA"))
# This domain should be available to register
self.assertTrue(check_domain_available("igorville"))
def test_not_available_domain(self):
"""gsa.gov is not available"""
@ -85,17 +87,17 @@ class AvailableViewTest(MockEppLib):
self.assertFalse(json.loads(response.content)["available"])
def test_available_domain(self):
"""igorvilleremixed.gov is still available"""
request = self.factory.get(API_BASE_PATH + "igorvilleremixed.gov")
"""igorville.gov is still available"""
request = self.factory.get(API_BASE_PATH + "igorville.gov")
request.user = self.user
response = available(request, domain="igorvilleremixed.gov")
response = available(request, domain="igorville.gov")
self.assertTrue(json.loads(response.content)["available"])
def test_available_domain_dotgov(self):
"""igorvilleremixed.gov is still available even without the .gov suffix"""
request = self.factory.get(API_BASE_PATH + "igorvilleremixed")
"""igorville.gov is still available even without the .gov suffix"""
request = self.factory.get(API_BASE_PATH + "igorville")
request.user = self.user
response = available(request, domain="igorvilleremixed")
response = available(request, domain="igorville")
self.assertTrue(json.loads(response.content)["available"])
def test_error_handling(self):
@ -105,10 +107,9 @@ class AvailableViewTest(MockEppLib):
request.user = self.user
response = available(request, domain=bad_string)
self.assertFalse(json.loads(response.content)["available"])
# domain set to raise error successfully raises error
with self.assertRaises(RegistryError):
error_domain_available = available(request, "errordomain.gov")
self.assertFalse(json.loads(error_domain_available.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"])
class AvailableAPITest(MockEppLib):

View file

@ -5,6 +5,8 @@ from django.http import JsonResponse
import requests
from login_required import login_not_required
from cachetools.func import ttl_cache
@ -23,6 +25,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.",
}
@ -50,22 +53,26 @@ def _domains():
return domains
def in_domains(domain):
"""Return true if the given domain is in the domains list.
def check_domain_available(domain):
"""Return true if the given domain is available.
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.
"""
Domain = apps.get_model("registrar.Domain")
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")
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
@require_http_methods(["GET"])
@login_not_required
def available(request, domain=""):
"""Is a given domain available or not.
@ -83,11 +90,16 @@ def available(request, domain=""):
{"available": False, "message": DOMAIN_API_MESSAGES["invalid"]}
)
# a domain is available if it is NOT in the list of current domains
if in_domains(domain):
try:
if check_domain_available(domain):
return JsonResponse(
{"available": True, "message": DOMAIN_API_MESSAGES["success"]}
)
else:
return JsonResponse(
{"available": False, "message": DOMAIN_API_MESSAGES["unavailable"]}
)
except Exception:
return JsonResponse(
{"available": False, "message": DOMAIN_API_MESSAGES["unavailable"]}
)
else:
return JsonResponse(
{"available": True, "message": DOMAIN_API_MESSAGES["success"]}
{"available": False, "message": DOMAIN_API_MESSAGES["error"]}
)

View file

@ -1,6 +1,6 @@
import re
from api.views import in_domains
from api.views import check_domain_available
from registrar.utility import errors
@ -44,7 +44,7 @@ class DomainHelper:
raise errors.ExtraDotsError()
if not DomainHelper.string_could_be_domain(domain + ".gov"):
raise ValueError()
if in_domains(domain):
if not check_domain_available(domain):
raise errors.DomainUnavailableError()
return domain

View file

@ -823,11 +823,17 @@ class MockEppLib(TestCase):
def mockCheckDomainCommand(self, _request, cleaned):
if "gsa.gov" in getattr(_request, "names", None):
return self._mockDomainName("gsa.gov", True)
return self._mockDomainName("gsa.gov", False)
elif "GSA.gov" in getattr(_request, "names", None):
return self._mockDomainName("GSA.gov", True)
elif "igorvilleremixed.gov" in getattr(_request, "names", None):
return self._mockDomainName("igorvilleremixed.gov", False)
return self._mockDomainName("GSA.gov", False)
elif "igorville.gov" in getattr(_request, "names", None):
return self._mockDomainName("igorvilleremixed.gov", True)
elif "top-level-agency.gov" in getattr(_request, "names", None):
return self._mockDomainName("top-level-agency.gov", True)
elif "city.gov" in getattr(_request, "names", None):
return self._mockDomainName("city.gov", True)
elif "city1.gov" in getattr(_request, "names", None):
return self._mockDomainName("city1.gov", True)
elif "errordomain.gov" in getattr(_request, "names", None):
raise RegistryError("Registry cannot find domain availability.")
else:

View file

@ -110,12 +110,13 @@ class TestURLAuth(TestCase):
# Note that the trailing slash is wobbly depending on how the URL was defined.
IGNORE_URLS = [
# These are the OIDC auth endpoints that always need
# to be public.
# to be public. Use the exact URLs that will be tested.
"/openid/login/",
"/openid/logout/",
"/openid/callback",
"/openid/callback/login/",
"/openid/callback/logout/",
"/api/v1/available/whitehouse.gov",
]
def assertURLIsProtectedByAuth(self, url):