mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-06-12 07:24:48 +02:00
Merge pull request #1347 from cisagov/dk/1217-domain-expiration-epp
Issue #1217 - Domain expiration date - EPP
This commit is contained in:
commit
310da70913
4 changed files with 102 additions and 5 deletions
|
@ -736,7 +736,7 @@ class DomainAdmin(ListHeaderAdmin):
|
||||||
search_help_text = "Search by domain name."
|
search_help_text = "Search by domain name."
|
||||||
change_form_template = "django/admin/domain_change_form.html"
|
change_form_template = "django/admin/domain_change_form.html"
|
||||||
change_list_template = "django/admin/domain_change_list.html"
|
change_list_template = "django/admin/domain_change_list.html"
|
||||||
readonly_fields = ["state"]
|
readonly_fields = ["state", "expiration_date"]
|
||||||
|
|
||||||
def export_data_type(self, request):
|
def export_data_type(self, request):
|
||||||
# match the CSV example with all the fields
|
# match the CSV example with all the fields
|
||||||
|
|
|
@ -211,12 +211,56 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
|
|
||||||
@Cache
|
@Cache
|
||||||
def registry_expiration_date(self) -> date:
|
def registry_expiration_date(self) -> date:
|
||||||
"""Get or set the `ex_date` element from the registry."""
|
"""Get or set the `ex_date` element from the registry.
|
||||||
return self._get_property("ex_date")
|
Additionally, update the expiration date in the registrar"""
|
||||||
|
try:
|
||||||
|
self.expiration_date = self._get_property("ex_date")
|
||||||
|
self.save()
|
||||||
|
return self.expiration_date
|
||||||
|
except Exception as e:
|
||||||
|
# exception raised during the save to registrar
|
||||||
|
logger.error(f"error updating expiration date in registrar: {e}")
|
||||||
|
raise (e)
|
||||||
|
|
||||||
@registry_expiration_date.setter # type: ignore
|
@registry_expiration_date.setter # type: ignore
|
||||||
def registry_expiration_date(self, ex_date: date):
|
def registry_expiration_date(self, ex_date: date):
|
||||||
pass
|
"""
|
||||||
|
Direct setting of the expiration date in the registry is not implemented.
|
||||||
|
|
||||||
|
To update the expiration date, use renew_domain method."""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def renew_domain(self, length: int = 1, unit: epp.Unit = epp.Unit.YEAR):
|
||||||
|
"""
|
||||||
|
Renew the domain to a length and unit of time relative to the current
|
||||||
|
expiration date.
|
||||||
|
|
||||||
|
Default length and unit of time are 1 year.
|
||||||
|
"""
|
||||||
|
# if no expiration date from registry, set to today
|
||||||
|
try:
|
||||||
|
cur_exp_date = self.registry_expiration_date
|
||||||
|
except KeyError:
|
||||||
|
logger.warning("current expiration date not set; setting to today")
|
||||||
|
cur_exp_date = date.today()
|
||||||
|
|
||||||
|
# create RenewDomain request
|
||||||
|
request = commands.RenewDomain(name=self.name, cur_exp_date=cur_exp_date, period=epp.Period(length, unit))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# update expiration date in registry, and set the updated
|
||||||
|
# expiration date in the registrar, and in the cache
|
||||||
|
self._cache["ex_date"] = registry.send(request, cleaned=True).res_data[0].ex_date
|
||||||
|
self.expiration_date = self._cache["ex_date"]
|
||||||
|
self.save()
|
||||||
|
except RegistryError as err:
|
||||||
|
# if registry error occurs, log the error, and raise it as well
|
||||||
|
logger.error(f"registry error renewing domain: {err}")
|
||||||
|
raise (err)
|
||||||
|
except Exception as e:
|
||||||
|
# exception raised during the save to registrar
|
||||||
|
logger.error(f"error updating expiration date in registrar: {e}")
|
||||||
|
raise (e)
|
||||||
|
|
||||||
@Cache
|
@Cache
|
||||||
def password(self) -> str:
|
def password(self) -> str:
|
||||||
|
|
|
@ -556,6 +556,7 @@ class MockEppLib(TestCase):
|
||||||
avail=...,
|
avail=...,
|
||||||
addrs=...,
|
addrs=...,
|
||||||
registrant=...,
|
registrant=...,
|
||||||
|
ex_date=...,
|
||||||
):
|
):
|
||||||
self.auth_info = auth_info
|
self.auth_info = auth_info
|
||||||
self.cr_date = cr_date
|
self.cr_date = cr_date
|
||||||
|
@ -565,6 +566,7 @@ class MockEppLib(TestCase):
|
||||||
self.avail = avail # use for CheckDomain
|
self.avail = avail # use for CheckDomain
|
||||||
self.addrs = addrs
|
self.addrs = addrs
|
||||||
self.registrant = registrant
|
self.registrant = registrant
|
||||||
|
self.ex_date = ex_date
|
||||||
|
|
||||||
def dummyInfoContactResultData(
|
def dummyInfoContactResultData(
|
||||||
self,
|
self,
|
||||||
|
@ -811,6 +813,11 @@ class MockEppLib(TestCase):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mockRenewedDomainExpDate = fakedEppObject(
|
||||||
|
"fake.gov",
|
||||||
|
ex_date=datetime.date(2023, 5, 25),
|
||||||
|
)
|
||||||
|
|
||||||
def _mockDomainName(self, _name, _avail=False):
|
def _mockDomainName(self, _name, _avail=False):
|
||||||
return MagicMock(
|
return MagicMock(
|
||||||
res_data=[
|
res_data=[
|
||||||
|
@ -870,6 +877,8 @@ class MockEppLib(TestCase):
|
||||||
return self.mockCheckDomainCommand(_request, cleaned)
|
return self.mockCheckDomainCommand(_request, cleaned)
|
||||||
case commands.DeleteDomain:
|
case commands.DeleteDomain:
|
||||||
return self.mockDeleteDomainCommands(_request, cleaned)
|
return self.mockDeleteDomainCommands(_request, cleaned)
|
||||||
|
case commands.RenewDomain:
|
||||||
|
return self.mockRenewDomainCommand(_request, cleaned)
|
||||||
case _:
|
case _:
|
||||||
return MagicMock(res_data=[self.mockDataInfoHosts])
|
return MagicMock(res_data=[self.mockDataInfoHosts])
|
||||||
|
|
||||||
|
@ -890,6 +899,15 @@ class MockEppLib(TestCase):
|
||||||
raise RegistryError(code=ErrorCode.OBJECT_ASSOCIATION_PROHIBITS_OPERATION)
|
raise RegistryError(code=ErrorCode.OBJECT_ASSOCIATION_PROHIBITS_OPERATION)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def mockRenewDomainCommand(self, _request, cleaned):
|
||||||
|
if getattr(_request, "name", None) == "fake-error.gov":
|
||||||
|
raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
|
||||||
|
else:
|
||||||
|
return MagicMock(
|
||||||
|
res_data=[self.mockRenewedDomainExpDate],
|
||||||
|
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
|
||||||
|
)
|
||||||
|
|
||||||
def mockInfoDomainCommands(self, _request, cleaned):
|
def mockInfoDomainCommands(self, _request, cleaned):
|
||||||
request_name = getattr(_request, "name", None)
|
request_name = getattr(_request, "name", None)
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ class TestDomainCache(MockEppLib):
|
||||||
self.assertFalse("avail" in domain._cache.keys())
|
self.assertFalse("avail" in domain._cache.keys())
|
||||||
|
|
||||||
# using a setter should clear the cache
|
# using a setter should clear the cache
|
||||||
domain.registry_expiration_date = datetime.date.today()
|
domain.dnssecdata = []
|
||||||
self.assertEquals(domain._cache, {})
|
self.assertEquals(domain._cache, {})
|
||||||
|
|
||||||
# send should have been called only once
|
# send should have been called only once
|
||||||
|
@ -1953,6 +1953,41 @@ class TestRegistrantDNSSEC(MockEppLib):
|
||||||
self.assertTrue(err.is_client_error() or err.is_session_error() or err.is_server_error())
|
self.assertTrue(err.is_client_error() or err.is_session_error() or err.is_server_error())
|
||||||
|
|
||||||
|
|
||||||
|
class TestExpirationDate(MockEppLib):
|
||||||
|
"""User may renew expiration date by a number of units of time"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Domain exists in registry
|
||||||
|
"""
|
||||||
|
super().setUp()
|
||||||
|
# for the tests, need a domain in the ready state
|
||||||
|
self.domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
|
||||||
|
# for the test, need a domain that will raise an exception
|
||||||
|
self.domain_w_error, _ = Domain.objects.get_or_create(name="fake-error.gov", state=Domain.State.READY)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
Domain.objects.all().delete()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
def test_expiration_date_setter_not_implemented(self):
|
||||||
|
"""assert that the setter for expiration date is not implemented and will raise error"""
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
self.domain.registry_expiration_date = datetime.date.today()
|
||||||
|
|
||||||
|
def test_renew_domain(self):
|
||||||
|
"""assert that the renew_domain sets new expiration date in cache and saves to registrar"""
|
||||||
|
self.domain.renew_domain()
|
||||||
|
test_date = datetime.date(2023, 5, 25)
|
||||||
|
self.assertEquals(self.domain._cache["ex_date"], test_date)
|
||||||
|
self.assertEquals(self.domain.expiration_date, test_date)
|
||||||
|
|
||||||
|
def test_renew_domain_error(self):
|
||||||
|
"""assert that the renew_domain raises an exception when registry raises error"""
|
||||||
|
with self.assertRaises(RegistryError):
|
||||||
|
self.domain_w_error.renew_domain()
|
||||||
|
|
||||||
|
|
||||||
class TestAnalystClientHold(MockEppLib):
|
class TestAnalystClientHold(MockEppLib):
|
||||||
"""Rule: Analysts may suspend or restore a domain by using client hold"""
|
"""Rule: Analysts may suspend or restore a domain by using client hold"""
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue