diff --git a/java/google/registry/module/frontend/FrontendRequestComponent.java b/java/google/registry/module/frontend/FrontendRequestComponent.java index 1c36ac6ea..4d5e6b9aa 100644 --- a/java/google/registry/module/frontend/FrontendRequestComponent.java +++ b/java/google/registry/module/frontend/FrontendRequestComponent.java @@ -36,9 +36,9 @@ import google.registry.rdap.RdapNameserverSearchAction; import google.registry.request.RequestModule; import google.registry.request.RequestScope; import google.registry.ui.server.registrar.ConsoleUiAction; -import google.registry.ui.server.registrar.RegistrarAction; import google.registry.ui.server.registrar.RegistrarPaymentAction; import google.registry.ui.server.registrar.RegistrarPaymentSetupAction; +import google.registry.ui.server.registrar.RegistrarSettingsAction; import google.registry.ui.server.registrar.RegistrarUserModule; import google.registry.whois.WhoisHttpServer; import google.registry.whois.WhoisModule; @@ -66,7 +66,7 @@ interface FrontendRequestComponent { RdapAutnumAction rdapAutnumAction(); RegistrarPaymentAction registrarPaymentAction(); RegistrarPaymentSetupAction registrarPaymentSetupAction(); - RegistrarAction registrarAction(); + RegistrarSettingsAction registrarAction(); RdapDomainAction rdapDomainAction(); RdapDomainSearchAction rdapDomainSearchAction(); RdapEntityAction rdapEntityAction(); diff --git a/java/google/registry/ui/server/registrar/RegistrarAction.java b/java/google/registry/ui/server/registrar/RegistrarSettingsAction.java similarity index 97% rename from java/google/registry/ui/server/registrar/RegistrarAction.java rename to java/google/registry/ui/server/registrar/RegistrarSettingsAction.java index 5fa86f61a..14a66577c 100644 --- a/java/google/registry/ui/server/registrar/RegistrarAction.java +++ b/java/google/registry/ui/server/registrar/RegistrarSettingsAction.java @@ -58,12 +58,12 @@ import javax.servlet.http.HttpServletRequest; * preserve history. */ @Action( - path = RegistrarAction.PATH, + path = RegistrarSettingsAction.PATH, requireLogin = true, xsrfProtection = true, xsrfScope = "console", method = Action.Method.POST) -public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction { +public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonAction { public static final String PATH = "/registrar-settings"; @@ -76,7 +76,7 @@ public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction { @Inject Registrar initialRegistrar; @Inject @Config("registrarChangesNotificationEmailAddresses") ImmutableList registrarChangesNotificationEmailAddresses; - @Inject RegistrarAction() {} + @Inject RegistrarSettingsAction() {} private static final Predicate HAS_PHONE = new Predicate() { @Override @@ -84,19 +84,42 @@ public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction { return contact.getPhoneNumber() != null; }}; - /** Thrown when a set of contacts doesn't meet certain constraints. */ - private static class ContactRequirementException extends FormException { - ContactRequirementException(String msg) { - super(msg); - } - - ContactRequirementException(RegistrarContact.Type type) { - super("Must have at least one " + type.getDisplayName() + " contact"); - } + @Override + public void run() { + jsonActionRunner.run(this); } - public Map read(Map args, Registrar registrar) { - return JsonResponseHelper.create(SUCCESS, "Success", registrar.toJsonMap()); + @Override + public Map handleJsonRequest(Map input) { + if (input == null) { + throw new BadRequestException("Malformed JSON"); + } + + if (!sessionUtils.checkRegistrarConsoleLogin(request)) { + return JsonResponseHelper.create(ERROR, "Not authorized to access Registrar Console"); + } + + // Process the operation. Though originally derived from a CRUD + // handlder, registrar-settings really only supports read and update. + String op = Optional.fromNullable((String) input.get(OP_PARAM)).or("read"); + @SuppressWarnings("unchecked") + Map args = (Map) + Optional.fromNullable(input.get(ARGS_PARAM)).or(ImmutableMap.of()); + try { + switch (op) { + case "update": + return update(args, initialRegistrar); + case "read": + return read(args, initialRegistrar); + default: + return JsonResponseHelper.create(ERROR, "Unknown or unsupported operation: " + op); + } + } catch (FormFieldException e) { + return JsonResponseHelper.createFormFieldError(e.getMessage(), e.getFieldName()); + } catch (FormException ee) { + return JsonResponseHelper.create(ERROR, ee.getMessage()); + } + } Map update(final Map args, final Registrar registrar) { @@ -108,7 +131,8 @@ public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction { Map existingRegistrarMap = expandRegistrarWithContacts(oldContacts, registrar); Registrar.Builder builder = registrar.asBuilder(); - ImmutableSet updatedContacts = update(registrar, builder, args); + ImmutableSet updatedContacts = + changeRegistrarFields(registrar, builder, args); if (!updatedContacts.isEmpty()) { builder.setContactsRequireSyncing(true); } @@ -150,28 +174,54 @@ public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction { } /** - * Determines if any changes were made to the registrar besides the lastUpdateTime, and if so, - * sends an email with a diff of the changes to the configured notification email address and - * enqueues a task to re-sync the registrar sheet. + * Updates a registrar builder with the supplied args from the http request, and returns a list of + * the new registrar contacts. */ - private void sendExternalUpdatesIfNecessary( - String registrarName, - Map existingRegistrar, - Map updatedRegistrar) { - Map diffs = DiffUtils.deepDiff(existingRegistrar, updatedRegistrar, true); - @SuppressWarnings("unchecked") - Set changedKeys = (Set) diffs.keySet(); - if (CollectionUtils.difference(changedKeys, "lastUpdateTime").isEmpty()) { - return; + public static ImmutableSet changeRegistrarFields( + Registrar existingRegistrarObj, Registrar.Builder builder, Map args) { + + // WHOIS + builder.setWhoisServer( + RegistrarFormFields.WHOIS_SERVER_FIELD.extractUntyped(args).orNull()); + builder.setReferralUrl( + RegistrarFormFields.REFERRAL_URL_FIELD.extractUntyped(args).orNull()); + for (String email : + RegistrarFormFields.EMAIL_ADDRESS_FIELD.extractUntyped(args).asSet()) { + builder.setEmailAddress(email); } - SyncRegistrarsSheetAction.enqueueBackendTask(); - if (!registrarChangesNotificationEmailAddresses.isEmpty()) { - SendEmailUtils.sendEmail( - registrarChangesNotificationEmailAddresses, - String.format("Registrar %s updated", registrarName), - "The following changes were made to the registrar:\n" - + DiffUtils.prettyPrintDiffedMap(diffs, null)); + builder.setPhoneNumber( + RegistrarFormFields.PHONE_NUMBER_FIELD.extractUntyped(args).orNull()); + builder.setFaxNumber( + RegistrarFormFields.FAX_NUMBER_FIELD.extractUntyped(args).orNull()); + builder.setLocalizedAddress( + RegistrarFormFields.L10N_ADDRESS_FIELD.extractUntyped(args).orNull()); + + // Security + builder.setIpAddressWhitelist( + RegistrarFormFields.IP_ADDRESS_WHITELIST_FIELD.extractUntyped(args).or( + ImmutableList.of())); + for (String certificate + : RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.extractUntyped(args).asSet()) { + builder.setClientCertificate(certificate, ofy().getTransactionTime()); } + for (String certificate + : RegistrarFormFields.FAILOVER_CLIENT_CERTIFICATE_FIELD.extractUntyped(args).asSet()) { + builder.setFailoverClientCertificate(certificate, ofy().getTransactionTime()); + } + + builder.setUrl( + RegistrarFormFields.URL_FIELD.extractUntyped(args).orNull()); + builder.setReferralUrl( + RegistrarFormFields.REFERRAL_URL_FIELD.extractUntyped(args).orNull()); + + // Contact + ImmutableSet.Builder contacts = new ImmutableSet.Builder<>(); + for (RegistrarContact.Builder contactBuilder + : concat(RegistrarFormFields.CONTACTS_FIELD.extractUntyped(args).asSet())) { + contacts.add(contactBuilder.setParent(existingRegistrarObj).build()); + } + + return contacts.build(); } /** @@ -219,91 +269,42 @@ public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction { } /** - * Updates a registrar builder with the supplied args from the http request, and returns a list of - * the new registrar contacts. + * Determines if any changes were made to the registrar besides the lastUpdateTime, and if so, + * sends an email with a diff of the changes to the configured notification email address and + * enqueues a task to re-sync the registrar sheet. */ - public static ImmutableSet update( - Registrar existingRegistrarObj, Registrar.Builder builder, Map args) { - - // WHOIS - builder.setWhoisServer( - RegistrarFormFields.WHOIS_SERVER_FIELD.extractUntyped(args).orNull()); - builder.setReferralUrl( - RegistrarFormFields.REFERRAL_URL_FIELD.extractUntyped(args).orNull()); - for (String email : - RegistrarFormFields.EMAIL_ADDRESS_FIELD.extractUntyped(args).asSet()) { - builder.setEmailAddress(email); - } - builder.setPhoneNumber( - RegistrarFormFields.PHONE_NUMBER_FIELD.extractUntyped(args).orNull()); - builder.setFaxNumber( - RegistrarFormFields.FAX_NUMBER_FIELD.extractUntyped(args).orNull()); - builder.setLocalizedAddress( - RegistrarFormFields.L10N_ADDRESS_FIELD.extractUntyped(args).orNull()); - - // Security - builder.setIpAddressWhitelist( - RegistrarFormFields.IP_ADDRESS_WHITELIST_FIELD.extractUntyped(args).or( - ImmutableList.of())); - for (String certificate - : RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.extractUntyped(args).asSet()) { - builder.setClientCertificate(certificate, ofy().getTransactionTime()); - } - for (String certificate - : RegistrarFormFields.FAILOVER_CLIENT_CERTIFICATE_FIELD.extractUntyped(args).asSet()) { - builder.setFailoverClientCertificate(certificate, ofy().getTransactionTime()); - } - - builder.setUrl( - RegistrarFormFields.URL_FIELD.extractUntyped(args).orNull()); - builder.setReferralUrl( - RegistrarFormFields.REFERRAL_URL_FIELD.extractUntyped(args).orNull()); - - // Contact - ImmutableSet.Builder contacts = new ImmutableSet.Builder<>(); - for (RegistrarContact.Builder contactBuilder - : concat(RegistrarFormFields.CONTACTS_FIELD.extractUntyped(args).asSet())) { - contacts.add(contactBuilder.setParent(existingRegistrarObj).build()); - } - - return contacts.build(); - } - - @Override - public Map handleJsonRequest(Map input) { - if (input == null) { - throw new BadRequestException("Malformed JSON"); - } - - if (!sessionUtils.checkRegistrarConsoleLogin(request)) { - return JsonResponseHelper.create(ERROR, "Not authorized to access Registrar Console"); - } - - // Process the operation. Though originally derived from a CRUD - // handlder, registrar-settings really only supports read and update. - String op = Optional.fromNullable((String) input.get(OP_PARAM)).or("read"); + private void sendExternalUpdatesIfNecessary( + String registrarName, + Map existingRegistrar, + Map updatedRegistrar) { + Map diffs = DiffUtils.deepDiff(existingRegistrar, updatedRegistrar, true); @SuppressWarnings("unchecked") - Map args = (Map) - Optional.fromNullable(input.get(ARGS_PARAM)).or(ImmutableMap.of()); - try { - switch (op) { - case "update": - return update(args, initialRegistrar); - case "read": - return read(args, initialRegistrar); - default: - return JsonResponseHelper.create(ERROR, "Unknown or unsupported operation: " + op); - } - } catch (FormFieldException e) { - return JsonResponseHelper.createFormFieldError(e.getMessage(), e.getFieldName()); - } catch (FormException ee) { - return JsonResponseHelper.create(ERROR, ee.getMessage()); + Set changedKeys = (Set) diffs.keySet(); + if (CollectionUtils.difference(changedKeys, "lastUpdateTime").isEmpty()) { + return; + } + SyncRegistrarsSheetAction.enqueueBackendTask(); + if (!registrarChangesNotificationEmailAddresses.isEmpty()) { + SendEmailUtils.sendEmail( + registrarChangesNotificationEmailAddresses, + String.format("Registrar %s updated", registrarName), + "The following changes were made to the registrar:\n" + + DiffUtils.prettyPrintDiffedMap(diffs, null)); } - } - @Override - public void run() { - jsonActionRunner.run(this); + public Map read(Map args, Registrar registrar) { + return JsonResponseHelper.create(SUCCESS, "Success", registrar.toJsonMap()); + } + + /** Thrown when a set of contacts doesn't meet certain constraints. */ + private static class ContactRequirementException extends FormException { + ContactRequirementException(String msg) { + super(msg); + } + + ContactRequirementException(RegistrarContact.Type type) { + super("Must have at least one " + type.getDisplayName() + " contact"); + } } } diff --git a/javatests/google/registry/ui/server/registrar/ContactSettingsTest.java b/javatests/google/registry/ui/server/registrar/ContactSettingsTest.java index c74c6f210..c0876dfb5 100644 --- a/javatests/google/registry/ui/server/registrar/ContactSettingsTest.java +++ b/javatests/google/registry/ui/server/registrar/ContactSettingsTest.java @@ -32,13 +32,13 @@ import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; /** - * Unit tests for contact_settings.js use of {@link RegistrarAction}. + * Unit tests for contact_settings.js use of {@link RegistrarSettingsAction}. * *

The default read and session validation tests are handled by the * superclass. */ @RunWith(MockitoJUnitRunner.class) -public class ContactSettingsTest extends RegistrarActionTestCase { +public class ContactSettingsTest extends RegistrarSettingsActionTestCase { @Test public void testPost_readContacts_success() throws Exception { diff --git a/javatests/google/registry/ui/server/registrar/RegistrarActionTest.java b/javatests/google/registry/ui/server/registrar/RegistrarSettingsActionTest.java similarity index 97% rename from javatests/google/registry/ui/server/registrar/RegistrarActionTest.java rename to javatests/google/registry/ui/server/registrar/RegistrarSettingsActionTest.java index dcfa96f8d..64168200a 100644 --- a/javatests/google/registry/ui/server/registrar/RegistrarActionTest.java +++ b/javatests/google/registry/ui/server/registrar/RegistrarSettingsActionTest.java @@ -36,9 +36,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; -/** Tests for {@link RegistrarAction}. */ +/** Tests for {@link RegistrarSettingsAction}. */ @RunWith(MockitoJUnitRunner.class) -public class RegistrarActionTest extends RegistrarActionTestCase { +public class RegistrarSettingsActionTest extends RegistrarSettingsActionTestCase { @Rule public final ExceptionRule thrown = new ExceptionRule(); diff --git a/javatests/google/registry/ui/server/registrar/RegistrarActionTestCase.java b/javatests/google/registry/ui/server/registrar/RegistrarSettingsActionTestCase.java similarity index 96% rename from javatests/google/registry/ui/server/registrar/RegistrarActionTestCase.java rename to javatests/google/registry/ui/server/registrar/RegistrarSettingsActionTestCase.java index d14e6622e..d1144cf22 100644 --- a/javatests/google/registry/ui/server/registrar/RegistrarActionTestCase.java +++ b/javatests/google/registry/ui/server/registrar/RegistrarSettingsActionTestCase.java @@ -55,9 +55,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -/** Base class for tests using {@link RegistrarAction}. */ +/** Base class for tests using {@link RegistrarSettingsAction}. */ @RunWith(MockitoJUnitRunner.class) -public class RegistrarActionTestCase { +public class RegistrarSettingsActionTestCase { static final String CLIENT_ID = "TheRegistrar"; @@ -90,7 +90,7 @@ public class RegistrarActionTestCase { Message message; - final RegistrarAction action = new RegistrarAction(); + final RegistrarSettingsAction action = new RegistrarSettingsAction(); final StringWriter writer = new StringWriter(); final Supplier> json = createJsonResponseSupplier(writer); final FakeClock clock = new FakeClock(DateTime.parse("2014-01-01T00:00:00Z")); diff --git a/javatests/google/registry/ui/server/registrar/SecuritySettingsTest.java b/javatests/google/registry/ui/server/registrar/SecuritySettingsTest.java index b9acab890..ae121bb19 100644 --- a/javatests/google/registry/ui/server/registrar/SecuritySettingsTest.java +++ b/javatests/google/registry/ui/server/registrar/SecuritySettingsTest.java @@ -31,13 +31,13 @@ import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; /** - * Unit tests for security_settings.js use of {@link RegistrarAction}. + * Unit tests for security_settings.js use of {@link RegistrarSettingsAction}. * *

The default read and session validation tests are handled by the * superclass. */ @RunWith(MockitoJUnitRunner.class) -public class SecuritySettingsTest extends RegistrarActionTestCase { +public class SecuritySettingsTest extends RegistrarSettingsActionTestCase { @Test public void testPost_updateCert_success() throws Exception { diff --git a/javatests/google/registry/ui/server/registrar/WhoisSettingsTest.java b/javatests/google/registry/ui/server/registrar/WhoisSettingsTest.java index c614e3607..29b16be36 100644 --- a/javatests/google/registry/ui/server/registrar/WhoisSettingsTest.java +++ b/javatests/google/registry/ui/server/registrar/WhoisSettingsTest.java @@ -28,12 +28,12 @@ import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; /** - * Unit tests for security_settings.js use of {@link RegistrarAction}. + * Unit tests for security_settings.js use of {@link RegistrarSettingsAction}. * *

The default read and session validation tests are handled by the superclass. */ @RunWith(MockitoJUnitRunner.class) -public class WhoisSettingsTest extends RegistrarActionTestCase { +public class WhoisSettingsTest extends RegistrarSettingsActionTestCase { @Test public void testPost_update_success() throws Exception {