Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,12 @@ public Optional<UserProfileDetails> findProfileById(Long userId) {
public List<UserProfileDetails> findProfilesByIds(List<Long> userIds) {
return userService.findProfilesDetailsByIds(userIds);
}

/**
* {@inheritDoc}
*/
@Override
public Optional<List<Long>> findUserIdsBySearchWithinIds(String search, List<Long> candidateIds) {
return userService.findUserIdsBySearch(search, candidateIds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,21 @@ public interface UserFacade {
* omitted from the result, consistent with {@link #findByIds}.
*/
List<UserProfileDetails> findProfilesByIds(List<Long> userIds);

/**
* Filters a provided list of candidate user IDs based on a text search against
* the user's first name, surname or email, required by {@code participation}
* module.
* <p>
* This method is designed to perform a constrained search. Instead of searching
* the entire database, it only searches within the provided
* {@code candidateIds}.
* </p>
*
* @param search the text search query (e.g., "Ivan", "ivan@email.com").
* @param candidateIds the pool of user IDs to restrict the search to.
* @return an {@code Optional} containing the filtered list of matching user
* IDs, or {@code Optional.empty()} if the search string is null/blank.
*/
Optional<List<Long>> findUserIdsBySearchWithinIds(String search, List<Long> candidateIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,19 @@ Page<User> findAllBySearchAndRoles(
Pageable pageable);

Page<User> findAllByIdIn(List<Long> ids, Pageable pageable);

@Query("""
SELECT u.id FROM User u
WHERE u.id IN :candidateIds
AND (
:search IS NULL
OR :search = ''
OR LOWER(u.email) LIKE LOWER(CONCAT('%', :search, '%')) ESCAPE '\\'
OR LOWER(u.firstName) LIKE LOWER(CONCAT('%', :search, '%')) ESCAPE '\\'
OR LOWER(u.surname) LIKE LOWER(CONCAT('%', :search, '%')) ESCAPE '\\'
OR LOWER(CONCAT(u.firstName, ' ', u.surname)) LIKE LOWER(CONCAT('%', :search, '%')) ESCAPE '\\'
OR LOWER(CONCAT(u.surname, ' ', u.firstName)) LIKE LOWER(CONCAT('%', :search, '%')) ESCAPE '\\'
)
""")
List<Long> findIdsBySearch(@Param("search") String search, @Param("candidateIds") List<Long> candidateIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,7 @@ public ResponseUserDTO changeUserRole(@NonNull Long userId, @NonNull Role newRol
throw new InsufficientPermissionsException();
}

String normalizedSearch = search == null || search.isBlank()
? null
: search.trim()
.replaceAll("\\s+", " ")
.replace("\\", "\\\\")
.replace("%", "\\%")
.replace("_", "\\_");
String normalizedSearch = normalizeSearch(search);

List<Role> normalizedRoles = roles == null || roles.isEmpty()
? null
Expand Down Expand Up @@ -167,4 +161,23 @@ public ResponseUserDTO changeUserRole(@NonNull Long userId, @NonNull Role newRol
user.setUserStatus(newStatus);
return mapper.toResponseUserDTO(repository.save(user));
}

@Override
public Optional<List<Long>> findUserIdsBySearch(String search, List<Long> candidateIds) {
String normalizedSearch = normalizeSearch(search);
if (normalizedSearch == null) {
return Optional.empty();
}
return Optional.of(repository.findIdsBySearch(normalizedSearch, candidateIds));
}

private String normalizeSearch(String search) {
return search == null || search.isBlank()
? null
: search.trim()
.replaceAll("\\s+", " ")
.replace("\\", "\\\\")
.replace("%", "\\%")
.replace("_", "\\_");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,21 @@ public interface UserService {
*/
@NonNull
ResponseUserDTO changeUserStatus(@NonNull Long userId, @NonNull UserStatus newStatus);

/**
* Filters a provided list of candidate user IDs based on a text search against
* the user's first name, surname or email, required by
* {@code UserFacade.findUserIdsBySearchWithinIds}.
* <p>
* This method is designed to perform a constrained search. Instead of searching
* the entire database, it only searches within the provided
* {@code candidateIds}.
* </p>
*
* @param search the text search query (e.g., "Ivan", "ivan@email.com").
* @param candidateIds the pool of user IDs to restrict the search to.
* @return an {@code Optional} containing the filtered list of matching user
* IDs, or {@code Optional.empty()} if the search string is null/blank.
*/
Optional<List<Long>> findUserIdsBySearch(String search, List<Long> candidateIds);
}
Loading