mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
Replace command.applyTo() with inlined builder operations
These are much easier to understand. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=137446273
This commit is contained in:
parent
b84d7f1fb5
commit
1dbc5f6bb0
28 changed files with 489 additions and 426 deletions
|
@ -978,6 +978,7 @@ are enqueued to update DNS accordingly.
|
|||
* Resource status prohibits this operation.
|
||||
* Cannot remove all IP addresses from a subordinate host.
|
||||
* 2306
|
||||
* Cannot add and remove the same value.
|
||||
* Host names must be at least two levels below the public suffix.
|
||||
|
||||
## HostInfoFlow
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package google.registry.flows;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.EppResourceUtils.queryDomainsUsingResource;
|
||||
import static google.registry.model.domain.DomainResource.extendRegistrationWithCap;
|
||||
|
@ -33,6 +34,8 @@ import com.googlecode.objectify.Work;
|
|||
import google.registry.flows.EppException.AuthorizationErrorException;
|
||||
import google.registry.flows.EppException.InvalidAuthorizationInformationErrorException;
|
||||
import google.registry.flows.EppException.ObjectDoesNotExistException;
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.flows.EppException.ParameterValueRangeErrorException;
|
||||
import google.registry.flows.exceptions.MissingTransferRequestAuthInfoException;
|
||||
import google.registry.flows.exceptions.NotPendingTransferException;
|
||||
import google.registry.flows.exceptions.NotTransferInitiatorException;
|
||||
|
@ -359,6 +362,25 @@ public final class ResourceFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Check that the same values aren't being added and removed in an update command. */
|
||||
public static void checkSameValuesNotAddedAndRemoved(
|
||||
ImmutableSet<?> fieldsToAdd, ImmutableSet<?> fieldsToRemove)
|
||||
throws AddRemoveSameValueException {
|
||||
if (!intersection(fieldsToAdd, fieldsToRemove).isEmpty()) {
|
||||
throw new AddRemoveSameValueException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that all {@link StatusValue} objects in a set are client-settable. */
|
||||
public static void verifyAllStatusesAreClientSettable(Set<StatusValue> statusValues)
|
||||
throws StatusNotClientSettableException {
|
||||
for (StatusValue statusValue : statusValues) {
|
||||
if (!statusValue.isClientSettable()) {
|
||||
throw new StatusNotClientSettableException(statusValue.getXmlName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Resource with this id does not exist. */
|
||||
public static class ResourceDoesNotExistException extends ObjectDoesNotExistException {
|
||||
public ResourceDoesNotExistException(Class<?> type, String targetId) {
|
||||
|
@ -380,4 +402,18 @@ public final class ResourceFlowUtils {
|
|||
super("Authorization information for accessing resource is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/** Cannot add and remove the same value. */
|
||||
public static class AddRemoveSameValueException extends ParameterValuePolicyErrorException {
|
||||
public AddRemoveSameValueException() {
|
||||
super("Cannot add and remove the same value");
|
||||
}
|
||||
}
|
||||
|
||||
/** The specified status value cannot be set by clients. */
|
||||
public static class StatusNotClientSettableException extends ParameterValueRangeErrorException {
|
||||
public StatusNotClientSettableException(String statusValue) {
|
||||
super(String.format("Status value %s cannot be set by clients", statusValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,12 +65,18 @@ public final class ContactCreateFlow extends Flow implements TransactionalFlow {
|
|||
validateClientIsLoggedIn(clientId);
|
||||
Create command = (Create) resourceCommand;
|
||||
verifyResourceDoesNotExist(ContactResource.class, targetId, now);
|
||||
Builder builder = new Builder();
|
||||
command.applyTo(builder);
|
||||
ContactResource newContact = builder
|
||||
ContactResource newContact = new Builder()
|
||||
.setContactId(targetId)
|
||||
.setAuthInfo(command.getAuthInfo())
|
||||
.setCreationClientId(clientId)
|
||||
.setCurrentSponsorClientId(clientId)
|
||||
.setRepoId(createContactHostRoid(ObjectifyService.allocateId()))
|
||||
.setFaxNumber(command.getFax())
|
||||
.setVoiceNumber(command.getVoice())
|
||||
.setDisclose(command.getDisclose())
|
||||
.setEmailAddress(command.getEmail())
|
||||
.setInternationalizedPostalInfo(command.getInternationalizedPostalInfo())
|
||||
.setLocalizedPostalInfo(command.getLocalizedPostalInfo())
|
||||
.build();
|
||||
validateAsciiPostalInfo(newContact.getInternationalizedPostalInfo());
|
||||
validateContactAgainstPolicy(newContact);
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
|
||||
package google.registry.flows.contact;
|
||||
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
|
@ -26,7 +29,6 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
|||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
|
@ -34,30 +36,30 @@ import google.registry.flows.Flow;
|
|||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.model.contact.ContactCommand.Update;
|
||||
import google.registry.model.contact.ContactCommand.Update.Change;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.contact.ContactResource.Builder;
|
||||
import google.registry.model.contact.PostalInfo;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that updates a contact.
|
||||
*
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link google.registry.flows.exceptions.AddRemoveSameValueEppException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
|
||||
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
|
||||
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}
|
||||
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
|
||||
*/
|
||||
|
@ -88,15 +90,11 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
|
|||
Update command = (Update) resourceCommand;
|
||||
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
|
||||
verifyOptionalAuthInfoForResource(authInfo, existingContact);
|
||||
if (!isSuperuser) {
|
||||
ImmutableSet<StatusValue> statusToRemove = command.getInnerRemove().getStatusValues();
|
||||
ImmutableSet<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues();
|
||||
if (!isSuperuser) { // The superuser can update any contact and set any status.
|
||||
verifyResourceOwnership(clientId, existingContact);
|
||||
}
|
||||
for (StatusValue statusValue : Sets.union(
|
||||
command.getInnerAdd().getStatusValues(),
|
||||
command.getInnerRemove().getStatusValues())) {
|
||||
if (!isSuperuser && !statusValue.isClientSettable()) { // The superuser can set any status.
|
||||
throw new StatusNotClientSettableException(statusValue.getXmlName());
|
||||
}
|
||||
verifyAllStatusesAreClientSettable(union(statusesToAdd, statusToRemove));
|
||||
}
|
||||
verifyNoDisallowedStatuses(existingContact, DISALLOWED_STATUSES);
|
||||
historyBuilder
|
||||
|
@ -104,15 +102,39 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
|
|||
.setModificationTime(now)
|
||||
.setXmlBytes(null) // We don't want to store contact details in the history entry.
|
||||
.setParent(Key.create(existingContact));
|
||||
checkSameValuesNotAddedAndRemoved(statusesToAdd, statusToRemove);
|
||||
Builder builder = existingContact.asBuilder();
|
||||
try {
|
||||
command.applyTo(builder);
|
||||
} catch (AddRemoveSameValueException e) {
|
||||
throw new AddRemoveSameValueEppException();
|
||||
Change change = command.getInnerChange();
|
||||
// The spec requires the following behaviors:
|
||||
// * If you update part of a postal info, the fields that you didn't update are unchanged.
|
||||
// * If you update one postal info but not the other, the other is deleted.
|
||||
// Therefore, if you want to preserve one postal info and update another you need to send the
|
||||
// update and also something that technically updates the preserved one, even if it only
|
||||
// "updates" it by setting just one field to the same value.
|
||||
PostalInfo internationalized = change.getInternationalizedPostalInfo();
|
||||
PostalInfo localized = change.getLocalizedPostalInfo();
|
||||
if (internationalized != null) {
|
||||
builder.overlayInternationalizedPostalInfo(internationalized);
|
||||
if (localized == null) {
|
||||
builder.setLocalizedPostalInfo(null);
|
||||
}
|
||||
}
|
||||
if (localized != null) {
|
||||
builder.overlayLocalizedPostalInfo(localized);
|
||||
if (internationalized == null) {
|
||||
builder.setInternationalizedPostalInfo(null);
|
||||
}
|
||||
}
|
||||
ContactResource newContact = builder
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateClientId(clientId)
|
||||
.setAuthInfo(preferFirst(change.getAuthInfo(), existingContact.getAuthInfo()))
|
||||
.setDisclose(preferFirst(change.getDisclose(), existingContact.getDisclose()))
|
||||
.setEmailAddress(preferFirst(change.getEmail(), existingContact.getEmailAddress()))
|
||||
.setFaxNumber(preferFirst(change.getFax(), existingContact.getFaxNumber()))
|
||||
.setVoiceNumber(preferFirst(change.getVoice(), existingContact.getVoiceNumber()))
|
||||
.addStatusValues(statusesToAdd)
|
||||
.removeStatusValues(statusToRemove)
|
||||
.build();
|
||||
// If the resource is marked with clientUpdateProhibited, and this update did not clear that
|
||||
// status, then the update must be disallowed (unless a superuser is requesting the change).
|
||||
|
@ -126,4 +148,10 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
|
|||
ofy().save().<Object>entities(newContact, historyBuilder.build());
|
||||
return createOutput(SUCCESS);
|
||||
}
|
||||
|
||||
/** Return the first non-null param, or null if both are null. */
|
||||
@Nullable
|
||||
private static <T> T preferFirst(@Nullable T a, @Nullable T b) {
|
||||
return a != null ? a : b;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,9 +146,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
|
|||
domainName, application, historyEntry, isSunrushAddGracePeriod, registry, years);
|
||||
entitiesToSave.addAll(billsAndPolls);
|
||||
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
|
||||
DomainResource.Builder domainBuilder = new DomainResource.Builder();
|
||||
command.applyTo(domainBuilder);
|
||||
DomainResource newDomain = domainBuilder
|
||||
DomainResource newDomain = new DomainResource.Builder()
|
||||
.setCreationClientId(clientId)
|
||||
.setCurrentSponsorClientId(clientId)
|
||||
.setRepoId(repoId)
|
||||
|
@ -167,6 +165,11 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
|
|||
.setStatusValues(ReservationType.NAME_COLLISION == getReservationType(domainName)
|
||||
? ImmutableSet.of(StatusValue.SERVER_HOLD)
|
||||
: ImmutableSet.<StatusValue>of())
|
||||
.setRegistrant(command.getRegistrant())
|
||||
.setAuthInfo(command.getAuthInfo())
|
||||
.setFullyQualifiedDomainName(targetId)
|
||||
.setNameservers(command.getNameservers())
|
||||
.setContacts(command.getContacts())
|
||||
.build();
|
||||
entitiesToSave.add(
|
||||
newDomain,
|
||||
|
|
|
@ -210,9 +210,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
|
|||
validateFeeChallenge(targetId, tld, now, feeCreate, commandOperations.getTotalCost());
|
||||
SecDnsCreateExtension secDnsCreate =
|
||||
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
|
||||
DomainApplication.Builder applicationBuilder = new DomainApplication.Builder();
|
||||
command.applyTo(applicationBuilder);
|
||||
applicationBuilder
|
||||
DomainApplication newApplication = new DomainApplication.Builder()
|
||||
.setCreationTrid(trid)
|
||||
.setCreationClientId(clientId)
|
||||
.setCurrentSponsorClientId(clientId)
|
||||
|
@ -224,6 +222,11 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
|
|||
.setApplicationStatus(ApplicationStatus.VALIDATED)
|
||||
.addStatusValue(StatusValue.PENDING_CREATE)
|
||||
.setDsData(secDnsCreate == null ? null : secDnsCreate.getDsData())
|
||||
.setRegistrant(command.getRegistrant())
|
||||
.setAuthInfo(command.getAuthInfo())
|
||||
.setFullyQualifiedDomainName(targetId)
|
||||
.setNameservers(command.getNameservers())
|
||||
.setContacts(command.getContacts())
|
||||
.setEncodedSignedMarks(FluentIterable
|
||||
.from(launchCreate.getSignedMarks())
|
||||
.transform(new Function<AbstractSignedMark, EncodedSignedMark>() {
|
||||
|
@ -231,8 +234,8 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
|
|||
public EncodedSignedMark apply(AbstractSignedMark abstractSignedMark) {
|
||||
return (EncodedSignedMark) abstractSignedMark;
|
||||
}})
|
||||
.toList());
|
||||
DomainApplication newApplication = applicationBuilder.build();
|
||||
.toList())
|
||||
.build();
|
||||
HistoryEntry historyEntry = buildHistory(newApplication.getRepoId(), command.getPeriod());
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
handleExtraFlowLogic(
|
||||
|
|
|
@ -16,7 +16,11 @@ package google.registry.flows.domain;
|
|||
|
||||
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
|
||||
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
|
||||
|
@ -34,7 +38,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateRequiredConta
|
|||
import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyStatusChangesAreClientSettable;
|
||||
import static google.registry.model.EppResourceUtils.loadDomainApplication;
|
||||
import static google.registry.model.domain.fee.Fee.FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
|
||||
|
@ -52,11 +55,11 @@ import google.registry.flows.FlowModule.ApplicationId;
|
|||
import google.registry.flows.FlowModule.ClientId;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.domain.DomainApplication.Builder;
|
||||
import google.registry.model.domain.DomainCommand.Update;
|
||||
import google.registry.model.domain.DomainCommand.Update.AddRemove;
|
||||
import google.registry.model.domain.DomainCommand.Update.Change;
|
||||
import google.registry.model.domain.launch.ApplicationStatus;
|
||||
import google.registry.model.domain.launch.LaunchUpdateExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
|
@ -64,7 +67,6 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
|||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import javax.inject.Inject;
|
||||
|
@ -76,12 +78,12 @@ import javax.inject.Inject;
|
|||
* cannot change the domain name that is being applied for.
|
||||
*
|
||||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link google.registry.flows.exceptions.AddRemoveSameValueEppException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
|
||||
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
|
||||
* @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException}
|
||||
* @error {@link DomainFlowUtils.DuplicateContactForRoleException}
|
||||
* @error {@link DomainFlowUtils.EmptySecDnsUpdateException}
|
||||
|
@ -151,10 +153,12 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
|
|||
|
||||
protected final void verifyUpdateAllowed(
|
||||
DomainApplication existingApplication, Update command) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
if (!isSuperuser) {
|
||||
verifyResourceOwnership(clientId, existingApplication);
|
||||
verifyClientUpdateNotProhibited(command, existingApplication);
|
||||
verifyStatusChangesAreClientSettable(command);
|
||||
verifyAllStatusesAreClientSettable(union(add.getStatusValues(), remove.getStatusValues()));
|
||||
}
|
||||
String tld = existingApplication.getTld();
|
||||
checkAllowedAccessToTld(clientId, tld);
|
||||
|
@ -164,14 +168,14 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
|
|||
existingApplication.getApplicationStatus());
|
||||
}
|
||||
verifyNotInPendingDelete(
|
||||
command.getInnerAdd().getContacts(),
|
||||
add.getContacts(),
|
||||
command.getInnerChange().getRegistrant(),
|
||||
command.getInnerAdd().getNameservers());
|
||||
validateContactsHaveTypes(command.getInnerAdd().getContacts());
|
||||
validateContactsHaveTypes(command.getInnerRemove().getContacts());
|
||||
add.getNameservers());
|
||||
validateContactsHaveTypes(add.getContacts());
|
||||
validateContactsHaveTypes(remove.getContacts());
|
||||
validateRegistrantAllowedOnTld(tld, command.getInnerChange().getRegistrantContactId());
|
||||
validateNameserversAllowedOnTld(
|
||||
tld, command.getInnerAdd().getNameserverFullyQualifiedHostNames());
|
||||
tld, add.getNameserverFullyQualifiedHostNames());
|
||||
}
|
||||
|
||||
private HistoryEntry buildHistory(DomainApplication existingApplication) {
|
||||
|
@ -183,20 +187,30 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
|
|||
}
|
||||
|
||||
private DomainApplication updateApplication(
|
||||
DomainApplication existingApplication, Update command) throws EppException {
|
||||
Builder builder = existingApplication.asBuilder();
|
||||
try {
|
||||
command.applyTo(builder);
|
||||
} catch (AddRemoveSameValueException e) {
|
||||
throw new AddRemoveSameValueEppException();
|
||||
}
|
||||
builder.setLastEppUpdateTime(now).setLastEppUpdateClientId(clientId);
|
||||
// Handle the secDNS extension.
|
||||
DomainApplication application, Update command) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
|
||||
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
|
||||
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
|
||||
Change change = command.getInnerChange();
|
||||
SecDnsUpdateExtension secDnsUpdate = eppInput.getSingleExtension(SecDnsUpdateExtension.class);
|
||||
if (secDnsUpdate != null) {
|
||||
builder.setDsData(updateDsData(existingApplication.getDsData(), secDnsUpdate));
|
||||
}
|
||||
return builder.build();
|
||||
return application.asBuilder()
|
||||
// Handle the secDNS extension.
|
||||
.setDsData(secDnsUpdate != null
|
||||
? updateDsData(application.getDsData(), secDnsUpdate)
|
||||
: application.getDsData())
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateClientId(clientId)
|
||||
.addStatusValues(add.getStatusValues())
|
||||
.removeStatusValues(remove.getStatusValues())
|
||||
.addNameservers(add.getNameservers())
|
||||
.removeNameservers(remove.getNameservers())
|
||||
.addContacts(add.getContacts())
|
||||
.removeContacts(remove.getContacts())
|
||||
.setRegistrant(firstNonNull(change.getRegistrant(), application.getRegistrant()))
|
||||
.setAuthInfo(firstNonNull(change.getAuthInfo(), application.getAuthInfo()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void validateNewApplication(DomainApplication newApplication) throws EppException {
|
||||
|
|
|
@ -245,9 +245,7 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
|
|||
if (!commandOperations.getEapCost().isZero()) {
|
||||
entitiesToSave.add(createEapBillingEvent(commandOperations, createBillingEvent));
|
||||
}
|
||||
DomainResource.Builder domainBuilder = new DomainResource.Builder();
|
||||
command.applyTo(domainBuilder);
|
||||
DomainResource newDomain = domainBuilder
|
||||
DomainResource newDomain = new DomainResource.Builder()
|
||||
.setCreationClientId(clientId)
|
||||
.setCurrentSponsorClientId(clientId)
|
||||
.setRepoId(repoId)
|
||||
|
@ -261,6 +259,11 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
|
|||
? verifySignedMarks(launchCreate.getSignedMarks(), domainLabel, now).getId()
|
||||
: null)
|
||||
.setDsData(secDnsCreate == null ? null : secDnsCreate.getDsData())
|
||||
.setRegistrant(command.getRegistrant())
|
||||
.setAuthInfo(command.getAuthInfo())
|
||||
.setFullyQualifiedDomainName(targetId)
|
||||
.setNameservers(command.getNameservers())
|
||||
.setContacts(command.getContacts())
|
||||
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent))
|
||||
.build();
|
||||
handleExtraFlowLogic(registry.getTldStr(), years, historyEntry, newDomain);
|
||||
|
|
|
@ -59,7 +59,6 @@ import google.registry.flows.EppException.UnimplementedOptionException;
|
|||
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
|
||||
import google.registry.flows.exceptions.ResourceAlreadyExistsException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
|
@ -829,18 +828,6 @@ public class DomainFlowUtils {
|
|||
return ImmutableSet.copyOf(union(difference(oldDsData, toRemove), toAdd));
|
||||
}
|
||||
|
||||
/** Check that all of the status values added or removed in an update are client-settable. */
|
||||
static void verifyStatusChangesAreClientSettable(Update command)
|
||||
throws StatusNotClientSettableException {
|
||||
for (StatusValue statusValue : union(
|
||||
command.getInnerAdd().getStatusValues(),
|
||||
command.getInnerRemove().getStatusValues())) {
|
||||
if (!statusValue.isClientSettable()) {
|
||||
throw new StatusNotClientSettableException(statusValue.getXmlName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** If a domain or application has "clientUpdateProhibited" set, updates must clear it or fail. */
|
||||
static void verifyClientUpdateNotProhibited(Update command, DomainBase existingResource)
|
||||
throws ResourceHasClientUpdateProhibitedException {
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.collect.Sets.symmetricDifference;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
|
@ -33,7 +37,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateRegistrantAll
|
|||
import static google.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresent;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyStatusChangesAreClientSettable;
|
||||
import static google.registry.model.domain.fee.Fee.FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -52,11 +55,12 @@ import google.registry.flows.FlowModule.TargetId;
|
|||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForNonFreeUpdateException;
|
||||
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainCommand.Update;
|
||||
import google.registry.model.domain.DomainCommand.Update.AddRemove;
|
||||
import google.registry.model.domain.DomainCommand.Update.Change;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.fee.FeeTransformCommandExtension;
|
||||
|
@ -67,7 +71,6 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
|||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
|
@ -92,13 +95,13 @@ import org.joda.time.DateTime;
|
|||
* accordingly.
|
||||
*
|
||||
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link google.registry.flows.exceptions.AddRemoveSameValueEppException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
|
||||
* @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
|
||||
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
|
||||
* @error {@link DomainFlowUtils.DuplicateContactForRoleException}
|
||||
* @error {@link DomainFlowUtils.EmptySecDnsUpdateException}
|
||||
* @error {@link DomainFlowUtils.FeesMismatchException}
|
||||
|
@ -181,10 +184,12 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
|
|||
throws EppException {
|
||||
verifyNoDisallowedStatuses(existingDomain, UPDATE_DISALLOWED_STATUSES);
|
||||
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
if (!isSuperuser) {
|
||||
verifyResourceOwnership(clientId, existingDomain);
|
||||
verifyClientUpdateNotProhibited(command, existingDomain);
|
||||
verifyStatusChangesAreClientSettable(command);
|
||||
verifyAllStatusesAreClientSettable(union(add.getStatusValues(), remove.getStatusValues()));
|
||||
}
|
||||
String tld = existingDomain.getTld();
|
||||
checkAllowedAccessToTld(clientId, tld);
|
||||
|
@ -204,14 +209,14 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
|
|||
throw new FeesRequiredForNonFreeUpdateException();
|
||||
}
|
||||
verifyNotInPendingDelete(
|
||||
command.getInnerAdd().getContacts(),
|
||||
add.getContacts(),
|
||||
command.getInnerChange().getRegistrant(),
|
||||
command.getInnerAdd().getNameservers());
|
||||
validateContactsHaveTypes(command.getInnerAdd().getContacts());
|
||||
validateContactsHaveTypes(command.getInnerRemove().getContacts());
|
||||
add.getNameservers());
|
||||
validateContactsHaveTypes(add.getContacts());
|
||||
validateContactsHaveTypes(remove.getContacts());
|
||||
validateRegistrantAllowedOnTld(tld, command.getInnerChange().getRegistrantContactId());
|
||||
validateNameserversAllowedOnTld(
|
||||
tld, command.getInnerAdd().getNameserverFullyQualifiedHostNames());
|
||||
tld, add.getNameserverFullyQualifiedHostNames());
|
||||
}
|
||||
|
||||
private HistoryEntry buildHistoryEntry(DomainResource existingDomain) {
|
||||
|
@ -222,22 +227,31 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
|
|||
.build();
|
||||
}
|
||||
|
||||
private DomainResource performUpdate(Update command, DomainResource existingDomain)
|
||||
private DomainResource performUpdate(Update command, DomainResource domain)
|
||||
throws EppException {
|
||||
DomainResource.Builder builder = existingDomain.asBuilder()
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateClientId(clientId);
|
||||
try {
|
||||
command.applyTo(builder);
|
||||
} catch (AddRemoveSameValueException e) {
|
||||
throw new AddRemoveSameValueEppException();
|
||||
}
|
||||
// Handle the secDNS extension.
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
|
||||
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
|
||||
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
|
||||
Change change = command.getInnerChange();
|
||||
SecDnsUpdateExtension secDnsUpdate = eppInput.getSingleExtension(SecDnsUpdateExtension.class);
|
||||
if (secDnsUpdate != null) {
|
||||
builder.setDsData(updateDsData(existingDomain.getDsData(), secDnsUpdate));
|
||||
}
|
||||
return builder.build();
|
||||
return domain.asBuilder()
|
||||
// Handle the secDNS extension.
|
||||
.setDsData(secDnsUpdate != null
|
||||
? updateDsData(domain.getDsData(), secDnsUpdate)
|
||||
: domain.getDsData())
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateClientId(clientId)
|
||||
.addStatusValues(add.getStatusValues())
|
||||
.removeStatusValues(remove.getStatusValues())
|
||||
.addNameservers(add.getNameservers())
|
||||
.removeNameservers(remove.getNameservers())
|
||||
.addContacts(add.getContacts())
|
||||
.removeContacts(remove.getContacts())
|
||||
.setRegistrant(firstNonNull(change.getRegistrant(), domain.getRegistrant()))
|
||||
.setAuthInfo(firstNonNull(change.getAuthInfo(), domain.getAuthInfo()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainResource convertSunrushAddToAdd(
|
||||
|
|
|
@ -1,24 +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.flows.exceptions;
|
||||
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
|
||||
/** Cannot add and remove the same value. */
|
||||
public class AddRemoveSameValueEppException extends ParameterValuePolicyErrorException {
|
||||
public AddRemoveSameValueEppException() {
|
||||
super("Cannot add and remove the same value");
|
||||
}
|
||||
}
|
|
@ -1,24 +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.flows.exceptions;
|
||||
|
||||
import google.registry.flows.EppException.ParameterValueRangeErrorException;
|
||||
|
||||
/** The specified status value cannot be set by clients. */
|
||||
public class StatusNotClientSettableException extends ParameterValueRangeErrorException {
|
||||
public StatusNotClientSettableException(String statusValue) {
|
||||
super(String.format("Status value %s cannot be set by clients", statusValue));
|
||||
}
|
||||
}
|
|
@ -101,11 +101,11 @@ public final class HostCreateFlow extends Flow implements TransactionalFlow {
|
|||
? new SubordinateHostMustHaveIpException()
|
||||
: new UnexpectedExternalHostIpException();
|
||||
}
|
||||
Builder builder = new Builder();
|
||||
command.applyTo(builder);
|
||||
HostResource newHost = builder
|
||||
HostResource newHost = new Builder()
|
||||
.setCreationClientId(clientId)
|
||||
.setCurrentSponsorClientId(clientId)
|
||||
.setFullyQualifiedHostName(targetId)
|
||||
.setInetAddresses(command.getInetAddresses())
|
||||
.setRepoId(createContactHostRoid(ObjectifyService.allocateId()))
|
||||
.setSuperordinateDomain(
|
||||
superordinateDomain.isPresent() ? Key.create(superordinateDomain.get()) : null)
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
package google.registry.flows.host;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
|
@ -30,7 +33,6 @@ import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
|||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.flows.EppException;
|
||||
|
@ -44,20 +46,18 @@ import google.registry.flows.FlowModule.ClientId;
|
|||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.async.AsyncFlowEnqueuer;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppinput.ResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.host.HostCommand.Update;
|
||||
import google.registry.model.host.HostCommand.Update.AddRemove;
|
||||
import google.registry.model.host.HostCommand.Update.Change;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.host.HostResource.Builder;
|
||||
import google.registry.model.index.ForeignKeyIndex;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import java.util.Objects;
|
||||
|
@ -76,11 +76,12 @@ import javax.inject.Inject;
|
|||
* when it is renamed from external to internal at least one must be added. If the host is renamed
|
||||
* or IP addresses are added, tasks are enqueued to update DNS accordingly.
|
||||
*
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
|
||||
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
|
||||
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
|
||||
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
|
||||
* @error {@link HostFlowUtils.HostNameTooShallowException}
|
||||
* @error {@link HostFlowUtils.InvalidHostNameException}
|
||||
* @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException}
|
||||
|
@ -117,7 +118,8 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
|
|||
extensionManager.validate();
|
||||
validateClientIsLoggedIn(clientId);
|
||||
Update command = (Update) resourceCommand;
|
||||
String suppliedNewHostName = command.getInnerChange().getFullyQualifiedHostName();
|
||||
Change change = command.getInnerChange();
|
||||
String suppliedNewHostName = change.getFullyQualifiedHostName();
|
||||
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
|
||||
boolean isHostRename = suppliedNewHostName != null;
|
||||
String oldHostName = targetId;
|
||||
|
@ -128,13 +130,16 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
|
|||
if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) {
|
||||
throw new HostAlreadyExistsException(newHostName);
|
||||
}
|
||||
Builder builder = existingHost.asBuilder();
|
||||
try {
|
||||
command.applyTo(builder);
|
||||
} catch (AddRemoveSameValueException e) {
|
||||
throw new AddRemoveSameValueEppException();
|
||||
}
|
||||
builder
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
|
||||
checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses());
|
||||
HostResource newHost = existingHost.asBuilder()
|
||||
.setFullyQualifiedHostName(newHostName)
|
||||
.addStatusValues(add.getStatusValues())
|
||||
.removeStatusValues(remove.getStatusValues())
|
||||
.addInetAddresses(add.getInetAddresses())
|
||||
.removeInetAddresses(remove.getInetAddresses())
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateClientId(clientId)
|
||||
// The superordinateDomain can be missing if the new name is external.
|
||||
|
@ -142,9 +147,10 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
|
|||
// the lookupSuperordinateDomain(...) call above, so that it will never be stale.
|
||||
.setSuperordinateDomain(
|
||||
superordinateDomain.isPresent() ? Key.create(superordinateDomain.get()) : null)
|
||||
.setLastSuperordinateChange(superordinateDomain == null ? null : now);
|
||||
.setLastSuperordinateChange(superordinateDomain == null ? null : now)
|
||||
.build()
|
||||
// Rely on the host's cloneProjectedAtTime() method to handle setting of transfer data.
|
||||
HostResource newHost = builder.build().cloneProjectedAtTime(now);
|
||||
.cloneProjectedAtTime(now);
|
||||
verifyHasIpsIffIsExternal(command, existingHost, newHost);
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
entitiesToSave.add(newHost);
|
||||
|
@ -172,21 +178,16 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
|
|||
verifyOptionalAuthInfoForResource(authInfo, existingResource);
|
||||
if (!isSuperuser) {
|
||||
verifyResourceOwnership(clientId, existingResource);
|
||||
ImmutableSet<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues();
|
||||
ImmutableSet<StatusValue> statusesToRemove = command.getInnerRemove().getStatusValues();
|
||||
// If the resource is marked with clientUpdateProhibited, and this update does not clear that
|
||||
// status, then the update must be disallowed (unless a superuser is requesting the change).
|
||||
if (!isSuperuser
|
||||
&& existingResource.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED)
|
||||
&& !command.getInnerRemove().getStatusValues()
|
||||
.contains(StatusValue.CLIENT_UPDATE_PROHIBITED)) {
|
||||
&& !statusesToRemove.contains(StatusValue.CLIENT_UPDATE_PROHIBITED)) {
|
||||
throw new ResourceHasClientUpdateProhibitedException();
|
||||
}
|
||||
}
|
||||
for (StatusValue statusValue : Sets.union(
|
||||
command.getInnerAdd().getStatusValues(),
|
||||
command.getInnerRemove().getStatusValues())) {
|
||||
if (!isSuperuser && !statusValue.isClientSettable()) { // The superuser can set any status.
|
||||
throw new StatusNotClientSettableException(statusValue.getXmlName());
|
||||
}
|
||||
verifyAllStatusesAreClientSettable(union(statusesToAdd, statusesToRemove));
|
||||
}
|
||||
verifyDomainIsSameRegistrar(superordinateDomain, clientId);
|
||||
verifyNoDisallowedStatuses(existingResource, DISALLOWED_STATUSES);
|
||||
|
|
|
@ -20,7 +20,6 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.ContactResource.Builder;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
|
||||
|
@ -75,23 +74,32 @@ public class ContactCommand {
|
|||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(Builder builder) {
|
||||
if (authInfo != null) {
|
||||
builder.setAuthInfo(authInfo);
|
||||
public ContactPhoneNumber getVoice() {
|
||||
return voice;
|
||||
}
|
||||
if (disclose != null) {
|
||||
builder.setDisclose(disclose);
|
||||
|
||||
public ContactPhoneNumber getFax() {
|
||||
return fax;
|
||||
}
|
||||
if (email != null) {
|
||||
builder.setEmailAddress(email);
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
if (fax != null) {
|
||||
builder.setFaxNumber(fax);
|
||||
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
if (voice != null) {
|
||||
builder.setVoiceNumber(voice);
|
||||
|
||||
public Disclose getDisclose() {
|
||||
return disclose;
|
||||
}
|
||||
|
||||
public PostalInfo getInternationalizedPostalInfo() {
|
||||
return getPostalInfosAsMap().get(Type.INTERNATIONALIZED);
|
||||
}
|
||||
|
||||
public PostalInfo getLocalizedPostalInfo() {
|
||||
return getPostalInfosAsMap().get(Type.LOCALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,21 +142,6 @@ public class ContactCommand {
|
|||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(ContactResource.Builder builder) {
|
||||
super.applyTo(builder);
|
||||
if (contactId != null) {
|
||||
builder.setContactId(contactId);
|
||||
}
|
||||
Map<Type, PostalInfo> postalInfosAsMap = getPostalInfosAsMap();
|
||||
if (postalInfosAsMap.containsKey(Type.INTERNATIONALIZED)) {
|
||||
builder.setInternationalizedPostalInfo(postalInfosAsMap.get(Type.INTERNATIONALIZED));
|
||||
}
|
||||
if (postalInfosAsMap.containsKey(Type.LOCALIZED)) {
|
||||
builder.setLocalizedPostalInfo(postalInfosAsMap.get(Type.LOCALIZED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A delete command for a {@link ContactResource}. */
|
||||
|
@ -204,34 +197,6 @@ public class ContactCommand {
|
|||
|
||||
/** The inner change type on a contact update command. */
|
||||
@XmlType(propOrder = {"postalInfo", "voice", "fax", "email", "authInfo", "disclose"})
|
||||
public static class Change extends ContactCreateOrChange {
|
||||
/**
|
||||
* The spec requires the following behaviors:
|
||||
* <ul>
|
||||
* <li>If you update part of a postal info, the fields that you didn't update are unchanged.
|
||||
* <li>If you update one postal info but not the other, the other is deleted.
|
||||
* </ul>
|
||||
* Therefore, if you want to preserve one postal info and update another you need to send the
|
||||
* update and also something that technically updates the preserved one, even if it only
|
||||
* "updates" it by setting just one field to the same value.
|
||||
*/
|
||||
@Override
|
||||
public void applyTo(ContactResource.Builder builder) {
|
||||
super.applyTo(builder);
|
||||
Map<Type, PostalInfo> postalInfosAsMap = getPostalInfosAsMap();
|
||||
if (postalInfosAsMap.containsKey(Type.INTERNATIONALIZED)) {
|
||||
builder.overlayInternationalizedPostalInfo(postalInfosAsMap.get(Type.INTERNATIONALIZED));
|
||||
if (postalInfosAsMap.size() == 1) {
|
||||
builder.setLocalizedPostalInfo(null);
|
||||
}
|
||||
}
|
||||
if (postalInfosAsMap.containsKey(Type.LOCALIZED)) {
|
||||
builder.overlayLocalizedPostalInfo(postalInfosAsMap.get(Type.LOCALIZED));
|
||||
if (postalInfosAsMap.size() == 1) {
|
||||
builder.setInternationalizedPostalInfo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class Change extends ContactCreateOrChange {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import google.registry.model.EppResource;
|
|||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||
import google.registry.model.annotations.ExternalMessagingName;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
@ -147,7 +146,7 @@ public class ContactResource extends EppResource implements ForeignKeyedEppResou
|
|||
return email;
|
||||
}
|
||||
|
||||
public AuthInfo getAuthInfo() {
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ import google.registry.model.contact.ContactResource;
|
|||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.host.HostResource;
|
||||
import java.util.Set;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
@ -221,7 +220,7 @@ public abstract class DomainBase extends EppResource {
|
|||
.toSet();
|
||||
}
|
||||
|
||||
public AuthInfo getAuthInfo() {
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.collect.Maps.transformValues;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.CollectionUtils.difference;
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
|
@ -37,7 +36,6 @@ import com.googlecode.objectify.Work;
|
|||
import google.registry.model.EppResource;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
|
||||
import google.registry.model.eppinput.ResourceCommand.ResourceCreateOrChange;
|
||||
|
@ -98,14 +96,8 @@ public class DomainCommand {
|
|||
return registrant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(B builder) {
|
||||
if (registrant != null) {
|
||||
builder.setRegistrant(registrant);
|
||||
}
|
||||
if (authInfo != null) {
|
||||
builder.setAuthInfo(authInfo);
|
||||
}
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,24 +167,10 @@ public class DomainCommand {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo getAuthInfo() {
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(DomainBase.Builder<?, ?> builder) {
|
||||
super.applyTo(builder);
|
||||
if (fullyQualifiedDomainName != null) {
|
||||
builder.setFullyQualifiedDomainName(fullyQualifiedDomainName);
|
||||
}
|
||||
if (nameservers != null) {
|
||||
builder.setNameservers(getNameservers());
|
||||
}
|
||||
if (contacts != null) {
|
||||
builder.setContacts(getContacts());
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a copy of this {@link Create} with hard links to hosts and contacts. */
|
||||
@Override
|
||||
public Create cloneAndLinkReferences(DateTime now) throws InvalidReferencesException {
|
||||
|
@ -422,24 +400,6 @@ public class DomainCommand {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(DomainBase.Builder<?, ?> builder) throws AddRemoveSameValueException {
|
||||
super.applyTo(builder);
|
||||
getInnerChange().applyTo(builder);
|
||||
AddRemove add = getInnerAdd();
|
||||
AddRemove remove = getInnerRemove();
|
||||
if (!intersection(add.getNameservers(), remove.getNameservers()).isEmpty()) {
|
||||
throw new AddRemoveSameValueException();
|
||||
}
|
||||
builder.addNameservers(add.getNameservers());
|
||||
builder.removeNameservers(remove.getNameservers());
|
||||
if (!intersection(add.getContacts(), remove.getContacts()).isEmpty()) {
|
||||
throw new AddRemoveSameValueException();
|
||||
}
|
||||
builder.addContacts(add.getContacts());
|
||||
builder.removeContacts(remove.getContacts());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this {@link Update} with hard links to hosts and contacts.
|
||||
*
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
package google.registry.model.eppinput;
|
||||
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
|
@ -83,9 +82,7 @@ public interface ResourceCommand {
|
|||
}
|
||||
|
||||
/** A create command, or the inner change (as opposed to add or remove) part of an update. */
|
||||
public interface ResourceCreateOrChange<B extends Builder<?>> {
|
||||
public abstract void applyTo(B builder);
|
||||
}
|
||||
public interface ResourceCreateOrChange<B extends Builder<?>> {}
|
||||
|
||||
/**
|
||||
* An update command for an {@link EppResource}.
|
||||
|
@ -133,18 +130,5 @@ public interface ResourceCommand {
|
|||
A remove = getNullableInnerRemove();
|
||||
return remove == null ? new TypeInstantiator<A>(getClass()){}.instantiate() : remove;
|
||||
}
|
||||
|
||||
public void applyTo(B builder) throws AddRemoveSameValueException {
|
||||
getInnerChange().applyTo(builder);
|
||||
if (!intersection(getInnerAdd().getStatusValues(), getInnerRemove().getStatusValues())
|
||||
.isEmpty()) {
|
||||
throw new AddRemoveSameValueException();
|
||||
}
|
||||
builder.addStatusValues(getInnerAdd().getStatusValues());
|
||||
builder.removeStatusValues(getInnerRemove().getStatusValues());
|
||||
}
|
||||
}
|
||||
|
||||
/** Exception for adding and removing the same value in {@link ResourceUpdate#applyTo}. */
|
||||
public static class AddRemoveSameValueException extends Exception {}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
package google.registry.model.host;
|
||||
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
|
@ -37,27 +36,9 @@ public class HostCommand {
|
|||
@XmlTransient
|
||||
abstract static class HostCreateOrChange extends AbstractSingleResourceCommand
|
||||
implements ResourceCreateOrChange<HostResource.Builder> {
|
||||
/** IP Addresses for this host. Can be null if this is an external host. */
|
||||
@XmlElement(name = "addr")
|
||||
Set<InetAddress> inetAddresses;
|
||||
|
||||
public ImmutableSet<InetAddress> getInetAddresses() {
|
||||
return nullSafeImmutableCopy(inetAddresses);
|
||||
}
|
||||
|
||||
public String getFullyQualifiedHostName() {
|
||||
return getTargetId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(HostResource.Builder builder) {
|
||||
if (getFullyQualifiedHostName() != null) {
|
||||
builder.setFullyQualifiedHostName(getFullyQualifiedHostName());
|
||||
}
|
||||
if (getInetAddresses() != null) {
|
||||
builder.setInetAddresses(getInetAddresses());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +48,15 @@ public class HostCommand {
|
|||
@XmlType(propOrder = {"targetId", "inetAddresses" })
|
||||
@XmlRootElement
|
||||
public static class Create
|
||||
extends HostCreateOrChange implements ResourceCreateOrChange<HostResource.Builder> {}
|
||||
extends HostCreateOrChange implements ResourceCreateOrChange<HostResource.Builder> {
|
||||
/** IP Addresses for this host. Can be null if this is an external host. */
|
||||
@XmlElement(name = "addr")
|
||||
Set<InetAddress> inetAddresses;
|
||||
|
||||
public ImmutableSet<InetAddress> getInetAddresses() {
|
||||
return nullSafeImmutableCopy(inetAddresses);
|
||||
}
|
||||
}
|
||||
|
||||
/** A delete command for a {@link HostResource}. */
|
||||
@XmlRootElement
|
||||
|
@ -124,18 +113,6 @@ public class HostCommand {
|
|||
}
|
||||
|
||||
/** The inner change type on a host update command. */
|
||||
@XmlType(propOrder = {"targetId", "inetAddresses" })
|
||||
public static class Change extends HostCreateOrChange {}
|
||||
|
||||
@Override
|
||||
public void applyTo(HostResource.Builder builder) throws AddRemoveSameValueException {
|
||||
super.applyTo(builder);
|
||||
if (!intersection(getInnerAdd().getInetAddresses(), getInnerRemove().getInetAddresses())
|
||||
.isEmpty()) {
|
||||
throw new AddRemoveSameValueException();
|
||||
}
|
||||
builder.addInetAddresses(getInnerAdd().getInetAddresses());
|
||||
builder.removeInetAddresses(getInnerRemove().getInetAddresses());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,14 +24,14 @@ import static google.registry.testing.DatastoreHelper.persistResource;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
import google.registry.flows.contact.ContactFlowUtils.BadInternationalizedPostalInfoException;
|
||||
import google.registry.flows.contact.ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.model.contact.ContactAddress;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.contact.PostalInfo;
|
||||
|
@ -84,7 +84,7 @@ public class ContactUpdateFlowTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_updatingOnePostalInfoDeletesTheOther() throws Exception {
|
||||
public void testSuccess_updatingInternationalizedPostalInfoDeletesLocalized() throws Exception {
|
||||
ContactResource contact =
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
|
@ -104,12 +104,60 @@ public class ContactUpdateFlowTest
|
|||
// the localized one since they are treated as a pair for update purposes.
|
||||
assertAboutContacts().that(contact)
|
||||
.hasNonNullLocalizedPostalInfo().and()
|
||||
.hasInternationalizedPostalInfo(null);
|
||||
.hasNullInternationalizedPostalInfo();
|
||||
|
||||
runFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
assertAboutContacts().that(reloadResourceByForeignKey())
|
||||
.hasLocalizedPostalInfo(null).and()
|
||||
.hasNonNullInternationalizedPostalInfo();
|
||||
.hasNullLocalizedPostalInfo().and()
|
||||
.hasInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("124 Example Dr.", "Suite 200"))
|
||||
.setCity("Dulles")
|
||||
.setState("VA")
|
||||
.setZip("20166-6503")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_updatingLocalizedPostalInfoDeletesInternationalized() throws Exception {
|
||||
setEppInput("contact_update_localized.xml");
|
||||
ContactResource contact =
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10011")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
// The test xml updates the localized postal info and should therefore implicitly delete
|
||||
// the internationalized one since they are treated as a pair for update purposes.
|
||||
assertAboutContacts().that(contact)
|
||||
.hasNonNullInternationalizedPostalInfo().and()
|
||||
.hasNullLocalizedPostalInfo();
|
||||
|
||||
runFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
assertAboutContacts().that(reloadResourceByForeignKey())
|
||||
.hasNullInternationalizedPostalInfo().and()
|
||||
.hasLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("124 Example Dr.", "Suite 200"))
|
||||
.setCity("Dulles")
|
||||
.setState("VA")
|
||||
.setZip("20166-6503")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -148,6 +196,73 @@ public class ContactUpdateFlowTest
|
|||
.build());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSuccess_updateOnePostalInfo_touchOtherPostalInfoPreservesIt() throws Exception {
|
||||
setEppInput("contact_update_partial_postalinfo_preserve_int.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("A. Person")
|
||||
.setOrg("Company Inc.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 4th st", "5th Floor"))
|
||||
.setCity("City")
|
||||
.setState("AB")
|
||||
.setZip("12345")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.setInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("B. Person")
|
||||
.setOrg("Company Co.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("100 200th Dr.", "6th Floor"))
|
||||
.setCity("Town")
|
||||
.setState("CD")
|
||||
.setZip("67890")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
// The test xml updates the address of the localized postal info. It also sets the name of the
|
||||
// internationalized postal info to the same value it previously had, which causes it to be
|
||||
// preserved. If the xml had not mentioned the internationalized one at all it would have been
|
||||
// deleted.
|
||||
runFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
assertAboutContacts().that(reloadResourceByForeignKey())
|
||||
.hasLocalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("A. Person")
|
||||
.setOrg("Company Inc.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("456 5th st"))
|
||||
.setCity("Place")
|
||||
.setState("CD")
|
||||
.setZip("54321")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.and()
|
||||
.hasInternationalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("B. Person")
|
||||
.setOrg("Company Co.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("100 200th Dr.", "6th Floor"))
|
||||
.setCity("Town")
|
||||
.setState("CD")
|
||||
.setZip("67890")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
thrown.expect(
|
||||
|
@ -264,7 +379,7 @@ public class ContactUpdateFlowTest
|
|||
public void testFailure_addRemoveSameValue() throws Exception {
|
||||
setEppInput("contact_update_add_remove_same.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
thrown.expect(AddRemoveSameValueEppException.class);
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
}
|
||||
|
|
36
javatests/google/registry/flows/contact/testdata/contact_update_localized.xml
vendored
Normal file
36
javatests/google/registry/flows/contact/testdata/contact_update_localized.xml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<contact:update
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:add>
|
||||
<contact:status s="clientDeleteProhibited"/>
|
||||
</contact:add>
|
||||
<contact:chg>
|
||||
<contact:postalInfo type="loc">
|
||||
<contact:org/>
|
||||
<contact:addr>
|
||||
<contact:street>124 Example Dr.</contact:street>
|
||||
<contact:street>Suite 200</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice>+1.7034444444</contact:voice>
|
||||
<contact:fax/>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="1">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:chg>
|
||||
</contact:update>
|
||||
</update>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -0,0 +1,25 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<contact:update
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:chg>
|
||||
<contact:postalInfo type="loc">
|
||||
<contact:addr>
|
||||
<contact:street>456 5th st</contact:street>
|
||||
<contact:city>Place</contact:city>
|
||||
<contact:sp>CD</contact:sp>
|
||||
<contact:pc>54321</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:org>Company Co.</contact:org>
|
||||
</contact:postalInfo>
|
||||
</contact:chg>
|
||||
</contact:update>
|
||||
</update>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -32,8 +32,10 @@ import com.google.common.collect.ImmutableSet;
|
|||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
import google.registry.flows.domain.DomainApplicationUpdateFlow.ApplicationStatusProhibitsUpdateException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.ApplicationDomainNameMismatchException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.DuplicateContactForRoleException;
|
||||
|
@ -50,10 +52,8 @@ import google.registry.flows.domain.DomainFlowUtils.SecDnsAllUsageException;
|
|||
import google.registry.flows.domain.DomainFlowUtils.TooManyDsRecordsException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.TooManyNameserversException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.UrgentAttributeNotSupportedException;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
|
@ -587,7 +587,7 @@ public class DomainApplicationUpdateFlowTest
|
|||
.setNameservers(ImmutableSet.of(Key.create(
|
||||
loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc()))))
|
||||
.build());
|
||||
thrown.expect(AddRemoveSameValueEppException.class);
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
|
@ -601,7 +601,7 @@ public class DomainApplicationUpdateFlowTest
|
|||
Key.create(
|
||||
loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc())))))
|
||||
.build());
|
||||
thrown.expect(AddRemoveSameValueEppException.class);
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,10 @@ import com.googlecode.objectify.Key;
|
|||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.DuplicateContactForRoleException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.EmptySecDnsUpdateException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException;
|
||||
|
@ -64,11 +66,9 @@ import google.registry.flows.domain.DomainFlowUtils.SecDnsAllUsageException;
|
|||
import google.registry.flows.domain.DomainFlowUtils.TooManyDsRecordsException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.TooManyNameserversException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.UrgentAttributeNotSupportedException;
|
||||
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
|
||||
import google.registry.flows.exceptions.OnlyToolCanPassMetadataException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
|
@ -1003,7 +1003,7 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
|
|||
.setNameservers(ImmutableSet.of(Key.create(
|
||||
loadByForeignKey(HostResource.class, "ns1.example.foo", clock.nowUtc()))))
|
||||
.build());
|
||||
thrown.expect(AddRemoveSameValueEppException.class);
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
|
@ -1018,7 +1018,7 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
|
|||
Key.create(
|
||||
loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc())))))
|
||||
.build());
|
||||
thrown.expect(AddRemoveSameValueEppException.class);
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package google.registry.flows.host;
|
||||
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.flows.async.RefreshDnsOnHostRenameAction.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
|
@ -41,11 +42,12 @@ import com.google.common.net.InetAddresses;
|
|||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
||||
import google.registry.flows.exceptions.StatusNotClientSettableException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
|
@ -69,14 +71,14 @@ import org.junit.Test;
|
|||
public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResource> {
|
||||
|
||||
private void setEppHostUpdateInput(
|
||||
String oldHostName, String newHostName, String addHostAddrs, String remHostAddrs) {
|
||||
String oldHostName, String newHostName, String ipOrStatusToAdd, String ipOrStatusToRem) {
|
||||
setEppInput(
|
||||
"host_update.xml",
|
||||
ImmutableMap.of(
|
||||
"OLD-HOSTNAME", oldHostName,
|
||||
"NEW-HOSTNAME", newHostName,
|
||||
"ADD-HOSTADDRS", (addHostAddrs == null) ? "" : addHostAddrs,
|
||||
"REM-HOSTADDRS", (remHostAddrs == null) ? "" : remHostAddrs));
|
||||
"ADD-HOSTADDRSORSTATUS", nullToEmpty(ipOrStatusToAdd),
|
||||
"REM-HOSTADDRSORSTATUS", nullToEmpty(ipOrStatusToRem)));
|
||||
}
|
||||
|
||||
public HostUpdateFlowTest() {
|
||||
|
@ -793,6 +795,34 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
|
|||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_addRemoveSameStatusValues() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld",
|
||||
"ns2.example.tld",
|
||||
"<host:status s=\"clientUpdateProhibited\"/>",
|
||||
"<host:status s=\"clientUpdateProhibited\"/>");
|
||||
persistActiveHost(oldHostName());
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_addRemoveSameInetAddresses() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld",
|
||||
"ns2.example.tld",
|
||||
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
|
||||
"<host:addr ip=\"v4\">192.0.2.22</host:addr>");
|
||||
persistActiveHost(oldHostName());
|
||||
thrown.expect(AddRemoveSameValueException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientProhibitedStatusValue() throws Exception {
|
||||
createTld("tld");
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
xmlns:host="urn:ietf:params:xml:ns:host-1.0">
|
||||
<host:name>%OLD-HOSTNAME%</host:name>
|
||||
<host:add>
|
||||
%ADD-HOSTADDRS%
|
||||
%ADD-HOSTADDRSORSTATUS%
|
||||
<host:status s="clientUpdateProhibited"/>
|
||||
</host:add>
|
||||
<host:rem>
|
||||
%REM-HOSTADDRS%
|
||||
%REM-HOSTADDRSORSTATUS%
|
||||
</host:rem>
|
||||
<host:chg>
|
||||
<host:name>%NEW-HOSTNAME%</host:name>
|
||||
|
|
|
@ -16,14 +16,10 @@ package google.registry.model.contact;
|
|||
|
||||
import static google.registry.flows.EppXmlTransformer.marshalInput;
|
||||
import static google.registry.flows.EppXmlTransformer.validateInput;
|
||||
import static google.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.xml.ValidationMode.LENIENT;
|
||||
import static google.registry.xml.XmlTestUtils.assertXmlEquals;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.EppLoader;
|
||||
import org.junit.Rule;
|
||||
|
@ -103,75 +99,4 @@ public class ContactCommandTest {
|
|||
public void testTransferRequest() throws Exception {
|
||||
doXmlRoundtripTest("contact_transfer_request.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostalInfoOverlay() {
|
||||
createTld("foo");
|
||||
|
||||
ContactResource contact = new ContactResource.Builder()
|
||||
.setLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("loc name")
|
||||
.build())
|
||||
.setInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("int name")
|
||||
.build())
|
||||
.build();
|
||||
ContactCommand.Update.Change change = new ContactCommand.Update.Change();
|
||||
|
||||
// Updating one field of the loc should delete the int and leave the loc otherwise untouched.
|
||||
change.postalInfo = ImmutableList.of(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setOrg("org")
|
||||
.build());
|
||||
ContactResource.Builder builder = contact.asBuilder();
|
||||
change.applyTo(builder);
|
||||
ContactResource changed = builder.build();
|
||||
assertAboutContacts().that(changed)
|
||||
.hasNullInternationalizedPostalInfo().and()
|
||||
.hasLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("loc name")
|
||||
.setOrg("org")
|
||||
.build());
|
||||
|
||||
// Updating one field of the int should delete the loc and leave the int otherwise untouched.
|
||||
change.postalInfo = ImmutableList.of(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setOrg("org")
|
||||
.build());
|
||||
builder = contact.asBuilder();
|
||||
change.applyTo(builder);
|
||||
changed = builder.build();
|
||||
assertAboutContacts().that(changed)
|
||||
.hasNullLocalizedPostalInfo().and()
|
||||
.hasInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("int name")
|
||||
.setOrg("org")
|
||||
.build());
|
||||
|
||||
// Updating one field of the int and touching the loc with no changes should preserve both.
|
||||
change.postalInfo = ImmutableList.of(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("new int name")
|
||||
.build(),
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.build());
|
||||
builder = contact.asBuilder();
|
||||
change.applyTo(builder);
|
||||
changed = builder.build();
|
||||
assertAboutContacts().that(changed)
|
||||
.hasLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("loc name")
|
||||
.build()).and()
|
||||
.hasInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("new int name")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue