mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 00:17:20 +02:00
Add support for RDAP retrieval of all registrars
This CL also fixes a bug. Registrars were returned in an arbitrary order. This caused cursor-based pagination to fail. Now we always sort by registrar name (even for handle searches), and use the registrar name in the cursor, to ensure proper behavior. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=182098187
This commit is contained in:
parent
c416b3892d
commit
e577d2f5e9
2 changed files with 89 additions and 13 deletions
|
@ -41,6 +41,7 @@ import google.registry.request.Parameter;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -194,6 +195,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
results =
|
results =
|
||||||
searchByHandle(
|
searchByHandle(
|
||||||
recordWildcardType(RdapSearchPattern.create(handleParam.get(), false)),
|
recordWildcardType(RdapSearchPattern.create(handleParam.get(), false)),
|
||||||
|
cursorType,
|
||||||
cursorQueryString,
|
cursorQueryString,
|
||||||
subtype,
|
subtype,
|
||||||
now);
|
now);
|
||||||
|
@ -244,14 +246,17 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
Optional<String> cursorQueryString,
|
Optional<String> cursorQueryString,
|
||||||
Subtype subtype,
|
Subtype subtype,
|
||||||
DateTime now) {
|
DateTime now) {
|
||||||
// For wildcard searches, make sure the initial string is long enough, and don't allow suffixes.
|
// Don't allow wildcard suffixes when searching for entities.
|
||||||
if (partialStringQuery.getHasWildcard() && (partialStringQuery.getSuffix() != null)) {
|
if (partialStringQuery.getHasWildcard() && (partialStringQuery.getSuffix() != null)) {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException(
|
||||||
partialStringQuery.getHasWildcard()
|
partialStringQuery.getHasWildcard()
|
||||||
? "Suffixes not allowed in wildcard entity name searches"
|
? "Suffixes not allowed in wildcard entity name searches"
|
||||||
: "Suffixes not allowed when searching for deleted entities");
|
: "Suffixes not allowed when searching for deleted entities");
|
||||||
}
|
}
|
||||||
|
// For wildcards, make sure the initial string is long enough, except in the special case of
|
||||||
|
// searching for all registrars, where we aren't worried about inefficient searches.
|
||||||
if (partialStringQuery.getHasWildcard()
|
if (partialStringQuery.getHasWildcard()
|
||||||
|
&& (subtype != Subtype.REGISTRARS)
|
||||||
&& (partialStringQuery.getInitialString().length()
|
&& (partialStringQuery.getInitialString().length()
|
||||||
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH)) {
|
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH)) {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException(
|
||||||
|
@ -267,6 +272,8 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
} else {
|
} else {
|
||||||
registrars =
|
registrars =
|
||||||
Streams.stream(Registrar.loadAllCached())
|
Streams.stream(Registrar.loadAllCached())
|
||||||
|
.sorted(
|
||||||
|
Comparator.comparing(Registrar::getRegistrarName, String.CASE_INSENSITIVE_ORDER))
|
||||||
.filter(
|
.filter(
|
||||||
registrar ->
|
registrar ->
|
||||||
partialStringQuery.matches(registrar.getRegistrarName())
|
partialStringQuery.matches(registrar.getRegistrarName())
|
||||||
|
@ -320,6 +327,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
*/
|
*/
|
||||||
private RdapSearchResults searchByHandle(
|
private RdapSearchResults searchByHandle(
|
||||||
final RdapSearchPattern partialStringQuery,
|
final RdapSearchPattern partialStringQuery,
|
||||||
|
CursorType cursorType,
|
||||||
Optional<String> cursorQueryString,
|
Optional<String> cursorQueryString,
|
||||||
Subtype subtype,
|
Subtype subtype,
|
||||||
DateTime now) {
|
DateTime now) {
|
||||||
|
@ -358,13 +366,34 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
now);
|
now);
|
||||||
// Handle queries with a wildcard (or including deleted), but no suffix. Because the handle
|
// Handle queries with a wildcard (or including deleted), but no suffix. Because the handle
|
||||||
// for registrars is the IANA identifier number, don't allow wildcard searches for registrars,
|
// for registrars is the IANA identifier number, don't allow wildcard searches for registrars,
|
||||||
// by simply not searching for registrars if a wildcard is present. Fetch an extra contact to
|
// by simply not searching for registrars if a wildcard is present (unless the request is for
|
||||||
// detect result set truncation.
|
// all registrars, in which case we know what to do). Fetch an extra contact to detect result
|
||||||
|
// set truncation.
|
||||||
} else {
|
} else {
|
||||||
ImmutableList<Registrar> registrars =
|
ImmutableList<Registrar> registrars;
|
||||||
((subtype == Subtype.CONTACTS) || partialStringQuery.getHasWildcard())
|
if ((subtype == Subtype.REGISTRARS)
|
||||||
? ImmutableList.of()
|
&& partialStringQuery.getHasWildcard()
|
||||||
: getMatchingRegistrars(partialStringQuery.getInitialString());
|
&& partialStringQuery.getInitialString().isEmpty()) {
|
||||||
|
// Even though we are searching by IANA identifier, we should still sort by name, because
|
||||||
|
// the IANA identifier can by missing, and sorting on that would screw up our cursors.
|
||||||
|
registrars =
|
||||||
|
Streams.stream(Registrar.loadAllCached())
|
||||||
|
.sorted(
|
||||||
|
Comparator.comparing(
|
||||||
|
Registrar::getRegistrarName, String.CASE_INSENSITIVE_ORDER))
|
||||||
|
.filter(
|
||||||
|
registrar ->
|
||||||
|
((cursorType != CursorType.REGISTRAR)
|
||||||
|
|| (registrar.getRegistrarName().compareTo(cursorQueryString.get())
|
||||||
|
> 0))
|
||||||
|
&& shouldBeVisible(registrar))
|
||||||
|
.limit(rdapResultSetMaxSize + 1)
|
||||||
|
.collect(toImmutableList());
|
||||||
|
} else if ((subtype == Subtype.CONTACTS) || partialStringQuery.getHasWildcard()) {
|
||||||
|
registrars = ImmutableList.of();
|
||||||
|
} else {
|
||||||
|
registrars = getMatchingRegistrars(partialStringQuery.getInitialString());
|
||||||
|
}
|
||||||
// Get the contact matches and return the results, fetching an additional contact to detect
|
// Get the contact matches and return the results, fetching an additional contact to detect
|
||||||
// truncation. If we are including deleted entries, we must fetch more entries, in case some
|
// truncation. If we are including deleted entries, we must fetch more entries, in case some
|
||||||
// get excluded due to permissioning. Any cursor present must be a contact cursor, because we
|
// get excluded due to permissioning. Any cursor present must be a contact cursor, because we
|
||||||
|
@ -500,12 +529,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
}
|
}
|
||||||
jsonOutputList.add(rdapJsonFormatter.makeRdapJsonForRegistrar(
|
jsonOutputList.add(rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||||
registrar, false, fullServletPath, rdapWhoisServer, now, outputDataType));
|
registrar, false, fullServletPath, rdapWhoisServer, now, outputDataType));
|
||||||
newCursor =
|
newCursor = Optional.of(REGISTRAR_CURSOR_PREFIX + registrar.getRegistrarName());
|
||||||
Optional.of(
|
|
||||||
REGISTRAR_CURSOR_PREFIX
|
|
||||||
+ ((queryType == QueryType.FULL_NAME)
|
|
||||||
? registrar.getRegistrarName()
|
|
||||||
: registrar.getIanaIdentifier()));
|
|
||||||
}
|
}
|
||||||
return RdapSearchResults.create(
|
return RdapSearchResults.create(
|
||||||
ImmutableList.copyOf(jsonOutputList),
|
ImmutableList.copyOf(jsonOutputList),
|
||||||
|
|
|
@ -851,6 +851,32 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase {
|
||||||
"Entity 9"));
|
"Entity 9"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchRegistrars_cursorNavigationThroughAll() throws Exception {
|
||||||
|
createManyContactsAndRegistrars(0, 13, registrarTest);
|
||||||
|
action.subtypeParam = Optional.of("registrars");
|
||||||
|
checkCursorNavigation(
|
||||||
|
QueryType.FULL_NAME,
|
||||||
|
"*",
|
||||||
|
ImmutableList.of(
|
||||||
|
"Entity 1",
|
||||||
|
"Entity 10",
|
||||||
|
"Entity 11",
|
||||||
|
"Entity 12",
|
||||||
|
"Entity 13",
|
||||||
|
"Entity 2",
|
||||||
|
"Entity 3",
|
||||||
|
"Entity 4",
|
||||||
|
"Entity 5",
|
||||||
|
"Entity 6",
|
||||||
|
"Entity 7",
|
||||||
|
"Entity 8",
|
||||||
|
"Entity 9",
|
||||||
|
"New Registrar",
|
||||||
|
"The Registrar",
|
||||||
|
"Yes Virginia <script>"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMatchMix_truncated() throws Exception {
|
public void testNameMatchMix_truncated() throws Exception {
|
||||||
login("2-RegistrarTest");
|
login("2-RegistrarTest");
|
||||||
|
@ -1241,6 +1267,32 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase {
|
||||||
verifyErrorMetrics(0);
|
verifyErrorMetrics(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleMatchRegistrars_cursorNavigationThroughAll() throws Exception {
|
||||||
|
createManyContactsAndRegistrars(0, 13, registrarTest);
|
||||||
|
action.subtypeParam = Optional.of("registrars");
|
||||||
|
checkCursorNavigation(
|
||||||
|
QueryType.HANDLE,
|
||||||
|
"*",
|
||||||
|
ImmutableList.of(
|
||||||
|
"Entity 1",
|
||||||
|
"Entity 10",
|
||||||
|
"Entity 11",
|
||||||
|
"Entity 12",
|
||||||
|
"Entity 13",
|
||||||
|
"Entity 2",
|
||||||
|
"Entity 3",
|
||||||
|
"Entity 4",
|
||||||
|
"Entity 5",
|
||||||
|
"Entity 6",
|
||||||
|
"Entity 7",
|
||||||
|
"Entity 8",
|
||||||
|
"Entity 9",
|
||||||
|
"New Registrar",
|
||||||
|
"The Registrar",
|
||||||
|
"Yes Virginia <script>"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHandleMatchMix_found_truncated() throws Exception {
|
public void testHandleMatchMix_found_truncated() throws Exception {
|
||||||
createManyContactsAndRegistrars(30, 0, registrarTest);
|
createManyContactsAndRegistrars(30, 0, registrarTest);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue