Inject a DomainPricingLogic into ExpandRecurringBillingEventsAction (#1648)

* Inject a DomainPricingLogic into ExpandRecurringBillingEventsAction

This will be used in other PRs to set the renewal price correctly based on the
renewal price behavior of the BillingRecurrence event.

Note that, in order for this to work, a not-null constraint has been lifted on
the EPP flow state when the DomainPricingCustomLogic is being constructed, as
the pricing here will occur in a backend action outside the context of any EPP
flow.
This commit is contained in:
Ben McIlwain 2022-05-27 11:46:36 -04:00 committed by GitHub
parent 1e6e8c79f3
commit 1888b2c9a1
10 changed files with 71 additions and 30 deletions

View file

@ -44,6 +44,7 @@ import com.google.common.collect.Range;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig.Config;
import google.registry.flows.domain.DomainPricingLogic;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.mapreduce.inputs.NullInput;
import google.registry.model.ImmutableObject;
@ -98,6 +99,8 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
@Inject @Parameter(PARAM_DRY_RUN) boolean isDryRun;
@Inject @Parameter(PARAM_CURSOR_TIME) Optional<DateTime> cursorTimeParam;
@Inject DomainPricingLogic domainPricingLogic;
@Inject Response response;
@Inject ExpandRecurringBillingEventsAction() {}

View file

@ -17,6 +17,8 @@ package google.registry.flows.custom;
import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.model.eppinput.EppInput;
import java.util.Optional;
import javax.annotation.Nullable;
/**
* An abstract base class for all flow custom logic that stores the flow's {@link EppInput} and
@ -24,26 +26,38 @@ import google.registry.model.eppinput.EppInput;
*/
public abstract class BaseFlowCustomLogic {
private final EppInput eppInput;
private final SessionMetadata sessionMetadata;
private final FlowMetadata flowMetadata;
@Nullable private final EppInput eppInput;
@Nullable private final SessionMetadata sessionMetadata;
@Nullable private final FlowMetadata flowMetadata;
/**
* Constructs a BaseFlowCustomLogic for the specified EPP flow state.
*
* <p>Note that it is possible for the EPP flow state to be absent, which happens when the custom
* logic is running outside the context of an EPP flow (e.g. {@link DomainPricingCustomLogic} in
* backend actions).
*/
protected BaseFlowCustomLogic(
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
@Nullable EppInput eppInput,
@Nullable SessionMetadata sessionMetadata,
@Nullable FlowMetadata flowMetadata) {
this.eppInput = eppInput;
this.sessionMetadata = sessionMetadata;
this.flowMetadata = flowMetadata;
}
protected EppInput getEppInput() {
return eppInput;
/** Returns the {@link EppInput}, which may be empty outside a flow context. */
protected Optional<EppInput> getEppInput() {
return Optional.ofNullable(eppInput);
}
protected SessionMetadata getSessionMetadata() {
return sessionMetadata;
/** Returns the {@link SessionMetadata}, which may be empty outside a flow context. */
protected Optional<SessionMetadata> getSessionMetadata() {
return Optional.ofNullable(sessionMetadata);
}
protected FlowMetadata getFlowMetadata() {
return flowMetadata;
/** Returns the {@link FlowMetadata}, which may be empty outside a flow context. */
protected Optional<FlowMetadata> getFlowMetadata() {
return Optional.ofNullable(flowMetadata);
}
}

View file

@ -18,6 +18,7 @@ import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.model.eppinput.EppInput;
import java.util.Optional;
/**
* A no-op base custom logic factory.
@ -63,7 +64,10 @@ public class CustomLogicFactory {
}
public DomainPricingCustomLogic forDomainPricing(
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
return new DomainPricingCustomLogic(eppInput, sessionMetadata, flowMetadata);
Optional<EppInput> eppInput,
Optional<SessionMetadata> sessionMetadata,
Optional<FlowMetadata> flowMetadata) {
return new DomainPricingCustomLogic(
eppInput.orElse(null), sessionMetadata.orElse(null), flowMetadata.orElse(null));
}
}

View file

@ -14,15 +14,17 @@
package google.registry.flows.custom;
import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.model.eppinput.EppInput;
import java.util.Optional;
/** Dagger module to provide instances of custom logic classes for EPP flows. */
@Module
public class CustomLogicModule {
public abstract class CustomLogicModule {
@Provides
static DomainCreateFlowCustomLogic provideDomainCreateFlowCustomLogic(
@ -81,9 +83,20 @@ public class CustomLogicModule {
@Provides
static DomainPricingCustomLogic provideDomainPricingCustomLogic(
CustomLogicFactory factory,
EppInput eppInput,
SessionMetadata sessionMetadata,
FlowMetadata flowMetadata) {
Optional<EppInput> eppInput,
Optional<SessionMetadata> sessionMetadata,
Optional<FlowMetadata> flowMetadata) {
// Note that, for DomainPricingCustomLogic, the EPP flow state won't be present outside the
// context of an EPP flow.
return factory.forDomainPricing(eppInput, sessionMetadata, flowMetadata);
}
@BindsOptionalOf
abstract EppInput optionalEppInput();
@BindsOptionalOf
abstract SessionMetadata optionalSessionMetadata();
@BindsOptionalOf
abstract FlowMetadata optionalFlowMetadata();
}

View file

@ -24,6 +24,7 @@ import google.registry.flows.domain.FeesAndCredits;
import google.registry.model.ImmutableObject;
import google.registry.model.eppinput.EppInput;
import google.registry.model.tld.Registry;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
/**
@ -34,7 +35,9 @@ import org.joda.time.DateTime;
public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
public DomainPricingCustomLogic(
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
@Nullable EppInput eppInput,
@Nullable SessionMetadata sessionMetadata,
@Nullable FlowMetadata flowMetadata) {
super(eppInput, sessionMetadata, flowMetadata);
}

View file

@ -23,7 +23,6 @@ import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.FlowScope;
import google.registry.flows.custom.DomainPricingCustomLogic;
import google.registry.flows.custom.DomainPricingCustomLogic.CreatePriceParameters;
import google.registry.flows.custom.DomainPricingCustomLogic.RenewPriceParameters;
@ -50,7 +49,6 @@ import org.joda.time.DateTime;
* providing a {@link DomainPricingCustomLogic} implementation that operates on cross-TLD or per-TLD
* logic.
*/
@FlowScope
public final class DomainPricingLogic {
@Inject DomainPricingCustomLogic customLogic;

View file

@ -61,6 +61,7 @@ import google.registry.export.UploadDatastoreBackupAction;
import google.registry.export.sheet.SheetModule;
import google.registry.export.sheet.SyncRegistrarsSheetAction;
import google.registry.flows.FlowComponent;
import google.registry.flows.custom.CustomLogicModule;
import google.registry.mapreduce.MapreduceModule;
import google.registry.model.replay.ReplicateToDatastoreAction;
import google.registry.monitoring.whitebox.WhiteboxModule;
@ -103,6 +104,7 @@ import google.registry.tools.javascrap.CreateSyntheticHistoryEntriesAction;
BillingModule.class,
CloudDnsWriterModule.class,
CronModule.class,
CustomLogicModule.class,
DnsCountQueryCoordinatorModule.class,
DnsModule.class,
DnsUpdateConfigModule.class,

View file

@ -48,14 +48,14 @@ import google.registry.tools.server.VerifyOteAction;
@RequestScope
@Subcomponent(
modules = {
BackupModule.class,
DnsModule.class,
EppToolModule.class,
LoadTestModule.class,
MapreduceModule.class,
RequestModule.class,
ToolsServerModule.class,
WhiteboxModule.class,
BackupModule.class,
DnsModule.class,
EppToolModule.class,
LoadTestModule.class,
MapreduceModule.class,
RequestModule.class,
ToolsServerModule.class,
WhiteboxModule.class,
})
interface ToolsRequestComponent {
CreateGroupsAction createGroupsAction();

View file

@ -17,6 +17,7 @@ package google.registry.flows.custom;
import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.model.eppinput.EppInput;
import java.util.Optional;
/** A custom logic factory for testing. */
public class TestCustomLogicFactory extends CustomLogicFactory {
@ -29,7 +30,10 @@ public class TestCustomLogicFactory extends CustomLogicFactory {
@Override
public DomainPricingCustomLogic forDomainPricing(
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
return new TestDomainPricingCustomLogic(eppInput, sessionMetadata, flowMetadata);
Optional<EppInput> eppInput,
Optional<SessionMetadata> sessionMetadata,
Optional<FlowMetadata> flowMetadata) {
return new TestDomainPricingCustomLogic(
eppInput.orElse(null), sessionMetadata.orElse(null), flowMetadata.orElse(null));
}
}

View file

@ -36,7 +36,7 @@ public class TestDomainCreateFlowCustomLogic extends DomainCreateFlowCustomLogic
new PollMessage.OneTime.Builder()
.setParent(parameters.historyEntry())
.setEventTime(tm().getTransactionTime())
.setRegistrarId(getSessionMetadata().getRegistrarId())
.setRegistrarId(getSessionMetadata().get().getRegistrarId())
.setMsg("Custom logic was triggered")
.build();
return EntityChanges.newBuilder()