diff --git a/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java b/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java index f5c52884b..035760e17 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java @@ -38,6 +38,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; +import com.google.common.flogger.FluentLogger; import com.google.common.net.InternetDomainName; import google.registry.config.RegistryConfig.Config; import google.registry.flows.EppException; @@ -116,6 +117,7 @@ import org.joda.time.DateTime; @ReportingSpec(ActivityReportField.DOMAIN_CHECK) public final class DomainCheckFlow implements Flow { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); @Inject ResourceCommand resourceCommand; @Inject ExtensionManager extensionManager; @Inject EppInput eppInput; @@ -271,6 +273,12 @@ public final class DomainCheckFlow implements Flow { for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) { for (String domainName : getDomainNamesToCheckForFee(feeCheckItem, domainNames.keySet())) { + Optional defaultToken = + DomainFlowUtils.checkForDefaultToken( + Registry.get(InternetDomainName.from(domainName).parent().toString()), + domainName, + registrarId, + now); FeeCheckResponseExtensionItem.Builder builder = feeCheckItem.createResponseBuilder(); Optional domain = Optional.ofNullable(domainObjs.get(domainName)); handleFeeRequest( @@ -281,7 +289,7 @@ public final class DomainCheckFlow implements Flow { feeCheck.getCurrency(), now, pricingLogic, - allocationToken, + allocationToken.isPresent() ? allocationToken : defaultToken, availableDomains.contains(domainName), recurrences.getOrDefault(domainName, null)); responseItems.add(builder.setDomainNameIfSupported(domainName).build()); diff --git a/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java b/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java index 12bab5789..4cf7c683c 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java @@ -15,8 +15,6 @@ package google.registry.flows.domain; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static google.registry.flows.FlowUtils.persistEntityChanges; import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn; @@ -54,7 +52,6 @@ import static google.registry.model.tld.Registry.TldState.QUIET_PERIOD; import static google.registry.model.tld.Registry.TldState.START_DATE_SUNRISE; import static google.registry.model.tld.label.ReservationType.NAME_COLLISION; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; -import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.leapSafeAddYears; @@ -64,7 +61,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.net.InternetDomainName; import google.registry.dns.DnsUtils; import google.registry.flows.EppException; -import google.registry.flows.EppException.AssociationProhibitsOperationException; import google.registry.flows.EppException.CommandUseErrorException; import google.registry.flows.EppException.ParameterValuePolicyErrorException; import google.registry.flows.ExtensionManager; @@ -121,9 +117,7 @@ import google.registry.model.tld.Registry.TldType; import google.registry.model.tld.label.ReservationType; import google.registry.model.tmch.ClaimsList; import google.registry.model.tmch.ClaimsListDao; -import google.registry.persistence.VKey; import google.registry.tmch.LordnTaskUtils.LordnPhase; -import java.util.Map; import java.util.Optional; import javax.annotation.Nullable; import javax.inject.Inject; @@ -280,7 +274,8 @@ public final class DomainCreateFlow implements TransactionalFlow { eppInput.getSingleExtension(AllocationTokenExtension.class)); boolean defaultTokenUsed = false; if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) { - allocationToken = checkForDefaultToken(registry, command); + allocationToken = + DomainFlowUtils.checkForDefaultToken(registry, command.getDomainName(), registrarId, now); if (allocationToken.isPresent()) { defaultTokenUsed = true; } @@ -454,36 +449,6 @@ public final class DomainCreateFlow implements TransactionalFlow { .build(); } - private Optional checkForDefaultToken( - Registry registry, DomainCommand.Create command) throws EppException { - Map, Optional> tokens = - AllocationToken.getAll(registry.getDefaultPromoTokens()); - ImmutableList> tokenList = - registry.getDefaultPromoTokens().stream() - .map(tokens::get) - .filter(Optional::isPresent) - .collect(toImmutableList()); - checkState( - !isNullOrEmpty(tokenList), - "Failure while loading default TLD promotions from the database"); - // Check if any of the tokens are valid for this domain registration - for (Optional token : tokenList) { - try { - AllocationTokenFlowUtils.validateToken( - InternetDomainName.from(command.getDomainName()), - token.get(), - registrarId, - tm().getTransactionTime()); - } catch (AssociationProhibitsOperationException e) { - // Allocation token was not valid for this registration, continue to check the next token in - // the list - continue; - } - // Only use the first valid token in the list - return token; - } - return Optional.empty(); - } /** * Verifies that signed marks are only sent during sunrise. * diff --git a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java index d4b692e36..697fb05de 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java +++ b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java @@ -39,6 +39,7 @@ import static google.registry.model.tld.label.ReservationType.RESERVED_FOR_ANCHO import static google.registry.model.tld.label.ReservationType.RESERVED_FOR_SPECIFIC_USE; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.pricing.PricingEngineProxy.isDomainPremium; +import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.isAtOrAfter; @@ -63,6 +64,7 @@ import com.google.common.collect.Sets; import com.google.common.collect.Streams; import com.google.common.net.InternetDomainName; import google.registry.flows.EppException; +import google.registry.flows.EppException.AssociationProhibitsOperationException; import google.registry.flows.EppException.AuthorizationErrorException; import google.registry.flows.EppException.CommandUseErrorException; import google.registry.flows.EppException.ObjectDoesNotExistException; @@ -72,6 +74,7 @@ import google.registry.flows.EppException.ParameterValueSyntaxErrorException; import google.registry.flows.EppException.RequiredParameterMissingException; import google.registry.flows.EppException.StatusProhibitsOperationException; import google.registry.flows.EppException.UnimplementedOptionException; +import google.registry.flows.domain.token.AllocationTokenFlowUtils; import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException; import google.registry.model.EppResource; import google.registry.model.billing.BillingEvent; @@ -1191,6 +1194,44 @@ public class DomainFlowUtils { .getResultList(); } + /** + * Checks if there is a valid default token to be used for a domain create command. + * + *

If there is more than one valid default token for the registration, only the first valid + * token found on the TLD's default token list will be returned. + */ + public static Optional checkForDefaultToken( + Registry registry, String domainName, String registrarId, DateTime now) throws EppException { + if (isNullOrEmpty(registry.getDefaultPromoTokens())) { + return Optional.empty(); + } + Map, Optional> tokens = + AllocationToken.getAll(registry.getDefaultPromoTokens()); + ImmutableList> tokenList = + registry.getDefaultPromoTokens().stream() + .map(tokens::get) + .filter(Optional::isPresent) + .collect(toImmutableList()); + checkState( + !isNullOrEmpty(tokenList), + "Failure while loading default TLD promotions from the database"); + // Check if any of the tokens are valid for this domain registration + for (Optional token : tokenList) { + try { + AllocationTokenFlowUtils.validateToken( + InternetDomainName.from(domainName), token.get(), registrarId, now); + } catch (AssociationProhibitsOperationException | StatusProhibitsOperationException e) { + // Allocation token was not valid for this registration, continue to check the next token in + // the list + continue; + } + // Only use the first valid token in the list + return token; + } + // No valid default token found + return Optional.empty(); + } + /** Resource linked to this domain does not exist. */ static class LinkedResourcesDoNotExistException extends ObjectDoesNotExistException { public LinkedResourcesDoNotExistException(Class type, ImmutableSet resourceIds) { diff --git a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java index 672227906..30f304b36 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java @@ -17,6 +17,7 @@ package google.registry.flows.domain; import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT; import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM; import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED; +import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO; import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE; import static google.registry.model.eppoutput.CheckData.DomainCheck.create; @@ -38,6 +39,7 @@ import static org.joda.money.CurrencyUnit.USD; import static org.junit.jupiter.api.Assertions.assertThrows; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; @@ -350,6 +352,28 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCasenaturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput("domain_check_allocationtoken_fee.xml"); + runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_response.xml")); + } + @Test void testSuccess_allocationTokenPromotion_multiYearAndPremiums() throws Exception { createTld("example"); @@ -760,6 +784,31 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCasenaturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(2), TokenStatus.VALID) + .put(clock.nowUtc().minusDays(1), TokenStatus.ENDED) + .build()) + .build()); + persistResource( + Registry.get("tld") + .asBuilder() + .setDefaultPromoTokens( + ImmutableList.of(defaultToken1.createVKey(), defaultToken2.createVKey())) + .build()); + doSuccessfulTest(); + } + BillingEvent.OneTime runTest_defaultToken(String token) throws Exception { setEppInput("domain_create.xml", ImmutableMap.of("DOMAIN", "example.tld")); runFlowAssertResponse( diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v06.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v06.xml new file mode 100644 index 000000000..233773e57 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v06.xml @@ -0,0 +1,54 @@ + + + + Command completed successfully + + + + + rich.example + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + + rich.example + USD + create + 1 + 100.00 + premium + + + example2.tld + USD + create + 1 + 4.00 + + + example3.tld + USD + create + 2 + 12.00 + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v11.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v11.xml new file mode 100644 index 000000000..121b695f2 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v11.xml @@ -0,0 +1,70 @@ + + + + Command completed successfully + + + + + rich.example + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + + + rich.example + + create + USD + 1 + 100.00 + premium + + + + example1.tld + + create + USD + 1 + 6.50 + + + + example2.tld + + create + USD + 1 + 6.50 + + + + example3.tld + + create + USD + 1 + 6.50 + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v12.xml new file mode 100644 index 000000000..0ab60f4f0 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_response_v12.xml @@ -0,0 +1,71 @@ + + + + Command completed successfully + + + + + rich.example + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + USD + + + rich.example + + + 1 + 100.00 + premium + + + + + example1.tld + + + 1 + 6.50 + + + + + example2.tld + + + 1 + 6.50 + + + + + example3.tld + + + 1 + 6.50 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v06.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v06.xml new file mode 100644 index 000000000..83900bd6b --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v06.xml @@ -0,0 +1,33 @@ + + + + + rich.example + example1.example + example2.example + example3.example + + + + + + rich.example + create + + + example2.tld + %CURRENCY% + create + 1 + + + example3.tld + %CURRENCY% + create + 2 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v11.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v11.xml new file mode 100644 index 000000000..d2cbdd7a6 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v11.xml @@ -0,0 +1,24 @@ + + + + + rich.example + example1.tld + example2.tld + example3.tld + + + + + custom + + + create + USD + 1 + premium + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v12.xml new file mode 100644 index 000000000..3f189fd4e --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_default_token_multiple_names_v12.xml @@ -0,0 +1,25 @@ + + + + + rich.example + example1.tld + example2.tld + example3.tld + + + + + custom + + + USD + + 1 + premium + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_default_token_response_v06.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_default_token_response_v06.xml new file mode 100644 index 000000000..caa97f5c3 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_default_token_response_v06.xml @@ -0,0 +1,57 @@ + + + + Command completed successfully + + + + + example1.tld + + + + + + + example1.tld + USD + create + 1 + 6.50 + + + example1.tld + USD + renew + 1 + 11.00 + + + example1.tld + USD + transfer + 1 + 11.00 + + + example1.tld + USD + restore + 1 + 17.00 + + + example1.tld + USD + update + 1 + 0.00 + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_default_token_response_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_default_token_response_v12.xml new file mode 100644 index 000000000..c2812ffe3 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_default_token_response_v12.xml @@ -0,0 +1,68 @@ + + + + Command completed successfully + + + + + example1.tld + + + + + + + + example1.tld + + + 1 + 6.50 + + + + + example1.tld + + + 1 + 11.00 + + + + + example1.tld + + + 1 + 11.00 + + + + + example1.tld + + + 1 + 17.00 + + + + + example1.tld + + + 1 + 0.00 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v06.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v06.xml new file mode 100644 index 000000000..37b1b8cc1 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v06.xml @@ -0,0 +1,43 @@ + + + + Command completed successfully + + + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + + example2.tld + USD + create + 1 + 6.50 + + + example3.tld + USD + create + 2 + 19.50 + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v11.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v11.xml new file mode 100644 index 000000000..c0fb6ecb2 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v11.xml @@ -0,0 +1,57 @@ + + + + Command completed successfully + + + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + + + example1.tld + + create + USD + 1 + 6.50 + + + + example2.tld + + create + USD + 1 + 6.50 + + + + example3.tld + + create + USD + 1 + 6.50 + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v12.xml new file mode 100644 index 000000000..326055f89 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_default_token_v12.xml @@ -0,0 +1,58 @@ + + + + Command completed successfully + + + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + USD + + + example1.tld + + + 1 + 6.50 + + + + + example2.tld + + + 1 + 6.50 + + + + + example3.tld + + + 1 + 6.50 + + + + + + ABC-12345 + server-trid + + +