Convert RegistrarServlet to RegistrarAction

Convert to an action and remove ResourceServlet, JsonTransportServlet and
JsonTransportServlet, all of which exist only to support it.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=137519385
This commit is contained in:
mmuller 2016-10-28 09:32:24 -07:00 committed by Ben McIlwain
parent 2e4273c4f4
commit bbd20ec71d
24 changed files with 330 additions and 858 deletions

View file

@ -26,7 +26,6 @@ java_library(
"//java/google/registry/model",
"//java/google/registry/request",
"//java/google/registry/security",
"//java/google/registry/security:servlets",
"//java/google/registry/ui/forms",
"//java/google/registry/ui/server",
"//java/google/registry/ui/soy:soy_java_wrappers",

View file

@ -18,23 +18,29 @@ import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Sets.difference;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.security.JsonResponseHelper.Status.ERROR;
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.googlecode.objectify.Work;
import google.registry.config.RegistryConfig;
import google.registry.config.RegistryEnvironment;
import google.registry.config.ConfigModule.Config;
import google.registry.export.sheet.SyncRegistrarsSheetAction;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.request.Action;
import google.registry.request.HttpException.BadRequestException;
import google.registry.request.JsonActionRunner;
import google.registry.security.JsonResponseHelper;
import google.registry.ui.forms.FormException;
import google.registry.ui.forms.FormFieldException;
import google.registry.ui.server.RegistrarFormFields;
import google.registry.util.CidrAddressBlock;
import google.registry.util.CollectionUtils;
@ -44,15 +50,33 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
/**
* Admin servlet that allows creating or updating a registrar. Deletes are not allowed so as to
* preserve history.
*/
public class RegistrarServlet extends ResourceServlet {
@Action(
path = RegistrarAction.PATH,
requireLogin = true,
xsrfProtection = true,
xsrfScope = "console",
method = Action.Method.POST)
public class RegistrarAction implements Runnable, JsonActionRunner.JsonAction {
private static final RegistryConfig CONFIG = RegistryEnvironment.get().config();
public static final String PATH = "/registrar-settings";
private static final String OP_PARAM = "op";
private static final String ARGS_PARAM = "args";
@Inject HttpServletRequest request;
@Inject SessionUtils sessionUtils;
@Inject JsonActionRunner jsonActionRunner;
@Inject Registrar initialRegistrar;
@Inject @Config("registrarChangesNotificationEmailAddresses") ImmutableList<String>
registrarChangesNotificationEmailAddresses;
@Inject RegistrarAction() {}
private static final Predicate<RegistrarContact> HAS_PHONE = new Predicate<RegistrarContact>() {
@Override
@ -71,25 +95,20 @@ public class RegistrarServlet extends ResourceServlet {
}
}
@Override
public Map<String, Object> read(HttpServletRequest req, Map<String, ?> args) {
String clientId = sessionUtils.getRegistrarClientId(req);
Registrar registrar = getCheckedRegistrar(clientId);
public Map<String, Object> read(Map<String, ?> args, Registrar registrar) {
return JsonResponseHelper.create(SUCCESS, "Success", registrar.toJsonMap());
}
@Override
Map<String, Object> update(HttpServletRequest req, final Map<String, ?> args) {
final String clientId = sessionUtils.getRegistrarClientId(req);
Map<String, Object> update(final Map<String, ?> args, final Registrar registrar) {
final String clientId = sessionUtils.getRegistrarClientId(request);
return ofy().transact(new Work<Map<String, Object>>() {
@Override
public Map<String, Object> run() {
Registrar existingRegistrar = getCheckedRegistrar(clientId);
ImmutableSet<RegistrarContact> oldContacts = existingRegistrar.getContacts();
ImmutableSet<RegistrarContact> oldContacts = registrar.getContacts();
Map<String, Object> existingRegistrarMap =
expandRegistrarWithContacts(existingRegistrar, oldContacts);
Registrar.Builder builder = existingRegistrar.asBuilder();
ImmutableSet<RegistrarContact> updatedContacts = update(existingRegistrar, builder, args);
expandRegistrarWithContacts(oldContacts, registrar);
Registrar.Builder builder = registrar.asBuilder();
ImmutableSet<RegistrarContact> updatedContacts = update(registrar, builder, args);
if (!updatedContacts.isEmpty()) {
builder.setContactsRequireSyncing(true);
}
@ -102,7 +121,7 @@ public class RegistrarServlet extends ResourceServlet {
// Update the registrar map with updated contacts to bypass Objectify caching issues that
// come into play with calling getContacts().
Map<String, Object> updatedRegistrarMap =
expandRegistrarWithContacts(updatedRegistrar, updatedContacts);
expandRegistrarWithContacts(updatedContacts, updatedRegistrar);
sendExternalUpdatesIfNecessary(
updatedRegistrar.getRegistrarName(),
existingRegistrarMap,
@ -114,8 +133,8 @@ public class RegistrarServlet extends ResourceServlet {
}});
}
private Map<String, Object> expandRegistrarWithContacts(
Registrar registrar, Iterable<RegistrarContact> contacts) {
private Map<String, Object> expandRegistrarWithContacts(Iterable<RegistrarContact> contacts,
Registrar registrar) {
ImmutableSet<Map<String, Object>> expandedContacts = FluentIterable.from(contacts)
.transform(new Function<RegistrarContact, Map<String, Object>>() {
@Override
@ -146,21 +165,15 @@ public class RegistrarServlet extends ResourceServlet {
return;
}
SyncRegistrarsSheetAction.enqueueBackendTask();
ImmutableList<String> toEmailAddress = CONFIG.getRegistrarChangesNotificationEmailAddresses();
if (!toEmailAddress.isEmpty()) {
if (!registrarChangesNotificationEmailAddresses.isEmpty()) {
SendEmailUtils.sendEmail(
toEmailAddress,
registrarChangesNotificationEmailAddresses,
String.format("Registrar %s updated", registrarName),
"The following changes were made to the registrar:\n"
+ DiffUtils.prettyPrintDiffedMap(diffs, null));
}
}
private Registrar getCheckedRegistrar(String clientId) {
return checkExists(Registrar.loadByClientId(clientId),
"No registrar exists with the given client id: " + clientId);
}
/**
* Enforces business logic checks on registrar contacts.
*
@ -255,4 +268,42 @@ public class RegistrarServlet extends ResourceServlet {
return contacts.build();
}
@Override
public Map<String, Object> handleJsonRequest(Map<String, ?> 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<String, ?> args = (Map<String, Object>)
Optional.<Object>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());
}
}
@Override
public void run() {
jsonActionRunner.run(this);
}
}

View file

@ -1,105 +0,0 @@
// Copyright 2016 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.appengine.api.users.UserServiceFactory.getUserService;
import static google.registry.flows.EppConsoleAction.XSRF_SCOPE;
import static google.registry.security.JsonResponseHelper.Status.ERROR;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import google.registry.request.HttpException.NotFoundException;
import google.registry.security.JsonResponseHelper;
import google.registry.security.JsonTransportServlet;
import google.registry.ui.forms.FormException;
import google.registry.ui.forms.FormFieldException;
import google.registry.util.NonFinalForTesting;
import java.util.Map;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
/** A servlet for callbacks that manipulate resources. */
public abstract class ResourceServlet extends JsonTransportServlet {
private static final String OP_PARAM = "op";
private static final String ARGS_PARAM = "args";
@NonFinalForTesting
protected static SessionUtils sessionUtils = new SessionUtils(getUserService());
public ResourceServlet() {
super(XSRF_SCOPE, false);
}
@Override
public Map<String, Object> doJsonPost(HttpServletRequest req, Map<String, ?> params) {
if (!sessionUtils.isLoggedIn()) {
return JsonResponseHelper.create(ERROR, "Not logged in");
}
if (!sessionUtils.checkRegistrarConsoleLogin(req)) {
return JsonResponseHelper.create(ERROR, "Not authorized to access Registrar Console");
}
String op = Optional.fromNullable((String) params.get(OP_PARAM)).or("read");
@SuppressWarnings("unchecked")
Map<String, ?> args = (Map<String, Object>)
Optional.<Object>fromNullable(params.get(ARGS_PARAM)).or(ImmutableMap.of());
try {
switch (op) {
case "create":
return create(req, args);
case "update":
return update(req, args);
case "delete":
return delete(req, args);
case "read":
return read(req, args);
default:
return JsonResponseHelper.create(ERROR, "Unknown operation: " + op);
}
} catch (FormFieldException e) {
return JsonResponseHelper.createFormFieldError(e.getMessage(), e.getFieldName());
} catch (FormException ee) {
return JsonResponseHelper.create(ERROR, ee.getMessage());
}
}
@SuppressWarnings("unused")
Map<String, Object> create(HttpServletRequest req, Map<String, ?> args) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unused")
Map<String, Object> read(HttpServletRequest req, Map<String, ?> args) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unused")
Map<String, Object> update(HttpServletRequest req, Map<String, ?> args) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unused")
Map<String, Object> delete(HttpServletRequest req, Map<String, ?> args) {
throw new UnsupportedOperationException();
}
/** Like checkNotNull, but throws NotFoundException if given arg is null. */
protected static <T> T checkExists(@Nullable T obj, String msg) {
if (obj == null) {
throw new NotFoundException(msg);
}
return obj;
}
}