Skip to content

Commit

Permalink
Implemented search users
Browse files Browse the repository at this point in the history
  • Loading branch information
ScarletRedMan committed Jan 31, 2024
1 parent 3e679f2 commit be203cc
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ default List<RUser> all(RRoom room) throws NodeNotFoundException, RoomNotFoundEx
}

List<RUser> all(RRoom room, Set<UserDetails> details) throws NodeNotFoundException, RoomNotFoundException;

List<RUser> search(String input, Set<UserDetails> details);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.dragonestia.picker.api.repository.response;

import ru.dragonestia.picker.api.repository.response.type.RUser;

import java.util.List;

public record SearchUserResponse(List<RUser> users) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ru.dragonestia.picker.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ru.dragonestia.picker.api.repository.details.UserDetails;
import ru.dragonestia.picker.api.repository.response.SearchUserResponse;
import ru.dragonestia.picker.service.UserService;
import ru.dragonestia.picker.util.NamingValidator;

import java.util.HashSet;
import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/users")
public class UserController {

private final UserService userService;
private final NamingValidator namingValidator;

@GetMapping("/search")
SearchUserResponse search(@RequestParam(name = "input") String input,
@RequestParam(name = "requiredDetails", required = false, defaultValue = "") String detailsSeq) {

if (!namingValidator.validateUserId(input) || input.isEmpty()) {
return new SearchUserResponse(List.of());
}

var details = new HashSet<UserDetails>();
for (var detailStr: detailsSeq.split(",")) {
try {
details.add(UserDetails.valueOf(detailStr.toUpperCase()));
} catch (IllegalArgumentException ignore) {}
}

return new SearchUserResponse(userService.searchUsers(input, details));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ru.dragonestia.picker.repository;

import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.api.repository.response.type.RUser;
import ru.dragonestia.picker.model.Room;
import ru.dragonestia.picker.model.User;

Expand All @@ -19,4 +20,6 @@ public interface UserRepository {
void onRemoveRoom(Room room);

List<User> usersOf(Room room);

List<User> search(String input);
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ public List<User> usersOf(Room room) {
}
}

@Override
public List<User> search(String input) {
synchronized (usersMap) {
return usersMap.keySet().stream()
.filter(user -> user.id().startsWith(input))
.sorted(Comparator.comparing(User::id))
.toList();
}
}

private record NodeRoomPath(String node, String bucket) {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public interface UserService {
List<User> getRoomUsers(Room room);

List<RUser> getRoomUsersWithDetailsResponse(Room room, Set<UserDetails> details);

List<RUser> searchUsers(String input, Set<UserDetails> details);
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,20 @@ public List<RUser> getRoomUsersWithDetailsResponse(Room room, Set<UserDetails> d
}
return users;
}

@Override
public List<RUser> searchUsers(String input, Set<UserDetails> details) {
return userRepository.search(input).stream()
.map(user -> {
var responseUser = user.toResponseObject();

for (var detail: details) {
if (detail == UserDetails.COUNT_ROOMS) {
responseUser.putDetail(UserDetails.COUNT_ROOMS, Integer.toString(getUserRooms(user).size()));
}
}

return responseUser;
}).toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void validateRoomId(String nodeId, String input) throws InvalidRoomIdenti
throw new InvalidRoomIdentifierException(nodeId, input);
}

private boolean validateUserId(String input) {
public boolean validateUserId(String input) {
return ValidateIdentifier.forUser(input);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private Component createLogo() {
private SideNav createSideNav() {
var nav = new SideNav();
nav.addItem(new SideNavItem("Nodes list", NodesPage.class, VaadinIcon.FOLDER_O.create()));
nav.addItem(new SideNavItem("Search users", HomePage.class, VaadinIcon.SEARCH.create()));
nav.addItem(new SideNavItem("Search users", UserSearchPage.class, VaadinIcon.SEARCH.create()));
nav.addItem(new SideNavItem("Documentation", "https://github.com/ScarletRedMan/RoomPicker", VaadinIcon.BOOK.create()));
nav.addItem(new SideNavItem("Sign-out", HomePage.class, VaadinIcon.SIGN_OUT.create()));
return nav;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ru.dragonestia.picker.cp.page;

import com.vaadin.flow.component.Unit;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired;
import ru.dragonestia.picker.api.repository.UserRepository;
import ru.dragonestia.picker.api.repository.details.UserDetails;
import ru.dragonestia.picker.api.repository.response.type.RUser;
import ru.dragonestia.picker.cp.component.Notifications;

import java.util.LinkedList;
import java.util.List;

@PageTitle("Search users")
@Route(value = "/users", layout = MainLayout.class)
public class UserSearchPage extends VerticalLayout {

private final UserRepository userRepository;
private final TextField fieldUsername;
private final Grid<RUser> userGrid;
private List<RUser> cachedUsers = new LinkedList<>();

@Autowired
public UserSearchPage(UserRepository userRepository) {
this.userRepository = userRepository;

add(fieldUsername = createUsernameInputField());
add(userGrid = createUserGrid());
}

private TextField createUsernameInputField() {
var field = new TextField();
field.setLabel("Username");
field.setPlaceholder("some-user-identifier");
field.setRequired(true);
field.setMinWidth(30, Unit.PERCENTAGE);

var button = new Button(new Icon(VaadinIcon.SEARCH));
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
button.getStyle().set("color", "#FFFFFF");
button.addClickListener(event -> search(fieldUsername.getValue().trim()));

field.setSuffixComponent(button);
return field;
}

private Grid<RUser> createUserGrid() {
var grid = new Grid<RUser>();

grid.addColumn(RUser::getId).setHeader("Identifier")
.setFooter("Found %s users".formatted(cachedUsers.size()));

grid.addColumn(user -> user.getDetail(UserDetails.COUNT_ROOMS)).setTextAlign(ColumnTextAlign.CENTER).setHeader("Linked with rooms");

grid.addComponentColumn(user -> new Span("buttons")).setHeader("Manage"); // TODO

return grid;
}

private void search(String input) {
userGrid.setItems(cachedUsers = userRepository.search(input, UserRepository.ALL_DETAILS));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import ru.dragonestia.picker.api.exception.NodeNotFoundException;
import ru.dragonestia.picker.api.exception.RoomAreFullException;
import ru.dragonestia.picker.api.exception.RoomNotFoundException;
import ru.dragonestia.picker.api.repository.response.SearchUserResponse;
import ru.dragonestia.picker.api.repository.response.type.RRoom;
import ru.dragonestia.picker.api.repository.response.type.RUser;
import ru.dragonestia.picker.api.repository.UserRepository;
Expand Down Expand Up @@ -54,4 +55,17 @@ public List<RUser> all(RRoom room, Set<UserDetails> details) throws NodeNotFound
params.put("requiredDetails", detailsStr);
}).users();
}

@Override
public List<RUser> search(String input, Set<UserDetails> details) {
return rest.query("/users/search",
HttpMethod.GET,
SearchUserResponse.class,
params -> {
var detailsStr = String.join(",", details.stream().map(Enum::toString).toList());

params.put("requiredDetails", detailsStr);
params.put("input", input);
}).users();
}
}

0 comments on commit be203cc

Please sign in to comment.