From f63900a64b86b44e5ecef316518ecd96b7844f53 Mon Sep 17 00:00:00 2001 From: Park Sijun <79843980+millwheel@users.noreply.github.com> Date: Tue, 19 Mar 2024 02:55:19 +0900 Subject: [PATCH] Searching organization members with multiple name as query parameter (#208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Add function to search for members with multiple user name with comma * test: Add test for searching members of organization with multiple member names with comma * refactor add indent * fix: null to empty array in searchForMembersStream --------- Co-authored-by: 박시준 --- .../model/jpa/OrganizationAdapter.java | 17 +++- .../resource/OrganizationResourceTest.java | 94 +++++++++++++++++++ 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/phasetwo/service/model/jpa/OrganizationAdapter.java b/src/main/java/io/phasetwo/service/model/jpa/OrganizationAdapter.java index 9c76964f..3bc55e4b 100644 --- a/src/main/java/io/phasetwo/service/model/jpa/OrganizationAdapter.java +++ b/src/main/java/io/phasetwo/service/model/jpa/OrganizationAdapter.java @@ -165,15 +165,22 @@ public void setAttribute(String name, List values) { @Override public Stream searchForMembersStream( String search, Integer firstResult, Integer maxResults) { + String[] searchTerms = Strings.isNullOrEmpty(search) ? new String[0] : search.split(","); // TODO this could be optimized for large member lists with a query return getMembersStream() .filter( (m) -> { - if (Strings.isNullOrEmpty(search)) return true; - return (m.getEmail() != null && m.getEmail().toLowerCase().contains(search)) - || (m.getUsername() != null && m.getUsername().toLowerCase().contains(search)) - || (m.getFirstName() != null && m.getFirstName().toLowerCase().contains(search)) - || (m.getLastName() != null && m.getLastName().toLowerCase().contains(search)); + for (String searchTerm : searchTerms) { + String term = searchTerm.trim().toLowerCase(); + if (term.isEmpty()) continue; + if ((m.getEmail() != null && m.getEmail().toLowerCase().contains(term)) + || (m.getUsername() != null && m.getUsername().toLowerCase().contains(term)) + || (m.getFirstName() != null && m.getFirstName().toLowerCase().contains(term)) + || (m.getLastName() != null && m.getLastName().toLowerCase().contains(term))) { + return true; + } + } + return searchTerms.length == 0; }) .skip(firstResult) .limit(maxResults); diff --git a/src/test/java/io/phasetwo/service/resource/OrganizationResourceTest.java b/src/test/java/io/phasetwo/service/resource/OrganizationResourceTest.java index bc035cbc..c93ca027 100644 --- a/src/test/java/io/phasetwo/service/resource/OrganizationResourceTest.java +++ b/src/test/java/io/phasetwo/service/resource/OrganizationResourceTest.java @@ -451,6 +451,100 @@ void testAddGetDeleteMemberships() throws IOException { deleteOrganization(id); } + @Test + void testSearchMembersWithMultipleNameParameter() throws IOException { + OrganizationRepresentation org = createDefaultOrg(); + String id = org.getId(); + + Response response = getRequest(id, "members"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + + // create a user + UserRepresentation user1 = createUser(keycloak, REALM, "johndoe"); + UserRepresentation user2 = createUser(keycloak, REALM, "johndow"); + UserRepresentation user3 = createUser(keycloak, REALM, "jack"); + UserRepresentation user4 = createUser(keycloak, REALM, "jill"); + + // add membership + response = putRequest("foo", org.getId(), "members", user1.getId()); + assertThat(response.getStatusCode(), is(Status.CREATED.getStatusCode())); + response = putRequest("foo", org.getId(), "members", user2.getId()); + assertThat(response.getStatusCode(), is(Status.CREATED.getStatusCode())); + response = putRequest("foo", org.getId(), "members", user3.getId()); + assertThat(response.getStatusCode(), is(Status.CREATED.getStatusCode())); + response = putRequest("foo", org.getId(), "members", user4.getId()); + assertThat(response.getStatusCode(), is(Status.CREATED.getStatusCode())); + + response = getRequest(id, "members"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + List members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(5)); // including org admin default + + // search members with query parameter + response = getRequest(id, "members?search=john"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(2)); + assertThat(members, hasItem(hasProperty("username", is("johndoe")))); + assertThat(members, hasItem(hasProperty("username", is("johndow")))); + + response = getRequest(id, "members?search=jack,jill"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(2)); + assertThat(members, hasItem(hasProperty("username", is("jack")))); + assertThat(members, hasItem(hasProperty("username", is("jill")))); + + response = getRequest(id, "members?search=john, jack, jill"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(4)); + assertThat(members, hasItem(hasProperty("username", is("johndoe")))); + assertThat(members, hasItem(hasProperty("username", is("johndow")))); + assertThat(members, hasItem(hasProperty("username", is("jack")))); + assertThat(members, hasItem(hasProperty("username", is("jill")))); + + response = getRequest(id, "members?search=,,jack"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(1)); + assertThat(members, hasItem(hasProperty("username", is("jack")))); + + response = getRequest(id, "members?search=,, ,"); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(0)); + + response = getRequest(id, "members?search= ,, jack , "); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(1)); + assertThat(members, hasItem(hasProperty("username", is("jack")))); + + response = getRequest(id, "members?search="); + assertThat(response.statusCode(), is(Status.OK.getStatusCode())); + members = objectMapper().readValue(response.getBody().asString(), new TypeReference<>() {}); + assertThat(members, notNullValue()); + assertThat(members, hasSize(5)); + + + // delete user + deleteUser(keycloak, REALM, user1.getId()); + deleteUser(keycloak, REALM, user2.getId()); + deleteUser(keycloak, REALM, user3.getId()); + deleteUser(keycloak, REALM, user4.getId()); + + // delete org + deleteOrganization(id); + } + @Test void testDuplicateRoles() throws IOException { OrganizationRepresentation org = createDefaultOrg();