Support multiple versions of the EPP Fee Extension

We want to support multiple versions of the fee extension, to allow new features while maintaining backward compatibility. This CL extends the framework and adds one new version, 0.11 (spec version 7), to the existing version 0.6 (spec version 3). A follow-on CL will add version 0.12 (spec version 8).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=127849044
This commit is contained in:
Brian Mountford 2016-07-19 10:54:56 -07:00 committed by Justine Tunney
parent f75bb65fd3
commit 8443da5c5c
170 changed files with 4376 additions and 586 deletions

View file

@ -18,6 +18,8 @@ import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.io.Resources.getResource;
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
import static google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension.FEE_0_11;
import static google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension.FEE_0_6;
import static google.registry.model.registry.Registries.findTldForNameOrThrow;
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
@ -25,7 +27,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.json.simple.JSONValue.toJSONString;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.net.InternetDomainName;
import com.google.common.net.MediaType;
import com.google.template.soy.SoyFileSet;
@ -35,7 +37,6 @@ import dagger.Provides;
import google.registry.config.RegistryConfig;
import google.registry.flows.soy.DomainCheckFeeEppSoyInfo;
import google.registry.model.domain.fee.FeeCheckResponseExtension;
import google.registry.model.domain.fee.FeeCheckResponseExtension.FeeCheck;
import google.registry.model.eppoutput.CheckData.DomainCheck;
import google.registry.model.eppoutput.CheckData.DomainCheckData;
import google.registry.model.eppoutput.EppResponse;
@ -96,7 +97,7 @@ public class CheckApiAction implements Runnable {
.getBytes(UTF_8);
SessionMetadata sessionMetadata = new StatelessRequestSessionMetadata(
config.getCheckApiServletRegistrarClientId(),
ImmutableSet.of(FEE_0_6.getUri()));
FEE_EXTENSION_URIS);
EppResponse response = eppController
.handleEppCommand(
sessionMetadata,
@ -117,10 +118,16 @@ public class CheckApiAction implements Runnable {
.put("status", "success")
.put("available", available);
if (available) {
FeeCheckResponseExtension feeCheckResponse =
(FeeCheckResponseExtension) response.getExtensions().get(0);
FeeCheck feeCheck = feeCheckResponse.getChecks().get(0);
builder.put("tier", firstNonNull(feeCheck.getFeeClass(), "standard"));
FeeCheckResponseExtension<?> feeCheckResponseExtension =
(FeeCheckResponseExtension<?>) response.getFirstExtensionOfType(
FEE_0_11.getResponseExtensionClass(),
FEE_0_6.getResponseExtensionClass());
if (feeCheckResponseExtension != null) {
builder.put("tier",
firstNonNull(
Iterables.getOnlyElement(feeCheckResponseExtension.getItems()).getFeeClass(),
"standard"));
}
} else {
builder.put("reason", check.getReason());
}

View file

@ -55,7 +55,8 @@ public class EppXmlTransformer {
"domain.xsd",
"rgp.xsd",
"secdns.xsd",
"fee.xsd",
"fee06.xsd",
"fee11.xsd",
"metadata.xsd",
"mark.xsd",
"dsig.xsd",

View file

@ -26,6 +26,7 @@ import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.eppoutput.Result;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
@ -123,6 +124,11 @@ public abstract class Flow {
Collections.addAll(validExtensions, extensions);
}
protected final <E extends CommandExtension>
void registerExtensions(List<Class<? extends E>> extensions) {
validExtensions.addAll(extensions);
}
/** Get the legal command extension types for this flow. */
protected final Set<Class<? extends CommandExtension>> getValidRequestExtensions() {
return ImmutableSet.copyOf(validExtensions);

View file

@ -44,7 +44,9 @@ public abstract class LoggedInFlow extends Flow {
* declared on login.
*/
private static final ImmutableSet<String> UNDECLARED_URIS_BLACKLIST =
ImmutableSet.of(ServiceExtension.FEE_0_6.getUri());
ImmutableSet.of(
ServiceExtension.FEE_0_6.getUri(),
ServiceExtension.FEE_0_11.getUri());
/**
* The TLDs on which the logged-in registrar is allowed access domains.

View file

@ -33,6 +33,7 @@ import static google.registry.flows.domain.DomainFlowUtils.verifySignedMarks;
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.EppResourceUtils.createDomainRoid;
import static google.registry.model.EppResourceUtils.loadByUniqueId;
import static google.registry.model.domain.fee.Fee.FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.findTldForName;
import static google.registry.model.registry.label.ReservedList.matchesAnchorTenantReservation;
@ -52,7 +53,7 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainBase.Builder;
import google.registry.model.domain.DomainCommand.Create;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.fee.FeeCreateExtension;
import google.registry.model.domain.fee.FeeTransformCommandExtension;
import google.registry.model.domain.launch.LaunchCreateExtension;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.launch.LaunchNotice.InvalidChecksumException;
@ -83,7 +84,7 @@ public abstract class BaseDomainCreateFlow<R extends DomainBase, B extends Build
protected String domainLabel;
protected InternetDomainName domainName;
protected String idnTableName;
protected FeeCreateExtension feeCreate;
protected FeeTransformCommandExtension feeCreate;
protected EppCommandOperations commandOperations;
protected boolean hasSignedMarks;
protected SignedMark signedMark;
@ -96,7 +97,8 @@ public abstract class BaseDomainCreateFlow<R extends DomainBase, B extends Build
registerExtensions(SecDnsCreateExtension.class);
secDnsCreate = eppInput.getSingleExtension(SecDnsCreateExtension.class);
launchCreate = eppInput.getSingleExtension(LaunchCreateExtension.class);
feeCreate = eppInput.getSingleExtension(FeeCreateExtension.class);
feeCreate =
eppInput.getFirstExtensionOfClasses(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
hasSignedMarks = launchCreate != null && !launchCreate.getSignedMarks().isEmpty();
initDomainCreateFlow();
}

View file

@ -16,6 +16,7 @@ package google.registry.flows.domain;
import static google.registry.flows.domain.DomainFlowUtils.DISALLOWED_TLD_STATES_FOR_LAUNCH_FLOWS;
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.model.domain.fee.Fee.FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.eppoutput.Result.Code.Success;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.index.ForeignKeyIndex.loadAndGetReference;
@ -32,8 +33,6 @@ import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainApplication.Builder;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.Period;
import google.registry.model.domain.fee.FeeCreateExtension;
import google.registry.model.domain.fee.FeeCreateResponseExtension;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.domain.launch.LaunchCreateExtension;
import google.registry.model.domain.launch.LaunchCreateResponseExtension;
@ -117,7 +116,8 @@ public class DomainApplicationCreateFlow extends BaseDomainCreateFlow<DomainAppl
@Override
protected void initDomainCreateFlow() {
registerExtensions(FeeCreateExtension.class, LaunchCreateExtension.class);
registerExtensions(LaunchCreateExtension.class);
registerExtensions(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
}
@Override
@ -211,9 +211,9 @@ public class DomainApplicationCreateFlow extends BaseDomainCreateFlow<DomainAppl
.setApplicationId(newResource.getForeignKey())
.build());
if (feeCreate != null) {
responseExtensionsBuilder.add(new FeeCreateResponseExtension.Builder()
responseExtensionsBuilder.add(feeCreate.createResponseBuilder()
.setCurrency(commandOperations.getCurrency())
.setFee(commandOperations.getFees())
.setFees(commandOperations.getFees())
.build());
}

View file

@ -17,6 +17,8 @@ package google.registry.flows.domain;
import static google.registry.flows.domain.DomainFlowUtils.getReservationType;
import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest;
import static google.registry.model.EppResourceUtils.checkResourcesExist;
import static google.registry.model.domain.fee.Fee.FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.registry.label.ReservationType.UNRESERVED;
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
@ -26,16 +28,17 @@ import static google.registry.util.DomainNameUtils.getTldFromDomainName;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.fee.FeeCheckExtension;
import google.registry.model.domain.fee.FeeCheckCommandExtension;
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
import google.registry.model.domain.fee.FeeCheckResponseExtension;
import google.registry.model.domain.fee.FeeCheckResponseExtension.FeeCheck;
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
import google.registry.model.domain.launch.LaunchCheckExtension;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
import google.registry.model.eppoutput.CheckData;
import google.registry.model.eppoutput.CheckData.DomainCheck;
import google.registry.model.eppoutput.CheckData.DomainCheckData;
@ -43,8 +46,10 @@ import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.registry.label.ReservationType;
import java.util.Collections;
import java.util.Set;
import javax.inject.Inject;
import org.joda.money.CurrencyUnit;
/**
* An EPP flow that checks whether a domain can be provisioned.
@ -81,7 +86,8 @@ public class DomainCheckFlow extends BaseDomainCheckFlow {
@Override
protected void initDomainCheckFlow() throws EppException {
registerExtensions(LaunchCheckExtension.class, FeeCheckExtension.class);
registerExtensions(LaunchCheckExtension.class);
registerExtensions(FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
}
private String getMessageForCheck(String targetId, Set<String> existingIds) {
@ -103,8 +109,9 @@ public class DomainCheckFlow extends BaseDomainCheckFlow {
if (reservationType == UNRESERVED
&& getPricesForDomainName(domainName.toString(), now).isPremium()
&& registry.getPremiumPriceAckRequired()
&& !nullToEmpty(sessionMetadata.getServiceExtensionUris()).contains(
ServiceExtension.FEE_0_6.getUri())) {
&& Collections.disjoint(
nullToEmpty(sessionMetadata.getServiceExtensionUris()),
FEE_EXTENSION_URIS)) {
return "Premium names require EPP ext.";
}
return reservationType.getMessageForCheck();
@ -121,30 +128,59 @@ public class DomainCheckFlow extends BaseDomainCheckFlow {
return DomainCheckData.create(checks.build());
}
/** Handle the fee check extension. */
@Override
protected ImmutableList<? extends ResponseExtension> getResponseExtensions() throws EppException {
FeeCheckExtension feeCheck = eppInput.getSingleExtension(FeeCheckExtension.class);
if (feeCheck == null) {
return null; // No fee checks were requested.
}
ImmutableList.Builder<FeeCheck> feeChecksBuilder = new ImmutableList.Builder<>();
for (FeeCheckExtension.DomainCheck domainCheck : feeCheck.getDomains()) {
String domainName = domainCheck.getName();
if (!domainNames.containsKey(domainName)) {
/**
* Return the domains to be checked for a particular fee check item. Some versions of the fee
* extension specify the domain name in the extension item, while others use the list of domain
* names from the regular check domain availability list.
*/
private Set<String> getDomainNamesToCheck(FeeCheckCommandExtensionItem feeCheckItem)
throws OnlyCheckedNamesCanBeFeeCheckedException {
if (feeCheckItem.isDomainNameSupported()) {
String domainNameInExtension = feeCheckItem.getDomainName();
if (!domainNames.containsKey(domainNameInExtension)) {
// Although the fee extension explicitly says it's ok to fee check a domain name that you
// aren't also availability checking, we forbid it. This makes the experience simpler and
// also means we can assume any domain names in the fee checks have been validated.
throw new OnlyCheckedNamesCanBeFeeCheckedException();
}
FeeCheck.Builder builder = new FeeCheck.Builder();
handleFeeRequest(
domainCheck, builder, domainName, getTldFromDomainName(domainName), now);
feeChecksBuilder.add(builder.setName(domainName).build());
return ImmutableSet.of(domainNameInExtension);
} else {
// If this version of the fee extension is nameless, use the full list of domains.
return domainNames.keySet();
}
return ImmutableList.of(FeeCheckResponseExtension.create(feeChecksBuilder.build()));
}
}
/** Handle the fee check extension. */
@Override
protected ImmutableList<ResponseExtension> getResponseExtensions() throws EppException {
FeeCheckCommandExtension<
? extends FeeCheckCommandExtensionItem, ? extends FeeCheckResponseExtension<?>>
feeCheck = eppInput.getFirstExtensionOfClasses(
FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
if (feeCheck == null) {
return null; // No fee checks were requested.
}
CurrencyUnit topLevelCurrency = feeCheck.isCurrencySupported() ? feeCheck.getCurrency() : null;
ImmutableList.Builder<FeeCheckResponseExtensionItem> feeCheckResponseItemsBuilder =
new ImmutableList.Builder<>();
for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) {
for (String domainName : getDomainNamesToCheck(feeCheckItem)) {
FeeCheckResponseExtensionItem.Builder builder = feeCheckItem.createResponseBuilder();
handleFeeRequest(
feeCheckItem,
builder,
domainName,
getTldFromDomainName(domainName),
topLevelCurrency,
now);
feeCheckResponseItemsBuilder
.add(builder.setDomainNameIfSupported(domainName).build());
}
}
return ImmutableList.<ResponseExtension>of(
feeCheck.createResponse(feeCheckResponseItemsBuilder.build()));
}
/** By server policy, fee check names must be listed in the availability check. */
static class OnlyCheckedNamesCanBeFeeCheckedException extends ParameterValuePolicyErrorException {
OnlyCheckedNamesCanBeFeeCheckedException() {

View file

@ -15,6 +15,7 @@
package google.registry.flows.domain;
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.model.domain.fee.Fee.FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.ofy.ObjectifyService.ofy;
@ -28,7 +29,6 @@ import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainResource.Builder;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.fee.FeeCreateExtension;
import google.registry.model.domain.launch.LaunchCreateExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.registry.Registry;
@ -124,7 +124,8 @@ public class DomainCreateFlow extends DomainCreateOrAllocateFlow {
@Override
protected final void initDomainCreateOrAllocateFlow() {
registerExtensions(FeeCreateExtension.class, LaunchCreateExtension.class);
registerExtensions(LaunchCreateExtension.class);
registerExtensions(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
}
@Override

View file

@ -29,7 +29,6 @@ import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.DomainResource.Builder;
import google.registry.model.domain.Period;
import google.registry.model.domain.fee.FeeCreateResponseExtension;
import google.registry.model.eppoutput.CreateData.DomainCreateData;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.Result;
@ -108,9 +107,9 @@ public abstract class DomainCreateOrAllocateFlow
now,
newResource.getRegistrationExpirationTime()),
(feeCreate == null) ? null : ImmutableList.of(
new FeeCreateResponseExtension.Builder()
feeCreate.createResponseBuilder()
.setCurrency(commandOperations.getCurrency())
.setFee(commandOperations.getFees())
.setFees(commandOperations.getFees())
.build()));
}
}

View file

@ -37,7 +37,9 @@ import google.registry.model.domain.DomainResource;
import google.registry.model.domain.DomainResource.Builder;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.fee.Credit;
import google.registry.model.domain.fee.FeeDeleteResponseExtension;
import google.registry.model.domain.fee.FeeTransformResponseExtension;
import google.registry.model.domain.fee06.FeeDeleteResponseExtensionV06;
import google.registry.model.domain.fee11.FeeDeleteResponseExtensionV11;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
@ -48,6 +50,8 @@ import google.registry.model.poll.PendingActionNotificationResponse.DomainPendin
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
@ -169,18 +173,32 @@ public class DomainDeleteFlow extends ResourceSyncDeleteFlow<DomainResource, Bui
? SuccessWithActionPending : Success;
}
@Nullable
private FeeTransformResponseExtension.Builder getDeleteResponseBuilder() {
Set<String> uris = nullToEmpty(sessionMetadata.getServiceExtensionUris());
if (uris.contains(ServiceExtension.FEE_0_11.getUri())) {
return new FeeDeleteResponseExtensionV11.Builder();
}
if (uris.contains(ServiceExtension.FEE_0_6.getUri())) {
return new FeeDeleteResponseExtensionV06.Builder();
}
return null;
}
@Override
@Nullable
protected final ImmutableList<? extends ResponseExtension> getDeleteResponseExtensions() {
if (!credits.isEmpty()
&& nullToEmpty(sessionMetadata.getServiceExtensionUris()).contains(
ServiceExtension.FEE_0_6.getUri())) {
return ImmutableList.of(new FeeDeleteResponseExtension.Builder()
.setCurrency(checkNotNull(creditsCurrencyUnit))
.setCredits(credits)
.build());
} else {
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

View file

@ -62,11 +62,12 @@ import google.registry.model.domain.DomainCommand.CreateOrUpdate;
import google.registry.model.domain.DomainCommand.InvalidReferencesException;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.Period;
import google.registry.model.domain.fee.BaseFeeCommand;
import google.registry.model.domain.fee.BaseFeeRequest;
import google.registry.model.domain.fee.BaseFeeResponse;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeCommandDescriptor;
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem;
import google.registry.model.domain.fee.FeeQueryResponseExtensionItem;
import google.registry.model.domain.fee.FeeTransformCommandExtension;
import google.registry.model.domain.launch.LaunchExtension;
import google.registry.model.domain.launch.LaunchPhase;
import google.registry.model.domain.secdns.DelegationSignerData;
@ -101,9 +102,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.parsers.ParserConfigurationException;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.xml.sax.SAXException;
@ -555,42 +558,47 @@ public class DomainFlowUtils {
}
/**
* Validates a {@link BaseFeeRequest} and sets the appropriate fields on a {@link BaseFeeResponse}
* builder.
* Validates a {@link FeeCheckCommandExtensionItem} and sets the appropriate fields on a
* {@link FeeCheckResponseExtensionItem} builder.
*/
static void handleFeeRequest(
BaseFeeRequest feeRequest,
BaseFeeResponse.Builder<?, ?> builder,
FeeQueryCommandExtensionItem feeRequest,
FeeQueryResponseExtensionItem.Builder builder,
String domainName,
String tld,
@Nullable CurrencyUnit topLevelCurrency,
DateTime now) throws EppException {
InternetDomainName domain = InternetDomainName.from(domainName);
FeeCommandDescriptor feeCommand = feeRequest.getCommand();
Registry registry = Registry.get(tld);
int years = verifyUnitIsYears(feeRequest.getPeriod()).getValue();
boolean isSunrise = registry.getTldState(now).equals(TldState.SUNRISE);
if (feeCommand.getPhase() != null || feeCommand.getSubphase() != null) {
if (feeRequest.getPhase() != null || feeRequest.getSubphase() != null) {
throw new FeeChecksDontSupportPhasesException();
}
if (feeRequest.getCurrency() != null
&& !feeRequest.getCurrency().equals(registry.getCurrency())) {
CurrencyUnit currency =
feeRequest.isCurrencySupported() ? feeRequest.getCurrency() : topLevelCurrency;
if ((currency != null) && !currency.equals(registry.getCurrency())) {
throw new CurrencyUnitMismatchException();
}
builder
.setCommand(feeCommand)
.setCurrency(registry.getCurrency())
.setCommand(feeRequest.getCommandName(), feeRequest.getPhase(), feeRequest.getSubphase())
.setCurrencyIfSupported(registry.getCurrency())
.setPeriod(feeRequest.getPeriod())
.setClass(TldSpecificLogicProxy.getFeeClass(domainName, now).orNull());
switch (feeCommand.getCommand()) {
switch (feeRequest.getCommandName()) {
case UNKNOWN:
throw new UnknownFeeCommandException(feeCommand.getUnparsedCommandName());
throw new UnknownFeeCommandException(feeRequest.getUnparsedCommandName());
case CREATE:
if (isReserved(domain, isSunrise)) { // Don't return a create price for reserved names.
builder.setClass("reserved"); // Override whatever class we've set above.
builder.setAvailIfSupported(false);
builder.setReasonIfSupported("reserved");
} else {
builder.setAvailIfSupported(true);
builder.setFees(
TldSpecificLogicProxy.getCreatePrice(registry, domainName, now, years).getFees());
}
@ -599,11 +607,14 @@ public class DomainFlowUtils {
if (years != 1) {
throw new RestoresAreAlwaysForOneYearException();
}
builder.setAvailIfSupported(true);
builder.setFees(
TldSpecificLogicProxy.getRestorePrice(registry, domainName, now, years).getFees());
break;
// TODO(mountford): handle UPDATE
default:
// Anything else (transfer|renew) will have a "renew" fee.
builder.setAvailIfSupported(true);
builder.setFees(
TldSpecificLogicProxy.getRenewPrice(registry, domainName, now, years).getFees());
}
@ -613,7 +624,7 @@ public class DomainFlowUtils {
String domainName,
String tld,
DateTime priceTime,
final BaseFeeCommand feeCommand,
final FeeTransformCommandExtension feeCommand,
Money cost,
Money... otherCosts)
throws EppException {
@ -1014,3 +1025,4 @@ public class DomainFlowUtils {
}
}

View file

@ -21,8 +21,8 @@ import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.DomainResource.Builder;
import google.registry.model.domain.fee.FeeInfoExtension;
import google.registry.model.domain.fee.FeeInfoResponseExtension;
import google.registry.model.domain.fee06.FeeInfoCommandExtensionV06;
import google.registry.model.domain.fee06.FeeInfoResponseExtensionV06;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.rgp.RgpInfoExtension;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
@ -44,7 +44,7 @@ public class DomainInfoFlow extends BaseDomainInfoFlow<DomainResource, Builder>
@Override
protected void initSingleResourceFlow() throws EppException {
registerExtensions(FeeInfoExtension.class);
registerExtensions(FeeInfoCommandExtensionV06.class);
}
@Override
@ -87,11 +87,17 @@ public class DomainInfoFlow extends BaseDomainInfoFlow<DomainResource, Builder>
if (!gracePeriodStatuses.isEmpty()) {
extensions.add(RgpInfoExtension.create(gracePeriodStatuses));
}
FeeInfoExtension feeInfo = eppInput.getSingleExtension(FeeInfoExtension.class);
FeeInfoCommandExtensionV06 feeInfo =
eppInput.getSingleExtension(FeeInfoCommandExtensionV06.class);
if (feeInfo != null) { // Fee check was requested.
FeeInfoResponseExtension.Builder builder = new FeeInfoResponseExtension.Builder();
FeeInfoResponseExtensionV06.Builder builder = new FeeInfoResponseExtensionV06.Builder();
handleFeeRequest(
feeInfo, builder, getTargetId(), existingResource.getTld(), now);
feeInfo,
builder,
getTargetId(),
existingResource.getTld(),
null,
now);
extensions.add(builder.build());
}
return extensions.build();

View file

@ -22,6 +22,7 @@ import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurr
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.domain.DomainResource.MAX_REGISTRATION_YEARS;
import static google.registry.model.domain.fee.Fee.FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.eppoutput.Result.Code.Success;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
@ -42,8 +43,7 @@ import google.registry.model.domain.DomainResource;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeRenewExtension;
import google.registry.model.domain.fee.FeeRenewResponseExtension;
import google.registry.model.domain.fee.FeeTransformCommandExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppoutput.EppOutput;
@ -80,7 +80,7 @@ public class DomainRenewFlow extends OwnedResourceMutateFlow<DomainResource, Ren
StatusValue.PENDING_DELETE,
StatusValue.SERVER_RENEW_PROHIBITED);
protected FeeRenewExtension feeRenew;
protected FeeTransformCommandExtension feeRenew;
protected Money renewCost;
@Inject DomainRenewFlow() {}
@ -92,8 +92,9 @@ public class DomainRenewFlow extends OwnedResourceMutateFlow<DomainResource, Ren
@Override
public final void initResourceCreateOrMutateFlow() throws EppException {
registerExtensions(FeeRenewExtension.class);
feeRenew = eppInput.getSingleExtension(FeeRenewExtension.class);
registerExtensions(FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
feeRenew =
eppInput.getFirstExtensionOfClasses(FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
}
@Override
@ -176,9 +177,9 @@ public class DomainRenewFlow extends OwnedResourceMutateFlow<DomainResource, Ren
newResource.getFullyQualifiedDomainName(),
newResource.getRegistrationExpirationTime()),
(feeRenew == null) ? null : ImmutableList.of(
new FeeRenewResponseExtension.Builder()
feeRenew.createResponseBuilder()
.setCurrency(renewCost.getCurrencyUnit())
.setFee(ImmutableList.of(Fee.create(renewCost.getAmount(), "renew")))
.setFees(ImmutableList.of(Fee.create(renewCost.getAmount(), "renew")))
.build()));
}

View file

@ -20,6 +20,7 @@ import static google.registry.flows.domain.DomainFlowUtils.newAutorenewPollMessa
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotReserved;
import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked;
import static google.registry.model.domain.fee.Fee.FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.eppoutput.Result.Code.Success;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
@ -38,8 +39,7 @@ import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeUpdateExtension;
import google.registry.model.domain.fee.FeeUpdateResponseExtension;
import google.registry.model.domain.fee.FeeTransformCommandExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.rgp.RgpUpdateExtension;
import google.registry.model.eppcommon.StatusValue;
@ -71,7 +71,7 @@ import org.joda.time.DateTime;
*/
public class DomainRestoreRequestFlow extends OwnedResourceMutateFlow<DomainResource, Update> {
protected FeeUpdateExtension feeUpdate;
protected FeeTransformCommandExtension feeUpdate;
protected Money restoreCost;
protected Money renewCost;
@ -79,7 +79,8 @@ public class DomainRestoreRequestFlow extends OwnedResourceMutateFlow<DomainReso
@Override
protected final void initResourceCreateOrMutateFlow() throws EppException {
registerExtensions(FeeUpdateExtension.class, RgpUpdateExtension.class);
registerExtensions(RgpUpdateExtension.class);
registerExtensions(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
}
@Override
@ -101,7 +102,8 @@ public class DomainRestoreRequestFlow extends OwnedResourceMutateFlow<DomainReso
verifyNotReserved(InternetDomainName.from(targetId), false);
verifyPremiumNameIsNotBlocked(targetId, now, getClientId());
}
feeUpdate = eppInput.getSingleExtension(FeeUpdateExtension.class);
feeUpdate = eppInput.getFirstExtensionOfClasses(
FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
restoreCost = Registry.get(tld).getStandardRestoreCost();
renewCost = getDomainRenewCost(targetId, now, 1);
validateFeeChallenge(targetId, tld, now, feeUpdate, restoreCost, renewCost);
@ -186,9 +188,9 @@ public class DomainRestoreRequestFlow extends OwnedResourceMutateFlow<DomainReso
Success,
null,
(feeUpdate == null) ? null : ImmutableList.of(
new FeeUpdateResponseExtension.Builder()
feeUpdate.createResponseBuilder()
.setCurrency(restoreCost.getCurrencyUnit())
.setFee(ImmutableList.of(
.setFees(ImmutableList.of(
Fee.create(restoreCost.getAmount(), "restore"),
Fee.create(renewCost.getAmount(), "renew")))
.build()));

View file

@ -14,13 +14,13 @@
package google.registry.flows.domain;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked;
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.domain.DomainResource.extendRegistrationWithCap;
import static google.registry.model.domain.fee.Fee.FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@ -38,8 +38,7 @@ import google.registry.model.domain.DomainCommand.Transfer;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.Period;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeTransferExtension;
import google.registry.model.domain.fee.FeeTransferResponseExtension;
import google.registry.model.domain.fee.FeeTransformCommandExtension;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
@ -92,7 +91,7 @@ public class DomainTransferRequestFlow
/**
* An optional extension from the client specifying how much they think the transfer should cost.
*/
private FeeTransferExtension feeTransfer;
private FeeTransformCommandExtension feeTransfer;
@Inject DomainTransferRequestFlow() {}
@ -103,8 +102,9 @@ public class DomainTransferRequestFlow
@Override
protected final void initResourceTransferRequestFlow() {
registerExtensions(FeeTransferExtension.class);
feeTransfer = eppInput.getSingleExtension(FeeTransferExtension.class);
registerExtensions(FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
feeTransfer = eppInput.getFirstExtensionOfClasses(
FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
// The "existingResource" field is loaded before this function is called, but it may be null if
// the domain name specified is invalid or doesn't exist. If that's the case, simply exit
// early, and ResourceMutateFlow will later throw ResourceToMutateDoesNotExistException.
@ -162,9 +162,9 @@ public class DomainTransferRequestFlow
@Override
protected ImmutableList<? extends ResponseExtension> getTransferResponseExtensions() {
if (feeTransfer != null) {
return ImmutableList.of(new FeeTransferResponseExtension.Builder()
return ImmutableList.of(feeTransfer.createResponseBuilder()
.setCurrency(renewCost.getCurrencyUnit())
.setFee(ImmutableList.of(Fee.create(renewCost.getAmount(), "renew")))
.setFees(ImmutableList.of(Fee.create(renewCost.getAmount(), "renew")))
.build());
} else {
return null;