Support date and notAfter in fee extension response v12

When custom effective date is passed in the check command, the response should
contain that date as an acknowledgemant that the check is performed at a time
different from now.

Also when the fee(s) returned contains a validDateRange (i. e. EAP fees that
are only valid during a certain period), the response will contain a notAfter
field which is the date after which the quoted fee(s) are no longer valid. (i.
e. the earliest of the end dates of all fees that would expire.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=133989775
This commit is contained in:
jianglai 2016-09-22 13:07:21 -07:00 committed by Ben McIlwain
parent 863eac3b11
commit b783acfcc6
13 changed files with 139 additions and 25 deletions

View file

@ -187,9 +187,7 @@ public final class DomainCheckFlow extends LoggedInFlow {
domainNames.get(domainName), domainNames.get(domainName),
clientId, clientId,
feeCheck.getCurrency(), feeCheck.getCurrency(),
feeCheckItem.getEffectiveDate().isPresent() now,
? feeCheckItem.getEffectiveDate().get()
: now,
eppInput); eppInput);
responseItems.add(builder.setDomainNameIfSupported(domainName).build()); responseItems.add(builder.setDomainNameIfSupported(domainName).build());
} }

View file

@ -27,6 +27,7 @@ import static google.registry.model.registry.label.ReservedList.getReservation;
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName; import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
import static google.registry.tldconfig.idn.IdnLabelValidator.findValidIdnTableForTld; import static google.registry.tldconfig.idn.IdnLabelValidator.findValidIdnTableForTld;
import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.isAtOrAfter; import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static google.registry.util.DomainNameUtils.ACE_PREFIX; import static google.registry.util.DomainNameUtils.ACE_PREFIX;
@ -64,8 +65,6 @@ import google.registry.model.domain.DomainResource;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.fee.Credit; import google.registry.model.domain.fee.Credit;
import google.registry.model.domain.fee.Fee; import google.registry.model.domain.fee.Fee;
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.FeeQueryCommandExtensionItem;
import google.registry.model.domain.fee.FeeQueryResponseExtensionItem; import google.registry.model.domain.fee.FeeQueryResponseExtensionItem;
import google.registry.model.domain.fee.FeeTransformCommandExtension; import google.registry.model.domain.fee.FeeTransformCommandExtension;
@ -570,8 +569,8 @@ public class DomainFlowUtils {
} }
/** /**
* Validates a {@link FeeCheckCommandExtensionItem} and sets the appropriate fields on a * Validates a {@link FeeQueryCommandExtensionItem} and sets the appropriate fields on a {@link
* {@link FeeCheckResponseExtensionItem} builder. * FeeQueryResponseExtensionItem} builder.
*/ */
static void handleFeeRequest( static void handleFeeRequest(
FeeQueryCommandExtensionItem feeRequest, FeeQueryCommandExtensionItem feeRequest,
@ -579,8 +578,14 @@ public class DomainFlowUtils {
InternetDomainName domain, InternetDomainName domain,
String clientId, String clientId,
@Nullable CurrencyUnit topLevelCurrency, @Nullable CurrencyUnit topLevelCurrency,
DateTime now, DateTime currentDate,
EppInput eppInput) throws EppException { EppInput eppInput) throws EppException {
DateTime now = currentDate;
// Use the custom effective date specified in the fee check request, if there is one.
if (feeRequest.getEffectiveDate().isPresent()) {
now = feeRequest.getEffectiveDate().get();
builder.setEffectiveDateIfSupported(now);
}
String domainNameString = domain.toString(); String domainNameString = domain.toString();
Registry registry = Registry.get(domain.parent().toString()); Registry registry = Registry.get(domain.parent().toString());
int years = verifyUnitIsYears(feeRequest.getPeriod()).getValue(); int years = verifyUnitIsYears(feeRequest.getPeriod()).getValue();
@ -602,6 +607,7 @@ public class DomainFlowUtils {
.setPeriod(feeRequest.getPeriod()) .setPeriod(feeRequest.getPeriod())
.setClass(TldSpecificLogicProxy.getFeeClass(domainNameString, now).orNull()); .setClass(TldSpecificLogicProxy.getFeeClass(domainNameString, now).orNull());
List<Fee> fees = ImmutableList.of();
switch (feeRequest.getCommandName()) { switch (feeRequest.getCommandName()) {
case CREATE: case CREATE:
if (isReserved(domain, isSunrise)) { // Don't return a create price for reserved names. if (isReserved(domain, isSunrise)) { // Don't return a create price for reserved names.
@ -610,36 +616,53 @@ public class DomainFlowUtils {
builder.setReasonIfSupported("reserved"); builder.setReasonIfSupported("reserved");
} else { } else {
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
builder.setFees(TldSpecificLogicProxy.getCreatePrice( fees = TldSpecificLogicProxy.getCreatePrice(
registry, domainNameString, clientId, now, years, eppInput).getFees()); registry, domainNameString, clientId, now, years, eppInput).getFees();
} }
break; break;
case RENEW: case RENEW:
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
builder.setFees(TldSpecificLogicProxy.getRenewPrice( fees = TldSpecificLogicProxy.getRenewPrice(
registry, domainNameString, clientId, now, years, eppInput).getFees()); registry, domainNameString, clientId, now, years, eppInput).getFees();
break; break;
case RESTORE: case RESTORE:
if (years != 1) { if (years != 1) {
throw new RestoresAreAlwaysForOneYearException(); throw new RestoresAreAlwaysForOneYearException();
} }
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
builder.setFees(TldSpecificLogicProxy.getRestorePrice( fees = TldSpecificLogicProxy.getRestorePrice(
registry, domainNameString, clientId, now, eppInput).getFees()); registry, domainNameString, clientId, now, eppInput).getFees();
break; break;
case TRANSFER: case TRANSFER:
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
builder.setFees(TldSpecificLogicProxy.getTransferPrice( fees = TldSpecificLogicProxy.getTransferPrice(
registry, domainNameString, clientId, now, years, eppInput).getFees()); registry, domainNameString, clientId, now, years, eppInput).getFees();
break; break;
case UPDATE: case UPDATE:
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
builder.setFees(TldSpecificLogicProxy.getUpdatePrice( fees = TldSpecificLogicProxy.getUpdatePrice(
registry, domainNameString, clientId, now, eppInput).getFees()); registry, domainNameString, clientId, now, eppInput).getFees();
break; break;
default: default:
throw new UnknownFeeCommandException(feeRequest.getUnparsedCommandName()); throw new UnknownFeeCommandException(feeRequest.getUnparsedCommandName());
} }
// Set the fees, and based on the validDateRange of the fees, set the notAfterDate.
if (!fees.isEmpty()) {
builder.setFees(fees);
DateTime notAfterDate = null;
for (Fee fee : fees) {
if (fee.hasValidDateRange()) {
DateTime endDate = fee.getValidDateRange().upperEndpoint();
if (notAfterDate == null || notAfterDate.isAfter(endDate)) {
notAfterDate = endDate;
}
}
}
if (notAfterDate != null && !notAfterDate.equals(END_OF_TIME)) {
builder.setNotAfterDateIfSupported(notAfterDate);
}
}
} }
public static void validateFeeChallenge( public static void validateFeeChallenge(

View file

@ -128,7 +128,7 @@ public final class DomainInfoFlow extends LoggedInFlow {
InternetDomainName.from(targetId), InternetDomainName.from(targetId),
clientId, clientId,
null, null,
feeInfo.getEffectiveDate().isPresent() ? feeInfo.getEffectiveDate().get() : now, now,
eppInput); eppInput);
extensions.add(builder.build()); extensions.add(builder.build());
} }

View file

@ -119,6 +119,11 @@ public abstract class BaseFee extends ImmutableObject {
return validDateRange != null; return validDateRange != null;
} }
public Range<DateTime> getValidDateRange() {
checkState(hasValidDateRange());
return validDateRange;
}
protected void generateDescription(Object... args) { protected void generateDescription(Object... args) {
checkState(type != null); checkState(type != null);
description = type.renderDescription(args); description = type.renderDescription(args);

View file

@ -18,6 +18,7 @@ import google.registry.model.domain.Period;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName; import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import java.util.List; import java.util.List;
import org.joda.money.CurrencyUnit; import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
/** /**
* Interface for individual query items in Check and Info response. Each item indicates the fees and * Interface for individual query items in Check and Info response. Each item indicates the fees and
@ -50,6 +51,12 @@ public interface FeeQueryResponseExtensionItem {
/** The reason that the check item cannot be calculated. */ /** The reason that the check item cannot be calculated. */
public Builder setReasonIfSupported(String reason); public Builder setReasonIfSupported(String reason);
/** The effective date that the check is run on. */
public Builder setEffectiveDateIfSupported(DateTime effectiveDate);
/** The date after which the quoted fees are no longer valid. */
public Builder setNotAfterDateIfSupported(DateTime notAfterDate);
public Builder setCommand(CommandName commandName, String phase, String subphase); public Builder setCommand(CommandName commandName, String phase, String subphase);
public Builder setPeriod(Period period); public Builder setPeriod(Period period);

View file

@ -18,6 +18,7 @@ import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
import google.registry.model.domain.fee.FeeQueryResponseExtensionItemImpl; import google.registry.model.domain.fee.FeeQueryResponseExtensionItemImpl;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import org.joda.money.CurrencyUnit; import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
/** The version 0.6 response for a domain check on a single resource. */ /** The version 0.6 response for a domain check on a single resource. */
@XmlType(propOrder = {"name", "currency", "command", "period", "fee", "feeClass"}) @XmlType(propOrder = {"name", "currency", "command", "period", "fee", "feeClass"})
@ -54,5 +55,16 @@ public class FeeCheckResponseExtensionItemV06
public Builder setReasonIfSupported(String reason) { public Builder setReasonIfSupported(String reason) {
return this; return this;
} }
@Override
public Builder setEffectiveDateIfSupported(DateTime effectiveDate) {
return this;
}
@Override
public Builder setNotAfterDateIfSupported(DateTime notAfterDate) {
return this;
}
} }
} }

