mirror of
https://github.com/google/nomulus.git
synced 2025-05-20 11:19:35 +02:00
RDAP: Implement entity name search
Adds the ability to search for entities (contacts and registrars) by name. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=130305930
This commit is contained in:
parent
64abebec82
commit
160266f37a
8 changed files with 368 additions and 66 deletions
|
@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.primitives.Booleans;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.config.ConfigModule.Config;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
|
@ -34,7 +33,6 @@ import google.registry.request.Action;
|
|||
import google.registry.request.HttpException;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
import google.registry.request.HttpException.NotImplementedException;
|
||||
import google.registry.request.HttpException.UnprocessableEntityException;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.util.Clock;
|
||||
|
@ -88,15 +86,8 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
|||
ImmutableList<ImmutableMap<String, Object>> results;
|
||||
if (fnParam.isPresent()) {
|
||||
// syntax: /rdap/entities?fn=Bobby%20Joe*
|
||||
// TODO(b/25973399): implement entity name search, and move the comment below to that routine
|
||||
// As per Gustavo Lozano of ICANN, registrar name search should be by registrar name only, not
|
||||
// by registrar contact name:
|
||||
//
|
||||
// The search is by registrar name only. The profile is supporting the functionality defined
|
||||
// in the Base Registry Agreement (see 1.6 of Section 4 of the Base Registry Agreement,
|
||||
// https://newgtlds.icann.org/sites/default/files/agreements/
|
||||
// agreement-approved-09jan14-en.htm).
|
||||
throw new NotImplementedException("Entity name search not implemented");
|
||||
// The name is the contact name or registrar name (not registrar contact name).
|
||||
results = searchByName(RdapSearchPattern.create(fnParam.get(), false), now);
|
||||
} else {
|
||||
// syntax: /rdap/entities?handle=12345-*
|
||||
// The handle is either the contact roid or the registrar clientId.
|
||||
|
@ -111,6 +102,57 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for entities by name, returning a JSON array of entity info maps.
|
||||
*
|
||||
* <p>As per Gustavo Lozano of ICANN, registrar name search should be by registrar name only, not
|
||||
* by registrar contact name:
|
||||
*
|
||||
* <p>The search is by registrar name only. The profile is supporting the functionality defined
|
||||
* in the Base Registry Agreement (see 1.6 of Section 4 of the Base Registry Agreement,
|
||||
* https://newgtlds.icann.org/sites/default/files/agreements/
|
||||
* agreement-approved-09jan14-en.htm).
|
||||
*
|
||||
* <p>According to RFC 7482 section 6.1, punycode is only used for domain name labels, so we can
|
||||
* assume that entity names are regular unicode.
|
||||
*/
|
||||
private ImmutableList<ImmutableMap<String, Object>>
|
||||
searchByName(final RdapSearchPattern partialStringQuery, DateTime now) throws HttpException {
|
||||
// Handle queries without a wildcard -- load by name, which may not be unique.
|
||||
if (!partialStringQuery.getHasWildcard()) {
|
||||
Registrar registrar = Registrar.loadByName(partialStringQuery.getInitialString());
|
||||
return makeSearchResults(
|
||||
ofy().load()
|
||||
.type(ContactResource.class)
|
||||
.filter("searchName", partialStringQuery.getInitialString())
|
||||
.filter("deletionTime", END_OF_TIME)
|
||||
.limit(rdapResultSetMaxSize),
|
||||
(registrar == null)
|
||||
? ImmutableList.<Registrar>of() : ImmutableList.of(registrar),
|
||||
now);
|
||||
// Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will
|
||||
// always be END_OF_TIME for non-deleted records; unlike domain resources, we don't need to
|
||||
// worry about deletion times in the future. That allows us to use an equality query for the
|
||||
// deletion time.
|
||||
} else if (partialStringQuery.getSuffix() == null) {
|
||||
return makeSearchResults(
|
||||
ofy().load()
|
||||
.type(ContactResource.class)
|
||||
.filter("searchName >=", partialStringQuery.getInitialString())
|
||||
.filter("searchName <", partialStringQuery.getNextInitialString())
|
||||
.filter("deletionTime", END_OF_TIME)
|
||||
.limit(rdapResultSetMaxSize),
|
||||
Registrar.loadByNameRange(
|
||||
partialStringQuery.getInitialString(),
|
||||
partialStringQuery.getNextInitialString(),
|
||||
rdapResultSetMaxSize),
|
||||
now);
|
||||
// Don't allow suffixes in entity name search queries.
|
||||
} else {
|
||||
throw new UnprocessableEntityException("Suffixes not allowed in entity name searches");
|
||||
}
|
||||
}
|
||||
|
||||
/** Searches for entities by handle, returning a JSON array of entity info maps. */
|
||||
private ImmutableList<ImmutableMap<String, Object>> searchByHandle(
|
||||
final RdapSearchPattern partialStringQuery, DateTime now) throws HttpException {
|
||||
|
@ -121,63 +163,62 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
|||
.id(partialStringQuery.getInitialString())
|
||||
.now();
|
||||
Registrar registrar = Registrar.loadByClientId(partialStringQuery.getInitialString());
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
|
||||
if ((contactResource != null) && contactResource.getDeletionTime().isEqual(END_OF_TIME)) {
|
||||
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
||||
// they are global, and might have different roles for different domains.
|
||||
builder.add(RdapJsonFormatter.makeRdapJsonForContact(
|
||||
contactResource,
|
||||
false,
|
||||
Optional.<DesignatedContact.Type>absent(),
|
||||
rdapLinkBase,
|
||||
rdapWhoisServer,
|
||||
now));
|
||||
}
|
||||
if ((registrar != null) && registrar.isActiveAndPubliclyVisible()) {
|
||||
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, false, rdapLinkBase, rdapWhoisServer, now));
|
||||
}
|
||||
return builder.build();
|
||||
return makeSearchResults(
|
||||
((contactResource == null) || !contactResource.getDeletionTime().isEqual(END_OF_TIME))
|
||||
? ImmutableList.<ContactResource>of() : ImmutableList.of(contactResource),
|
||||
(registrar == null)
|
||||
? ImmutableList.<Registrar>of() : ImmutableList.of(registrar),
|
||||
now);
|
||||
// Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will
|
||||
// always be END_OF_TIME for non-deleted records; unlike domain resources, we don't need to
|
||||
// worry about deletion times in the future. That allows us to use an equality query for the
|
||||
// deletion time.
|
||||
} else if (partialStringQuery.getSuffix() == null) {
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
|
||||
Query<ContactResource> query = ofy().load()
|
||||
.type(ContactResource.class)
|
||||
.filterKey(">=", Key.create(ContactResource.class, partialStringQuery.getInitialString()))
|
||||
.filterKey(
|
||||
"<", Key.create(ContactResource.class, partialStringQuery.getNextInitialString()))
|
||||
.filter("deletionTime", END_OF_TIME)
|
||||
.limit(rdapResultSetMaxSize);
|
||||
for (ContactResource contactResource : query) {
|
||||
builder.add(RdapJsonFormatter.makeRdapJsonForContact(
|
||||
contactResource,
|
||||
false,
|
||||
Optional.<DesignatedContact.Type>absent(),
|
||||
rdapLinkBase,
|
||||
rdapWhoisServer,
|
||||
now));
|
||||
}
|
||||
for (Registrar registrar
|
||||
: Registrar.loadByClientIdRange(
|
||||
return makeSearchResults(
|
||||
ofy().load()
|
||||
.type(ContactResource.class)
|
||||
.filterKey(
|
||||
">=", Key.create(ContactResource.class, partialStringQuery.getInitialString()))
|
||||
.filterKey(
|
||||
"<", Key.create(ContactResource.class, partialStringQuery.getNextInitialString()))
|
||||
.filter("deletionTime", END_OF_TIME)
|
||||
.limit(rdapResultSetMaxSize),
|
||||
Registrar.loadByClientIdRange(
|
||||
partialStringQuery.getInitialString(),
|
||||
partialStringQuery.getNextInitialString(),
|
||||
rdapResultSetMaxSize)) {
|
||||
if (registrar.isActiveAndPubliclyVisible()) {
|
||||
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, false, rdapLinkBase, rdapWhoisServer, now));
|
||||
}
|
||||
}
|
||||
// In theory, there could be more results than our max size, so limit the size.
|
||||
ImmutableList<ImmutableMap<String, Object>> resultSet = builder.build();
|
||||
return (resultSet.size() <= rdapResultSetMaxSize)
|
||||
? resultSet
|
||||
: resultSet.subList(0, rdapResultSetMaxSize);
|
||||
rdapResultSetMaxSize),
|
||||
now);
|
||||
// Don't allow suffixes in entity handle search queries.
|
||||
} else {
|
||||
throw new UnprocessableEntityException("Suffixes not allowed in entity handle searches");
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds a JSON array of entity info maps based on the specified contacts and registrars. */
|
||||
private ImmutableList<ImmutableMap<String, Object>> makeSearchResults(
|
||||
Iterable<ContactResource> contactResources, Iterable<Registrar> registrars, DateTime now)
|
||||
throws HttpException {
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
|
||||
for (ContactResource contact : contactResources) {
|
||||
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
||||
// they are global, and might have different roles for different domains.
|
||||
builder.add(RdapJsonFormatter.makeRdapJsonForContact(
|
||||
contact,
|
||||
false,
|
||||
Optional.<DesignatedContact.Type>absent(),
|
||||
rdapLinkBase,
|
||||
rdapWhoisServer, now));
|
||||
}
|
||||
for (Registrar registrar : registrars) {
|
||||
if (registrar.isActiveAndPubliclyVisible()) {
|
||||
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, false, rdapLinkBase, rdapWhoisServer, now));
|
||||
}
|
||||
}
|
||||
// In theory, there could be more results than our max size, so limit the size.
|
||||
ImmutableList<ImmutableMap<String, Object>> resultSet = builder.build();
|
||||
return (resultSet.size() <= rdapResultSetMaxSize)
|
||||
? resultSet
|
||||
: resultSet.subList(0, rdapResultSetMaxSize);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue