Commit 10812270 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Generic search improvements: added checkboxes for filtering on users or groups

parent d245dfa9
...@@ -325,7 +325,9 @@ export default { ...@@ -325,7 +325,9 @@ export default {
}, },
search(input) { search(input) {
let url = BASE_API_URL + 'search?query=' + input.genericSearch.filter + let url = BASE_API_URL + 'search?query=' + input.genericSearch.filter +
'&page=' + input.genericSearch.paginatorPage + '&pageSize=' + input.genericSearch.paginatorPageSize; '&paginatorPage=' + input.genericSearch.paginatorPage +
'&paginatorPageSize=' + input.genericSearch.paginatorPageSize +
'&users=' + input.genericSearch.users + "&groups=" + input.genericSearch.groups;
return apiRequest({ return apiRequest({
method: 'GET', method: 'GET',
......
<template> <template>
<div class="mt-sm-3"> <div class="mt-sm-3">
<b-form inline>
Includes:
<b-form-checkbox class="ml-4" v-model="input.genericSearch.users" @input="updateTypeFilter">users</b-form-checkbox>
<b-form-checkbox class="ml-4" v-model="input.genericSearch.groups" @input="updateTypeFilter">groups</b-form-checkbox>
</b-form>
<div> <div>
<div v-if="model.genericSearchResults.items && model.genericSearchResults.items.length > 0"> <div v-if="model.genericSearchResults.items && model.genericSearchResults.items.length > 0">
<p>Search results:</p> <p>Search results:</p>
...@@ -40,7 +45,7 @@ export default { ...@@ -40,7 +45,7 @@ export default {
'$route': 'updateSearchResults' '$route': 'updateSearchResults'
}, },
methods: { methods: {
openSearchResult: function(result) { openSearchResult(result) {
switch (result.type) { switch (result.type) {
case 'GROUP': case 'GROUP':
this.$store.dispatch('openGroup', result.id); this.$store.dispatch('openGroup', result.id);
...@@ -50,7 +55,11 @@ export default { ...@@ -50,7 +55,11 @@ export default {
break; break;
} }
}, },
updateSearchResults: function() { updateTypeFilter() {
this.input.genericSearch.paginatorPage = 1;
this.updateSearchResults();
},
updateSearchResults() {
this.$store.dispatch('search', this.$route.query.q); this.$store.dispatch('search', this.$route.query.q);
} }
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<b-nav-item href="help/index.html" target="blank_" class="mr-4">Help</b-nav-item> <b-nav-item href="help/index.html" target="blank_" class="mr-4">Help</b-nav-item>
<b-nav-form> <b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search" v-model.trim="input.genericSearch.filter" @keydown.native.enter.prevent="genericSearch"></b-form-input> <b-form-input size="sm" class="mr-sm-2" placeholder="Search" v-model.trim="input.genericSearch.filter" @keydown.native.enter.prevent="genericSearch"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" type="button" v-on:click="genericSearch()">Search</b-button> <b-button size="sm" type="button" v-on:click="genericSearch()">Search</b-button>
</b-nav-form> </b-nav-form>
<b-nav-item-dropdown :text="user" right v-if="user"> <b-nav-item-dropdown :text="user" right v-if="user">
<b-dropdown-item href="logout">Logout</b-dropdown-item> <b-dropdown-item href="logout">Logout</b-dropdown-item>
...@@ -39,10 +39,8 @@ export default { ...@@ -39,10 +39,8 @@ export default {
this.$router.push('/', () => {}); this.$router.push('/', () => {});
}, },
genericSearch() { genericSearch() {
this.input.genericSearch.page = 1;
this.input.genericSearch.pageSize = 20;
this.$router.push({ path: '/search', query: { q: this.input.genericSearch.filter } }, () => {}); this.$router.push({ path: '/search', query: { q: this.input.genericSearch.filter } }, () => {});
this.$store.dispatch('search', this.input.genericSearch.filter); this.$store.commit('setGenericSearchFilter', this.input.genericSearch.filter);
} }
} }
} }
......
...@@ -36,7 +36,9 @@ export default new Vuex.Store({ ...@@ -36,7 +36,9 @@ export default new Vuex.Store({
genericSearch: { genericSearch: {
filter: '', filter: '',
paginatorPage: 1, paginatorPage: 1,
paginatorPageSize: 20 paginatorPageSize: 20,
users: true,
groups: true
} }
}, },
loading: false loading: false
...@@ -97,6 +99,10 @@ export default new Vuex.Store({ ...@@ -97,6 +99,10 @@ export default new Vuex.Store({
}, },
setGenericSearchFilter(state, filter) { setGenericSearchFilter(state, filter) {
state.input.genericSearch.filter = filter; state.input.genericSearch.filter = filter;
state.input.genericSearch.paginatorPage = 1;
state.input.genericSearch.paginatorPageSize = 20;
state.input.genericSearch.users = true;
state.input.genericSearch.groups = true;
}, },
removeInvitedRegistration(state, regId) { removeInvitedRegistration(state, regId) {
let index = -1; let index = -1;
...@@ -117,7 +123,9 @@ export default new Vuex.Store({ ...@@ -117,7 +123,9 @@ export default new Vuex.Store({
.then(model => commit('updateHomePageModel', model)); .then(model => commit('updateHomePageModel', model));
}, },
search({ commit, state }, filter) { search({ commit, state }, filter) {
commit('setGenericSearchFilter', filter); if (state.input.genericSearch.filter !== filter) {
commit('setGenericSearchFilter', filter);
}
client.search(state.input) client.search(state.input)
.then(results => commit('displaySearchResults', results)); .then(results => commit('displaySearchResults', results));
}, },
......
package it.inaf.ia2.gms.controller; package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.model.request.GenericSearchRequest;
import it.inaf.ia2.gms.model.response.PaginatedData; import it.inaf.ia2.gms.model.response.PaginatedData;
import it.inaf.ia2.gms.model.response.SearchResponseItem; import it.inaf.ia2.gms.model.response.SearchResponseItem;
import it.inaf.ia2.gms.model.response.UserSearchResponse; import it.inaf.ia2.gms.model.response.UserSearchResponse;
import it.inaf.ia2.gms.service.SearchService; import it.inaf.ia2.gms.service.SearchService;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
...@@ -23,10 +24,8 @@ public class SearchController { ...@@ -23,10 +24,8 @@ public class SearchController {
private SearchService searchService; private SearchService searchService;
@GetMapping(value = "/search", produces = MediaType.APPLICATION_JSON_VALUE) @GetMapping(value = "/search", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PaginatedData<SearchResponseItem>> getSearchResults(@RequestParam("query") String query, public ResponseEntity<PaginatedData<SearchResponseItem>> getSearchResults(@Valid GenericSearchRequest searchRequest) {
@RequestParam("page") int page, @RequestParam("pageSize") int pageSize) { PaginatedData<SearchResponseItem> response = searchService.search(searchRequest, servletRequest.getUserPrincipal().getName());
PaginatedData<SearchResponseItem> response = searchService.search(query, servletRequest.getUserPrincipal().getName(), page, pageSize);
return ResponseEntity.ok(response); return ResponseEntity.ok(response);
} }
......
package it.inaf.ia2.gms.model.request;
public class GenericSearchRequest extends PaginatedModelRequest {
private String query;
private boolean users;
private boolean groups;
public GenericSearchRequest() {
this.users = true;
this.groups = true;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public boolean isUsers() {
return users;
}
public void setUsers(boolean users) {
this.users = users;
}
public boolean isGroups() {
return groups;
}
public void setGroups(boolean groups) {
this.groups = groups;
}
}
...@@ -8,6 +8,11 @@ public class PaginatedModelRequest { ...@@ -8,6 +8,11 @@ public class PaginatedModelRequest {
private int paginatorPage; private int paginatorPage;
private int paginatorPageSize; private int paginatorPageSize;
public PaginatedModelRequest() {
this.paginatorPage = 1;
this.paginatorPageSize = 20;
}
public int getPaginatorPage() { public int getPaginatorPage() {
return paginatorPage; return paginatorPage;
} }
......
...@@ -14,6 +14,7 @@ import it.inaf.ia2.gms.persistence.PermissionsDAO; ...@@ -14,6 +14,7 @@ import it.inaf.ia2.gms.persistence.PermissionsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity; import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity; import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.authn.RapClient; import it.inaf.ia2.gms.authn.RapClient;
import it.inaf.ia2.gms.model.request.GenericSearchRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -46,15 +47,21 @@ public class SearchService { ...@@ -46,15 +47,21 @@ public class SearchService {
/** /**
* Generic search (both groups and users). * Generic search (both groups and users).
*/ */
public PaginatedData<SearchResponseItem> search(String query, String userId, int page, int pageSize) { public PaginatedData<SearchResponseItem> search(GenericSearchRequest searchRequest, String userId) {
List<SearchResponseItem> items = searchUsers(query); List<SearchResponseItem> items = new ArrayList<>();
items.addAll(searchGroups(query, userId));
if (searchRequest.isUsers()) {
items.addAll(searchUsers(searchRequest.getQuery()));
}
if (searchRequest.isGroups()) {
items.addAll(searchGroups(searchRequest.getQuery(), userId));
}
// sort by label // sort by label
items.sort((i1, i2) -> i1.getLabel().compareTo(i2.getLabel())); items.sort((i1, i2) -> i1.getLabel().compareTo(i2.getLabel()));
return new PaginatedData<>(items, page, pageSize); return new PaginatedData<>(items, searchRequest.getPaginatorPage(), searchRequest.getPaginatorPageSize());
} }
private List<SearchResponseItem> searchUsers(String query) { private List<SearchResponseItem> searchUsers(String query) {
......
...@@ -8,11 +8,14 @@ import it.inaf.ia2.gms.model.response.UserSearchResponse; ...@@ -8,11 +8,14 @@ import it.inaf.ia2.gms.model.response.UserSearchResponse;
import it.inaf.ia2.gms.service.SearchService; import it.inaf.ia2.gms.service.SearchService;
import java.util.ArrayList; import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
...@@ -53,13 +56,20 @@ public class SearchControllerTest { ...@@ -53,13 +56,20 @@ public class SearchControllerTest {
PaginatedData<SearchResponseItem> response = new PaginatedData<>(new ArrayList<>(), 1, 10); PaginatedData<SearchResponseItem> response = new PaginatedData<>(new ArrayList<>(), 1, 10);
when(searchService.search(any(), any(), anyInt(), anyInt())).thenReturn(response); when(searchService.search(any(), any())).thenReturn(response);
mockMvc.perform(get("/search?query=searchText&page=1&pageSize=10") mockMvc.perform(get("/search?query=searchText&paginatorPage=1&paginatorPageSize=10&groups=false")
.contentType(MediaType.APPLICATION_JSON_VALUE)) .contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk()); .andExpect(status().isOk());
verify(searchService, times(1)).search(eq("searchText"), eq("admin_id"), eq(1), eq(10)); verify(searchService, times(1)).search(argThat(req -> {
assertEquals("searchText", req.getQuery());
assertEquals(1, req.getPaginatorPage());
assertEquals(10, req.getPaginatorPageSize());
assertTrue(req.isUsers());
assertFalse(req.isGroups());
return true;
}), eq("admin_id"));
} }
@Test @Test
......
...@@ -12,6 +12,7 @@ import it.inaf.ia2.gms.persistence.PermissionsDAO; ...@@ -12,6 +12,7 @@ import it.inaf.ia2.gms.persistence.PermissionsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity; import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity; import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.authn.RapClient; import it.inaf.ia2.gms.authn.RapClient;
import it.inaf.ia2.gms.model.request.GenericSearchRequest;
import it.inaf.ia2.rap.data.Identity; import it.inaf.ia2.rap.data.Identity;
import it.inaf.ia2.rap.data.IdentityType; import it.inaf.ia2.rap.data.IdentityType;
import it.inaf.ia2.rap.data.RapUser; import it.inaf.ia2.rap.data.RapUser;
...@@ -118,7 +119,10 @@ public class SearchServiceTest { ...@@ -118,7 +119,10 @@ public class SearchServiceTest {
when(permissionsDAO.findUserPermissions(any())).thenReturn( when(permissionsDAO.findUserPermissions(any())).thenReturn(
Collections.singletonList(permission)); Collections.singletonList(permission));
PaginatedData<SearchResponseItem> response = searchService.search("foo", "manager_id", 1, 10); GenericSearchRequest searchRequest = new GenericSearchRequest();
searchRequest.setQuery("foo");
PaginatedData<SearchResponseItem> response = searchService.search(searchRequest, "manager_id");
assertEquals(2, response.getTotalItems()); assertEquals(2, response.getTotalItems());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment