mirror of
https://github.com/google/nomulus.git
synced 2025-08-05 17:28:25 +02:00
The dark lord Gosling designed the Java package naming system so that ownership flows from the DNS system. Since we own the domain name registry.google, it seems only appropriate that we should use google.registry as our package name.
320 lines
9.6 KiB
Java
320 lines
9.6 KiB
Java
// Copyright 2016 The Domain Registry 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.registrar;
|
|
|
|
import static com.google.common.base.Functions.toStringFunction;
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
import static com.google.common.collect.Iterables.transform;
|
|
import static com.google.common.collect.Sets.difference;
|
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
import static google.registry.model.ofy.Ofy.RECOMMENDED_MEMCACHE_EXPIRATION;
|
|
import static google.registry.util.CollectionUtils.nullToEmptyImmutableSortedCopy;
|
|
import static google.registry.util.ObjectifyUtils.OBJECTS_TO_KEYS;
|
|
|
|
import com.google.common.base.Enums;
|
|
import com.google.common.base.Joiner;
|
|
import com.google.common.collect.FluentIterable;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import com.google.common.collect.ImmutableSortedSet;
|
|
|
|
import com.googlecode.objectify.Key;
|
|
import com.googlecode.objectify.VoidWork;
|
|
import com.googlecode.objectify.annotation.Cache;
|
|
import com.googlecode.objectify.annotation.Entity;
|
|
import com.googlecode.objectify.annotation.Id;
|
|
import com.googlecode.objectify.annotation.Index;
|
|
import com.googlecode.objectify.annotation.Parent;
|
|
|
|
import google.registry.model.Buildable;
|
|
import google.registry.model.ImmutableObject;
|
|
import google.registry.model.JsonMapBuilder;
|
|
import google.registry.model.Jsonifiable;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* A contact for a Registrar. Note, equality, hashCode and comparable have been overridden to only
|
|
* enable key equality.
|
|
*
|
|
* <p>IMPORTANT NOTE: Any time that you change, update, or delete RegistrarContact entities, you
|
|
* *MUST* also modify the persisted Registrar entity with {@link Registrar#contactsRequireSyncing}
|
|
* set to true.
|
|
*/
|
|
@Cache(expirationSeconds = RECOMMENDED_MEMCACHE_EXPIRATION)
|
|
@Entity
|
|
public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
|
|
|
@Parent
|
|
Key<Registrar> parent;
|
|
|
|
/**
|
|
* Registrar contacts types for partner communication tracking.
|
|
*
|
|
* <p><b>Note:</b> These types only matter to the registry. They are not meant to be used for
|
|
* WHOIS or RDAP results.
|
|
*/
|
|
public enum Type {
|
|
ABUSE("abuse", true),
|
|
ADMIN("primary", true),
|
|
BILLING("billing", true),
|
|
LEGAL("legal", true),
|
|
MARKETING("marketing", false),
|
|
TECH("technical", true),
|
|
WHOIS("whois-inquiry", true);
|
|
|
|
private final String displayName;
|
|
|
|
private final boolean required;
|
|
|
|
public String getDisplayName() {
|
|
return displayName;
|
|
}
|
|
|
|
public boolean isRequired() {
|
|
return required;
|
|
}
|
|
|
|
private Type(String display, boolean required) {
|
|
this.displayName = display;
|
|
this.required = required;
|
|
}
|
|
}
|
|
|
|
/** The name of the contact. */
|
|
String name;
|
|
|
|
/** The email address of the contact. */
|
|
@Id
|
|
String emailAddress;
|
|
|
|
/** The voice number of the contact. */
|
|
String phoneNumber;
|
|
|
|
/** The fax number of the contact. */
|
|
String faxNumber;
|
|
|
|
/**
|
|
* Multiple types are used to associate the registrar contact with
|
|
* various mailing groups. This data is internal to the registry.
|
|
*/
|
|
Set<Type> types;
|
|
|
|
/**
|
|
* A GAE user ID allowed to act as this registrar contact.
|
|
*
|
|
* <p>This can be derived from a known email address using http://email-to-gae-id.appspot.com.
|
|
*
|
|
* @see com.google.appengine.api.users.User#getUserId()
|
|
*/
|
|
@Index
|
|
String gaeUserId;
|
|
|
|
/**
|
|
* Whether this contact is publicly visible in WHOIS results as an Admin contact.
|
|
*/
|
|
boolean visibleInWhoisAsAdmin = false;
|
|
|
|
/**
|
|
* Whether this contact is publicly visible in WHOIS results as a Technical contact.
|
|
*/
|
|
boolean visibleInWhoisAsTech = false;
|
|
|
|
public static ImmutableSet<Type> typesFromCSV(String csv) {
|
|
return typesFromStrings(Arrays.asList(csv.split(",")));
|
|
}
|
|
|
|
public static ImmutableSet<Type> typesFromStrings(Iterable<String> typeNames) {
|
|
return FluentIterable.from(typeNames).transform(Enums.stringConverter(Type.class)).toSet();
|
|
}
|
|
|
|
/**
|
|
* Helper to update the contacts associated with a Registrar. This requires querying for the
|
|
* existing contacts, deleting existing contacts that are not part of the given {@code contacts}
|
|
* set, and then saving the given {@code contacts}.
|
|
*
|
|
* <p>IMPORTANT NOTE: If you call this method then it is your responsibility to also persist the
|
|
* relevant Registrar entity with the {@link Registrar#contactsRequireSyncing} field set to true.
|
|
*/
|
|
public static void updateContacts(
|
|
final Registrar registrar, final Set<RegistrarContact> contacts) {
|
|
ofy().transact(new VoidWork() {
|
|
@Override
|
|
public void vrun() {
|
|
ofy().delete().keys(difference(
|
|
ImmutableSet.copyOf(
|
|
ofy().load().type(RegistrarContact.class).ancestor(registrar).keys()),
|
|
FluentIterable.from(contacts).transform(OBJECTS_TO_KEYS).toSet()));
|
|
ofy().save().entities(contacts);
|
|
}});
|
|
}
|
|
|
|
public Key<Registrar> getParent() {
|
|
return parent;
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public String getEmailAddress() {
|
|
return emailAddress;
|
|
}
|
|
|
|
public String getPhoneNumber() {
|
|
return phoneNumber;
|
|
}
|
|
|
|
public String getFaxNumber() {
|
|
return faxNumber;
|
|
}
|
|
|
|
public ImmutableSortedSet<Type> getTypes() {
|
|
return nullToEmptyImmutableSortedCopy(types);
|
|
}
|
|
|
|
public boolean getVisibleInWhoisAsAdmin() {
|
|
return visibleInWhoisAsAdmin;
|
|
}
|
|
|
|
public boolean getVisibleInWhoisAsTech() {
|
|
return visibleInWhoisAsTech;
|
|
}
|
|
|
|
public String getGaeUserId() {
|
|
return gaeUserId;
|
|
}
|
|
|
|
public Builder asBuilder() {
|
|
return new Builder(clone(this));
|
|
}
|
|
|
|
/**
|
|
* Returns a string representation that's human friendly.
|
|
*
|
|
* <p>The output will look something like this:<pre> {@code
|
|
*
|
|
* Some Person
|
|
* person@example.com
|
|
* Tel: +1.2125650666
|
|
* Types: [ADMIN, WHOIS]
|
|
* Visible in WHOIS as Admin contact: Yes
|
|
* Visible in WHOIS as Technical contact: No
|
|
* GAE-UserID: 1234567890}</pre>
|
|
*/
|
|
public String toStringMultilinePlainText() {
|
|
StringBuilder result = new StringBuilder(256);
|
|
result.append(getName()).append('\n');
|
|
result.append(getEmailAddress()).append('\n');
|
|
if (phoneNumber != null) {
|
|
result.append("Tel: ").append(getPhoneNumber()).append('\n');
|
|
}
|
|
if (faxNumber != null) {
|
|
result.append("Fax: ").append(getFaxNumber()).append('\n');
|
|
}
|
|
result.append("Types: ").append(getTypes()).append('\n');
|
|
result.append("Visible in WHOIS as Admin contact: ")
|
|
.append(getVisibleInWhoisAsAdmin() ? "Yes" : "No")
|
|
.append("\n");
|
|
result.append("Visible in WHOIS as Technical contact: ")
|
|
.append(getVisibleInWhoisAsTech() ? "Yes" : "No")
|
|
.append("\n");
|
|
if (getGaeUserId() != null) {
|
|
result.append("GAE-UserID: ").append(getGaeUserId()).append('\n');
|
|
}
|
|
return result.toString();
|
|
}
|
|
|
|
@Override
|
|
public Map<String, Object> toJsonMap() {
|
|
return new JsonMapBuilder()
|
|
.put("name", name)
|
|
.put("emailAddress", emailAddress)
|
|
.put("phoneNumber", phoneNumber)
|
|
.put("faxNumber", faxNumber)
|
|
.put("types", Joiner.on(',').join(transform(getTypes(), toStringFunction())))
|
|
.put("visibleInWhoisAsAdmin", visibleInWhoisAsAdmin)
|
|
.put("visibleInWhoisAsTech", visibleInWhoisAsTech)
|
|
.put("gaeUserId", gaeUserId)
|
|
.build();
|
|
}
|
|
|
|
/** A builder for constructing a {@link RegistrarContact}, since it is immutable. */
|
|
public static class Builder extends Buildable.Builder<RegistrarContact> {
|
|
public Builder() {}
|
|
|
|
private Builder(RegistrarContact instance) {
|
|
super(instance);
|
|
}
|
|
|
|
public Builder setParent(Registrar parent) {
|
|
return this.setParent(Key.create(parent));
|
|
}
|
|
|
|
public Builder setParent(Key<Registrar> parentKey) {
|
|
getInstance().parent = parentKey;
|
|
return this;
|
|
}
|
|
|
|
/** Build the registrar, nullifying empty fields. */
|
|
@Override
|
|
public RegistrarContact build() {
|
|
checkNotNull(getInstance().parent, "Registrar parent cannot be null");
|
|
checkNotNull(getInstance().emailAddress, "Email address cannot be null");
|
|
return cloneEmptyToNull(super.build());
|
|
}
|
|
|
|
public Builder setName(String name) {
|
|
getInstance().name = name;
|
|
return this;
|
|
}
|
|
|
|
public Builder setEmailAddress(String emailAddress) {
|
|
getInstance().emailAddress = emailAddress;
|
|
return this;
|
|
}
|
|
|
|
public Builder setPhoneNumber(String phoneNumber) {
|
|
getInstance().phoneNumber = phoneNumber;
|
|
return this;
|
|
}
|
|
|
|
public Builder setFaxNumber(String faxNumber) {
|
|
getInstance().faxNumber = faxNumber;
|
|
return this;
|
|
}
|
|
|
|
public Builder setTypes(Iterable<Type> types) {
|
|
getInstance().types = ImmutableSet.copyOf(types);
|
|
return this;
|
|
}
|
|
|
|
public Builder setVisibleInWhoisAsAdmin(boolean visible) {
|
|
getInstance().visibleInWhoisAsAdmin = visible;
|
|
return this;
|
|
}
|
|
|
|
public Builder setVisibleInWhoisAsTech(boolean visible) {
|
|
getInstance().visibleInWhoisAsTech = visible;
|
|
return this;
|
|
}
|
|
|
|
public Builder setGaeUserId(String gaeUserId) {
|
|
getInstance().gaeUserId = gaeUserId;
|
|
return this;
|
|
}
|
|
}
|
|
}
|