Use feature flag for minimum dataset in domain flows to decide when to check for required contacts (#2486)

* Check FeatureFlag in domain flows before checking contacts

Check if phase 1 has begun of the transition to the minimum registry dataset, and if it has, do not require the presence of contacts in domain flows.

* Add tests

* Small test fixes

* rename flag

* Fix merge conflicts

* Change todo

* Add isActive methods

* Add javadocs

* small fix
This commit is contained in:
sarahcaseybot
2024-07-17 22:06:09 +00:00
committed by GitHub
parent 68b46735cd
commit 0241937dee
10 changed files with 237 additions and 10 deletions
@@ -24,6 +24,8 @@ import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static com.google.common.collect.Sets.union;
import static google.registry.bsa.persistence.BsaLabelUtils.isLabelBlocked;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.isActiveNow;
import static google.registry.model.domain.Domain.MAX_REGISTRATION_YEARS;
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
@@ -481,10 +483,14 @@ public class DomainFlowUtils {
}
}
static void validateRequiredContactsPresent(
static void validateRequiredContactsPresentIfRequiredForDataset(
Optional<VKey<Contact>> registrant, Set<DesignatedContact> contacts)
throws RequiredParameterMissingException {
// TODO: Check minimum reg data set migration schedule here and don't throw when any are empty.
// TODO(b/353347632): Change this flag check to a registry config check.
if (isActiveNow(MINIMUM_DATASET_CONTACTS_OPTIONAL)) {
// Contacts are not required once we have begun the migration to the minimum dataset
return;
}
if (registrant.isEmpty()) {
throw new MissingRegistrantException();
}
@@ -1041,7 +1047,8 @@ public class DomainFlowUtils {
String tldStr = tld.getTldStr();
validateRegistrantAllowedOnTld(tldStr, command.getRegistrantContactId());
validateNoDuplicateContacts(command.getContacts());
validateRequiredContactsPresent(command.getRegistrant(), command.getContacts());
validateRequiredContactsPresentIfRequiredForDataset(
command.getRegistrant(), command.getContacts());
ImmutableSet<String> hostNames = command.getNameserverHostNames();
validateNameserversCountForTld(tldStr, domainName, hostNames.size());
validateNameserversAllowedOnTld(tldStr, hostNames);
@@ -38,9 +38,11 @@ import static google.registry.flows.domain.DomainFlowUtils.validateNameserversAl
import static google.registry.flows.domain.DomainFlowUtils.validateNameserversCountForTld;
import static google.registry.flows.domain.DomainFlowUtils.validateNoDuplicateContacts;
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrantAllowedOnTld;
import static google.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresent;
import static google.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresentIfRequiredForDataset;
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.isActiveNow;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_UPDATE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
@@ -248,7 +250,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
Change change = command.getInnerChange();
validateRegistrantIsntBeingRemoved(change);
validateRegistrantIsntBeingRemovedIfRequiredForDataset(change);
Optional<SecDnsUpdateExtension> secDnsUpdate =
eppInput.getSingleExtension(SecDnsUpdateExtension.class);
@@ -300,9 +302,13 @@ public final class DomainUpdateFlow implements MutatingFlow {
return domainBuilder.build();
}
private static void validateRegistrantIsntBeingRemoved(Change change) throws EppException {
// TODO(mcilwain): Make this check the minimum registration data set migration schedule
// and not require presence of a registrant in later stages.
private static void validateRegistrantIsntBeingRemovedIfRequiredForDataset(Change change)
throws EppException {
// TODO(b/353347632): Change this flag check to a registry config check.
if (isActiveNow(MINIMUM_DATASET_CONTACTS_OPTIONAL)) {
// registrants are not required once we have begun the migration to the minimum dataset
return;
}
if (change.getRegistrantContactId().isPresent()
&& change.getRegistrantContactId().get().isEmpty()) {
throw new MissingRegistrantException();
@@ -317,7 +323,8 @@ public final class DomainUpdateFlow implements MutatingFlow {
* cause Domain update failure.
*/
private static void validateNewState(Domain newDomain) throws EppException {
validateRequiredContactsPresent(newDomain.getRegistrant(), newDomain.getContacts());
validateRequiredContactsPresentIfRequiredForDataset(
newDomain.getRegistrant(), newDomain.getContacts());
validateDsData(newDomain.getDsData());
validateNameserversCountForTld(
newDomain.getTld(),
@@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -150,6 +151,17 @@ public class FeatureFlag extends ImmutableObject implements Buildable {
return status.getValueAtTime(time);
}
/** Returns if the FeatureFlag with the given FeatureName is active now. */
public static boolean isActiveNow(FeatureName featureName) {
tm().assertInTransaction();
return isActiveAt(featureName, tm().getTransactionTime());
}
/** Returns if the FeatureFlag with the given FeatureName is active at a given time. */
public static boolean isActiveAt(FeatureName featureName, DateTime dateTime) {
return FeatureFlag.get(featureName).getStatus(dateTime).equals(ACTIVE);
}
@Override
public FeatureFlag.Builder asBuilder() {
return new FeatureFlag.Builder(clone(this));