mirror of
https://github.com/google/nomulus.git
synced 2025-05-22 04:09:46 +02:00
Refactor ContactResource into ContactBase and create ContactHistory (#634)
* Create ContactHistory class + table This is similar to #587, but with contacts instead of hosts. This also includes a couple cleanups for HostHistoryTest and RegistryLockDaoTest, just making code more proper (we shouldn't be referencing constant revision IDs when using a sequence that is used by multiple classes, and RLDT can extend EntityTest) Note as well that we set ContactHistory to use the same revision ID sequence as HostHistory. * Move ContactResource -> ContactBase * Alter ContactBase and ContactResource
This commit is contained in:
parent
bd77edb491
commit
43230eee09
14 changed files with 908 additions and 365 deletions
|
@ -0,0 +1,398 @@
|
||||||
|
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package google.registry.model.contact;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||||
|
import static google.registry.model.EppResourceUtils.projectResourceOntoBuilderAtTime;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.googlecode.objectify.Key;
|
||||||
|
import com.googlecode.objectify.annotation.IgnoreSave;
|
||||||
|
import com.googlecode.objectify.annotation.Index;
|
||||||
|
import com.googlecode.objectify.condition.IfNull;
|
||||||
|
import google.registry.model.EppResource;
|
||||||
|
import google.registry.model.EppResource.ResourceWithTransferData;
|
||||||
|
import google.registry.model.transfer.ContactTransferData;
|
||||||
|
import google.registry.persistence.VKey;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
|
import javax.persistence.AttributeOverride;
|
||||||
|
import javax.persistence.AttributeOverrides;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A persistable contact resource including mutable and non-mutable fields.
|
||||||
|
*
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc5733">RFC 5733</a>
|
||||||
|
* <p>This class deliberately does not include an {@link javax.persistence.Id} so that any
|
||||||
|
* foreign-keyed fields can refer to the proper parent entity's ID, whether we're storing this
|
||||||
|
* in the DB itself or as part of another entity
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
@Embeddable
|
||||||
|
@Access(AccessType.FIELD)
|
||||||
|
public class ContactBase extends EppResource implements ResourceWithTransferData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier for this contact.
|
||||||
|
*
|
||||||
|
* <p>This is only unique in the sense that for any given lifetime specified as the time range
|
||||||
|
* from (creationTime, deletionTime) there can only be one contact in Datastore with this id.
|
||||||
|
* However, there can be many contacts with the same id and non-overlapping lifetimes.
|
||||||
|
*/
|
||||||
|
String contactId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Localized postal info for the contact. All contained values must be representable in the 7-bit
|
||||||
|
* US-ASCII character set. Personal info; cleared by {@link ContactResource.Builder#wipeOut}.
|
||||||
|
*/
|
||||||
|
@IgnoreSave(IfNull.class)
|
||||||
|
@Embedded
|
||||||
|
@AttributeOverrides({
|
||||||
|
@AttributeOverride(name = "name", column = @Column(name = "addr_local_name")),
|
||||||
|
@AttributeOverride(name = "org", column = @Column(name = "addr_local_org")),
|
||||||
|
@AttributeOverride(name = "type", column = @Column(name = "addr_local_type")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.streetLine1",
|
||||||
|
column = @Column(name = "addr_local_street_line1")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.streetLine2",
|
||||||
|
column = @Column(name = "addr_local_street_line2")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.streetLine3",
|
||||||
|
column = @Column(name = "addr_local_street_line3")),
|
||||||
|
@AttributeOverride(name = "address.city", column = @Column(name = "addr_local_city")),
|
||||||
|
@AttributeOverride(name = "address.state", column = @Column(name = "addr_local_state")),
|
||||||
|
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_local_zip")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.countryCode",
|
||||||
|
column = @Column(name = "addr_local_country_code"))
|
||||||
|
})
|
||||||
|
PostalInfo localizedPostalInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internationalized postal info for the contact. Personal info; cleared by {@link
|
||||||
|
* ContactResource.Builder#wipeOut}.
|
||||||
|
*/
|
||||||
|
@IgnoreSave(IfNull.class)
|
||||||
|
@Embedded
|
||||||
|
@AttributeOverrides({
|
||||||
|
@AttributeOverride(name = "name", column = @Column(name = "addr_i18n_name")),
|
||||||
|
@AttributeOverride(name = "org", column = @Column(name = "addr_i18n_org")),
|
||||||
|
@AttributeOverride(name = "type", column = @Column(name = "addr_i18n_type")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.streetLine1",
|
||||||
|
column = @Column(name = "addr_i18n_street_line1")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.streetLine2",
|
||||||
|
column = @Column(name = "addr_i18n_street_line2")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.streetLine3",
|
||||||
|
column = @Column(name = "addr_i18n_street_line3")),
|
||||||
|
@AttributeOverride(name = "address.city", column = @Column(name = "addr_i18n_city")),
|
||||||
|
@AttributeOverride(name = "address.state", column = @Column(name = "addr_i18n_state")),
|
||||||
|
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_i18n_zip")),
|
||||||
|
@AttributeOverride(
|
||||||
|
name = "address.countryCode",
|
||||||
|
column = @Column(name = "addr_i18n_country_code"))
|
||||||
|
})
|
||||||
|
PostalInfo internationalizedPostalInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact name used for name searches. This is set automatically to be the internationalized
|
||||||
|
* postal name, or if null, the localized postal name, or if that is null as well, null. Personal
|
||||||
|
* info; cleared by {@link ContactResource.Builder#wipeOut}.
|
||||||
|
*/
|
||||||
|
@Index String searchName;
|
||||||
|
|
||||||
|
/** Contact’s voice number. Personal info; cleared by {@link ContactResource.Builder#wipeOut}. */
|
||||||
|
@IgnoreSave(IfNull.class)
|
||||||
|
@Embedded
|
||||||
|
@AttributeOverrides({
|
||||||
|
@AttributeOverride(name = "phoneNumber", column = @Column(name = "voice_phone_number")),
|
||||||
|
@AttributeOverride(name = "extension", column = @Column(name = "voice_phone_extension")),
|
||||||
|
})
|
||||||
|
ContactPhoneNumber voice;
|
||||||
|
|
||||||
|
/** Contact’s fax number. Personal info; cleared by {@link ContactResource.Builder#wipeOut}. */
|
||||||
|
@IgnoreSave(IfNull.class)
|
||||||
|
@Embedded
|
||||||
|
@AttributeOverrides({
|
||||||
|
@AttributeOverride(name = "phoneNumber", column = @Column(name = "fax_phone_number")),
|
||||||
|
@AttributeOverride(name = "extension", column = @Column(name = "fax_phone_extension")),
|
||||||
|
})
|
||||||
|
ContactPhoneNumber fax;
|
||||||
|
|
||||||
|
/** Contact’s email address. Personal info; cleared by {@link ContactResource.Builder#wipeOut}. */
|
||||||
|
@IgnoreSave(IfNull.class)
|
||||||
|
String email;
|
||||||
|
|
||||||
|
/** Authorization info (aka transfer secret) of the contact. */
|
||||||
|
@Embedded
|
||||||
|
@AttributeOverrides({
|
||||||
|
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
|
||||||
|
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
|
||||||
|
})
|
||||||
|
ContactAuthInfo authInfo;
|
||||||
|
|
||||||
|
/** Data about any pending or past transfers on this contact. */
|
||||||
|
ContactTransferData transferData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time that this resource was last transferred.
|
||||||
|
*
|
||||||
|
* <p>Can be null if the resource has never been transferred.
|
||||||
|
*/
|
||||||
|
DateTime lastTransferTime;
|
||||||
|
|
||||||
|
// If any new fields are added which contain personal information, make sure they are cleared by
|
||||||
|
// the wipeOut() function, so that data is not kept around for deleted contacts.
|
||||||
|
|
||||||
|
/** Disclosure policy. */
|
||||||
|
@Embedded
|
||||||
|
@AttributeOverrides({
|
||||||
|
@AttributeOverride(name = "name", column = @Column(name = "disclose_types_name")),
|
||||||
|
@AttributeOverride(name = "org", column = @Column(name = "disclose_types_org")),
|
||||||
|
@AttributeOverride(name = "addr", column = @Column(name = "disclose_types_addr")),
|
||||||
|
@AttributeOverride(name = "flag", column = @Column(name = "disclose_mode_flag")),
|
||||||
|
@AttributeOverride(name = "voice.marked", column = @Column(name = "disclose_show_voice")),
|
||||||
|
@AttributeOverride(name = "fax.marked", column = @Column(name = "disclose_show_fax")),
|
||||||
|
@AttributeOverride(name = "email.marked", column = @Column(name = "disclose_show_email"))
|
||||||
|
})
|
||||||
|
Disclose disclose;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VKey<? extends ContactBase> createVKey() {
|
||||||
|
// TODO(mmuller): create symmetric keys if we can ever reload both sides.
|
||||||
|
return VKey.create(ContactBase.class, getRepoId(), Key.create(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostalInfo getLocalizedPostalInfo() {
|
||||||
|
return localizedPostalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostalInfo getInternationalizedPostalInfo() {
|
||||||
|
return internationalizedPostalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSearchName() {
|
||||||
|
return searchName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactPhoneNumber getVoiceNumber() {
|
||||||
|
return voice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactPhoneNumber getFaxNumber() {
|
||||||
|
return fax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmailAddress() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactAuthInfo getAuthInfo() {
|
||||||
|
return authInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Disclose getDisclose() {
|
||||||
|
return disclose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getCurrentSponsorClientId() {
|
||||||
|
return getPersistedCurrentSponsorClientId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ContactTransferData getTransferData() {
|
||||||
|
return Optional.ofNullable(transferData).orElse(ContactTransferData.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DateTime getLastTransferTime() {
|
||||||
|
return lastTransferTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getForeignKey() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Postal info for the contact.
|
||||||
|
*
|
||||||
|
* <p>The XML marshalling expects the {@link PostalInfo} objects in a list, but we can't actually
|
||||||
|
* persist them to Datastore that way because Objectify can't handle collections of embedded
|
||||||
|
* objects that themselves contain collections, and there's a list of streets inside. This method
|
||||||
|
* transforms the persisted format to the XML format for marshalling.
|
||||||
|
*/
|
||||||
|
@XmlElement(name = "postalInfo")
|
||||||
|
public ImmutableList<PostalInfo> getPostalInfosAsList() {
|
||||||
|
return Stream.of(localizedPostalInfo, internationalizedPostalInfo)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(toImmutableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContactBase cloneProjectedAtTime(DateTime now) {
|
||||||
|
return cloneContactProjectedAtTime(this, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the contact (or subclass). A separate static method so that we can pass in and return a
|
||||||
|
* T without the compiler complaining.
|
||||||
|
*/
|
||||||
|
protected static <T extends ContactBase> T cloneContactProjectedAtTime(T contact, DateTime now) {
|
||||||
|
Builder builder = contact.asBuilder();
|
||||||
|
projectResourceOntoBuilderAtTime(contact, builder, now);
|
||||||
|
return (T) builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder asBuilder() {
|
||||||
|
return new Builder<>(clone(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A builder for constructing {@link ContactResource}, since it is immutable. */
|
||||||
|
public static class Builder<T extends ContactBase, B extends Builder<T, B>>
|
||||||
|
extends EppResource.Builder<T, B> implements BuilderWithTransferData<ContactTransferData, B> {
|
||||||
|
|
||||||
|
public Builder() {}
|
||||||
|
|
||||||
|
protected Builder(T instance) {
|
||||||
|
super(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setContactId(String contactId) {
|
||||||
|
getInstance().contactId = contactId;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
||||||
|
checkArgument(
|
||||||
|
localizedPostalInfo == null
|
||||||
|
|| PostalInfo.Type.LOCALIZED.equals(localizedPostalInfo.getType()));
|
||||||
|
getInstance().localizedPostalInfo = localizedPostalInfo;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
||||||
|
checkArgument(
|
||||||
|
internationalizedPostalInfo == null
|
||||||
|
|| PostalInfo.Type.INTERNATIONALIZED.equals(internationalizedPostalInfo.getType()));
|
||||||
|
getInstance().internationalizedPostalInfo = internationalizedPostalInfo;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B overlayLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
||||||
|
return setLocalizedPostalInfo(
|
||||||
|
getInstance().localizedPostalInfo == null
|
||||||
|
? localizedPostalInfo
|
||||||
|
: getInstance().localizedPostalInfo.overlay(localizedPostalInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public B overlayInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
||||||
|
return setInternationalizedPostalInfo(
|
||||||
|
getInstance().internationalizedPostalInfo == null
|
||||||
|
? internationalizedPostalInfo
|
||||||
|
: getInstance().internationalizedPostalInfo.overlay(internationalizedPostalInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setVoiceNumber(ContactPhoneNumber voiceNumber) {
|
||||||
|
getInstance().voice = voiceNumber;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setFaxNumber(ContactPhoneNumber faxNumber) {
|
||||||
|
getInstance().fax = faxNumber;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setEmailAddress(String emailAddress) {
|
||||||
|
getInstance().email = emailAddress;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setAuthInfo(ContactAuthInfo authInfo) {
|
||||||
|
getInstance().authInfo = authInfo;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B setDisclose(Disclose disclose) {
|
||||||
|
getInstance().disclose = disclose;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public B setTransferData(ContactTransferData transferData) {
|
||||||
|
getInstance().transferData = transferData;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public B setLastTransferTime(DateTime lastTransferTime) {
|
||||||
|
getInstance().lastTransferTime = lastTransferTime;
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all personally identifying information about a contact.
|
||||||
|
*
|
||||||
|
* <p>This should be used when deleting a contact so that the soft-deleted entity doesn't
|
||||||
|
* contain information that the registrant requested to be deleted.
|
||||||
|
*/
|
||||||
|
public B wipeOut() {
|
||||||
|
setEmailAddress(null);
|
||||||
|
setFaxNumber(null);
|
||||||
|
setInternationalizedPostalInfo(null);
|
||||||
|
setLocalizedPostalInfo(null);
|
||||||
|
setVoiceNumber(null);
|
||||||
|
return thisCastToDerived();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T build() {
|
||||||
|
T instance = getInstance();
|
||||||
|
// If TransferData is totally empty, set it to null.
|
||||||
|
if (ContactTransferData.EMPTY.equals(instance.transferData)) {
|
||||||
|
setTransferData(null);
|
||||||
|
}
|
||||||
|
// Set the searchName using the internationalized and localized postal info names.
|
||||||
|
if ((instance.internationalizedPostalInfo != null)
|
||||||
|
&& (instance.internationalizedPostalInfo.getName() != null)) {
|
||||||
|
instance.searchName = instance.internationalizedPostalInfo.getName();
|
||||||
|
} else if ((instance.localizedPostalInfo != null)
|
||||||
|
&& (instance.localizedPostalInfo.getName() != null)) {
|
||||||
|
instance.searchName = instance.localizedPostalInfo.getName();
|
||||||
|
} else {
|
||||||
|
instance.searchName = null;
|
||||||
|
}
|
||||||
|
return super.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package google.registry.model.contact;
|
||||||
|
|
||||||
|
import com.googlecode.objectify.Key;
|
||||||
|
import google.registry.model.EppResource;
|
||||||
|
import google.registry.model.reporting.HistoryEntry;
|
||||||
|
import google.registry.persistence.VKey;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A persisted history entry representing an EPP modification to a contact.
|
||||||
|
*
|
||||||
|
* <p>In addition to the general history fields (e.g. action time, registrar ID) we also persist a
|
||||||
|
* copy of the host entity at this point in time. We persist a raw {@link ContactBase} so that the
|
||||||
|
* foreign-keyed fields in that class can refer to this object.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@javax.persistence.Table(
|
||||||
|
indexes = {
|
||||||
|
@javax.persistence.Index(columnList = "creationTime"),
|
||||||
|
@javax.persistence.Index(columnList = "historyRegistrarId"),
|
||||||
|
@javax.persistence.Index(columnList = "historyType"),
|
||||||
|
@javax.persistence.Index(columnList = "historyModificationTime")
|
||||||
|
})
|
||||||
|
public class ContactHistory extends HistoryEntry {
|
||||||
|
// Store ContactBase instead of ContactResource so we don't pick up its @Id
|
||||||
|
ContactBase contactBase;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
VKey<ContactResource> contactRepoId;
|
||||||
|
|
||||||
|
/** The state of the {@link ContactBase} object at this point in time. */
|
||||||
|
public ContactBase getContactBase() {
|
||||||
|
return contactBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The key to the {@link ContactResource} this is based off of. */
|
||||||
|
public VKey<ContactResource> getContactRepoId() {
|
||||||
|
return contactRepoId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder asBuilder() {
|
||||||
|
return new Builder(clone(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends HistoryEntry.Builder<ContactHistory, ContactHistory.Builder> {
|
||||||
|
|
||||||
|
public Builder() {}
|
||||||
|
|
||||||
|
public Builder(ContactHistory instance) {
|
||||||
|
super(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setContactBase(ContactBase contactBase) {
|
||||||
|
getInstance().contactBase = contactBase;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setContactRepoId(VKey<ContactResource> contactRepoId) {
|
||||||
|
getInstance().contactRepoId = contactRepoId;
|
||||||
|
contactRepoId.maybeGetOfyKey().ifPresent(parent -> getInstance().parent = parent);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can remove this once all HistoryEntries are converted to History objects
|
||||||
|
@Override
|
||||||
|
public Builder setParent(Key<? extends EppResource> parent) {
|
||||||
|
super.setParent(parent);
|
||||||
|
getInstance().contactRepoId = VKey.create(ContactResource.class, parent.getName(), parent);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,36 +14,16 @@
|
||||||
|
|
||||||
package google.registry.model.contact;
|
package google.registry.model.contact;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
|
||||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
|
||||||
import static google.registry.model.EppResourceUtils.projectResourceOntoBuilderAtTime;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
import com.googlecode.objectify.annotation.Entity;
|
||||||
import com.googlecode.objectify.annotation.IgnoreSave;
|
|
||||||
import com.googlecode.objectify.annotation.Index;
|
|
||||||
import com.googlecode.objectify.condition.IfNull;
|
|
||||||
import google.registry.model.EppResource;
|
|
||||||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||||
import google.registry.model.EppResource.ResourceWithTransferData;
|
|
||||||
import google.registry.model.annotations.ExternalMessagingName;
|
import google.registry.model.annotations.ExternalMessagingName;
|
||||||
import google.registry.model.annotations.ReportedOn;
|
import google.registry.model.annotations.ReportedOn;
|
||||||
import google.registry.model.contact.PostalInfo.Type;
|
|
||||||
import google.registry.model.transfer.ContactTransferData;
|
|
||||||
import google.registry.persistence.VKey;
|
import google.registry.persistence.VKey;
|
||||||
import google.registry.persistence.WithStringVKey;
|
import google.registry.persistence.WithStringVKey;
|
||||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import javax.persistence.Access;
|
import javax.persistence.Access;
|
||||||
import javax.persistence.AccessType;
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.AttributeOverride;
|
|
||||||
import javax.persistence.AttributeOverrides;
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Embedded;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,149 +37,21 @@ import org.joda.time.DateTime;
|
||||||
@javax.persistence.Table(
|
@javax.persistence.Table(
|
||||||
name = "Contact",
|
name = "Contact",
|
||||||
indexes = {
|
indexes = {
|
||||||
@javax.persistence.Index(columnList = "creationTime"),
|
@javax.persistence.Index(columnList = "creationTime"),
|
||||||
@javax.persistence.Index(columnList = "currentSponsorRegistrarId"),
|
@javax.persistence.Index(columnList = "currentSponsorRegistrarId"),
|
||||||
@javax.persistence.Index(columnList = "deletionTime"),
|
@javax.persistence.Index(columnList = "deletionTime"),
|
||||||
@javax.persistence.Index(columnList = "contactId", unique = true),
|
@javax.persistence.Index(columnList = "contactId", unique = true),
|
||||||
@javax.persistence.Index(columnList = "searchName")
|
@javax.persistence.Index(columnList = "searchName")
|
||||||
})
|
})
|
||||||
@ExternalMessagingName("contact")
|
@ExternalMessagingName("contact")
|
||||||
@WithStringVKey
|
@WithStringVKey
|
||||||
@Access(AccessType.FIELD)
|
@Access(AccessType.FIELD)
|
||||||
public class ContactResource extends EppResource
|
public class ContactResource extends ContactBase
|
||||||
implements DatastoreAndSqlEntity, ForeignKeyedEppResource, ResourceWithTransferData {
|
implements DatastoreAndSqlEntity, ForeignKeyedEppResource {
|
||||||
|
|
||||||
/**
|
|
||||||
* Unique identifier for this contact.
|
|
||||||
*
|
|
||||||
* <p>This is only unique in the sense that for any given lifetime specified as the time range
|
|
||||||
* from (creationTime, deletionTime) there can only be one contact in Datastore with this id.
|
|
||||||
* However, there can be many contacts with the same id and non-overlapping lifetimes.
|
|
||||||
*/
|
|
||||||
String contactId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Localized postal info for the contact. All contained values must be representable in the 7-bit
|
|
||||||
* US-ASCII character set. Personal info; cleared by {@link Builder#wipeOut}.
|
|
||||||
*/
|
|
||||||
@IgnoreSave(IfNull.class)
|
|
||||||
@Embedded
|
|
||||||
@AttributeOverrides({
|
|
||||||
@AttributeOverride(name = "name", column = @Column(name = "addr_local_name")),
|
|
||||||
@AttributeOverride(name = "org", column = @Column(name = "addr_local_org")),
|
|
||||||
@AttributeOverride(name = "type", column = @Column(name = "addr_local_type")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.streetLine1",
|
|
||||||
column = @Column(name = "addr_local_street_line1")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.streetLine2",
|
|
||||||
column = @Column(name = "addr_local_street_line2")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.streetLine3",
|
|
||||||
column = @Column(name = "addr_local_street_line3")),
|
|
||||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_local_city")),
|
|
||||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_local_state")),
|
|
||||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_local_zip")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.countryCode",
|
|
||||||
column = @Column(name = "addr_local_country_code"))
|
|
||||||
})
|
|
||||||
PostalInfo localizedPostalInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internationalized postal info for the contact. Personal info; cleared by {@link
|
|
||||||
* Builder#wipeOut}.
|
|
||||||
*/
|
|
||||||
@IgnoreSave(IfNull.class)
|
|
||||||
@Embedded
|
|
||||||
@AttributeOverrides({
|
|
||||||
@AttributeOverride(name = "name", column = @Column(name = "addr_i18n_name")),
|
|
||||||
@AttributeOverride(name = "org", column = @Column(name = "addr_i18n_org")),
|
|
||||||
@AttributeOverride(name = "type", column = @Column(name = "addr_i18n_type")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.streetLine1",
|
|
||||||
column = @Column(name = "addr_i18n_street_line1")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.streetLine2",
|
|
||||||
column = @Column(name = "addr_i18n_street_line2")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.streetLine3",
|
|
||||||
column = @Column(name = "addr_i18n_street_line3")),
|
|
||||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_i18n_city")),
|
|
||||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_i18n_state")),
|
|
||||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_i18n_zip")),
|
|
||||||
@AttributeOverride(
|
|
||||||
name = "address.countryCode",
|
|
||||||
column = @Column(name = "addr_i18n_country_code"))
|
|
||||||
})
|
|
||||||
PostalInfo internationalizedPostalInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contact name used for name searches. This is set automatically to be the internationalized
|
|
||||||
* postal name, or if null, the localized postal name, or if that is null as well, null. Personal
|
|
||||||
* info; cleared by {@link Builder#wipeOut}.
|
|
||||||
*/
|
|
||||||
@Index
|
|
||||||
String searchName;
|
|
||||||
|
|
||||||
/** Contact’s voice number. Personal info; cleared by {@link Builder#wipeOut}. */
|
|
||||||
@IgnoreSave(IfNull.class)
|
|
||||||
@Embedded
|
|
||||||
@AttributeOverrides({
|
|
||||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "voice_phone_number")),
|
|
||||||
@AttributeOverride(name = "extension", column = @Column(name = "voice_phone_extension")),
|
|
||||||
})
|
|
||||||
ContactPhoneNumber voice;
|
|
||||||
|
|
||||||
/** Contact’s fax number. Personal info; cleared by {@link Builder#wipeOut}. */
|
|
||||||
@IgnoreSave(IfNull.class)
|
|
||||||
@Embedded
|
|
||||||
@AttributeOverrides({
|
|
||||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "fax_phone_number")),
|
|
||||||
@AttributeOverride(name = "extension", column = @Column(name = "fax_phone_extension")),
|
|
||||||
})
|
|
||||||
ContactPhoneNumber fax;
|
|
||||||
|
|
||||||
/** Contact’s email address. Personal info; cleared by {@link Builder#wipeOut}. */
|
|
||||||
@IgnoreSave(IfNull.class)
|
|
||||||
String email;
|
|
||||||
|
|
||||||
/** Authorization info (aka transfer secret) of the contact. */
|
|
||||||
@Embedded
|
|
||||||
@AttributeOverrides({
|
|
||||||
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
|
|
||||||
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
|
|
||||||
})
|
|
||||||
ContactAuthInfo authInfo;
|
|
||||||
|
|
||||||
/** Data about any pending or past transfers on this contact. */
|
|
||||||
ContactTransferData transferData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time that this resource was last transferred.
|
|
||||||
*
|
|
||||||
* <p>Can be null if the resource has never been transferred.
|
|
||||||
*/
|
|
||||||
DateTime lastTransferTime;
|
|
||||||
|
|
||||||
// If any new fields are added which contain personal information, make sure they are cleared by
|
|
||||||
// the wipeOut() function, so that data is not kept around for deleted contacts.
|
|
||||||
|
|
||||||
/** Disclosure policy. */
|
|
||||||
@Embedded
|
|
||||||
@AttributeOverrides({
|
|
||||||
@AttributeOverride(name = "name", column = @Column(name = "disclose_types_name")),
|
|
||||||
@AttributeOverride(name = "org", column = @Column(name = "disclose_types_org")),
|
|
||||||
@AttributeOverride(name = "addr", column = @Column(name = "disclose_types_addr")),
|
|
||||||
@AttributeOverride(name = "flag", column = @Column(name = "disclose_mode_flag")),
|
|
||||||
@AttributeOverride(name = "voice.marked", column = @Column(name = "disclose_show_voice")),
|
|
||||||
@AttributeOverride(name = "fax.marked", column = @Column(name = "disclose_show_fax")),
|
|
||||||
@AttributeOverride(name = "email.marked", column = @Column(name = "disclose_show_email"))
|
|
||||||
})
|
|
||||||
Disclose disclose;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VKey<ContactResource> createVKey() {
|
public VKey<ContactResource> createVKey() {
|
||||||
|
// TODO(mmuller): create symmetric keys if we can ever reload both sides.
|
||||||
return VKey.create(ContactResource.class, getRepoId(), Key.create(this));
|
return VKey.create(ContactResource.class, getRepoId(), Key.create(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,81 +62,9 @@ public class ContactResource extends EppResource
|
||||||
return super.getRepoId();
|
return super.getRepoId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContactId() {
|
|
||||||
return contactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PostalInfo getLocalizedPostalInfo() {
|
|
||||||
return localizedPostalInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PostalInfo getInternationalizedPostalInfo() {
|
|
||||||
return internationalizedPostalInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSearchName() {
|
|
||||||
return searchName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactPhoneNumber getVoiceNumber() {
|
|
||||||
return voice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactPhoneNumber getFaxNumber() {
|
|
||||||
return fax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEmailAddress() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactAuthInfo getAuthInfo() {
|
|
||||||
return authInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Disclose getDisclose() {
|
|
||||||
return disclose;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getCurrentSponsorClientId() {
|
|
||||||
return getPersistedCurrentSponsorClientId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContactTransferData getTransferData() {
|
|
||||||
return Optional.ofNullable(transferData).orElse(ContactTransferData.EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DateTime getLastTransferTime() {
|
|
||||||
return lastTransferTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getForeignKey() {
|
|
||||||
return contactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Postal info for the contact.
|
|
||||||
*
|
|
||||||
* <p>The XML marshalling expects the {@link PostalInfo} objects in a list, but we can't actually
|
|
||||||
* persist them to Datastore that way because Objectify can't handle collections of embedded
|
|
||||||
* objects that themselves contain collections, and there's a list of streets inside. This method
|
|
||||||
* transforms the persisted format to the XML format for marshalling.
|
|
||||||
*/
|
|
||||||
@XmlElement(name = "postalInfo")
|
|
||||||
public ImmutableList<PostalInfo> getPostalInfosAsList() {
|
|
||||||
return Stream.of(localizedPostalInfo, internationalizedPostalInfo)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(toImmutableList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContactResource cloneProjectedAtTime(DateTime now) {
|
public ContactResource cloneProjectedAtTime(DateTime now) {
|
||||||
Builder builder = this.asBuilder();
|
return ContactBase.cloneContactProjectedAtTime(this, now);
|
||||||
projectResourceOntoBuilderAtTime(this, builder, now);
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,116 +73,12 @@ public class ContactResource extends EppResource
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A builder for constructing {@link ContactResource}, since it is immutable. */
|
/** A builder for constructing {@link ContactResource}, since it is immutable. */
|
||||||
public static class Builder extends EppResource.Builder<ContactResource, Builder>
|
public static class Builder extends ContactBase.Builder<ContactResource, Builder> {
|
||||||
implements BuilderWithTransferData<ContactTransferData, Builder> {
|
|
||||||
|
|
||||||
public Builder() {}
|
public Builder() {}
|
||||||
|
|
||||||
private Builder(ContactResource instance) {
|
private Builder(ContactResource instance) {
|
||||||
super(instance);
|
super(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setContactId(String contactId) {
|
|
||||||
getInstance().contactId = contactId;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
|
||||||
checkArgument(localizedPostalInfo == null
|
|
||||||
|| Type.LOCALIZED.equals(localizedPostalInfo.getType()));
|
|
||||||
getInstance().localizedPostalInfo = localizedPostalInfo;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
|
||||||
checkArgument(internationalizedPostalInfo == null
|
|
||||||
|| Type.INTERNATIONALIZED.equals(internationalizedPostalInfo.getType()));
|
|
||||||
getInstance().internationalizedPostalInfo = internationalizedPostalInfo;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder overlayLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
|
||||||
return setLocalizedPostalInfo(getInstance().localizedPostalInfo == null
|
|
||||||
? localizedPostalInfo
|
|
||||||
: getInstance().localizedPostalInfo.overlay(localizedPostalInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder overlayInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
|
||||||
return setInternationalizedPostalInfo(getInstance().internationalizedPostalInfo == null
|
|
||||||
? internationalizedPostalInfo
|
|
||||||
: getInstance().internationalizedPostalInfo.overlay(internationalizedPostalInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setVoiceNumber(ContactPhoneNumber voiceNumber) {
|
|
||||||
getInstance().voice = voiceNumber;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setFaxNumber(ContactPhoneNumber faxNumber) {
|
|
||||||
getInstance().fax = faxNumber;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setEmailAddress(String emailAddress) {
|
|
||||||
getInstance().email = emailAddress;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setAuthInfo(ContactAuthInfo authInfo) {
|
|
||||||
getInstance().authInfo = authInfo;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setDisclose(Disclose disclose) {
|
|
||||||
getInstance().disclose = disclose;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder setTransferData(ContactTransferData transferData) {
|
|
||||||
getInstance().transferData = transferData;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder setLastTransferTime(DateTime lastTransferTime) {
|
|
||||||
getInstance().lastTransferTime = lastTransferTime;
|
|
||||||
return thisCastToDerived();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all personally identifying information about a contact.
|
|
||||||
*
|
|
||||||
* <p>This should be used when deleting a contact so that the soft-deleted entity doesn't
|
|
||||||
* contain information that the registrant requested to be deleted.
|
|
||||||
*/
|
|
||||||
public Builder wipeOut() {
|
|
||||||
setEmailAddress(null);
|
|
||||||
setFaxNumber(null);
|
|
||||||
setInternationalizedPostalInfo(null);
|
|
||||||
setLocalizedPostalInfo(null);
|
|
||||||
setVoiceNumber(null);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContactResource build() {
|
|
||||||
ContactResource instance = getInstance();
|
|
||||||
// If TransferData is totally empty, set it to null.
|
|
||||||
if (ContactTransferData.EMPTY.equals(instance.transferData)) {
|
|
||||||
setTransferData(null);
|
|
||||||
}
|
|
||||||
// Set the searchName using the internationalized and localized postal info names.
|
|
||||||
if ((instance.internationalizedPostalInfo != null)
|
|
||||||
&& (instance.internationalizedPostalInfo.getName() != null)) {
|
|
||||||
instance.searchName = instance.internationalizedPostalInfo.getName();
|
|
||||||
} else if ((instance.localizedPostalInfo != null)
|
|
||||||
&& (instance.localizedPostalInfo.getName() != null)) {
|
|
||||||
instance.searchName = instance.localizedPostalInfo.getName();
|
|
||||||
} else {
|
|
||||||
instance.searchName = null;
|
|
||||||
}
|
|
||||||
return super.build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ public class HostBase extends EppResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VKey<? extends EppResource> createVKey() {
|
public VKey<? extends HostBase> createVKey() {
|
||||||
return VKey.create(HostBase.class, getRepoId(), Key.create(this));
|
return VKey.create(HostBase.class, getRepoId(), Key.create(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class HostHistory extends HistoryEntry {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setHostResourceId(VKey<HostResource> hostRepoId) {
|
public Builder setHostRepoId(VKey<HostResource> hostRepoId) {
|
||||||
getInstance().hostRepoId = hostRepoId;
|
getInstance().hostRepoId = hostRepoId;
|
||||||
hostRepoId.maybeGetOfyKey().ifPresent(parent -> getInstance().parent = parent);
|
hostRepoId.maybeGetOfyKey().ifPresent(parent -> getInstance().parent = parent);
|
||||||
return this;
|
return this;
|
||||||
|
@ -83,8 +83,7 @@ public class HostHistory extends HistoryEntry {
|
||||||
@Override
|
@Override
|
||||||
public Builder setParent(Key<? extends EppResource> parent) {
|
public Builder setParent(Key<? extends EppResource> parent) {
|
||||||
super.setParent(parent);
|
super.setParent(parent);
|
||||||
getInstance().hostRepoId =
|
getInstance().hostRepoId = VKey.create(HostResource.class, parent.getName(), parent);
|
||||||
VKey.create(HostResource.class, parent.getName(), (Key<HostResource>) parent);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,10 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
|
||||||
@Transient // domain-specific
|
@Transient // domain-specific
|
||||||
Set<DomainTransactionRecord> domainTransactionRecords;
|
Set<DomainTransactionRecord> domainTransactionRecords;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public Key<? extends EppResource> getParent() {
|
public Key<? extends EppResource> getParent() {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<class>google.registry.model.billing.BillingEvent$Cancellation</class>
|
<class>google.registry.model.billing.BillingEvent$Cancellation</class>
|
||||||
<class>google.registry.model.billing.BillingEvent$OneTime</class>
|
<class>google.registry.model.billing.BillingEvent$OneTime</class>
|
||||||
<class>google.registry.model.billing.BillingEvent$Recurring</class>
|
<class>google.registry.model.billing.BillingEvent$Recurring</class>
|
||||||
|
<class>google.registry.model.contact.ContactHistory</class>
|
||||||
<class>google.registry.model.contact.ContactResource</class>
|
<class>google.registry.model.contact.ContactResource</class>
|
||||||
<class>google.registry.model.domain.DomainBase</class>
|
<class>google.registry.model.domain.DomainBase</class>
|
||||||
<class>google.registry.model.host.HostHistory</class>
|
<class>google.registry.model.host.HostHistory</class>
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package google.registry.model.history;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||||
|
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
import google.registry.model.EntityTestCase;
|
||||||
|
import google.registry.model.contact.ContactHistory;
|
||||||
|
import google.registry.model.contact.ContactResource;
|
||||||
|
import google.registry.model.eppcommon.Trid;
|
||||||
|
import google.registry.model.reporting.HistoryEntry;
|
||||||
|
import google.registry.model.transfer.ContactTransferData;
|
||||||
|
import google.registry.persistence.VKey;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/** Tests for {@link ContactHistory}. */
|
||||||
|
public class ContactHistoryTest extends EntityTestCase {
|
||||||
|
|
||||||
|
public ContactHistoryTest() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistence() {
|
||||||
|
saveRegistrar("registrar1");
|
||||||
|
|
||||||
|
ContactResource contact =
|
||||||
|
new ContactResource.Builder()
|
||||||
|
.setRepoId("contact1")
|
||||||
|
.setContactId("contactId")
|
||||||
|
.setCreationClientId("registrar1")
|
||||||
|
.setPersistedCurrentSponsorClientId("registrar1")
|
||||||
|
.setTransferData(new ContactTransferData.Builder().build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
jpaTm().transact(() -> jpaTm().saveNew(contact));
|
||||||
|
VKey<ContactResource> contactVKey = VKey.createSql(ContactResource.class, "contact1");
|
||||||
|
ContactResource contactFromDb = jpaTm().transact(() -> jpaTm().load(contactVKey));
|
||||||
|
ContactHistory contactHistory =
|
||||||
|
new ContactHistory.Builder()
|
||||||
|
.setType(HistoryEntry.Type.HOST_CREATE)
|
||||||
|
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
|
||||||
|
.setModificationTime(fakeClock.nowUtc())
|
||||||
|
.setClientId("registrar1")
|
||||||
|
.setTrid(Trid.create("ABC-123", "server-trid"))
|
||||||
|
.setBySuperuser(false)
|
||||||
|
.setReason("reason")
|
||||||
|
.setRequestedByRegistrar(true)
|
||||||
|
.setContactBase(contactFromDb)
|
||||||
|
.setContactRepoId(contactVKey)
|
||||||
|
.build();
|
||||||
|
jpaTm().transact(() -> jpaTm().saveNew(contactHistory));
|
||||||
|
jpaTm()
|
||||||
|
.transact(
|
||||||
|
() -> {
|
||||||
|
ContactHistory fromDatabase = jpaTm().load(VKey.createSql(ContactHistory.class, 1L));
|
||||||
|
assertContactHistoriesEqual(fromDatabase, contactHistory);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertContactHistoriesEqual(ContactHistory one, ContactHistory two) {
|
||||||
|
// enough of the fields get changed during serialization that we can't depend on .equals()
|
||||||
|
assertThat(one.getClientId()).isEqualTo(two.getClientId());
|
||||||
|
assertThat(one.getContactRepoId()).isEqualTo(two.getContactRepoId());
|
||||||
|
assertThat(one.getBySuperuser()).isEqualTo(two.getBySuperuser());
|
||||||
|
assertThat(one.getRequestedByRegistrar()).isEqualTo(two.getRequestedByRegistrar());
|
||||||
|
assertThat(one.getReason()).isEqualTo(two.getReason());
|
||||||
|
assertThat(one.getTrid()).isEqualTo(two.getTrid());
|
||||||
|
assertThat(one.getType()).isEqualTo(two.getType());
|
||||||
|
assertThat(one.getContactBase().getContactId()).isEqualTo(two.getContactBase().getContactId());
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,13 +61,14 @@ public class HostHistoryTest extends EntityTestCase {
|
||||||
.setReason("reason")
|
.setReason("reason")
|
||||||
.setRequestedByRegistrar(true)
|
.setRequestedByRegistrar(true)
|
||||||
.setHostBase(hostFromDb)
|
.setHostBase(hostFromDb)
|
||||||
.setHostResourceId(hostVKey)
|
.setHostRepoId(hostVKey)
|
||||||
.build();
|
.build();
|
||||||
jpaTm().transact(() -> jpaTm().saveNew(hostHistory));
|
jpaTm().transact(() -> jpaTm().saveNew(hostHistory));
|
||||||
jpaTm()
|
jpaTm()
|
||||||
.transact(
|
.transact(
|
||||||
() -> {
|
() -> {
|
||||||
HostHistory fromDatabase = jpaTm().load(VKey.createSql(HostHistory.class, 1L));
|
HostHistory fromDatabase =
|
||||||
|
jpaTm().load(VKey.createSql(HostHistory.class, hostHistory.getId()));
|
||||||
assertHostHistoriesEqual(fromDatabase, hostHistory);
|
assertHostHistoriesEqual(fromDatabase, hostHistory);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,26 +26,18 @@ import static google.registry.testing.SqlHelper.getRegistryLocksByRegistrarId;
|
||||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
|
|
||||||
|
import google.registry.model.EntityTestCase;
|
||||||
import google.registry.schema.domain.RegistryLock;
|
import google.registry.schema.domain.RegistryLock;
|
||||||
import google.registry.testing.AppEngineRule;
|
|
||||||
import google.registry.testing.FakeClock;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
|
|
||||||
/** Unit tests for {@link RegistryLockDao}. */
|
/** Unit tests for {@link RegistryLockDao}. */
|
||||||
public final class RegistryLockDaoTest {
|
public final class RegistryLockDaoTest extends EntityTestCase {
|
||||||
|
|
||||||
private final FakeClock fakeClock = new FakeClock();
|
public RegistryLockDaoTest() {
|
||||||
|
super(true);
|
||||||
@RegisterExtension
|
}
|
||||||
public final AppEngineRule appEngine =
|
|
||||||
AppEngineRule.builder()
|
|
||||||
.withDatastoreAndCloudSql()
|
|
||||||
.enableJpaEntityCoverageCheck(true)
|
|
||||||
.withClock(fakeClock)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSaveAndLoad_success() {
|
public void testSaveAndLoad_success() {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assert_;
|
||||||
import google.registry.model.billing.BillingEventTest;
|
import google.registry.model.billing.BillingEventTest;
|
||||||
import google.registry.model.contact.ContactResourceTest;
|
import google.registry.model.contact.ContactResourceTest;
|
||||||
import google.registry.model.domain.DomainBaseSqlTest;
|
import google.registry.model.domain.DomainBaseSqlTest;
|
||||||
|
import google.registry.model.history.ContactHistoryTest;
|
||||||
import google.registry.model.history.HostHistoryTest;
|
import google.registry.model.history.HostHistoryTest;
|
||||||
import google.registry.model.poll.PollMessageTest;
|
import google.registry.model.poll.PollMessageTest;
|
||||||
import google.registry.model.registry.RegistryLockDaoTest;
|
import google.registry.model.registry.RegistryLockDaoTest;
|
||||||
|
@ -74,6 +75,7 @@ import org.junit.runner.RunWith;
|
||||||
BeforeSuiteTest.class,
|
BeforeSuiteTest.class,
|
||||||
BillingEventTest.class,
|
BillingEventTest.class,
|
||||||
ClaimsListDaoTest.class,
|
ClaimsListDaoTest.class,
|
||||||
|
ContactHistoryTest.class,
|
||||||
ContactResourceTest.class,
|
ContactResourceTest.class,
|
||||||
CursorDaoTest.class,
|
CursorDaoTest.class,
|
||||||
DomainBaseSqlTest.class,
|
DomainBaseSqlTest.class,
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
-- Copyright 2020 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.
|
||||||
|
|
||||||
|
CREATE TABLE "ContactHistory" (
|
||||||
|
history_revision_id int8 NOT NULL,
|
||||||
|
history_by_superuser boolean NOT NULL,
|
||||||
|
history_registrar_id text,
|
||||||
|
history_modification_time timestamptz NOT NULL,
|
||||||
|
history_reason text NOT NULL,
|
||||||
|
history_requested_by_registrar boolean NOT NULL,
|
||||||
|
history_client_transaction_id text,
|
||||||
|
history_server_transaction_id text,
|
||||||
|
history_type text NOT NULL,
|
||||||
|
history_xml_bytes bytea NOT NULL,
|
||||||
|
auth_info_repo_id text,
|
||||||
|
auth_info_value text,
|
||||||
|
contact_id text,
|
||||||
|
disclose_types_addr text[],
|
||||||
|
disclose_show_email boolean,
|
||||||
|
disclose_show_fax boolean,
|
||||||
|
disclose_mode_flag boolean,
|
||||||
|
disclose_types_name text[],
|
||||||
|
disclose_types_org text[],
|
||||||
|
disclose_show_voice boolean,
|
||||||
|
email text,
|
||||||
|
fax_phone_extension text,
|
||||||
|
fax_phone_number text,
|
||||||
|
addr_i18n_city text,
|
||||||
|
addr_i18n_country_code text,
|
||||||
|
addr_i18n_state text,
|
||||||
|
addr_i18n_street_line1 text,
|
||||||
|
addr_i18n_street_line2 text,
|
||||||
|
addr_i18n_street_line3 text,
|
||||||
|
addr_i18n_zip text,
|
||||||
|
addr_i18n_name text,
|
||||||
|
addr_i18n_org text,
|
||||||
|
addr_i18n_type text,
|
||||||
|
last_transfer_time timestamptz,
|
||||||
|
addr_local_city text,
|
||||||
|
addr_local_country_code text,
|
||||||
|
addr_local_state text,
|
||||||
|
addr_local_street_line1 text,
|
||||||
|
addr_local_street_line2 text,
|
||||||
|
addr_local_street_line3 text,
|
||||||
|
addr_local_zip text,
|
||||||
|
addr_local_name text,
|
||||||
|
addr_local_org text,
|
||||||
|
addr_local_type text,
|
||||||
|
search_name text,
|
||||||
|
transfer_gaining_poll_message_id int8,
|
||||||
|
transfer_losing_poll_message_id int8,
|
||||||
|
transfer_client_txn_id text,
|
||||||
|
transfer_server_txn_id text,
|
||||||
|
transfer_gaining_registrar_id text,
|
||||||
|
transfer_losing_registrar_id text,
|
||||||
|
transfer_pending_expiration_time timestamptz,
|
||||||
|
transfer_request_time timestamptz,
|
||||||
|
transfer_status text,
|
||||||
|
voice_phone_extension text,
|
||||||
|
voice_phone_number text,
|
||||||
|
creation_registrar_id text NOT NULL,
|
||||||
|
creation_time timestamptz NOT NULL,
|
||||||
|
current_sponsor_registrar_id text NOT NULL,
|
||||||
|
deletion_time timestamptz,
|
||||||
|
last_epp_update_registrar_id text,
|
||||||
|
last_epp_update_time timestamptz,
|
||||||
|
statuses text[],
|
||||||
|
contact_repo_id text NOT NULL,
|
||||||
|
primary key (history_revision_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
create index IDXo1xdtpij2yryh0skxe9v91sep on "ContactHistory" (creation_time);
|
||||||
|
create index IDXhp33wybmb6tbpr1bq7ttwk8je on "ContactHistory" (history_registrar_id);
|
||||||
|
create index IDX9q53px6r302ftgisqifmc6put on "ContactHistory" (history_type);
|
||||||
|
create index IDXsudwswtwqnfnx2o1hx4s0k0g5 on "ContactHistory" (history_modification_time);
|
||||||
|
|
||||||
|
ALTER TABLE IF EXISTS "ContactHistory"
|
||||||
|
ADD CONSTRAINT fk_contact_history_registrar_id
|
||||||
|
FOREIGN KEY (history_registrar_id)
|
||||||
|
REFERENCES "Registrar";
|
||||||
|
|
||||||
|
ALTER TABLE IF EXISTS "ContactHistory"
|
||||||
|
ADD CONSTRAINT fk_contact_history_contact_repo_id
|
||||||
|
FOREIGN KEY (contact_repo_id)
|
||||||
|
REFERENCES "Contact";
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."ContactHistory" ALTER COLUMN history_revision_id
|
||||||
|
SET DEFAULT nextval('public."history_id_sequence"'::regclass);
|
|
@ -133,6 +133,74 @@ create sequence history_id_sequence start 1 increment 1;
|
||||||
primary key (repo_id)
|
primary key (repo_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create table "ContactHistory" (
|
||||||
|
history_revision_id int8 not null,
|
||||||
|
history_by_superuser boolean not null,
|
||||||
|
history_registrar_id text,
|
||||||
|
history_modification_time timestamptz not null,
|
||||||
|
history_reason text not null,
|
||||||
|
history_requested_by_registrar boolean not null,
|
||||||
|
history_client_transaction_id text,
|
||||||
|
history_server_transaction_id text,
|
||||||
|
history_type text not null,
|
||||||
|
history_xml_bytes bytea not null,
|
||||||
|
auth_info_repo_id text,
|
||||||
|
auth_info_value text,
|
||||||
|
contact_id text,
|
||||||
|
disclose_types_addr text[],
|
||||||
|
disclose_show_email boolean,
|
||||||
|
disclose_show_fax boolean,
|
||||||
|
disclose_mode_flag boolean,
|
||||||
|
disclose_types_name text[],
|
||||||
|
disclose_types_org text[],
|
||||||
|
disclose_show_voice boolean,
|
||||||
|
email text,
|
||||||
|
fax_phone_extension text,
|
||||||
|
fax_phone_number text,
|
||||||
|
addr_i18n_city text,
|
||||||
|
addr_i18n_country_code text,
|
||||||
|
addr_i18n_state text,
|
||||||
|
addr_i18n_street_line1 text,
|
||||||
|
addr_i18n_street_line2 text,
|
||||||
|
addr_i18n_street_line3 text,
|
||||||
|
addr_i18n_zip text,
|
||||||
|
addr_i18n_name text,
|
||||||
|
addr_i18n_org text,
|
||||||
|
addr_i18n_type text,
|
||||||
|
last_transfer_time timestamptz,
|
||||||
|
addr_local_city text,
|
||||||
|
addr_local_country_code text,
|
||||||
|
addr_local_state text,
|
||||||
|
addr_local_street_line1 text,
|
||||||
|
addr_local_street_line2 text,
|
||||||
|
addr_local_street_line3 text,
|
||||||
|
addr_local_zip text,
|
||||||
|
addr_local_name text,
|
||||||
|
addr_local_org text,
|
||||||
|
addr_local_type text,
|
||||||
|
search_name text,
|
||||||
|
transfer_gaining_poll_message_id int8,
|
||||||
|
transfer_losing_poll_message_id int8,
|
||||||
|
transfer_client_txn_id text,
|
||||||
|
transfer_server_txn_id text,
|
||||||
|
transfer_gaining_registrar_id text,
|
||||||
|
transfer_losing_registrar_id text,
|
||||||
|
transfer_pending_expiration_time timestamptz,
|
||||||
|
transfer_request_time timestamptz,
|
||||||
|
transfer_status text,
|
||||||
|
voice_phone_extension text,
|
||||||
|
voice_phone_number text,
|
||||||
|
creation_registrar_id text not null,
|
||||||
|
creation_time timestamptz not null,
|
||||||
|
current_sponsor_registrar_id text not null,
|
||||||
|
deletion_time timestamptz,
|
||||||
|
last_epp_update_registrar_id text,
|
||||||
|
last_epp_update_time timestamptz,
|
||||||
|
statuses text[],
|
||||||
|
contact_repo_id text not null,
|
||||||
|
primary key (history_revision_id)
|
||||||
|
);
|
||||||
|
|
||||||
create table "Cursor" (
|
create table "Cursor" (
|
||||||
scope text not null,
|
scope text not null,
|
||||||
type text not null,
|
type text not null,
|
||||||
|
@ -437,6 +505,10 @@ create index IDX1p3esngcwwu6hstyua6itn6ff on "Contact" (search_name);
|
||||||
|
|
||||||
alter table if exists "Contact"
|
alter table if exists "Contact"
|
||||||
add constraint UKoqd7n4hbx86hvlgkilq75olas unique (contact_id);
|
add constraint UKoqd7n4hbx86hvlgkilq75olas unique (contact_id);
|
||||||
|
create index IDXo1xdtpij2yryh0skxe9v91sep on "ContactHistory" (creation_time);
|
||||||
|
create index IDXhp33wybmb6tbpr1bq7ttwk8je on "ContactHistory" (history_registrar_id);
|
||||||
|
create index IDX9q53px6r302ftgisqifmc6put on "ContactHistory" (history_type);
|
||||||
|
create index IDXsudwswtwqnfnx2o1hx4s0k0g5 on "ContactHistory" (history_modification_time);
|
||||||
create index IDX8nr0ke9mrrx4ewj6pd2ag4rmr on "Domain" (creation_time);
|
create index IDX8nr0ke9mrrx4ewj6pd2ag4rmr on "Domain" (creation_time);
|
||||||
create index IDXhsjqiy2lyobfymplb28nm74lm on "Domain" (current_sponsor_registrar_id);
|
create index IDXhsjqiy2lyobfymplb28nm74lm on "Domain" (current_sponsor_registrar_id);
|
||||||
create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time);
|
create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time);
|
||||||
|
|
|
@ -254,6 +254,90 @@ CREATE TABLE public."Contact" (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: history_id_sequence; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.history_id_sequence
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: ContactHistory; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public."ContactHistory" (
|
||||||
|
history_revision_id bigint DEFAULT nextval('public.history_id_sequence'::regclass) NOT NULL,
|
||||||
|
history_by_superuser boolean NOT NULL,
|
||||||
|
history_registrar_id text,
|
||||||
|
history_modification_time timestamp with time zone NOT NULL,
|
||||||
|
history_reason text NOT NULL,
|
||||||
|
history_requested_by_registrar boolean NOT NULL,
|
||||||
|
history_client_transaction_id text,
|
||||||
|
history_server_transaction_id text,
|
||||||
|
history_type text NOT NULL,
|
||||||
|
history_xml_bytes bytea NOT NULL,
|
||||||
|
auth_info_repo_id text,
|
||||||
|
auth_info_value text,
|
||||||
|
contact_id text,
|
||||||
|
disclose_types_addr text[],
|
||||||
|
disclose_show_email boolean,
|
||||||
|
disclose_show_fax boolean,
|
||||||
|
disclose_mode_flag boolean,
|
||||||
|
disclose_types_name text[],
|
||||||
|
disclose_types_org text[],
|
||||||
|
disclose_show_voice boolean,
|
||||||
|
email text,
|
||||||
|
fax_phone_extension text,
|
||||||
|
fax_phone_number text,
|
||||||
|
addr_i18n_city text,
|
||||||
|
addr_i18n_country_code text,
|
||||||
|
addr_i18n_state text,
|
||||||
|
addr_i18n_street_line1 text,
|
||||||
|
addr_i18n_street_line2 text,
|
||||||
|
addr_i18n_street_line3 text,
|
||||||
|
addr_i18n_zip text,
|
||||||
|
addr_i18n_name text,
|
||||||
|
addr_i18n_org text,
|
||||||
|
addr_i18n_type text,
|
||||||
|
last_transfer_time timestamp with time zone,
|
||||||
|
addr_local_city text,
|
||||||
|
addr_local_country_code text,
|
||||||
|
addr_local_state text,
|
||||||
|
addr_local_street_line1 text,
|
||||||
|
addr_local_street_line2 text,
|
||||||
|
addr_local_street_line3 text,
|
||||||
|
addr_local_zip text,
|
||||||
|
addr_local_name text,
|
||||||
|
addr_local_org text,
|
||||||
|
addr_local_type text,
|
||||||
|
search_name text,
|
||||||
|
transfer_gaining_poll_message_id bigint,
|
||||||
|
transfer_losing_poll_message_id bigint,
|
||||||
|
transfer_client_txn_id text,
|
||||||
|
transfer_server_txn_id text,
|
||||||
|
transfer_gaining_registrar_id text,
|
||||||
|
transfer_losing_registrar_id text,
|
||||||
|
transfer_pending_expiration_time timestamp with time zone,
|
||||||
|
transfer_request_time timestamp with time zone,
|
||||||
|
transfer_status text,
|
||||||
|
voice_phone_extension text,
|
||||||
|
voice_phone_number text,
|
||||||
|
creation_registrar_id text NOT NULL,
|
||||||
|
creation_time timestamp with time zone NOT NULL,
|
||||||
|
current_sponsor_registrar_id text NOT NULL,
|
||||||
|
deletion_time timestamp with time zone,
|
||||||
|
last_epp_update_registrar_id text,
|
||||||
|
last_epp_update_time timestamp with time zone,
|
||||||
|
statuses text[],
|
||||||
|
contact_repo_id text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: Cursor; Type: TABLE; Schema: public; Owner: -
|
-- Name: Cursor; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -325,18 +409,6 @@ CREATE TABLE public."DomainHost" (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: history_id_sequence; Type: SEQUENCE; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE SEQUENCE public.history_id_sequence
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: HostHistory; Type: TABLE; Schema: public; Owner: -
|
-- Name: HostHistory; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -793,6 +865,14 @@ ALTER TABLE ONLY public."ClaimsList"
|
||||||
ADD CONSTRAINT "ClaimsList_pkey" PRIMARY KEY (revision_id);
|
ADD CONSTRAINT "ClaimsList_pkey" PRIMARY KEY (revision_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: ContactHistory ContactHistory_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."ContactHistory"
|
||||||
|
ADD CONSTRAINT "ContactHistory_pkey" PRIMARY KEY (history_revision_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: Contact Contact_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: Contact Contact_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -1013,6 +1093,13 @@ CREATE INDEX idx73l103vc5900ig3p4odf0cngt ON public."BillingEvent" USING btree (
|
||||||
CREATE INDEX idx8nr0ke9mrrx4ewj6pd2ag4rmr ON public."Domain" USING btree (creation_time);
|
CREATE INDEX idx8nr0ke9mrrx4ewj6pd2ag4rmr ON public."Domain" USING btree (creation_time);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: idx9q53px6r302ftgisqifmc6put; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX idx9q53px6r302ftgisqifmc6put ON public."ContactHistory" USING btree (history_type);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: idx_registry_lock_registrar_id; Type: INDEX; Schema: public; Owner: -
|
-- Name: idx_registry_lock_registrar_id; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -1069,6 +1156,13 @@ CREATE INDEX idxfg2nnjlujxo6cb9fha971bq2n ON public."HostHistory" USING btree (c
|
||||||
CREATE INDEX idxhmv411mdqo5ibn4vy7ykxpmlv ON public."BillingEvent" USING btree (allocation_token_id);
|
CREATE INDEX idxhmv411mdqo5ibn4vy7ykxpmlv ON public."BillingEvent" USING btree (allocation_token_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: idxhp33wybmb6tbpr1bq7ttwk8je; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX idxhp33wybmb6tbpr1bq7ttwk8je ON public."ContactHistory" USING btree (history_registrar_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: idxj77pfwhui9f0i7wjq6lmibovj; Type: INDEX; Schema: public; Owner: -
|
-- Name: idxj77pfwhui9f0i7wjq6lmibovj; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -1111,6 +1205,13 @@ CREATE INDEX idxn1f711wicdnooa2mqb7g1m55o ON public."Contact" USING btree (delet
|
||||||
CREATE INDEX idxn898pb9mwcg359cdwvolb11ck ON public."BillingRecurrence" USING btree (registrar_id);
|
CREATE INDEX idxn898pb9mwcg359cdwvolb11ck ON public."BillingRecurrence" USING btree (registrar_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: idxo1xdtpij2yryh0skxe9v91sep; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX idxo1xdtpij2yryh0skxe9v91sep ON public."ContactHistory" USING btree (creation_time);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: idxp3usbtvk0v1m14i5tdp4xnxgc; Type: INDEX; Schema: public; Owner: -
|
-- Name: idxp3usbtvk0v1m14i5tdp4xnxgc; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -1139,6 +1240,13 @@ CREATE INDEX idxqa3g92jc17e8dtiaviy4fet4x ON public."BillingCancellation" USING
|
||||||
CREATE INDEX idxrwl38wwkli1j7gkvtywi9jokq ON public."Domain" USING btree (tld);
|
CREATE INDEX idxrwl38wwkli1j7gkvtywi9jokq ON public."Domain" USING btree (tld);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: idxsudwswtwqnfnx2o1hx4s0k0g5; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX idxsudwswtwqnfnx2o1hx4s0k0g5 ON public."ContactHistory" USING btree (history_modification_time);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: premiumlist_name_idx; Type: INDEX; Schema: public; Owner: -
|
-- Name: premiumlist_name_idx; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -1299,6 +1407,22 @@ ALTER TABLE ONLY public."BillingRecurrence"
|
||||||
ADD CONSTRAINT fk_billing_recurrence_registrar_id FOREIGN KEY (registrar_id) REFERENCES public."Registrar"(registrar_id);
|
ADD CONSTRAINT fk_billing_recurrence_registrar_id FOREIGN KEY (registrar_id) REFERENCES public."Registrar"(registrar_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: ContactHistory fk_contact_history_contact_repo_id; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."ContactHistory"
|
||||||
|
ADD CONSTRAINT fk_contact_history_contact_repo_id FOREIGN KEY (contact_repo_id) REFERENCES public."Contact"(repo_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: ContactHistory fk_contact_history_registrar_id; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."ContactHistory"
|
||||||
|
ADD CONSTRAINT fk_contact_history_registrar_id FOREIGN KEY (history_registrar_id) REFERENCES public."Registrar"(registrar_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: Contact fk_contact_transfer_gaining_registrar_id; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: Contact fk_contact_transfer_gaining_registrar_id; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue