Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add search for users #86

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
@@ -1,18 +1,23 @@
package com.exelaration.abstractmemery.controllers;

import com.exelaration.abstractmemery.domains.ApplicationUser;
import com.exelaration.abstractmemery.services.UserService;
import com.exelaration.abstractmemery.services.implementations.UserDetailsServiceImpl;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

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

@Autowired private UserService userService;
@Autowired private UserDetailsServiceImpl userDetailsService;

@PostMapping("/sign-up")
Expand All @@ -32,4 +37,9 @@ public String updateSettings(@RequestBody ApplicationUser user) {
}
return "User already exists";
}

@GetMapping(value = "/", params = "text")
public ArrayList<String> getUsersForSearch(@RequestParam String text) throws Exception {
return userService.getUsersWithText(text);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.exelaration.abstractmemery.projections;

public interface UserProjection {
String getUsername();

void setUsername(String username);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.exelaration.abstractmemery.repositories;

import com.exelaration.abstractmemery.domains.ApplicationUser;
import com.exelaration.abstractmemery.projections.UserProjection;
import java.util.ArrayList;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<ApplicationUser, Integer> {
ApplicationUser findByUsername(String username);

ArrayList<UserProjection> findByUsernameIgnoreCaseContains(String username);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.exelaration.abstractmemery.services;

import java.util.ArrayList;
import javax.transaction.Transactional;

@Transactional
public interface UserService {

public ArrayList<String> getUsersWithText(String text);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.exelaration.abstractmemery.services.implementations;

import com.exelaration.abstractmemery.projections.UserProjection;
import com.exelaration.abstractmemery.repositories.UserRepository;
import com.exelaration.abstractmemery.services.UserService;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements UserService {

@Autowired private UserRepository userRepository;

public ArrayList<String> getUsersWithText(String username) {
ArrayList<UserProjection> usernamesProjections =
userRepository.findByUsernameIgnoreCaseContains(username);
ArrayList<String> usernames = new ArrayList<String>();
for (UserProjection name : usernamesProjections) {
usernames.add(name.getUsername());
}
return usernames;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.exelaration.abstractmemery.controllers;

import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

import com.exelaration.abstractmemery.domains.ApplicationUser;
import com.exelaration.abstractmemery.services.UserService;
import com.exelaration.abstractmemery.services.implementations.UserDetailsServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -27,6 +31,7 @@ public class UserControllerTest {
private MockMvc mockMvc;
@Autowired private UserController userController;
@MockBean private UserDetailsServiceImpl userDetailsService;
@MockBean private UserService userService;

@BeforeEach
public void setUp() {
Expand Down Expand Up @@ -93,4 +98,36 @@ public void UserControllerTest_WhenRegisterFails_ExpectStatus400() throws Except
.content(new ObjectMapper().writeValueAsString(testUser)))
.andExpect(badRequest);
}

@Test
public void getUsersForSearch_WhenUsersExist_Expect200andArray() throws Exception {
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
String url = "/users/?text=test";

ArrayList<String> expectedUsernames = new ArrayList<String>();
expectedUsernames.add("[email protected]");
when(userService.getUsersWithText(any())).thenReturn(expectedUsernames);

mockMvc
.perform(MockMvcRequestBuilders.get(url))
.andExpect(ok)
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0]", is("[email protected]")));
}

@Test
public void getUsersForSearch_WhenUsersDoesNotExist_Expect200andEmptyArray() throws Exception {
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
String url = "/users/?text=test";

ArrayList<String> expectedUsernames = new ArrayList<String>();
when(userService.getUsersWithText(any())).thenReturn(expectedUsernames);

mockMvc
.perform(MockMvcRequestBuilders.get(url))
.andExpect(ok)
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$", hasSize(0)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.exelaration.abstractmemery.services;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.exelaration.abstractmemery.projections.UserProjection;
import com.exelaration.abstractmemery.repositories.UserRepository;
import com.exelaration.abstractmemery.services.implementations.UserServiceImpl;
import java.util.ArrayList;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
public class UserServiceTest {
@Mock private UserRepository userRepository;
@InjectMocks private UserServiceImpl userService;

@BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
}

@Test
public void getUsersWithText_WhenUsersExist_ExpectArray() {
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
UserProjection userProjection = factory.createProjection(UserProjection.class);
userProjection.setUsername("[email protected]");
ArrayList<UserProjection> returnedUsernames = new ArrayList<UserProjection>();
returnedUsernames.add(userProjection);
Mockito.when(userRepository.findByUsernameIgnoreCaseContains("test"))
.thenReturn(returnedUsernames);

ArrayList<String> expectedUsernames = new ArrayList<String>();
expectedUsernames.add("[email protected]");
assertEquals(expectedUsernames, userService.getUsersWithText("test"));
}

@Test
public void getUsersWithText_WhenUsersDoesNotExist_ExpectArray() {
ArrayList<UserProjection> returnedUsernames = new ArrayList<UserProjection>();
Mockito.when(userRepository.findByUsernameIgnoreCaseContains("test"))
.thenReturn(returnedUsernames);
ArrayList<String> expectedUsernames = new ArrayList<String>();
assertEquals(expectedUsernames, userService.getUsersWithText("test"));
}
}
68 changes: 48 additions & 20 deletions ui/src/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ function SearchPage(props: any) {
const [memeResponses, setMemeResponses] = useState([]);
const [displayMessage, setDisplayMessage] = useState("");
const [isValid, setIsValid] = useState(true);
const [usernamesResponse, setUsernames] = useState([]);

useEffect(() => {
function getSearchURLs() {
Expand All @@ -29,6 +30,22 @@ function SearchPage(props: any) {
getSearchURLs();
}, [props.match.params.text]);

useEffect(() => {
function getUsernames() {
const response = axios
.get("http://localhost:8080/users/?text=" + props.match.params.text)
.then((response) => {
const usernamesResponse = response.data;
setUsernames(usernamesResponse);
})
.catch((error) => {
setDisplayMessage("There are no Users with this search criteria");
});
return response;
}
getUsernames();
}, [props.match.params.text]);

if (!isValid) {
return (
<div className="search">
Expand All @@ -39,18 +56,12 @@ function SearchPage(props: any) {
</header>
</div>
);
} else if (memeResponses.length === 0) {
return (
<div className="search">
<NavBar></NavBar>
<header className="searchHeader">
<h1>Search Results</h1>
<div>There are no images with this search criteria</div>
</header>
</div>
);
}
let memes;
if (memeResponses.length === 0) {
memes = <div>No image exists with this search criteria</div>;
} else {
const memes = memeResponses.map(function (meme) {
memes = memeResponses.map(function (meme) {
return (
<div key={meme["id"]}>
{" "}
Expand All @@ -63,16 +74,33 @@ function SearchPage(props: any) {
</div>
);
});
}

return (
<div className="search">
<NavBar></NavBar>
<header className="searchHeader">
<h1>Search Results</h1>
<ul>{memes}</ul>
</header>
</div>
);
let usernames;
if (usernamesResponse.length === 0) {
usernames = <div>No users exist with this search criteria</div>;
} else {
usernames = usernamesResponse.map(function (username) {
return (
<div>
{" "}
<div>{username}</div>
</div>
);
});
}

return (
<div className="search">
<NavBar></NavBar>
<header className="searchHeader">
<h1>Search Results</h1>
<h2>Users</h2>
<ul>{usernames}</ul>
<h2>Memes</h2>
<ul>{memes}</ul>
</header>
</div>
);
}
export default SearchPage;