Flatten the domain delete flows

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=133989378
This commit is contained in:
cgoldfeder 2016-09-22 13:04:36 -07:00 committed by Ben McIlwain
parent 096877f03e
commit 863eac3b11
4 changed files with 213 additions and 161 deletions

View file

@ -14,78 +14,103 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static google.registry.flows.ResourceFlowUtils.handlePendingTransferOnDelete;
import static google.registry.flows.ResourceFlowUtils.prepareDeletedResourceAsBuilder;
import static google.registry.flows.ResourceFlowUtils.updateForeignKeyIndexDeletionTime;
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.domain.DomainFlowUtils.DISALLOWED_TLD_STATES_FOR_LAUNCH_FLOWS; import static google.registry.flows.domain.DomainFlowUtils.DISALLOWED_TLD_STATES_FOR_LAUNCH_FLOWS;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchApplicationIdMatchesDomain; import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhase; import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhase;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.collect.ImmutableSet; import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.StatusProhibitsOperationException; import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ResourceSyncDeleteFlow; import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.BadCommandForRegistryPhaseException;
import google.registry.model.domain.DomainApplication; import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainApplication.Builder;
import google.registry.model.domain.DomainCommand.Delete;
import google.registry.model.domain.launch.LaunchDeleteExtension; import google.registry.model.domain.launch.LaunchDeleteExtension;
import google.registry.model.domain.launch.LaunchPhase; import google.registry.model.domain.launch.LaunchPhase;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.Registry.TldState;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
* An EPP flow that deletes a domain application. * An EPP flow that deletes a domain application.
* *
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException} * @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.ResourceFlow.BadCommandForRegistryPhaseException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.ResourceMutateFlow.ResourceDoesNotExistException} * @error {@link google.registry.flows.exceptions.BadCommandForRegistryPhaseException}
* @error {@link DomainApplicationDeleteFlow.SunriseApplicationCannotBeDeletedInLandrushException} * @error {@link DomainApplicationDeleteFlow.SunriseApplicationCannotBeDeletedInLandrushException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException} * @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException}
* @error {@link DomainFlowUtils.LaunchPhaseMismatchException} * @error {@link DomainFlowUtils.LaunchPhaseMismatchException}
*/ */
public class DomainApplicationDeleteFlow public final class DomainApplicationDeleteFlow extends LoggedInFlow implements TransactionalFlow {
extends ResourceSyncDeleteFlow<DomainApplication, Builder, Delete> {
@Inject Optional<AuthInfo> authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject @ApplicationId String applicationId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainApplicationDeleteFlow() {} @Inject DomainApplicationDeleteFlow() {}
@Override @Override
protected void initResourceCreateOrMutateFlow() throws EppException { protected final void initLoggedInFlow() throws EppException {
registerExtensions(MetadataExtension.class);
registerExtensions(LaunchDeleteExtension.class); registerExtensions(LaunchDeleteExtension.class);
} }
@Override @Override
protected void verifyMutationOnOwnedResourceAllowed() throws EppException { public final EppOutput run() throws EppException {
String tld = existingResource.getTld(); DomainApplication existingApplication = verifyExistence(
checkRegistryStateForTld(tld); DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
verifyApplicationDomainMatchesTargetId(existingApplication, targetId);
verifyOptionalAuthInfoForResource(authInfo, existingApplication);
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingApplication);
}
String tld = existingApplication.getTld();
Registry registry = Registry.get(tld);
if (!isSuperuser
&& DISALLOWED_TLD_STATES_FOR_LAUNCH_FLOWS.contains(registry.getTldState(now))) {
throw new BadCommandForRegistryPhaseException();
}
checkAllowedAccessToTld(getAllowedTlds(), tld); checkAllowedAccessToTld(getAllowedTlds(), tld);
verifyLaunchPhase(tld, eppInput.getSingleExtension(LaunchDeleteExtension.class), now); LaunchDeleteExtension launchDelete = eppInput.getSingleExtension(LaunchDeleteExtension.class);
verifyLaunchApplicationIdMatchesDomain(command, existingResource); verifyLaunchPhase(tld, launchDelete, now);
// Don't allow deleting a sunrise application during landrush. // Don't allow deleting a sunrise application during landrush.
if (existingResource.getPhase().equals(LaunchPhase.SUNRISE) if (existingApplication.getPhase().equals(LaunchPhase.SUNRISE)
&& Registry.get(existingResource.getTld()).getTldState(now).equals(TldState.LANDRUSH) && registry.getTldState(now).equals(TldState.LANDRUSH)
&& !isSuperuser) { && !isSuperuser) {
throw new SunriseApplicationCannotBeDeletedInLandrushException(); throw new SunriseApplicationCannotBeDeletedInLandrushException();
} }
} DomainApplication newApplication =
prepareDeletedResourceAsBuilder(existingApplication, now).build();
@Override HistoryEntry historyEntry = historyBuilder
protected final ImmutableSet<TldState> getDisallowedTldStates() { .setType(HistoryEntry.Type.DOMAIN_APPLICATION_DELETE)
return DISALLOWED_TLD_STATES_FOR_LAUNCH_FLOWS; .setModificationTime(now)
} .setParent(Key.create(existingApplication))
.build();
/** Domain applications do not respect status values that prohibit various operations. */ updateForeignKeyIndexDeletionTime(newApplication);
@Override handlePendingTransferOnDelete(existingApplication, newApplication, now, historyEntry);
protected Set<StatusValue> getDisallowedStatuses() { ofy().save().<Object>entities(newApplication, historyEntry);
return ImmutableSet.of(); return createOutput(SUCCESS);
}
@Override
protected final HistoryEntry.Type getHistoryEntryType() {
return HistoryEntry.Type.DOMAIN_APPLICATION_DELETE;
} }
/** A sunrise application cannot be deleted during landrush. */ /** A sunrise application cannot be deleted during landrush. */

View file

@ -15,6 +15,13 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.flows.ResourceFlowUtils.handlePendingTransferOnDelete;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.prepareDeletedResourceAsBuilder;
import static google.registry.flows.ResourceFlowUtils.updateForeignKeyIndexDeletionTime;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
import static google.registry.model.eppoutput.Result.Code.SUCCESS; import static google.registry.model.eppoutput.Result.Code.SUCCESS;
@ -30,10 +37,13 @@ import com.googlecode.objectify.Key;
import google.registry.dns.DnsQueue; import google.registry.dns.DnsQueue;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.AssociationProhibitsOperationException; import google.registry.flows.EppException.AssociationProhibitsOperationException;
import google.registry.flows.ResourceSyncDeleteFlow; import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.BadCommandForRegistryPhaseException;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.common.TimeOfYear;
import google.registry.model.domain.DomainCommand.Delete;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
import google.registry.model.domain.DomainResource.Builder; import google.registry.model.domain.DomainResource.Builder;
import google.registry.model.domain.GracePeriod; import google.registry.model.domain.GracePeriod;
@ -43,80 +53,74 @@ import google.registry.model.domain.fee.FeeTransformResponseExtension;
import google.registry.model.domain.fee06.FeeDeleteResponseExtensionV06; import google.registry.model.domain.fee06.FeeDeleteResponseExtensionV06;
import google.registry.model.domain.fee11.FeeDeleteResponseExtensionV11; import google.registry.model.domain.fee11.FeeDeleteResponseExtensionV11;
import google.registry.model.domain.fee12.FeeDeleteResponseExtensionV12; import google.registry.model.domain.fee12.FeeDeleteResponseExtensionV12;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.SecDnsUpdateExtension; import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension; import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppoutput.EppResponse.ResponseExtension; import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.Result.Code;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse; import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessage.OneTime;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money; import org.joda.money.Money;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** /**
* An EPP flow that deletes a domain resource. * An EPP flow that deletes a domain.
* *
* @error {@link google.registry.flows.ResourceCreateOrMutateFlow.OnlyToolCanPassMetadataException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.ResourceMutateFlow.ResourceDoesNotExistException} * @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
* @error {@link google.registry.flows.SingleResourceFlow.ResourceStatusProhibitsOperationException} * @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link DomainDeleteFlow.DomainToDeleteHasHostsException} * @error {@link DomainDeleteFlow.DomainToDeleteHasHostsException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/ */
public class DomainDeleteFlow extends ResourceSyncDeleteFlow<DomainResource, Builder, Delete> { public class DomainDeleteFlow extends LoggedInFlow implements TransactionalFlow {
PollMessage.OneTime deletePollMessage; private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
CurrencyUnit creditsCurrencyUnit; StatusValue.CLIENT_DELETE_PROHIBITED,
StatusValue.PENDING_DELETE,
ImmutableList<Credit> credits; StatusValue.SERVER_DELETE_PROHIBITED);
protected Optional<RegistryExtraFlowLogic> extraFlowLogic;
@Inject Optional<AuthInfo> authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainDeleteFlow() {} @Inject DomainDeleteFlow() {}
@Override @Override
protected void initResourceCreateOrMutateFlow() throws EppException { @SuppressWarnings("unchecked")
protected final void initLoggedInFlow() throws EppException {
registerExtensions(MetadataExtension.class);
registerExtensions(SecDnsUpdateExtension.class); registerExtensions(SecDnsUpdateExtension.class);
extraFlowLogic = RegistryExtraFlowLogicProxy.newInstanceForDomain(existingResource);
} }
@Override @Override
protected final void verifyMutationOnOwnedResourceAllowed() throws EppException { public final EppOutput run() throws EppException {
checkRegistryStateForTld(existingResource.getTld()); // Loads the target resource if it exists
checkAllowedAccessToTld(getAllowedTlds(), existingResource.getTld()); DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
if (!existingResource.getSubordinateHosts().isEmpty()) { Registry registry = Registry.get(existingDomain.getTld());
throw new DomainToDeleteHasHostsException(); verifyDeleteAllowed(existingDomain, registry);
} HistoryEntry historyEntry = buildHistoryEntry(existingDomain);
} Builder builder = (Builder) prepareDeletedResourceAsBuilder(existingDomain, now);
// If the domain is in the Add Grace Period, we delete it immediately, which is already
@Override // reflected in the builder we just prepared. Otherwise we give it a PENDING_DELETE status.
protected final void setDeleteProperties(Builder builder) throws EppException { if (!existingDomain.getGracePeriodStatuses().contains(GracePeriodStatus.ADD)) {
// Only set to PENDING_DELETE if this domain is not in the Add Grace Period. If domain is in Add // By default, this should be 30 days of grace, and 5 days of pending delete.
// Grace Period, we delete it immediately.
// The base class code already handles the immediate delete case, so we only have to handle the
// pending delete case here.
if (!existingResource.getGracePeriodStatuses().contains(GracePeriodStatus.ADD)) {
Registry registry = Registry.get(existingResource.getTld());
// By default, this should be 30 days of grace, and 5 days of pending delete. */
DateTime deletionTime = now DateTime deletionTime = now
.plus(registry.getRedemptionGracePeriodLength()) .plus(registry.getRedemptionGracePeriodLength())
.plus(registry.getPendingDeleteLength()); .plus(registry.getPendingDeleteLength());
deletePollMessage = new PollMessage.OneTime.Builder() PollMessage.OneTime deletePollMessage =
.setClientId(existingResource.getCurrentSponsorClientId()) createDeletePollMessage(existingDomain, historyEntry, deletionTime);
.setEventTime(deletionTime) ofy().save().entity(deletePollMessage);
.setMsg("Domain deleted.")
.setResponseData(ImmutableList.of(DomainPendingActionNotificationResponse.create(
existingResource.getFullyQualifiedDomainName(), true, trid, deletionTime)))
.setParent(historyEntry)
.build();
builder.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) builder.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
.setDeletionTime(deletionTime) .setDeletionTime(deletionTime)
// Clear out all old grace periods and add REDEMPTION, which does not include a key to a // Clear out all old grace periods and add REDEMPTION, which does not include a key to a
@ -124,70 +128,114 @@ public class DomainDeleteFlow extends ResourceSyncDeleteFlow<DomainResource, Bui
.setGracePeriods(ImmutableSet.of(GracePeriod.createWithoutBillingEvent( .setGracePeriods(ImmutableSet.of(GracePeriod.createWithoutBillingEvent(
GracePeriodStatus.REDEMPTION, GracePeriodStatus.REDEMPTION,
now.plus(registry.getRedemptionGracePeriodLength()), now.plus(registry.getRedemptionGracePeriodLength()),
getClientId()))) clientId)))
.setDeletePollMessage(Key.create(deletePollMessage)); .setDeletePollMessage(Key.create(deletePollMessage));
} }
handleExtraFlowLogic(existingDomain, historyEntry);
// Handle extra flow logic, if any. DomainResource newDomain = builder.build();
if (extraFlowLogic.isPresent()) { updateForeignKeyIndexDeletionTime(newDomain);
extraFlowLogic.get().performAdditionalDomainDeleteLogic( handlePendingTransferOnDelete(existingDomain, newDomain, now, historyEntry);
existingResource, getClientId(), now, eppInput, historyEntry); // Close the autorenew billing event and poll message. This may delete the poll message.
} updateAutorenewRecurrenceEndTime(existingDomain, now);
} // If there's a pending transfer, the gaining client's autorenew billing
// event and poll message will already have been deleted in
@Override // ResourceDeleteFlow since it's listed in serverApproveEntities.
protected final void enqueueTasks() { DnsQueue.create().addDomainRefreshTask(existingDomain.getFullyQualifiedDomainName());
DnsQueue.create().addDomainRefreshTask(existingResource.getFullyQualifiedDomainName());
}
@Override
protected final void modifySyncDeleteRelatedResources() {
// Cancel any grace periods that were still active. // Cancel any grace periods that were still active.
ImmutableList.Builder<Credit> creditsBuilder = new ImmutableList.Builder<>(); for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
for (GracePeriod gracePeriod : existingResource.getGracePeriods()) {
// No cancellation is written if the grace period was not for a billable event. // No cancellation is written if the grace period was not for a billable event.
if (gracePeriod.hasBillingEvent()) { if (gracePeriod.hasBillingEvent()) {
ofy().save().entity( ofy().save().entity(
BillingEvent.Cancellation.forGracePeriod(gracePeriod, historyEntry, targetId)); BillingEvent.Cancellation.forGracePeriod(gracePeriod, historyEntry, targetId));
Money cost;
if (gracePeriod.getType() == GracePeriodStatus.AUTO_RENEW) {
TimeOfYear recurrenceTimeOfYear =
ofy().load().key(checkNotNull(gracePeriod.getRecurringBillingEvent())).now()
.getRecurrenceTimeOfYear();
DateTime autoRenewTime = recurrenceTimeOfYear.getLastInstanceBeforeOrAt(now);
cost = getDomainRenewCost(targetId, autoRenewTime, 1);
} else {
cost =
ofy().load().key(checkNotNull(gracePeriod.getOneTimeBillingEvent())).now().getCost();
}
creditsBuilder.add(Credit.create(
cost.negated().getAmount(), FeeType.CREDIT, gracePeriod.getType().getXmlName()));
creditsCurrencyUnit = cost.getCurrencyUnit();
} }
} }
credits = creditsBuilder.build(); ofy().save().<ImmutableObject>entities(newDomain, historyEntry);
return createOutput(
// If the delete isn't immediate, save the poll message for when the delete will happen. newDomain.getDeletionTime().isAfter(now) ? SUCCESS_WITH_ACTION_PENDING : SUCCESS,
if (deletePollMessage != null) { null,
ofy().save().entity(deletePollMessage); getResponseExtensions(existingDomain));
}
// Close the autorenew billing event and poll message. This may delete the poll message.
updateAutorenewRecurrenceEndTime(existingResource, now);
if (extraFlowLogic.isPresent()) {
extraFlowLogic.get().commitAdditionalLogicChanges();
}
// If there's a pending transfer, the gaining client's autorenew billing
// event and poll message will already have been deleted in
// ResourceDeleteFlow since it's listed in serverApproveEntities.
} }
@Override private void verifyDeleteAllowed(DomainResource existingDomain, Registry registry)
protected final Code getDeleteResultCode() { throws EppException {
return newResource.getDeletionTime().isAfter(now) verifyNoDisallowedStatuses(existingDomain, DISALLOWED_STATUSES);
? SUCCESS_WITH_ACTION_PENDING : SUCCESS; verifyOptionalAuthInfoForResource(authInfo, existingDomain);
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingDomain);
if (TldState.PREDELEGATION.equals(registry.getTldState(now))) {
throw new BadCommandForRegistryPhaseException();
}
}
checkAllowedAccessToTld(getAllowedTlds(), registry.getTld().toString());
if (!existingDomain.getSubordinateHosts().isEmpty()) {
throw new DomainToDeleteHasHostsException();
}
}
private HistoryEntry buildHistoryEntry(DomainResource existingResource) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_DELETE)
.setModificationTime(now)
.setParent(Key.create(existingResource))
.build();
}
private OneTime createDeletePollMessage(
DomainResource existingResource, HistoryEntry historyEntry, DateTime deletionTime) {
return new PollMessage.OneTime.Builder()
.setClientId(existingResource.getCurrentSponsorClientId())
.setEventTime(deletionTime)
.setMsg("Domain deleted.")
.setResponseData(ImmutableList.of(
DomainPendingActionNotificationResponse.create(
existingResource.getFullyQualifiedDomainName(), true, trid, deletionTime)))
.setParent(historyEntry)
.build();
}
private void handleExtraFlowLogic(DomainResource existingResource, HistoryEntry historyEntry)
throws EppException {
Optional<RegistryExtraFlowLogic> extraFlowLogic =
RegistryExtraFlowLogicProxy.newInstanceForDomain(existingResource);
if (extraFlowLogic.isPresent()) {
extraFlowLogic.get().performAdditionalDomainDeleteLogic(
existingResource, clientId, now, eppInput, historyEntry);
extraFlowLogic.get().commitAdditionalLogicChanges();
}
}
@Nullable
private ImmutableList<FeeTransformResponseExtension> getResponseExtensions(
DomainResource existingDomain) {
FeeTransformResponseExtension.Builder feeResponseBuilder = getDeleteResponseBuilder();
if (feeResponseBuilder == null) {
return null;
}
ImmutableList.Builder<Credit> creditsBuilder = new ImmutableList.Builder<>();
for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
if (gracePeriod.hasBillingEvent()) {
Money cost = getGracePeriodCost(gracePeriod);
creditsBuilder.add(Credit.create(
cost.negated().getAmount(), FeeType.CREDIT, gracePeriod.getType().getXmlName()));
feeResponseBuilder.setCurrency(checkNotNull(cost.getCurrencyUnit()));
}
}
ImmutableList<Credit> credits = creditsBuilder.build();
if (credits.isEmpty()) {
return null;
}
return ImmutableList.of(feeResponseBuilder.setCredits(credits).build());
}
private Money getGracePeriodCost(GracePeriod gracePeriod) {
if (gracePeriod.getType() == GracePeriodStatus.AUTO_RENEW) {
DateTime autoRenewTime =
ofy().load().key(checkNotNull(gracePeriod.getRecurringBillingEvent())).now()
.getRecurrenceTimeOfYear()
.getLastInstanceBeforeOrAt(now);
return getDomainRenewCost(targetId, autoRenewTime, 1);
}
return ofy().load().key(checkNotNull(gracePeriod.getOneTimeBillingEvent())).now().getCost();
} }
@Nullable @Nullable
@ -205,27 +253,6 @@ public class DomainDeleteFlow extends ResourceSyncDeleteFlow<DomainResource, Bui
return null; return null;
} }
@Override
@Nullable
protected final ImmutableList<? extends ResponseExtension> getDeleteResponseExtensions() {
if (credits.isEmpty()) {
return null;
}
FeeTransformResponseExtension.Builder feeResponseBuilder = getDeleteResponseBuilder();
if (feeResponseBuilder == null) {
return null;
}
return ImmutableList.of(feeResponseBuilder
.setCurrency(checkNotNull(creditsCurrencyUnit))
.setCredits(credits)
.build());
}
@Override
protected final HistoryEntry.Type getHistoryEntryType() {
return HistoryEntry.Type.DOMAIN_DELETE;
}
/** Domain to be deleted has subordinate hosts. */ /** Domain to be deleted has subordinate hosts. */
static class DomainToDeleteHasHostsException extends AssociationProhibitsOperationException { static class DomainToDeleteHasHostsException extends AssociationProhibitsOperationException {
public DomainToDeleteHasHostsException() { public DomainToDeleteHasHostsException() {

View file

@ -28,14 +28,14 @@ import static google.registry.testing.GenericEppResourceSubject.assertAboutEppRe
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.ResourceFlow.BadCommandForRegistryPhaseException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
import google.registry.flows.ResourceMutateFlow.ResourceDoesNotExistException;
import google.registry.flows.domain.DomainApplicationDeleteFlow.SunriseApplicationCannotBeDeletedInLandrushException; import google.registry.flows.domain.DomainApplicationDeleteFlow.SunriseApplicationCannotBeDeletedInLandrushException;
import google.registry.flows.domain.DomainFlowUtils.ApplicationDomainNameMismatchException; import google.registry.flows.domain.DomainFlowUtils.ApplicationDomainNameMismatchException;
import google.registry.flows.domain.DomainFlowUtils.LaunchPhaseMismatchException; import google.registry.flows.domain.DomainFlowUtils.LaunchPhaseMismatchException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.exceptions.BadCommandForRegistryPhaseException;
import google.registry.model.EppResource; import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainApplication; import google.registry.model.domain.DomainApplication;

View file

@ -43,13 +43,13 @@ import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.ResourceCreateOrMutateFlow.OnlyToolCanPassMetadataException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
import google.registry.flows.ResourceMutateFlow.ResourceDoesNotExistException;
import google.registry.flows.SingleResourceFlow.ResourceStatusProhibitsOperationException;
import google.registry.flows.domain.DomainDeleteFlow.DomainToDeleteHasHostsException; import google.registry.flows.domain.DomainDeleteFlow.DomainToDeleteHasHostsException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.exceptions.OnlyToolCanPassMetadataException;
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag; import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.billing.BillingEvent.Reason;