diff --git a/gradle/core/build.gradle b/gradle/core/build.gradle
index a7ffd3e60..21f520db8 100644
--- a/gradle/core/build.gradle
+++ b/gradle/core/build.gradle
@@ -341,12 +341,6 @@ task soyToJava {
dir: "${javaDir}/google/registry/ui/soy/registrar",
include: ['**/*.soy']))
- soyToJava('google.registry.ui.soy.otesetup',
- "${generatedDir}/google/registry/ui/soy/otesetup",
- fileTree(
- dir: "${javaDir}/google/registry/ui/soy/otesetup",
- include: ['**/*.soy']))
-
soyToJava('google.registry.ui.soy',
"${generatedDir}/google/registry/ui/soy",
files {
diff --git a/java/google/registry/config/RegistryConfig.java b/java/google/registry/config/RegistryConfig.java
index a2299f917..f3bc7bf1d 100644
--- a/java/google/registry/config/RegistryConfig.java
+++ b/java/google/registry/config/RegistryConfig.java
@@ -1381,6 +1381,14 @@ public final class RegistryConfig {
}
}
+ /** Returns a singleton random string generator that uses digits only. */
+ @Singleton
+ @Provides
+ @Config("digitOnlyStringGenerator")
+ public static StringGenerator provideDigitsOnlyStringGenerator(SecureRandom secureRandom) {
+ return new RandomStringGenerator(StringGenerator.Alphabets.DIGITS_ONLY, secureRandom);
+ }
+
/** Returns a singleton random string generator using Base58 encoding. */
@Singleton
@Provides
diff --git a/java/google/registry/env/common/default/WEB-INF/web.xml b/java/google/registry/env/common/default/WEB-INF/web.xml
index bcbc77703..5861ad0c1 100644
--- a/java/google/registry/env/common/default/WEB-INF/web.xml
+++ b/java/google/registry/env/common/default/WEB-INF/web.xml
@@ -43,6 +43,12 @@
/registrar-ote-setup
+
+
+ frontend-servlet
+ /registrar-create
+
+
diff --git a/java/google/registry/module/frontend/BUILD b/java/google/registry/module/frontend/BUILD
index fc2d681fc..796bee607 100644
--- a/java/google/registry/module/frontend/BUILD
+++ b/java/google/registry/module/frontend/BUILD
@@ -21,7 +21,6 @@ java_library(
"//java/google/registry/request:modules",
"//java/google/registry/request/auth",
"//java/google/registry/ui",
- "//java/google/registry/ui/server/otesetup",
"//java/google/registry/ui/server/registrar",
"//java/google/registry/util",
"@com_google_appengine_api_1_0_sdk",
diff --git a/java/google/registry/module/frontend/FrontendRequestComponent.java b/java/google/registry/module/frontend/FrontendRequestComponent.java
index 277f2d745..42743cb83 100644
--- a/java/google/registry/module/frontend/FrontendRequestComponent.java
+++ b/java/google/registry/module/frontend/FrontendRequestComponent.java
@@ -25,7 +25,8 @@ import google.registry.monitoring.whitebox.WhiteboxModule;
import google.registry.request.RequestComponentBuilder;
import google.registry.request.RequestModule;
import google.registry.request.RequestScope;
-import google.registry.ui.server.otesetup.ConsoleOteSetupAction;
+import google.registry.ui.server.registrar.ConsoleOteSetupAction;
+import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
import google.registry.ui.server.registrar.ConsoleUiAction;
import google.registry.ui.server.registrar.OteStatusAction;
import google.registry.ui.server.registrar.RegistrarConsoleModule;
@@ -43,6 +44,7 @@ import google.registry.ui.server.registrar.RegistrarSettingsAction;
})
interface FrontendRequestComponent {
ConsoleOteSetupAction consoleOteSetupAction();
+ ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();
ConsoleUiAction consoleUiAction();
EppConsoleAction eppConsoleAction();
EppTlsAction eppTlsAction();
diff --git a/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java b/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java
index c1d080730..51ec7415b 100644
--- a/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java
+++ b/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java
@@ -329,7 +329,8 @@ public class AuthenticatedRegistrarAccessor {
.load()
.type(Registrar.class)
.forEach(registrar -> {
- if (!Registrar.Type.REAL.equals(registrar.getType())) {
+ if (registrar.getType() != Registrar.Type.REAL
+ || registrar.getState() == Registrar.State.PENDING) {
builder.put(registrar.getClientId(), Role.OWNER);
}
builder.put(registrar.getClientId(), Role.ADMIN);
diff --git a/java/google/registry/ui/server/otesetup/BUILD b/java/google/registry/ui/server/otesetup/BUILD
deleted file mode 100644
index 4ce526598..000000000
--- a/java/google/registry/ui/server/otesetup/BUILD
+++ /dev/null
@@ -1,43 +0,0 @@
-package(
- default_visibility = ["//visibility:public"],
-)
-
-licenses(["notice"]) # Apache 2.0
-
-java_library(
- name = "otesetup",
- srcs = glob(["*.java"]),
- resources = [
- "//java/google/registry/ui/css:registrar_bin.css.js",
- "//java/google/registry/ui/css:registrar_dbg.css.js",
- ],
- deps = [
- "//java/google/registry/config",
- "//java/google/registry/export/sheet",
- "//java/google/registry/flows",
- "//java/google/registry/model",
- "//java/google/registry/request",
- "//java/google/registry/request/auth",
- "//java/google/registry/security",
- "//java/google/registry/ui/forms",
- "//java/google/registry/ui/server",
- "//java/google/registry/ui/soy:soy_java_wrappers",
- "//java/google/registry/ui/soy/otesetup:soy_java_wrappers",
- "//java/google/registry/util",
- "//third_party/objectify:objectify-v4_1",
- "@com_google_appengine_api_1_0_sdk",
- "@com_google_auto_value",
- "@com_google_code_findbugs_jsr305",
- "@com_google_dagger",
- "@com_google_flogger",
- "@com_google_flogger_system_backend",
- "@com_google_guava",
- "@com_google_monitoring_client_metrics",
- "@com_google_re2j",
- "@io_bazel_rules_closure//closure/templates",
- "@javax_inject",
- "@javax_servlet_api",
- "@joda_time",
- "@org_joda_money",
- ],
-)
diff --git a/java/google/registry/ui/server/otesetup/ConsoleOteSetupAction.java b/java/google/registry/ui/server/registrar/ConsoleOteSetupAction.java
similarity index 95%
rename from java/google/registry/ui/server/otesetup/ConsoleOteSetupAction.java
rename to java/google/registry/ui/server/registrar/ConsoleOteSetupAction.java
index ee553f345..96ad6b292 100644
--- a/java/google/registry/ui/server/otesetup/ConsoleOteSetupAction.java
+++ b/java/google/registry/ui/server/registrar/ConsoleOteSetupAction.java
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package google.registry.ui.server.otesetup;
+package google.registry.ui.server.registrar;
+
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
@@ -44,7 +45,7 @@ import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SendEmailUtils;
import google.registry.ui.server.SoyTemplateUtils;
-import google.registry.ui.soy.otesetup.ConsoleSoyInfo;
+import google.registry.ui.soy.registrar.OteSetupConsoleSoyInfo;
import google.registry.util.StringGenerator;
import java.util.HashMap;
import java.util.Optional;
@@ -77,7 +78,7 @@ public final class ConsoleOteSetupAction implements Runnable {
SoyTemplateUtils.createTofuSupplier(
google.registry.ui.soy.ConsoleSoyInfo.getInstance(),
google.registry.ui.soy.FormsSoyInfo.getInstance(),
- google.registry.ui.soy.otesetup.ConsoleSoyInfo.getInstance());
+ google.registry.ui.soy.registrar.OteSetupConsoleSoyInfo.getInstance());
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier CSS_RENAMING_MAP_SUPPLIER =
@@ -145,7 +146,7 @@ public final class ConsoleOteSetupAction implements Runnable {
response.setPayload(
TOFU_SUPPLIER
.get()
- .newRenderer(ConsoleSoyInfo.WHOAREYOU)
+ .newRenderer(OteSetupConsoleSoyInfo.WHOAREYOU)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
@@ -185,7 +186,7 @@ public final class ConsoleOteSetupAction implements Runnable {
response.setPayload(
TOFU_SUPPLIER
.get()
- .newRenderer(ConsoleSoyInfo.RESULT_SUCCESS)
+ .newRenderer(OteSetupConsoleSoyInfo.RESULT_SUCCESS)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
@@ -196,7 +197,7 @@ public final class ConsoleOteSetupAction implements Runnable {
response.setPayload(
TOFU_SUPPLIER
.get()
- .newRenderer(ConsoleSoyInfo.FORM_PAGE)
+ .newRenderer(OteSetupConsoleSoyInfo.FORM_PAGE)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
@@ -211,7 +212,7 @@ public final class ConsoleOteSetupAction implements Runnable {
response.setPayload(
TOFU_SUPPLIER
.get()
- .newRenderer(ConsoleSoyInfo.FORM_PAGE)
+ .newRenderer(OteSetupConsoleSoyInfo.FORM_PAGE)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
diff --git a/java/google/registry/ui/server/registrar/ConsoleRegistrarCreatorAction.java b/java/google/registry/ui/server/registrar/ConsoleRegistrarCreatorAction.java
new file mode 100644
index 000000000..de79bc103
--- /dev/null
+++ b/java/google/registry/ui/server/registrar/ConsoleRegistrarCreatorAction.java
@@ -0,0 +1,369 @@
+// 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.ui.server.registrar;
+
+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 com.google.common.collect.ImmutableMap.toImmutableMap;
+import static com.google.common.net.HttpHeaders.LOCATION;
+import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
+import static google.registry.model.common.GaeUserIdConverter.convertEmailAddressToGaeUserId;
+import static google.registry.model.ofy.ObjectifyService.ofy;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
+
+import com.google.appengine.api.users.User;
+import com.google.appengine.api.users.UserService;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Ascii;
+import com.google.common.base.Splitter;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.flogger.FluentLogger;
+import com.google.common.io.Resources;
+import com.google.common.net.MediaType;
+import com.google.template.soy.shared.SoyCssRenamingMap;
+import com.google.template.soy.tofu.SoyTofu;
+import google.registry.config.RegistryConfig.Config;
+import google.registry.config.RegistryEnvironment;
+import google.registry.model.registrar.Registrar;
+import google.registry.model.registrar.RegistrarAddress;
+import google.registry.model.registrar.RegistrarContact;
+import google.registry.request.Action;
+import google.registry.request.Action.Method;
+import google.registry.request.Parameter;
+import google.registry.request.RequestMethod;
+import google.registry.request.Response;
+import google.registry.request.auth.Auth;
+import google.registry.request.auth.AuthResult;
+import google.registry.request.auth.AuthenticatedRegistrarAccessor;
+import google.registry.security.XsrfTokenManager;
+import google.registry.ui.server.SendEmailUtils;
+import google.registry.ui.server.SoyTemplateUtils;
+import google.registry.ui.soy.registrar.RegistrarCreateConsoleSoyInfo;
+import google.registry.util.StringGenerator;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import org.joda.money.CurrencyUnit;
+
+/**
+ * Action that serves Registrar creation page.
+ *
+ *
This Action does 2 things: - for GET, just returns the form that asks for the required
+ * information. - for POST, receives the information and creates the Registrar.
+ *
+ *
TODO(b/120201577): once we can have 2 different Actions with the same path (different
+ * Methods), separate this class to 2 Actions.
+ */
+@Action(
+ service = Action.Service.DEFAULT,
+ path = ConsoleRegistrarCreatorAction.PATH,
+ method = {Method.POST, Method.GET},
+ auth = Auth.AUTH_PUBLIC)
+public final class ConsoleRegistrarCreatorAction implements Runnable {
+
+ private static final int PASSWORD_LENGTH = 16;
+ private static final int PASSCODE_LENGTH = 5;
+
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public static final String PATH = "/registrar-create";
+
+ private static final Supplier TOFU_SUPPLIER =
+ SoyTemplateUtils.createTofuSupplier(
+ google.registry.ui.soy.ConsoleSoyInfo.getInstance(),
+ google.registry.ui.soy.FormsSoyInfo.getInstance(),
+ google.registry.ui.soy.registrar.RegistrarCreateConsoleSoyInfo.getInstance());
+
+ @VisibleForTesting // webdriver and screenshot tests need this
+ public static final Supplier CSS_RENAMING_MAP_SUPPLIER =
+ SoyTemplateUtils.createCssRenamingMapSupplier(
+ Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
+ Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
+
+ @Inject HttpServletRequest req;
+ @Inject @RequestMethod Method method;
+ @Inject Response response;
+ @Inject AuthenticatedRegistrarAccessor registrarAccessor;
+ @Inject UserService userService;
+ @Inject XsrfTokenManager xsrfTokenManager;
+ @Inject AuthResult authResult;
+ @Inject RegistryEnvironment registryEnvironment;
+ @Inject SendEmailUtils sendEmailUtils;
+ @Inject @Config("logoFilename") String logoFilename;
+ @Inject @Config("productName") String productName;
+ @Inject @Config("base58StringGenerator") StringGenerator passwordGenerator;
+ @Inject @Config("digitOnlyStringGenerator") StringGenerator passcodeGenerator;
+ @Inject @Parameter("clientId") Optional clientId;
+ @Inject @Parameter("name") Optional name;
+ @Inject @Parameter("billingAccount") Optional billingAccount;
+ @Inject @Parameter("ianaId") Optional ianaId;
+ @Inject @Parameter("referralEmail") Optional referralEmail;
+ @Inject @Parameter("driveId") Optional driveId;
+ @Inject @Parameter("email") Optional email;
+
+ // Address fields, some of which are required and others are optional.
+ @Inject @Parameter("street1") Optional street1;
+ @Inject @Parameter("street2") Optional optionalStreet2;
+ @Inject @Parameter("street3") Optional optionalStreet3;
+ @Inject @Parameter("city") Optional city;
+ @Inject @Parameter("state") Optional optionalState;
+ @Inject @Parameter("zip") Optional optionalZip;
+ @Inject @Parameter("countryCode") Optional countryCode;
+
+ @Inject @Parameter("password") Optional optionalPassword;
+ @Inject @Parameter("passcode") Optional optionalPasscode;
+
+ @Inject ConsoleRegistrarCreatorAction() {}
+
+ @Override
+ public void run() {
+ response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
+ response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
+
+ logger.atInfo().log(
+ "User %s is accessing the Registrar creation page. Method= %s",
+ registrarAccessor.userIdForLogging(), method);
+ if (!authResult.userAuthInfo().isPresent()) {
+ response.setStatus(SC_MOVED_TEMPORARILY);
+ String location;
+ try {
+ location = userService.createLoginURL(req.getRequestURI());
+ } catch (IllegalArgumentException e) {
+ // UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
+ // returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
+ // by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
+ // user information, which happens when the request has been authenticated as internal. In
+ // this case, we want to avoid dying before we can send the redirect, so just redirect to
+ // the root path.
+ location = "/";
+ }
+ response.setHeader(LOCATION, location);
+ return;
+ }
+ User user = authResult.userAuthInfo().get().user();
+
+ // Using HashMap to allow null values
+ HashMap data = new HashMap<>();
+ data.put("logoFilename", logoFilename);
+ data.put("productName", productName);
+ data.put("username", user.getNickname());
+ data.put("logoutUrl", userService.createLogoutURL(PATH));
+ data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
+ response.setContentType(MediaType.HTML_UTF_8);
+
+ if (!registrarAccessor.isAdmin()) {
+ response.setStatus(SC_FORBIDDEN);
+ response.setPayload(
+ TOFU_SUPPLIER
+ .get()
+ .newRenderer(RegistrarCreateConsoleSoyInfo.WHOAREYOU)
+ .setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
+ .setData(data)
+ .render());
+ return;
+ }
+ switch (method) {
+ case POST:
+ runPost(data);
+ return;
+ case GET:
+ runGet(data);
+ return;
+ default:
+ return;
+ }
+ }
+
+ private void checkPresent(Optional> value, String name) {
+ checkState(value.isPresent(), "Missing value for %s", name);
+ }
+
+ private static final Splitter LINE_SPLITTER =
+ Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings();
+
+ private static final Splitter ENTRY_SPLITTER =
+ Splitter.on('=').trimResults().omitEmptyStrings().limit(2);
+
+ private static ImmutableMap parseBillingAccount(String billingAccount) {
+ try {
+ return LINE_SPLITTER.splitToList(billingAccount).stream()
+ .map(ENTRY_SPLITTER::splitToList)
+ .peek(
+ list ->
+ checkState(
+ list.size() == 2,
+ "Can't parse line %s. The format should be [currency]=[account ID]",
+ list))
+ .collect(
+ toImmutableMap(
+ list -> CurrencyUnit.of(Ascii.toUpperCase(list.get(0))), list -> list.get(1)));
+ } catch (Throwable e) {
+ throw new RuntimeException("Error parsing billing accounts - " + e.getMessage(), e);
+ }
+ }
+
+ private void runPost(HashMap data) {
+ try {
+
+ checkPresent(clientId, "clientId");
+ checkPresent(name, "name");
+ checkPresent(billingAccount, "billingAccount");
+ checkPresent(ianaId, "ianaId");
+ checkPresent(referralEmail, "referralEmail");
+ checkPresent(driveId, "driveId");
+ checkPresent(email, "email");
+ checkPresent(street1, "street");
+ checkPresent(city, "city");
+ checkPresent(countryCode, "countryCode");
+
+ data.put("clientId", clientId.get());
+ data.put("name", name.get());
+ data.put("ianaId", ianaId.get());
+ data.put("referralEmail", referralEmail.get());
+ data.put("billingAccount", billingAccount.get());
+ data.put("driveId", driveId.get());
+ data.put("email", email.get());
+
+ data.put("street1", street1.get());
+ optionalStreet2.ifPresent(street2 -> data.put("street2", street2));
+ optionalStreet3.ifPresent(street3 -> data.put("street3", street3));
+ data.put("city", city.get());
+ optionalState.ifPresent(state -> data.put("state", state));
+ optionalZip.ifPresent(zip -> data.put("zip", zip));
+ data.put("countryCode", countryCode.get());
+
+ String gaeUserId =
+ checkNotNull(
+ convertEmailAddressToGaeUserId(email.get()),
+ "Email address %s is not associated with any GAE ID",
+ email.get());
+ String password = optionalPassword.orElse(passwordGenerator.createString(PASSWORD_LENGTH));
+ String phonePasscode =
+ optionalPasscode.orElse(passcodeGenerator.createString(PASSCODE_LENGTH));
+ Registrar registrar =
+ new Registrar.Builder()
+ .setClientId(clientId.get())
+ .setRegistrarName(name.get())
+ .setBillingAccountMap(parseBillingAccount(billingAccount.get()))
+ .setIanaIdentifier(Long.valueOf(ianaId.get()))
+ .setIcannReferralEmail(referralEmail.get())
+ .setDriveFolderId(driveId.get())
+ .setType(Registrar.Type.REAL)
+ .setPassword(password)
+ .setPhonePasscode(phonePasscode)
+ .setState(Registrar.State.PENDING)
+ .setLocalizedAddress(
+ new RegistrarAddress.Builder()
+ .setStreet(
+ Stream.of(street1, optionalStreet2, optionalStreet3)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(toImmutableList()))
+ .setCity(city.get())
+ .setState(optionalState.orElse(null))
+ .setCountryCode(countryCode.get())
+ .setZip(optionalZip.orElse(null))
+ .build())
+ .build();
+ RegistrarContact contact =
+ new RegistrarContact.Builder()
+ .setParent(registrar)
+ .setName(email.get())
+ .setEmailAddress(email.get())
+ .setGaeUserId(gaeUserId)
+ .build();
+ ofy()
+ .transact(
+ () -> {
+ checkState(
+ !Registrar.loadByClientId(registrar.getClientId()).isPresent(),
+ "Registrar with client ID %s already exists",
+ registrar.getClientId());
+ ofy().save().entities(registrar, contact);
+ });
+ data.put("password", password);
+ data.put("passcode", phonePasscode);
+
+ sendExternalUpdates();
+ response.setPayload(
+ TOFU_SUPPLIER
+ .get()
+ .newRenderer(RegistrarCreateConsoleSoyInfo.RESULT_SUCCESS)
+ .setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
+ .setData(data)
+ .render());
+ } catch (Throwable e) {
+ logger.atWarning().withCause(e).log(
+ "Failed to create registrar. clientId: %s, data: %s", clientId.get(), data);
+ data.put("errorMessage", e.getMessage());
+ response.setPayload(
+ TOFU_SUPPLIER
+ .get()
+ .newRenderer(RegistrarCreateConsoleSoyInfo.FORM_PAGE)
+ .setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
+ .setData(data)
+ .render());
+ }
+ }
+
+ private void runGet(HashMap data) {
+ // set the values to pre-fill, if given
+ data.put("clientId", clientId.orElse(null));
+ data.put("name", name.orElse(null));
+ data.put("ianaId", ianaId.orElse(null));
+ data.put("referralEmail", referralEmail.orElse(null));
+ data.put("driveId", driveId.orElse(null));
+ data.put("email", email.orElse(null));
+
+ response.setPayload(
+ TOFU_SUPPLIER
+ .get()
+ .newRenderer(RegistrarCreateConsoleSoyInfo.FORM_PAGE)
+ .setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
+ .setData(data)
+ .render());
+ }
+
+ private String toEmailLine(Optional> value, String name) {
+ return String.format(" %s: %s\n", name, value.orElse(null));
+ }
+ private void sendExternalUpdates() {
+ if (!sendEmailUtils.hasRecepients()) {
+ return;
+ }
+ String environment = Ascii.toLowerCase(String.valueOf(registryEnvironment));
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append(
+ String.format(
+ "The following registrar was created in %s by %s:\n",
+ environment, registrarAccessor.userIdForLogging()))
+ .append(toEmailLine(clientId, "clientId"))
+ .append(toEmailLine(name, "name"))
+ .append(toEmailLine(billingAccount, "billingAccount"))
+ .append(toEmailLine(ianaId, "ianaId"))
+ .append(toEmailLine(referralEmail, "referralEmail"))
+ .append(toEmailLine(driveId, "driveId"))
+ .append(String.format("Gave user %s web access to the registrar\n", email.get()));
+ sendEmailUtils.sendEmail(
+ String.format("Registrar %s created in %s", clientId.get(), environment),
+ builder.toString());
+ }
+}
diff --git a/java/google/registry/ui/server/registrar/RegistrarConsoleModule.java b/java/google/registry/ui/server/registrar/RegistrarConsoleModule.java
index f4b7d55b1..70f695184 100644
--- a/java/google/registry/ui/server/registrar/RegistrarConsoleModule.java
+++ b/java/google/registry/ui/server/registrar/RegistrarConsoleModule.java
@@ -15,6 +15,7 @@
package google.registry.ui.server.registrar;
+import static google.registry.request.RequestParameters.extractOptionalIntParameter;
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
@@ -42,6 +43,36 @@ public final class RegistrarConsoleModule {
return extractRequiredParameter(req, PARAM_CLIENT_ID);
}
+ @Provides
+ @Parameter("ianaId")
+ static Optional provideOptionalIanaId(HttpServletRequest req) {
+ return extractOptionalIntParameter(req, "ianaId");
+ }
+
+ @Provides
+ @Parameter("billingAccount")
+ static Optional provideOptionalBillingAccount(HttpServletRequest req) {
+ return extractOptionalParameter(req, "billingAccount");
+ }
+
+ @Provides
+ @Parameter("name")
+ static Optional provideOptionalName(HttpServletRequest req) {
+ return extractOptionalParameter(req, "name");
+ }
+
+ @Provides
+ @Parameter("driveId")
+ static Optional provideOptionalDriveId(HttpServletRequest req) {
+ return extractOptionalParameter(req, "driveId");
+ }
+
+ @Provides
+ @Parameter("referralEmail")
+ static Optional provideOptionalReferralEmail(HttpServletRequest req) {
+ return extractOptionalParameter(req, "referralEmail");
+ }
+
@Provides
@Parameter("email")
static Optional provideOptionalEmail(HttpServletRequest req) {
@@ -54,9 +85,57 @@ public final class RegistrarConsoleModule {
return extractRequiredParameter(req, "email");
}
+ @Provides
+ @Parameter("street1")
+ static Optional provideOptionalStreet1(HttpServletRequest req) {
+ return extractOptionalParameter(req, "street1");
+ }
+
+ @Provides
+ @Parameter("street2")
+ static Optional provideOptionalStreet2(HttpServletRequest req) {
+ return extractOptionalParameter(req, "street2");
+ }
+
+ @Provides
+ @Parameter("street3")
+ static Optional provideOptionalStreet3(HttpServletRequest req) {
+ return extractOptionalParameter(req, "street3");
+ }
+
+ @Provides
+ @Parameter("city")
+ static Optional provideOptionalCity(HttpServletRequest req) {
+ return extractOptionalParameter(req, "city");
+ }
+
+ @Provides
+ @Parameter("state")
+ static Optional provideOptionalState(HttpServletRequest req) {
+ return extractOptionalParameter(req, "state");
+ }
+
+ @Provides
+ @Parameter("zip")
+ static Optional provideOptionalZip(HttpServletRequest req) {
+ return extractOptionalParameter(req, "zip");
+ }
+
+ @Provides
+ @Parameter("countryCode")
+ static Optional provideOptionalCountryCode(HttpServletRequest req) {
+ return extractOptionalParameter(req, "countryCode");
+ }
+
@Provides
@Parameter("password")
static Optional provideOptionalPassword(HttpServletRequest req) {
return extractOptionalParameter(req, "password");
}
+
+ @Provides
+ @Parameter("passcode")
+ static Optional provideOptionalPasscode(HttpServletRequest req) {
+ return extractOptionalParameter(req, "passcode");
+ }
}
diff --git a/java/google/registry/ui/soy/otesetup/BUILD b/java/google/registry/ui/soy/otesetup/BUILD
deleted file mode 100644
index f19b6651c..000000000
--- a/java/google/registry/ui/soy/otesetup/BUILD
+++ /dev/null
@@ -1,21 +0,0 @@
-package(
- default_visibility = ["//java/google/registry:registry_project"],
-)
-
-licenses(["notice"]) # Apache 2.0
-
-load("@io_bazel_rules_closure//closure:defs.bzl", "closure_java_template_library", "closure_js_template_library")
-
-closure_js_template_library(
- name = "otesetup",
- srcs = glob(["*.soy"]),
- data = ["//java/google/registry/ui/css:registrar_raw"],
- globals = "//java/google/registry/ui:globals.txt",
- deps = ["//java/google/registry/ui/soy"],
-)
-
-closure_java_template_library(
- name = "soy_java_wrappers",
- srcs = glob(["*.soy"]),
- java_package = "google.registry.ui.soy.otesetup",
-)
diff --git a/java/google/registry/ui/soy/registrar/BUILD b/java/google/registry/ui/soy/registrar/BUILD
index f51b1ed6a..5481d63d4 100644
--- a/java/google/registry/ui/soy/registrar/BUILD
+++ b/java/google/registry/ui/soy/registrar/BUILD
@@ -8,7 +8,13 @@ load("@io_bazel_rules_closure//closure:defs.bzl", "closure_java_template_library
closure_js_template_library(
name = "registrar",
- srcs = glob(["*.soy"]),
+ srcs = glob(
+ ["*.soy"],
+ exclude = [
+ "OteSetupConsole.soy",
+ "RegistrarCreateConsole.soy",
+ ],
+ ),
data = ["//java/google/registry/ui/css:registrar_raw"],
globals = "//java/google/registry/ui:globals.txt",
deps = ["//java/google/registry/ui/soy"],
diff --git a/java/google/registry/ui/soy/otesetup/Console.soy b/java/google/registry/ui/soy/registrar/OteSetupConsole.soy
similarity index 98%
rename from java/google/registry/ui/soy/otesetup/Console.soy
rename to java/google/registry/ui/soy/registrar/OteSetupConsole.soy
index 81e306aa3..457bdcd26 100644
--- a/java/google/registry/ui/soy/otesetup/Console.soy
+++ b/java/google/registry/ui/soy/registrar/OteSetupConsole.soy
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-{namespace registry.soy.registrar.console}
+{namespace registry.soy.registrar.otesetup}
/**
@@ -35,7 +35,7 @@
{call registry.soy.console.googlebar data="all" /}