mirror of
https://github.com/google/nomulus.git
synced 2025-07-07 19:53:30 +02:00
Send an immediate poll message for superuser domain deletes (#1096)
* Send an immediate poll message for superuser domain deletes This poll message is in addition to the normal poll message that is sent when the domain's deletion is effective (typically 35 days later). It's needed because, in the event of a superuser deletion, the owning registrar won't otherwise necessarily know it's happening. Note that, in the case of a --immediate superuser deletion, the normal poll message is already being sent immediately, so this additional poll message is not necessary.
This commit is contained in:
parent
aac952d6a3
commit
844b5ab713
3 changed files with 61 additions and 15 deletions
|
@ -208,13 +208,21 @@ public final class DomainDeleteFlow implements TransactionalFlow {
|
||||||
// Enqueue the deletion poll message if the delete is asynchronous or if requested by a
|
// Enqueue the deletion poll message if the delete is asynchronous or if requested by a
|
||||||
// superuser (i.e. the registrar didn't request this delete and thus should be notified even if
|
// superuser (i.e. the registrar didn't request this delete and thus should be notified even if
|
||||||
// it is synchronous).
|
// it is synchronous).
|
||||||
if (!durationUntilDelete.equals(Duration.ZERO) || isSuperuser) {
|
if (durationUntilDelete.isLongerThan(Duration.ZERO) || isSuperuser) {
|
||||||
PollMessage.OneTime deletePollMessage =
|
PollMessage.OneTime deletePollMessage =
|
||||||
createDeletePollMessage(existingDomain, historyEntry, deletionTime);
|
createDeletePollMessage(existingDomain, historyEntry, deletionTime);
|
||||||
entitiesToSave.add(deletePollMessage);
|
entitiesToSave.add(deletePollMessage);
|
||||||
builder.setDeletePollMessage(deletePollMessage.createVKey());
|
builder.setDeletePollMessage(deletePollMessage.createVKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send a second poll message immediately if the domain is being deleted asynchronously by a
|
||||||
|
// registrar other than the sponsoring registrar (which will necessarily be a superuser).
|
||||||
|
if (durationUntilDelete.isLongerThan(Duration.ZERO)
|
||||||
|
&& !clientId.equals(existingDomain.getPersistedCurrentSponsorClientId())) {
|
||||||
|
entitiesToSave.add(
|
||||||
|
createImmediateDeletePollMessage(existingDomain, historyEntry, now, deletionTime));
|
||||||
|
}
|
||||||
|
|
||||||
// Cancel any grace periods that were still active, and set the expiration time accordingly.
|
// Cancel any grace periods that were still active, and set the expiration time accordingly.
|
||||||
DateTime newExpirationTime = existingDomain.getRegistrationExpirationTime();
|
DateTime newExpirationTime = existingDomain.getRegistrationExpirationTime();
|
||||||
for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
|
for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
|
||||||
|
@ -346,6 +354,19 @@ public final class DomainDeleteFlow implements TransactionalFlow {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PollMessage.OneTime createImmediateDeletePollMessage(
|
||||||
|
DomainBase existingDomain, HistoryEntry historyEntry, DateTime now, DateTime deletionTime) {
|
||||||
|
return new PollMessage.OneTime.Builder()
|
||||||
|
.setClientId(existingDomain.getPersistedCurrentSponsorClientId())
|
||||||
|
.setEventTime(now)
|
||||||
|
.setParent(historyEntry)
|
||||||
|
.setMsg(
|
||||||
|
String.format(
|
||||||
|
"Domain %s was deleted by registry administrator with final deletion effective: %s",
|
||||||
|
existingDomain.getDomainName(), deletionTime))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ImmutableList<FeeTransformResponseExtension> getResponseExtensions(
|
private ImmutableList<FeeTransformResponseExtension> getResponseExtensions(
|
||||||
DomainBase existingDomain, DateTime now) {
|
DomainBase existingDomain, DateTime now) {
|
||||||
|
|
|
@ -59,6 +59,7 @@ import static org.joda.time.Duration.standardDays;
|
||||||
import static org.joda.time.Duration.standardSeconds;
|
import static org.joda.time.Duration.standardSeconds;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.ImmutableSortedMap;
|
import com.google.common.collect.ImmutableSortedMap;
|
||||||
|
@ -87,6 +88,7 @@ import google.registry.model.eppcommon.StatusValue;
|
||||||
import google.registry.model.eppcommon.Trid;
|
import google.registry.model.eppcommon.Trid;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
import google.registry.model.poll.PendingActionNotificationResponse;
|
import google.registry.model.poll.PendingActionNotificationResponse;
|
||||||
|
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
|
||||||
import google.registry.model.poll.PollMessage;
|
import google.registry.model.poll.PollMessage;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.registry.Registry.TldType;
|
import google.registry.model.registry.Registry.TldType;
|
||||||
|
@ -328,12 +330,12 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||||
dryRunFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
|
dryRunFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doImmediateDeleteTest(GracePeriodStatus gracePeriodStatus, String responseFilename)
|
private void doAddGracePeriodDeleteTest(
|
||||||
throws Exception {
|
GracePeriodStatus gracePeriodStatus, String responseFilename) throws Exception {
|
||||||
doImmediateDeleteTest(gracePeriodStatus, responseFilename, ImmutableMap.of());
|
doAddGracePeriodDeleteTest(gracePeriodStatus, responseFilename, ImmutableMap.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doImmediateDeleteTest(
|
private void doAddGracePeriodDeleteTest(
|
||||||
GracePeriodStatus gracePeriodStatus,
|
GracePeriodStatus gracePeriodStatus,
|
||||||
String responseFilename,
|
String responseFilename,
|
||||||
Map<String, String> substitutions)
|
Map<String, String> substitutions)
|
||||||
|
@ -355,7 +357,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||||
graceBillingEvent, getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE));
|
graceBillingEvent, getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE));
|
||||||
assertDnsTasksEnqueued("example.tld");
|
assertDnsTasksEnqueued("example.tld");
|
||||||
// There should be no poll messages. The previous autorenew poll message should now be deleted.
|
// There should be no poll messages. The previous autorenew poll message should now be deleted.
|
||||||
assertThat(getPollMessages("TheRegistrar", A_MONTH_FROM_NOW)).isEmpty();
|
assertThat(getPollMessages("TheRegistrar")).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -385,25 +387,25 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_addGracePeriodResultsInImmediateDelete() throws Exception {
|
void testSuccess_addGracePeriodResultsInImmediateDelete() throws Exception {
|
||||||
sessionMetadata.setServiceExtensionUris(ImmutableSet.of());
|
sessionMetadata.setServiceExtensionUris(ImmutableSet.of());
|
||||||
doImmediateDeleteTest(GracePeriodStatus.ADD, "generic_success_response.xml");
|
doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "generic_success_response.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_addGracePeriodCredit_v06() throws Exception {
|
void testSuccess_addGracePeriodCredit_v06() throws Exception {
|
||||||
removeServiceExtensionUri(ServiceExtension.FEE_0_11.getUri());
|
removeServiceExtensionUri(ServiceExtension.FEE_0_11.getUri());
|
||||||
removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri());
|
removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri());
|
||||||
doImmediateDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_06_MAP);
|
doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_06_MAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_addGracePeriodCredit_v11() throws Exception {
|
void testSuccess_addGracePeriodCredit_v11() throws Exception {
|
||||||
removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri());
|
removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri());
|
||||||
doImmediateDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_11_MAP);
|
doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_11_MAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_addGracePeriodCredit_v12() throws Exception {
|
void testSuccess_addGracePeriodCredit_v12() throws Exception {
|
||||||
doImmediateDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_12_MAP);
|
doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_12_MAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doSuccessfulTest_noAddGracePeriod(String responseFilename) throws Exception {
|
private void doSuccessfulTest_noAddGracePeriod(String responseFilename) throws Exception {
|
||||||
|
@ -838,6 +840,30 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||||
clock.advanceOneMilli();
|
clock.advanceOneMilli();
|
||||||
runFlowAssertResponse(
|
runFlowAssertResponse(
|
||||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("domain_delete_response_pending.xml"));
|
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("domain_delete_response_pending.xml"));
|
||||||
|
|
||||||
|
HistoryEntry deleteHistoryEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE);
|
||||||
|
assertPollMessages(
|
||||||
|
new PollMessage.OneTime.Builder()
|
||||||
|
.setClientId("TheRegistrar")
|
||||||
|
.setParent(deleteHistoryEntry)
|
||||||
|
.setEventTime(clock.nowUtc())
|
||||||
|
.setMsg(
|
||||||
|
"Domain example.tld was deleted by registry administrator with final deletion"
|
||||||
|
+ " effective: 2000-07-11T22:00:00.013Z")
|
||||||
|
.build(),
|
||||||
|
new PollMessage.OneTime.Builder()
|
||||||
|
.setClientId("TheRegistrar")
|
||||||
|
.setParent(deleteHistoryEntry)
|
||||||
|
.setEventTime(DateTime.parse("2000-07-11T22:00:00.013Z"))
|
||||||
|
.setMsg("Deleted by registry administrator.")
|
||||||
|
.setResponseData(
|
||||||
|
ImmutableList.of(
|
||||||
|
DomainPendingActionNotificationResponse.create(
|
||||||
|
"example.tld",
|
||||||
|
true,
|
||||||
|
deleteHistoryEntry.getTrid(),
|
||||||
|
DateTime.parse("2000-07-11T22:00:00.013Z"))))
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1201,6 +1227,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_immediateDelete_withSuperuserAndMetadataExtension() throws Exception {
|
void testSuccess_immediateDelete_withSuperuserAndMetadataExtension() throws Exception {
|
||||||
|
sessionMetadata.setClientId("NewRegistrar");
|
||||||
eppRequestSource = EppRequestSource.TOOL;
|
eppRequestSource = EppRequestSource.TOOL;
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_delete_superuser_and_metadata_extension.xml",
|
"domain_delete_superuser_and_metadata_extension.xml",
|
||||||
|
|
|
@ -43,6 +43,7 @@ import static google.registry.util.CollectionUtils.difference;
|
||||||
import static google.registry.util.CollectionUtils.union;
|
import static google.registry.util.CollectionUtils.union;
|
||||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||||
import static google.registry.util.DomainNameUtils.ACE_PREFIX_REGEX;
|
import static google.registry.util.DomainNameUtils.ACE_PREFIX_REGEX;
|
||||||
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
||||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||||
|
@ -919,15 +920,12 @@ public class DatabaseHelper {
|
||||||
.collect(toImmutableList()));
|
.collect(toImmutableList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImmutableList<PollMessage> getPollMessages(String clientId, DateTime now) {
|
public static ImmutableList<PollMessage> getPollMessages(String clientId, DateTime beforeOrAt) {
|
||||||
return transactIfJpaTm(
|
return transactIfJpaTm(
|
||||||
() ->
|
() ->
|
||||||
tm().loadAllOf(PollMessage.class).stream()
|
tm().loadAllOf(PollMessage.class).stream()
|
||||||
.filter(pollMessage -> pollMessage.getClientId().equals(clientId))
|
.filter(pollMessage -> pollMessage.getClientId().equals(clientId))
|
||||||
.filter(
|
.filter(pollMessage -> isBeforeOrAt(pollMessage.getEventTime(), beforeOrAt))
|
||||||
pollMessage ->
|
|
||||||
pollMessage.getEventTime().isEqual(now)
|
|
||||||
|| pollMessage.getEventTime().isBefore(now))
|
|
||||||
.collect(toImmutableList()));
|
.collect(toImmutableList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue