Skip to content
Snippets Groups Projects
Commit f90c7f47 authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-3947 Search for Bearbeiter by full name' (#81) from...

Merge pull request 'OZG-3947 Search for Bearbeiter by full name' (#81) from OZG-3947-extend-bearbeiter-search-simple into master

Reviewed-on: https://git.ozg-sh.de/mgm/user-manager/pulls/81
parents d2edd1f5 dc82b2a5
Branches
Tags
No related merge requests found
...@@ -57,6 +57,8 @@ public class User { ...@@ -57,6 +57,8 @@ public class User {
public static final String LAST_SYNC_TIMESTAMP_FIELD = "lastSyncTimestamp"; public static final String LAST_SYNC_TIMESTAMP_FIELD = "lastSyncTimestamp";
public static final String LASTNAME_FIELD = "lastName"; public static final String LASTNAME_FIELD = "lastName";
public static final String FIRSTNAME_FIELD = "firstName"; public static final String FIRSTNAME_FIELD = "firstName";
public static final String FULL_NAME_FIELD = "fullName";
public static final String FULL_NAME_REVERSED_FIELD = "fullNameReversed";
public static final String USERNAME_FIELD = "username"; public static final String USERNAME_FIELD = "username";
public static final String ORGANISATIONS_EINHEIT_IDS_FIELD = "organisationsEinheitIds"; public static final String ORGANISATIONS_EINHEIT_IDS_FIELD = "organisationsEinheitIds";
public static final String NOTIFICATION_SEND_FOR_FIELD = "userSettings.notificationsSendFor"; public static final String NOTIFICATION_SEND_FOR_FIELD = "userSettings.notificationsSendFor";
...@@ -70,6 +72,10 @@ public class User { ...@@ -70,6 +72,10 @@ public class User {
private String keycloakUserId; private String keycloakUserId;
private String firstName; private String firstName;
private String lastName; private String lastName;
@JsonIgnore
private String fullName;
@JsonIgnore
private String fullNameReversed;
private String username; private String username;
private String email; private String email;
@JsonIgnore @JsonIgnore
......
...@@ -50,6 +50,8 @@ class UserRepository implements PanacheMongoRepository<User> { ...@@ -50,6 +50,8 @@ class UserRepository implements PanacheMongoRepository<User> {
private static final String SEARCH_QUERY = LASTNAME_FIELD + LIKE_OR + private static final String SEARCH_QUERY = LASTNAME_FIELD + LIKE_OR +
FIRSTNAME_FIELD + LIKE_OR + FIRSTNAME_FIELD + LIKE_OR +
USERNAME_FIELD + LIKE_OR + USERNAME_FIELD + LIKE_OR +
FULL_NAME_FIELD + LIKE_OR +
FULL_NAME_REVERSED_FIELD + LIKE_OR +
EMAIL_FIELD + " like " + param(PARAM_NAME_SEARCH_BY); EMAIL_FIELD + " like " + param(PARAM_NAME_SEARCH_BY);
private static final String AND_DELETED = " and deleted = " + param(PARAM_NAME_DELETED); private static final String AND_DELETED = " and deleted = " + param(PARAM_NAME_DELETED);
......
...@@ -31,6 +31,7 @@ import java.util.Map; ...@@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream;
import jakarta.inject.Inject; import jakarta.inject.Inject;
...@@ -58,6 +59,8 @@ public abstract class UserResourceMapper { ...@@ -58,6 +59,8 @@ public abstract class UserResourceMapper {
@Mapping(target = "email", expression = "java(mapEmail(userRes))") @Mapping(target = "email", expression = "java(mapEmail(userRes))")
@Mapping(target = "firstName", expression = "java(mapFirstName(userRes))") @Mapping(target = "firstName", expression = "java(mapFirstName(userRes))")
@Mapping(target = "lastName", expression = "java(mapLastName(userRes))") @Mapping(target = "lastName", expression = "java(mapLastName(userRes))")
@Mapping(target = "fullName", expression = "java(mapFullName(userRes))")
@Mapping(target = "fullNameReversed", expression = "java(mapFullNameReversed(userRes))")
@Mapping(target = "username", expression = "java(mapUsername(userRes))") @Mapping(target = "username", expression = "java(mapUsername(userRes))")
@Mapping(target = "externalId", expression = "java(mapId(userRes))") @Mapping(target = "externalId", expression = "java(mapId(userRes))")
@Mapping(target = "keycloakUserId", expression = "java(mapKeycloakUserId(userRes))") @Mapping(target = "keycloakUserId", expression = "java(mapKeycloakUserId(userRes))")
...@@ -97,7 +100,6 @@ public abstract class UserResourceMapper { ...@@ -97,7 +100,6 @@ public abstract class UserResourceMapper {
List<String> mapRoles(UserResource userRes) { List<String> mapRoles(UserResource userRes) {
var roleRepresentation = Optional.ofNullable(userRes.roles().getAll().getClientMappings()) var roleRepresentation = Optional.ofNullable(userRes.roles().getAll().getClientMappings())
.filter(Objects::nonNull)
.filter(map -> map.containsKey(properties.client())) .filter(map -> map.containsKey(properties.client()))
.map(map -> map.get(properties.client())) .map(map -> map.get(properties.client()))
.map(ClientMappingsRepresentation::getMappings) .map(ClientMappingsRepresentation::getMappings)
...@@ -111,7 +113,6 @@ public abstract class UserResourceMapper { ...@@ -111,7 +113,6 @@ public abstract class UserResourceMapper {
return Optional.ofNullable(userRepresentation.getAttributes()) return Optional.ofNullable(userRepresentation.getAttributes())
.map(attributes -> attributes.get(properties.ldapIdKey())) .map(attributes -> attributes.get(properties.ldapIdKey()))
.filter(Objects::nonNull)
.map(id -> id.get(0)) .map(id -> id.get(0))
.orElseGet(userRepresentation::getId); .orElseGet(userRepresentation::getId);
...@@ -136,4 +137,14 @@ public abstract class UserResourceMapper { ...@@ -136,4 +137,14 @@ public abstract class UserResourceMapper {
String mapUsername(UserResource userRes) { String mapUsername(UserResource userRes) {
return userRes.toRepresentation().getUsername(); return userRes.toRepresentation().getUsername();
} }
String mapFullName(UserResource userRes) {
return String.join(" ", Stream.of(userRes.toRepresentation().getFirstName(), userRes.toRepresentation().getLastName())
.filter(Objects::nonNull).toArray(String[]::new));
}
String mapFullNameReversed(UserResource userRes) {
return String.join(" ", Stream.of(userRes.toRepresentation().getLastName(), userRes.toRepresentation().getFirstName())
.filter(Objects::nonNull).toArray(String[]::new));
}
} }
...@@ -27,6 +27,7 @@ import static java.util.function.Predicate.not; ...@@ -27,6 +27,7 @@ import static java.util.function.Predicate.not;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import java.time.Instant; import java.time.Instant;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
...@@ -37,6 +38,9 @@ import org.junit.jupiter.api.BeforeEach; ...@@ -37,6 +38,9 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import com.thedeanda.lorem.LoremIpsum; import com.thedeanda.lorem.LoremIpsum;
...@@ -234,6 +238,73 @@ class UserRepositoryITCase { ...@@ -234,6 +238,73 @@ class UserRepositoryITCase {
} }
} }
@Nested
class TestFindByFullName {
@BeforeEach
void init() {
repository.deleteAll();
}
@ParameterizedTest
@MethodSource("provideDataForFindUsersByFullName")
void shouldFindUsersByFullName(String query, String[] expectedUsernames) {
Arrays.asList(
UserTestFactory.createBuilder().id(null).username("user1").fullName("Franz Vogel").build(),
UserTestFactory.createBuilder().id(null).username("user2").fullName("Franz von Holzhausen").build(),
UserTestFactory.createBuilder().id(null).username("user3").fullName("Peter Lustig").build()
).forEach(repository::persist);
var foundUsernames = repository.findUsers(query, 10).map(User::getUsername);
assertThat(foundUsernames).containsExactlyInAnyOrder(expectedUsernames);
}
private static Stream<Arguments> provideDataForFindUsersByFullName() {
return Stream.of(
Arguments.of("Fra", new String[] { "user1", "user2" }),
Arguments.of("Franz", new String[] { "user1", "user2" }),
Arguments.of("Franz v", new String[] { "user1", "user2" }),
Arguments.of("Franz Vo ", new String[0]),
Arguments.of("Franz von", new String[] { "user2" }),
Arguments.of("Franz von Holzhausen", new String[] { "user2" }),
Arguments.of("Franz L", new String[0]),
Arguments.of("Peter V", new String[0])
);
}
}
@Nested
class TestFindByFullNameReversed {
@BeforeEach
void init() {
repository.deleteAll();
}
@ParameterizedTest
@MethodSource("provideDataForFindUsersByFullNameReversed")
void shouldFindUsersByFullNameReversed(String query, String[] expectedUsernames) {
Arrays.asList(
UserTestFactory.createBuilder().id(null).username("user1").fullNameReversed("Langbein Franz").build(),
UserTestFactory.createBuilder().id(null).username("user2").fullNameReversed("Lustig Peter").build(),
UserTestFactory.createBuilder().id(null).username("user3").fullNameReversed("Ilona Nowak").build()
).forEach(repository::persist);
var foundUsernames = repository.findUsers(query, 10).map(User::getUsername);
assertThat(foundUsernames).containsExactlyInAnyOrder(expectedUsernames);
}
private static Stream<Arguments> provideDataForFindUsersByFullNameReversed() {
return Stream.of(
Arguments.of("L", new String[] { "user1", "user2", "user3" }),
Arguments.of("Lustig", new String[] { "user2" }),
Arguments.of("Lustig Peter", new String[] { "user2" })
);
}
}
@Nested @Nested
class TestFindUsersByDeletedAndOrganisationsEinheitId { class TestFindUsersByDeletedAndOrganisationsEinheitId {
......
...@@ -175,6 +175,20 @@ class UserResourceMapperTest { ...@@ -175,6 +175,20 @@ class UserResourceMapperTest {
assertThat(user.getKeycloakUserId()).isEqualTo(UserRepresentationTestFactory.EXTERNAL_ID_FALLBACK); assertThat(user.getKeycloakUserId()).isEqualTo(UserRepresentationTestFactory.EXTERNAL_ID_FALLBACK);
} }
@Test
void shouldMapFullName() {
var user = toKopUser();
assertThat(user.getFullName()).isEqualTo(UserRepresentationTestFactory.FIRST_NAME + " " + UserRepresentationTestFactory.LAST_NAME);
}
@Test
void shouldMapFullNameReversed() {
var user = toKopUser();
assertThat(user.getFullNameReversed()).isEqualTo(UserRepresentationTestFactory.LAST_NAME + " " + UserRepresentationTestFactory.FIRST_NAME);
}
private User toKopUser() { private User toKopUser() {
return toKopUser(UserResourceTestFactory.create()); return toKopUser(UserResourceTestFactory.create());
} }
......
...@@ -40,6 +40,8 @@ public class UserTestFactory { ...@@ -40,6 +40,8 @@ public class UserTestFactory {
public static final String FIRST_NAME = LoremIpsum.getInstance().getFirstName(); public static final String FIRST_NAME = LoremIpsum.getInstance().getFirstName();
public static final String LAST_NAME = LoremIpsum.getInstance().getLastName(); public static final String LAST_NAME = LoremIpsum.getInstance().getLastName();
public static final String FULL_NAME = FIRST_NAME + " " + LAST_NAME;
public static final String FULL_NAME_REVERSED = LAST_NAME + " " + FIRST_NAME;
public static final String USER_NAME = LoremIpsum.getInstance().getName(); public static final String USER_NAME = LoremIpsum.getInstance().getName();
public static final long LAST_SYNC_TIMESTAMP = 1001L; public static final long LAST_SYNC_TIMESTAMP = 1001L;
public static final String EMAIL = LoremIpsum.getInstance().getEmail(); public static final String EMAIL = LoremIpsum.getInstance().getEmail();
...@@ -57,6 +59,8 @@ public class UserTestFactory { ...@@ -57,6 +59,8 @@ public class UserTestFactory {
.keycloakUserId(KEYCLOAK_USER_ID) .keycloakUserId(KEYCLOAK_USER_ID)
.firstName(FIRST_NAME) .firstName(FIRST_NAME)
.lastName(LAST_NAME) .lastName(LAST_NAME)
.fullName(FULL_NAME)
.fullNameReversed(FULL_NAME_REVERSED)
.username(USER_NAME) .username(USER_NAME)
.lastSyncTimestamp(LAST_SYNC_TIMESTAMP) .lastSyncTimestamp(LAST_SYNC_TIMESTAMP)
.email(EMAIL) .email(EMAIL)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment