mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-15 05:54:11 +02:00
update deletion process and tests
This commit is contained in:
parent
ede01e3181
commit
b5e4f8b40c
3 changed files with 84 additions and 14 deletions
|
@ -254,7 +254,7 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
return not cls.available(domain)
|
return not cls.available(domain)
|
||||||
|
|
||||||
@Cache
|
@Cache
|
||||||
def contacts(self) -> dict[str, str]:
|
def registry_contacts(self) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Get a dictionary of registry IDs for the contacts for this domain.
|
Get a dictionary of registry IDs for the contacts for this domain.
|
||||||
|
|
||||||
|
@ -263,7 +263,10 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
{ PublicContact.ContactTypeChoices.REGISTRANT: "jd1234",
|
{ PublicContact.ContactTypeChoices.REGISTRANT: "jd1234",
|
||||||
PublicContact.ContactTypeChoices.ADMINISTRATIVE: "sh8013",...}
|
PublicContact.ContactTypeChoices.ADMINISTRATIVE: "sh8013",...}
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
if self._cache.get("contacts"):
|
||||||
|
return self._cache.get("contacts")
|
||||||
|
else:
|
||||||
|
return self._get_property("contacts")
|
||||||
|
|
||||||
@Cache
|
@Cache
|
||||||
def creation_date(self) -> date:
|
def creation_date(self) -> date:
|
||||||
|
@ -1032,17 +1035,19 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
logger.error(f"registry error removing client hold: {err}")
|
logger.error(f"registry error removing client hold: {err}")
|
||||||
raise (err)
|
raise (err)
|
||||||
|
|
||||||
def _delete_contacts(self):
|
def _delete_nonregistrant_contacts(self):
|
||||||
"""Contacts associated with this domain will be deleted.
|
"""Non-registrant contacts associated with this domain will be deleted.
|
||||||
RegistryErrors will be logged and raised. Additional
|
RegistryErrors will be logged and raised. Error
|
||||||
error handling should be provided by the caller.
|
handling should be provided by the caller.
|
||||||
"""
|
"""
|
||||||
logger.info("Deleting contacts for %s", self.name)
|
logger.info("Deleting contacts for %s", self.name)
|
||||||
contacts = self._cache.get("contacts")
|
contacts = self.registry_contacts
|
||||||
logger.debug("Contacts to delete for %s inside _delete_contacts -> %s", self.name, contacts)
|
logger.debug("Contacts to delete for %s inside _delete_contacts -> %s", self.name, contacts)
|
||||||
if contacts:
|
if contacts:
|
||||||
for contact in contacts:
|
for contact, id in contacts.items():
|
||||||
self._delete_contact(contact)
|
# registrants have to be deleted after the domain
|
||||||
|
if contact != PublicContact.ContactTypeChoices.REGISTRANT:
|
||||||
|
self._delete_contact(contact, id)
|
||||||
|
|
||||||
|
|
||||||
def _delete_subdomains(self):
|
def _delete_subdomains(self):
|
||||||
|
@ -1067,6 +1072,13 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
request = commands.DeleteDomain(name=self.name)
|
request = commands.DeleteDomain(name=self.name)
|
||||||
registry.send(request, cleaned=True)
|
registry.send(request, cleaned=True)
|
||||||
|
|
||||||
|
def _delete_domain_registrant(self):
|
||||||
|
"""This domain's registrant should be deleted from the registry
|
||||||
|
may raises RegistryError, should be caught or handled correctly by caller"""
|
||||||
|
registrantID = self.registrant_contact.registry_id
|
||||||
|
request = commands.DeleteContact(id=registrantID)
|
||||||
|
registry.send(request, cleaned=True)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@ -1475,8 +1487,9 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
try:
|
try:
|
||||||
logger.info("deletedInEpp()-> inside _delete_domain")
|
logger.info("deletedInEpp()-> inside _delete_domain")
|
||||||
self._delete_subdomains()
|
self._delete_subdomains()
|
||||||
self._delete_contacts()
|
self._delete_nonregistrant_contacts()
|
||||||
self._delete_domain()
|
self._delete_domain()
|
||||||
|
self._delete_domain_registrant()
|
||||||
self.deleted = timezone.now()
|
self.deleted = timezone.now()
|
||||||
except RegistryError as err:
|
except RegistryError as err:
|
||||||
logger.error(f"Could not delete domain. Registry returned error: {err}")
|
logger.error(f"Could not delete domain. Registry returned error: {err}")
|
||||||
|
@ -1678,15 +1691,15 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
|
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def _delete_contact(self, contact: PublicContact):
|
def _delete_contact(self, contact_name: str, registry_id: str):
|
||||||
"""Try to delete a contact from the registry.
|
"""Try to delete a contact from the registry.
|
||||||
|
|
||||||
raises:
|
raises:
|
||||||
RegistryError: if the registry is unable to delete the contact
|
RegistryError: if the registry is unable to delete the contact
|
||||||
"""
|
"""
|
||||||
logger.info("_delete_contact() -> Attempting to delete contact for %s from domain %s", contact.name, contact.domain)
|
logger.info("_delete_contact() -> Attempting to delete contact for %s from domain %s", contact_name, self.name)
|
||||||
try:
|
try:
|
||||||
req = commands.DeletContact(id=contact.registry_id)
|
req = commands.DeleteContact(id=registry_id)
|
||||||
return registry.send(req, cleaned=True).res_data[0]
|
return registry.send(req, cleaned=True).res_data[0]
|
||||||
except RegistryError as error:
|
except RegistryError as error:
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|
|
@ -1229,6 +1229,7 @@ class MockEppLib(TestCase):
|
||||||
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
common.Status(state="serverTransferProhibited", description="", lang="en"),
|
||||||
common.Status(state="inactive", description="", lang="en"),
|
common.Status(state="inactive", description="", lang="en"),
|
||||||
],
|
],
|
||||||
|
registrant="regContact",
|
||||||
ex_date=date(2023, 5, 25),
|
ex_date=date(2023, 5, 25),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1610,6 +1611,8 @@ class MockEppLib(TestCase):
|
||||||
return self.mockInfoContactCommands(_request, cleaned)
|
return self.mockInfoContactCommands(_request, cleaned)
|
||||||
case commands.CreateContact:
|
case commands.CreateContact:
|
||||||
return self.mockCreateContactCommands(_request, cleaned)
|
return self.mockCreateContactCommands(_request, cleaned)
|
||||||
|
case commands.DeleteContact:
|
||||||
|
return self.mockDeleteContactCommands(_request, cleaned)
|
||||||
case commands.UpdateDomain:
|
case commands.UpdateDomain:
|
||||||
return self.mockUpdateDomainCommands(_request, cleaned)
|
return self.mockUpdateDomainCommands(_request, cleaned)
|
||||||
case commands.CreateHost:
|
case commands.CreateHost:
|
||||||
|
@ -1731,6 +1734,7 @@ class MockEppLib(TestCase):
|
||||||
|
|
||||||
# Define a dictionary to map request names to data and extension values
|
# Define a dictionary to map request names to data and extension values
|
||||||
request_mappings = {
|
request_mappings = {
|
||||||
|
"fake.gov": (self.mockDataInfoDomain, None),
|
||||||
"security.gov": (self.infoDomainNoContact, None),
|
"security.gov": (self.infoDomainNoContact, None),
|
||||||
"dnssec-dsdata.gov": (
|
"dnssec-dsdata.gov": (
|
||||||
self.mockDataInfoDomain,
|
self.mockDataInfoDomain,
|
||||||
|
@ -1812,6 +1816,15 @@ class MockEppLib(TestCase):
|
||||||
raise ContactError(code=ContactErrorCodes.CONTACT_TYPE_NONE)
|
raise ContactError(code=ContactErrorCodes.CONTACT_TYPE_NONE)
|
||||||
return MagicMock(res_data=[self.mockDataInfoHosts])
|
return MagicMock(res_data=[self.mockDataInfoHosts])
|
||||||
|
|
||||||
|
def mockDeleteContactCommands(self, _request, cleaned):
|
||||||
|
if getattr(_request, "id", None) == "fail":
|
||||||
|
raise RegistryError(code=ErrorCode.OBJECT_EXISTS)
|
||||||
|
else:
|
||||||
|
return MagicMock(
|
||||||
|
res_data=[self.mockDataInfoContact],
|
||||||
|
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
|
||||||
|
)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""mock epp send function as this will fail locally"""
|
"""mock epp send function as this will fail locally"""
|
||||||
self.mockSendPatch = patch("registrar.models.domain.registry.send")
|
self.mockSendPatch = patch("registrar.models.domain.registry.send")
|
||||||
|
|
|
@ -2586,6 +2586,7 @@ class TestAnalystDelete(MockEppLib):
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
Host.objects.all().delete()
|
Host.objects.all().delete()
|
||||||
|
PublicContact.objects.all().delete()
|
||||||
Domain.objects.all().delete()
|
Domain.objects.all().delete()
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
|
@ -2643,7 +2644,7 @@ class TestAnalystDelete(MockEppLib):
|
||||||
call(
|
call(
|
||||||
commands.DeleteHost(name=common.HostObjSet(hosts=['ns1.sharedhost.com'])),
|
commands.DeleteHost(name=common.HostObjSet(hosts=['ns1.sharedhost.com'])),
|
||||||
cleaned=True,
|
cleaned=True,
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
# Domain itself should not be deleted
|
# Domain itself should not be deleted
|
||||||
|
@ -2651,6 +2652,49 @@ class TestAnalystDelete(MockEppLib):
|
||||||
# State should not have changed
|
# State should not have changed
|
||||||
self.assertEqual(domain.state, Domain.State.ON_HOLD)
|
self.assertEqual(domain.state, Domain.State.ON_HOLD)
|
||||||
|
|
||||||
|
def test_deletion_with_host_and_contacts(self):
|
||||||
|
"""
|
||||||
|
Scenario: Domain with related Host and Contacts is Deleted
|
||||||
|
When a contact and host exists that is tied to this domain
|
||||||
|
Then `commands.DeleteHost` is sent to the registry
|
||||||
|
Then `commands.DeleteContact` is sent to the registry
|
||||||
|
Then `commands.DeleteDomain` is sent to the registry
|
||||||
|
Then `commands.DeleteContact` is sent to the registry for the registrant contact
|
||||||
|
And `state` is set to `DELETED`
|
||||||
|
"""
|
||||||
|
# with less_console_noise():
|
||||||
|
# Desired domain
|
||||||
|
domain, _ = Domain.objects.get_or_create(name="freeman.gov", state=Domain.State.ON_HOLD)
|
||||||
|
# Put the domain in client hold
|
||||||
|
domain.place_client_hold()
|
||||||
|
# Delete it
|
||||||
|
domain.deletedInEpp()
|
||||||
|
domain.save()
|
||||||
|
|
||||||
|
# Check that the host and contacts are deleted, order doesn't matter
|
||||||
|
self.mockedSendFunction.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(commands.DeleteHost(name=common.HostObjSet(hosts=['fake.host.com'])), cleaned=True),
|
||||||
|
call(commands.DeleteContact(id="securityContact"), cleaned=True),
|
||||||
|
call(commands.DeleteContact(id="technicalContact"), cleaned=True),
|
||||||
|
call(commands.DeleteContact(id="adminContact"),cleaned=True,)
|
||||||
|
],
|
||||||
|
any_order=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# These calls need to be in order
|
||||||
|
self.mockedSendFunction.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(commands.DeleteDomain(name="freeman.gov"), cleaned=True),
|
||||||
|
call(commands.InfoContact(id="regContact"), cleaned=True),
|
||||||
|
call(commands.DeleteContact(id="regContact"), cleaned=True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
# Domain itself should not be deleted
|
||||||
|
self.assertNotEqual(domain, None)
|
||||||
|
# State should have changed
|
||||||
|
self.assertEqual(domain.state, Domain.State.DELETED)
|
||||||
|
|
||||||
def test_deletion_ready_fsm_failure(self):
|
def test_deletion_ready_fsm_failure(self):
|
||||||
"""
|
"""
|
||||||
Scenario: Domain deletion is unsuccessful due to FSM rules
|
Scenario: Domain deletion is unsuccessful due to FSM rules
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue