diff --git a/gms-ui/src/api/server/index.js b/gms-ui/src/api/server/index.js index cfb352e6cf78c9b814732462a06512e1fbbcc1ab..b73e02220319d8c4a7689bfa9cad65261831d35d 100644 --- a/gms-ui/src/api/server/index.js +++ b/gms-ui/src/api/server/index.js @@ -325,7 +325,9 @@ export default { }, search(input) { 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({ method: 'GET', diff --git a/gms-ui/src/components/GenericSearchResults.vue b/gms-ui/src/components/GenericSearchResults.vue index ea163ca4b3ced10e2d33fa9d1ddff5162ba78381..781de5b59740c198454f7dadce5204f358581ff1 100644 --- a/gms-ui/src/components/GenericSearchResults.vue +++ b/gms-ui/src/components/GenericSearchResults.vue @@ -1,5 +1,10 @@ <template> <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 v-if="model.genericSearchResults.items && model.genericSearchResults.items.length > 0"> <p>Search results:</p> @@ -40,7 +45,7 @@ export default { '$route': 'updateSearchResults' }, methods: { - openSearchResult: function(result) { + openSearchResult(result) { switch (result.type) { case 'GROUP': this.$store.dispatch('openGroup', result.id); @@ -50,7 +55,11 @@ export default { break; } }, - updateSearchResults: function() { + updateTypeFilter() { + this.input.genericSearch.paginatorPage = 1; + this.updateSearchResults(); + }, + updateSearchResults() { this.$store.dispatch('search', this.$route.query.q); } } diff --git a/gms-ui/src/components/TopMenu.vue b/gms-ui/src/components/TopMenu.vue index 1d92647b143783247a86d2e6bc14f8db81ad99f6..71ad85afc939d2012a46b51e272da1884e1c221c 100644 --- a/gms-ui/src/components/TopMenu.vue +++ b/gms-ui/src/components/TopMenu.vue @@ -12,7 +12,7 @@ <b-nav-item href="help/index.html" target="blank_" class="mr-4">Help</b-nav-item> <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-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-item-dropdown :text="user" right v-if="user"> <b-dropdown-item href="logout">Logout</b-dropdown-item> @@ -39,10 +39,8 @@ export default { this.$router.push('/', () => {}); }, genericSearch() { - this.input.genericSearch.page = 1; - this.input.genericSearch.pageSize = 20; 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); } } } diff --git a/gms-ui/src/store.js b/gms-ui/src/store.js index d4026005be31b2064fc94f8f165287f3980b4b23..9d8ffa828db3dde6d36cae49dfe779466b2e2e6c 100644 --- a/gms-ui/src/store.js +++ b/gms-ui/src/store.js @@ -36,7 +36,9 @@ export default new Vuex.Store({ genericSearch: { filter: '', paginatorPage: 1, - paginatorPageSize: 20 + paginatorPageSize: 20, + users: true, + groups: true } }, loading: false @@ -97,6 +99,10 @@ export default new Vuex.Store({ }, setGenericSearchFilter(state, 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) { let index = -1; @@ -117,7 +123,9 @@ export default new Vuex.Store({ .then(model => commit('updateHomePageModel', model)); }, search({ commit, state }, filter) { - commit('setGenericSearchFilter', filter); + if (state.input.genericSearch.filter !== filter) { + commit('setGenericSearchFilter', filter); + } client.search(state.input) .then(results => commit('displaySearchResults', results)); }, diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/SearchController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/SearchController.java index a7fcc04bd49d13e89763ad95920004261b1d32b6..20c18fc56c5be28c617b3f937368204ede895dc2 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/SearchController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/SearchController.java @@ -1,16 +1,17 @@ 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.SearchResponseItem; import it.inaf.ia2.gms.model.response.UserSearchResponse; import it.inaf.ia2.gms.service.SearchService; import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -23,10 +24,8 @@ public class SearchController { private SearchService searchService; @GetMapping(value = "/search", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<PaginatedData<SearchResponseItem>> getSearchResults(@RequestParam("query") String query, - @RequestParam("page") int page, @RequestParam("pageSize") int pageSize) { - - PaginatedData<SearchResponseItem> response = searchService.search(query, servletRequest.getUserPrincipal().getName(), page, pageSize); + public ResponseEntity<PaginatedData<SearchResponseItem>> getSearchResults(@Valid GenericSearchRequest searchRequest) { + PaginatedData<SearchResponseItem> response = searchService.search(searchRequest, servletRequest.getUserPrincipal().getName()); return ResponseEntity.ok(response); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/request/GenericSearchRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/request/GenericSearchRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..da973b458c471c5a7676f7cebb9f2a4848b8cfd9 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/model/request/GenericSearchRequest.java @@ -0,0 +1,37 @@ +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; + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/request/PaginatedModelRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/request/PaginatedModelRequest.java index 7910d69f1f50bd9d2bc1855902c073ebc35134bb..5c64c250a81759b472580f5a3dd92e378a7e1377 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/model/request/PaginatedModelRequest.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/request/PaginatedModelRequest.java @@ -8,6 +8,11 @@ public class PaginatedModelRequest { private int paginatorPage; private int paginatorPageSize; + public PaginatedModelRequest() { + this.paginatorPage = 1; + this.paginatorPageSize = 20; + } + public int getPaginatorPage() { return paginatorPage; } diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/SearchService.java b/gms/src/main/java/it/inaf/ia2/gms/service/SearchService.java index 9cd5d43e8f88e099e69b2e7ed85ab99dc2cc889e..47f45d814b58ddcb551e810947543f8a031b4c78 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/service/SearchService.java +++ b/gms/src/main/java/it/inaf/ia2/gms/service/SearchService.java @@ -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.PermissionEntity; import it.inaf.ia2.gms.authn.RapClient; +import it.inaf.ia2.gms.model.request.GenericSearchRequest; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -46,15 +47,21 @@ public class SearchService { /** * 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); - items.addAll(searchGroups(query, userId)); + List<SearchResponseItem> items = new ArrayList<>(); + + if (searchRequest.isUsers()) { + items.addAll(searchUsers(searchRequest.getQuery())); + } + if (searchRequest.isGroups()) { + items.addAll(searchGroups(searchRequest.getQuery(), userId)); + } // sort by label 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) { diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/SearchControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/SearchControllerTest.java index bfe0b1a1bb7b81ff65c4010b430779c011d2d1f5..4c98a67d48a48ac6b28df19edb294eb5a055a021 100644 --- a/gms/src/test/java/it/inaf/ia2/gms/controller/SearchControllerTest.java +++ b/gms/src/test/java/it/inaf/ia2/gms/controller/SearchControllerTest.java @@ -8,11 +8,14 @@ import it.inaf.ia2.gms.model.response.UserSearchResponse; import it.inaf.ia2.gms.service.SearchService; import java.util.ArrayList; 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.Test; import org.junit.runner.RunWith; 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 org.mockito.InjectMocks; import org.mockito.Mock; @@ -53,13 +56,20 @@ public class SearchControllerTest { 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)) .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 diff --git a/gms/src/test/java/it/inaf/ia2/gms/service/SearchServiceTest.java b/gms/src/test/java/it/inaf/ia2/gms/service/SearchServiceTest.java index 8cd002411bc75be3d45a482c9e28eb87770cb64e..1ed36a442c5e5b8b5853af588d5179d8d09851ec 100644 --- a/gms/src/test/java/it/inaf/ia2/gms/service/SearchServiceTest.java +++ b/gms/src/test/java/it/inaf/ia2/gms/service/SearchServiceTest.java @@ -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.PermissionEntity; 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.IdentityType; import it.inaf.ia2.rap.data.RapUser; @@ -118,7 +119,10 @@ public class SearchServiceTest { when(permissionsDAO.findUserPermissions(any())).thenReturn( 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());