View file

@ -20,6 +20,7 @@ import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import org.joda.money.CurrencyUnit; import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
/** /**
* An XML data object that represents a fee extension that may be present on the response to EPP * An XML data object that represents a fee extension that may be present on the response to EPP
@ -52,5 +53,15 @@ public class FeeInfoResponseExtensionV06
getInstance().currency = currency; getInstance().currency = currency;
return this; return this;
} }
@Override
public Builder setEffectiveDateIfSupported(DateTime effectiveDate) {
return this;
}
@Override
public Builder setNotAfterDateIfSupported(DateTime notAfterDate) {
return this;
}
} }
} }

View file

@ -20,6 +20,7 @@ import google.registry.model.domain.fee.FeeQueryResponseExtensionItemImpl;
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import org.joda.money.CurrencyUnit; import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
/** The version 0.11 response for a domain check on a single resource. */ /** The version 0.11 response for a domain check on a single resource. */
@XmlType(propOrder = {"object", "command", "currency", "period", "fee", "feeClass", "reason"}) @XmlType(propOrder = {"object", "command", "currency", "period", "fee", "feeClass", "reason"})
@ -66,5 +67,15 @@ public class FeeCheckResponseExtensionItemV11
getInstance().reason = reason; getInstance().reason = reason;
return this; return this;
} }
@Override
public Builder setEffectiveDateIfSupported(DateTime effectiveDate) {
return this;
}
@Override
public Builder setNotAfterDateIfSupported(DateTime notAfterDate) {
return this;
}
} }
} }

