// Copyright 2018 The Nomulus Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package google.registry.model; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.ImmutableList.toImmutableList; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.DateTimeUtils.START_OF_TIME; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.Sets; import com.google.common.collect.Streams; import com.googlecode.objectify.Key; import google.registry.config.RegistryEnvironment; import google.registry.model.common.GaeUserIdConverter; import google.registry.model.pricing.StaticPremiumListPricingEngine; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.RegistrarAddress; import google.registry.model.registrar.RegistrarContact; import google.registry.model.registry.Registry; import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.label.PremiumList; import google.registry.util.CidrAddressBlock; import java.util.Collection; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.regex.Pattern; import org.joda.money.CurrencyUnit; import org.joda.money.Money; import org.joda.time.DateTime; import org.joda.time.Duration; /** * Class to help build and persist all the OT&E entities in Datastore. * *
This includes the TLDs (Registries), Registrars, and the RegistrarContacts that can access the * web console. * * This class is basically a "builder" for the parameters needed to generate the OT&E entities. * Nothing is created until you call {@link #buildAndPersist}. * * Usage example: * *
{@code * OteAccountBuilder.forClientId("example") * .addContact("contact@email.com") // OPTIONAL * .setPassword("password") // OPTIONAL * .setCertificateHash(certificateHash) // OPTIONAL * .setIpWhitelist(ImmutableList.of("1.1.1.1", "2.2.2.0/24")) // OPTIONAL * .buildAndPersist(); * }*/ public final class OteAccountBuilder { // Regex: 3-14 lower-case alphanumeric characters or hyphens, the first of which must be a letter. private static final Pattern REGISTRAR_PATTERN = Pattern.compile("^[a-z][-a-z0-9]{2,13}$"); // Durations are short so that registrars can test with quick transfer (etc.) turnaround. private static final Duration SHORT_ADD_GRACE_PERIOD = Duration.standardMinutes(60); private static final Duration SHORT_REDEMPTION_GRACE_PERIOD = Duration.standardMinutes(10); private static final Duration SHORT_PENDING_DELETE_LENGTH = Duration.standardMinutes(5); private static final String DEFAULT_PREMIUM_LIST = "default_sandbox_list"; private static final RegistrarAddress DEFAULT_ADDRESS = new RegistrarAddress.Builder() .setStreet(ImmutableList.of("e-street")) .setCity("Neverland") .setState("NY") .setCountryCode("US") .setZip("55555") .build(); private static final ImmutableSortedMap
If true, any existing entity that conflicts with the entities we want to create will be * replaced with the newly created data. * *
If false, encountering an existing entity that conflicts with one we want to create will * throw an exception during {@link #buildAndPersist}. * *
NOTE that if we fail, no entities are created (the creation is atomic). * *
Default is false (failing if entities exist) */ public OteAccountBuilder setReplaceExisting(boolean replaceExisting) { this.replaceExisting = replaceExisting; return this; } /** * Adds a RegistrarContact with Web Console access. * *
NOTE: can be called more than once, adding multiple contacts. Each contact will have access * to all OT&E Registrars. * * @param email the contact email that will have web-console access to all the Registrars. Must be * from "our G Suite domain" (we have to be able to get its GaeUserId) */ public OteAccountBuilder addContact(String email) { String gaeUserId = checkNotNull( GaeUserIdConverter.convertEmailAddressToGaeUserId(email), "Email address %s is not associated with any GAE ID", email); registrars.forEach( registrar -> contactsBuilder.add(createRegistrarContact(email, gaeUserId, registrar))); return this; } /** * Apply a function on all the OT&E Registrars. * *
Use this to set up registrar fields. * *
NOTE: DO NOT change anything that would affect the {@link Key#create} result on Registrars.
* If you want to make this function public, add a check that the Key.create on the registrars
* hasn't changed.
*
* @param func a function setting the requested fields on Registrar Builders. Will be applied to
* all the Registrars.
*/
private OteAccountBuilder transformRegistrars(
Function