diff --git a/java/google/registry/rdap/RdapEntityAction.java b/java/google/registry/rdap/RdapEntityAction.java index c411e5320..f76a3e62e 100644 --- a/java/google/registry/rdap/RdapEntityAction.java +++ b/java/google/registry/rdap/RdapEntityAction.java @@ -66,6 +66,8 @@ public class RdapEntityAction extends RdapActionBase { wasValidKey = true; Key contactKey = Key.create(ContactResource.class, pathSearchString); ContactResource contactResource = ofy().load().key(contactKey).now(); + // 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. if ((contactResource != null) && clock.nowUtc().isBefore(contactResource.getDeletionTime())) { return RdapJsonFormatter.makeRdapJsonForContact( contactResource, diff --git a/java/google/registry/rdap/RdapEntitySearchAction.java b/java/google/registry/rdap/RdapEntitySearchAction.java index 62cf6ecb6..68b99ac0a 100644 --- a/java/google/registry/rdap/RdapEntitySearchAction.java +++ b/java/google/registry/rdap/RdapEntitySearchAction.java @@ -86,6 +86,14 @@ public class RdapEntitySearchAction extends RdapActionBase { ImmutableList> 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"); } else { // syntax: /rdap/entities?handle=12345-* @@ -113,6 +121,8 @@ public class RdapEntitySearchAction extends RdapActionBase { Registrar registrar = Registrar.loadByClientId(partialStringQuery.getInitialString()); ImmutableList.Builder> 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, diff --git a/java/google/registry/rdap/RdapJsonFormatter.java b/java/google/registry/rdap/RdapJsonFormatter.java index 263fb1c07..1aa4fa5a5 100644 --- a/java/google/registry/rdap/RdapJsonFormatter.java +++ b/java/google/registry/rdap/RdapJsonFormatter.java @@ -836,6 +836,23 @@ public class RdapJsonFormatter { ImmutableList.Builder builder = new ImmutableList.Builder<>(); builder.add(""); // PO box builder.add(""); // extended address + + // The vCard spec allows several different ways to handle multiline street addresses. Per + // Gustavo Lozano of ICANN, the one we should use is an embedded array of street address lines + // if there is more than one line: + // + // RFC7095 provides two examples of structured addresses, and one of the examples shows a + // street JSON element that contains several data elements. The example showing (see below) + // several data elements is the expected output when two or more elements + // exists in the contact object. + // + // ["adr", {}, "text", + // [ + // "", "", + // ["My Street", "Left Side", "Second Shack"], + // "Hometown", "PA", "18252", "U.S.A." + // ] + // ] ImmutableList street = address.getStreet(); if (street.isEmpty()) { builder.add(""); diff --git a/javatests/google/registry/rdap/RdapJsonFormatterTest.java b/javatests/google/registry/rdap/RdapJsonFormatterTest.java index 9d0660e94..498c37e78 100644 --- a/javatests/google/registry/rdap/RdapJsonFormatterTest.java +++ b/javatests/google/registry/rdap/RdapJsonFormatterTest.java @@ -295,6 +295,18 @@ public class RdapJsonFormatterTest { .isEqualTo(loadJson("rdapjson_techcontact.json")); } + @Test + public void testRolelessContact() throws Exception { + assertThat( + RdapJsonFormatter.makeRdapJsonForContact( + contactResourceTech, + false, + Optional.absent(), + LINK_BASE, + WHOIS_SERVER)) + .isEqualTo(loadJson("rdapjson_rolelesscontact.json")); + } + @Test public void testDomain_full() throws Exception { assertThat( diff --git a/javatests/google/registry/rdap/testdata/rdapjson_rolelesscontact.json b/javatests/google/registry/rdap/testdata/rdapjson_rolelesscontact.json new file mode 100644 index 000000000..b0dfa46af --- /dev/null +++ b/javatests/google/registry/rdap/testdata/rdapjson_rolelesscontact.json @@ -0,0 +1,45 @@ +{ + "objectClassName" : "entity", + "handle" : "6-ROID", + "status" : ["active"], + "links" : + [ + { + "value" : "http://myserver.google.com/entity/6-ROID", + "rel" : "self", + "href" : "http://myserver.google.com/entity/6-ROID", + "type" : "application/rdap+json" + } + ], + "events": [ + { + "eventAction": "registration", + "eventActor": "foo", + "eventDate": "1997-01-01T00:00:00.000Z" + }, + ], + "vcardArray" : + [ + "vcard", + [ + ["version", {}, "text", "4.0"], + ["fn", {}, "text", "The Raven"], + ["org", {}, "text", "GOOGLE INCORPORATED