View file

@ -27,11 +27,10 @@ import java.util.List;
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import org.joda.time.DateTime;
/** /** The version 0.12 response command entity for a domain check on a single resource. */
* The version 0.12 response command entity for a domain check on a single resource. @XmlType(propOrder = {"period", "fee", "feeClass", "effectiveDate", "notAfterDate"})
*/
@XmlType(propOrder = {"period", "fee", "feeClass"})
public class FeeCheckResponseExtensionItemCommandV12 extends ImmutableObject { public class FeeCheckResponseExtensionItemCommandV12 extends ImmutableObject {
/** The command that was checked. */ /** The command that was checked. */
@ -64,6 +63,15 @@ public class FeeCheckResponseExtensionItemCommandV12 extends ImmutableObject {
@XmlElement(name = "class") @XmlElement(name = "class")
String feeClass; String feeClass;
/** The effective date that the check is to be performed on (if specified in the query). */
@XmlElement(name = "date")
DateTime effectiveDate;
/** The date after which the quoted fee is no longer valid (if applicable). */
@XmlElement(name = "notAfter")
DateTime notAfterDate;
public String getFeeClass() { public String getFeeClass() {
return feeClass; return feeClass;
} }
@ -92,6 +100,16 @@ public class FeeCheckResponseExtensionItemCommandV12 extends ImmutableObject {
return this; return this;
} }
public Builder setEffectiveDate(DateTime effectiveDate) {
getInstance().effectiveDate = effectiveDate;
return this;
}
public Builder setNotAfterDate(DateTime notAfterDate) {
getInstance().notAfterDate = notAfterDate;
return this;
}
public Builder setFee(List<Fee> fees) { public Builder setFee(List<Fee> fees) {
getInstance().fee = forceEmptyToNull(ImmutableList.copyOf(fees)); getInstance().fee = forceEmptyToNull(ImmutableList.copyOf(fees));
return this; return this;

View file

@ -27,6 +27,7 @@ import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName
import java.util.List; import java.util.List;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import org.joda.money.CurrencyUnit; import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
/** /**
* The version 0.12 response for a domain check on a single resource. * The version 0.12 response for a domain check on a single resource.
@ -111,5 +112,17 @@ public class FeeCheckResponseExtensionItemV12
getInstance().command = commandBuilder.build(); getInstance().command = commandBuilder.build();
return super.build(); return super.build();
} }
@Override
public Builder setEffectiveDateIfSupported(DateTime effectiveDate) {
commandBuilder.setEffectiveDate(effectiveDate);
return this;
}
@Override
public Builder setNotAfterDateIfSupported(DateTime notAfterDate) {
commandBuilder.setNotAfterDate(notAfterDate);
return this;
}
} }
} }

View file

@ -60,6 +60,7 @@ 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;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
/** Unit tests for {@link DomainCheckFlow}. */ /** Unit tests for {@link DomainCheckFlow}. */
@ -804,4 +805,10 @@ public class DomainCheckFlowTest
"domain_check_eap_fee_response_date_v12.xml"); "domain_check_eap_fee_response_date_v12.xml");
} }
@Ignore
@Test
public void testSuccess_feeCheck_multipleRanges() throws Exception {
// TODO: If at some point we have more than one type of fees that are time dependent, populate
// this test to test if the notAfter date is the earliest of the end points of the ranges.
}
} }

View file

@ -29,6 +29,8 @@
<fee:period unit="y">1</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="create">13.00</fee:fee> <fee:fee description="create">13.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 2010-01-03T10:00:00.000Z">50.00</fee:fee> <fee:fee description="Early Access Period, fee expires: 2010-01-03T10:00:00.000Z">50.00</fee:fee>
<fee:date>2010-01-02T13:22:21Z</fee:date>
<fee:notAfter>2010-01-03T10:00:00.000Z</fee:notAfter>
</fee:command> </fee:command>
</fee:cd> </fee:cd>
<fee:cd> <fee:cd>
@ -39,6 +41,8 @@
<fee:period unit="y">1</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="create">13.00</fee:fee> <fee:fee description="create">13.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 2010-01-03T10:00:00.000Z">50.00</fee:fee> <fee:fee description="Early Access Period, fee expires: 2010-01-03T10:00:00.000Z">50.00</fee:fee>
<fee:date>2010-01-02T13:22:21Z</fee:date>
<fee:notAfter>2010-01-03T10:00:00.000Z</fee:notAfter>
</fee:command> </fee:command>
</fee:cd> </fee:cd>
<fee:cd> <fee:cd>
@ -49,6 +53,8 @@
<fee:period unit="y">1</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="create">13.00</fee:fee> <fee:fee description="create">13.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 2010-01-03T10:00:00.000Z">50.00</fee:fee> <fee:fee description="Early Access Period, fee expires: 2010-01-03T10:00:00.000Z">50.00</fee:fee>
<fee:date>2010-01-02T13:22:21Z</fee:date>
<fee:notAfter>2010-01-03T10:00:00.000Z</fee:notAfter>
</fee:command> </fee:command>
</fee:cd> </fee:cd>
</fee:chkData> </fee:chkData>

View file

@ -29,6 +29,7 @@
<fee:period unit="y">1</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="create">13.00</fee:fee> <fee:fee description="create">13.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00</fee:fee> <fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00</fee:fee>
<fee:notAfter>2010-01-02T10:00:00.000Z</fee:notAfter>
</fee:command> </fee:command>
</fee:cd> </fee:cd>
<fee:cd> <fee:cd>
@ -39,6 +40,7 @@
<fee:period unit="y">1</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="create">13.00</fee:fee> <fee:fee description="create">13.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00</fee:fee> <fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00</fee:fee>
<fee:notAfter>2010-01-02T10:00:00.000Z</fee:notAfter>
</fee:command> </fee:command>
</fee:cd> </fee:cd>
<fee:cd> <fee:cd>
@ -49,6 +51,7 @@
<fee:period unit="y">1</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="create">13.00</fee:fee> <fee:fee description="create">13.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00</fee:fee> <fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00</fee:fee>
<fee:notAfter>2010-01-02T10:00:00.000Z</fee:notAfter>
</fee:command> </fee:command>
</fee:cd> </fee:cd>
</fee:chkData> </fee:chkData>