Skip to content
Snippets Groups Projects
Commit d9e8fd00 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Search functionality

parent b9d62a20
No related branches found
No related tags found
No related merge requests found
Showing
with 618 additions and 62 deletions
......@@ -19,3 +19,21 @@ To build the image:
To run:
docker run --env-file docker-env -d -p 8081:8081 -i -t gms:latest
## Developer notes
Backend and frontend are 2 separate applications:
* the backend is the Maven application in the gms folder, based on Java and Spring Boot;
* the frontend is the npm application is the gms-ui folder, based on Vue.js.
The Maven application automatically packs the Vue.js products inside the final jar, however the frontend application can be tested isolatedly running `npm run serve` in order to take advantage of the npm autoreload functionalities.
By default http calls are mocked inside the Vue.js application.
In order to rely on real server calls edit the .env.development file in this way:
VUE_APP_API_CLIENT = 'server'
VUE_APP_API_BASE_URL = 'http://localhost:8081/gms/'
This assumes that your backend runs on 8081 port (with dev profile active, in order to enable the CORS policy) and the frontend runs on 8080 port.
First, do the login using the application running on the 8081 port, then you can access the frontend on the 8080.
<template>
<div id="app" v-if="model">
<TopMenu v-bind:user="model.user" />
<div class="container">
<Main />
</div>
<div id="loading" v-if="loading">
<div id="spinner-wrapper">
<b-spinner variant="primary" style="width: 3rem; height: 3rem;" label="Loading"></b-spinner>
</div>
<div id="app" v-if="model">
<TopMenu v-bind:user="model.user" />
<div class="container">
<Main v-if="page === 'main'" />
<GenericSearchResults v-if="page === 'search'" />
<UserSearchResult v-if="page === 'userSearch'" />
</div>
<div id="loading" v-if="loading">
<div id="spinner-wrapper">
<b-spinner variant="primary" style="width: 3rem; height: 3rem;" label="Loading"></b-spinner>
</div>
</div>
</div>
</template>
<script>
import TopMenu from './components/TopMenu.vue';
import Main from './components/Main.vue';
import { mapState } from 'vuex';
import GenericSearchResults from './components/GenericSearchResults.vue';
import UserSearchResult from './components/UserSearchResult.vue';
import {
mapState
} from 'vuex';
import client from 'api-client';
export default {
name: 'app',
components: {
TopMenu,
Main
Main,
GenericSearchResults,
UserSearchResult
},
computed: mapState({
model: state => state.model,
input: state => state.input,
loading: state => state.loading
loading: state => state.loading,
page: state => state.page
}),
mounted: function() {
var self = this;
document.addEventListener('apiError', function (event) {
document.addEventListener('apiError', function(event) {
self.$bvToast.toast(event.message, {
title: "Error",
variant: 'danger',
solid: true
});
});
document.addEventListener('loading', function (event) {
document.addEventListener('loading', function(event) {
self.$store.commit('setLoading', event.value);
});
......
{
"groups": [{
"id": "744e38e8f6d04e4e9418ae5f131c9b6b",
"name": "LBT",
"path": "744e38e8f6d04e4e9418ae5f131c9b6b"
}],
"permissions": [{
"userId": "4",
"groupId": "744e38e8f6d04e4e9418ae5f131c9b6b",
"permission": "VIEW_MEMBERS",
"groupPath": "744e38e8f6d04e4e9418ae5f131c9b6b"
}]
}
{
"items": [{
"id": "4",
"type": "USER",
"label": "Name Surname"
},
{
"id": "group_id",
"type": "GROUP",
"label": "Group 1"
}
],
"currentPage": 1,
"links": [1],
"totalItems": 2,
"pageSize": 20,
"totalPages": 1,
"hasPreviousPages": false,
"hasFollowingPages": false
}
......@@ -5,6 +5,8 @@ import membersPanel from './data/membersPanel';
import permissionsPanel from './data/permissionsPanel';
import searchUser from './data/searchUser';
import permission from './data/permission';
import search from './data/search';
import openUserSearchResult from './data/openUserSearchResult';
const fetch = (mockData, time = 0) => {
return new Promise((resolve) => {
......@@ -56,5 +58,11 @@ export default {
},
removeMember() {
return fetch(membersPanel, 500);
},
search() {
return fetch(search, 500);
},
openUserSearchResult() {
return fetch(openUserSearchResult, 500);
}
}
......@@ -275,5 +275,32 @@ export default {
'Accept': 'application/json',
}
});
},
search(input) {
let url = BASE_API_URL + 'search?query=' + input.genericSearch.filter +
'&page=' + input.genericSearch.paginatorPage + '&pageSize=' + input.genericSearch.paginatorPageSize;
return apiRequest(url, {
method: 'GET',
cache: 'no-cache',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
});
},
openUserSearchResult(userId) {
let url = BASE_API_URL + 'search/user/' + userId;
return apiRequest(url, {
method: 'GET',
cache: 'no-cache',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
});
}
};
<template>
<div class="mt-sm-3">
<div>
<p>Search results:</p>
<b-list-group v-for="item in model.genericSearchResults.items" v-bind:key="item.id">
<b-list-group-item href="#" v-on:click="openSearchResult(item)">
<span class="float-left">
<font-awesome-icon icon="folder" v-if="item.type === 'GROUP'"></font-awesome-icon>
<font-awesome-icon icon="user" v-if="item.type === 'USER'"></font-awesome-icon>
{{item.label}}
</span>
</b-list-group-item>
</b-list-group>
<Paginator :paginatedPanel="model.genericSearchResults" :onUpdate="updateSearchResults" />
</div>
</div>
</template>
<script>
import client from 'api-client';
import Paginator from './Paginator.vue';
import {
mapState
} from 'vuex';
export default {
name: 'GenericSearchResults',
components: {
Paginator
},
computed: mapState({
model: state => state.model,
input: state => state.input
}),
methods: {
openSearchResult: function(result) {
switch (result.type) {
case 'GROUP':
this.$store.commit('openGroup', result.id);
break;
case 'USER':
client.openUserSearchResult(result.id)
.then(model => {
this.$store.commit('displayUserSearchResults', [result.label, model]);
});
break;
}
},
updateSearchResults: function() {
}
}
}
</script>
......@@ -50,24 +50,9 @@ export default {
model: state => state.model,
input: state => state.input
}),
data: function() {
return {
groupFilter: ''
};
},
methods: {
openGroup: function(group) {
this.$store.state.input.selectedGroupId = group.groupId;
this.$store.state.input.searchFilter = null;
client.fetchGroupsTab(this.input)
.then(model => {
if (model.groupsPanel.items.length > 0) {
this.$store.commit('updateGroups', model);
} else {
// If there are no subgroups show the members panel
this.$store.commit('setTabIndex', '1');
}
});
this.$store.commit('openGroup', group.groupId);
},
openRenameGroupModal: function(group) {
this.$refs.renameGroupModal.openRenameGroupModal(group);
......
<template>
<div>
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand href="#" class="d-none d-md-block">Group Membership Service</b-navbar-brand>
<b-navbar-brand href="#" class="d-none d-md-block" v-on:click="showMainPage">Group Membership Service</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
......@@ -9,12 +9,10 @@
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
<!--
<b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search" v-model="input.genericSearch.filter"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" 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>
</b-nav-item-dropdown>
......@@ -25,10 +23,31 @@
</template>
<script>
import client from 'api-client';
import {
mapState
} from 'vuex';
export default {
name: 'TopMenu',
props: {
user: String
},
computed: mapState({
input: state => state.input,
}),
methods: {
showMainPage() {
this.$store.commit('showMainPage');
},
genericSearch() {
this.input.genericSearch.page = 1;
this.input.genericSearch.pageSize = 20;
client.search(this.input)
.then(results => {
this.$store.commit('displaySearchResults', results);
});
}
}
}
</script>
......
<template>
<div class="mt-sm-3" v-if="userLabel !== null">
<b-button variant="primary" class="float-right" v-on:click="back()">Back</b-button>
<h5>Results for <strong>{{userLabel}}</strong>:</h5>
<b-container class="mt-sm-5">
<b-row>
<b-col class="text-left">
<h5>Is member of</h5>
<div v-if="groups.length === 0">
No groups to show
</div>
<div v-if="groups.length > 0">
<ul>
<li v-for="group in groups" v-bind:key="group.groupId">
<a href="#" v-on:click="openGroup(group.groupId)">
{{group.groupCompleteName.join(' / ')}}
</a>
</li>
</ul>
</div>
</b-col>
<b-col v-if="permissions.length > 0">
<h5>Permissions</h5>
<table class="table table-striped">
<thead>
<tr>
<th>Group</th>
<th>Permission</th>
</tr>
</thead>
<tbody>
<tr v-for="(p, rowIndex) in permissions" v-bind:key="rowIndex">
<td>
<a href="#" v-on:click="openGroup(p.groupId)">
{{p.groupCompleteName.join(' / ')}}
</a>
</td>
<td>{{p.permission}}</td>
</tr>
</tbody>
</table>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
import {
mapState
} from 'vuex';
export default {
name: 'UserSearchResult',
computed: mapState({
userLabel: state => state.model.userSearchResults.userLabel,
groups: state => state.model.userSearchResults.groups,
permissions: state => state.model.userSearchResults.permissions
}),
methods: {
back() {
this.$store.commit('displaySearchResults');
},
openGroup(groupId) {
this.$store.commit('openGroup', groupId);
}
}
}
</script>
......@@ -5,10 +5,10 @@ import store from './store.js'
import './plugins/bootstrap-vue'
import App from './App.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faTrash, faEdit, faSpinner } from '@fortawesome/free-solid-svg-icons'
import { faTrash, faEdit, faSpinner, faFolder, faUser } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
library.add(faTrash, faEdit, faSpinner);
library.add(faTrash, faEdit, faSpinner, faFolder, faUser);
Vue.component('font-awesome-icon', FontAwesomeIcon);
......
......@@ -2,6 +2,7 @@
import Vue from 'vue';
import Vuex from 'vuex';
import client from 'api-client';
Vue.use(Vuex);
......@@ -14,7 +15,13 @@ export default new Vuex.Store({
permissionsPanel: null,
membersPanel: null,
permission: null,
user: null
user: null,
genericSearchResults: [],
userSearchResults: {
userLabel: null,
groups: {},
permissions: {}
}
},
// values used to perform API calls
input: {
......@@ -23,9 +30,15 @@ export default new Vuex.Store({
paginatorPage: 1,
selectedTab: 'groups',
tabIndex: 0,
searchFilter: null
searchFilter: null,
genericSearch: {
filter: null,
paginatorPage: 1,
paginatorPageSize: 20
}
},
loading: false
loading: false,
page: 'main'
},
mutations: {
updateHomePageModel(state, model) {
......@@ -34,6 +47,22 @@ export default new Vuex.Store({
this.state.model.permission = model.permission;
this.state.model.user = model.user;
},
openGroup(state, groupId) {
let input = this.state.input;
input.selectedGroupId = groupId;
input.searchFilter = null;
client.fetchGroupsTab(input)
.then(model => {
if (model.groupsPanel.items.length > 0) {
this.commit('setTabIndex', 0);
this.commit('updateGroups', model);
} else {
// If there are no subgroups show the members panel
this.commit('setTabIndex', 1);
}
this.commit('showMainPage');
});
},
updateGroups(state, model) {
this.state.model.breadcrumbs = model.breadcrumbs;
this.state.model.groupsPanel = model.groupsPanel;
......@@ -54,6 +83,24 @@ export default new Vuex.Store({
},
setLoading(state, loading) {
this.state.loading = loading;
},
showMainPage(state) {
this.state.page = 'main';
},
displaySearchResults(state, results) {
this.state.page = 'search';
if (results) {
this.state.model.genericSearchResults = results;
}
},
updateSearchResults(state, results) {
this.state.model.genericSearchResults = results;
},
displayUserSearchResults(state, data) {
this.state.page = 'userSearch';
this.state.model.userSearchResults.userLabel = data[0];
this.state.model.userSearchResults.groups = data[1].groups;
this.state.model.userSearchResults.permissions = data[1].permissions;
}
},
getters: {
......
package it.inaf.ia2.gms.authn;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
......@@ -23,6 +25,8 @@ import org.springframework.web.filter.CorsFilter;
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger LOG = LoggerFactory.getLogger(SecurityConfig.class);
@Autowired
private Environment env;
......@@ -92,6 +96,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Profile("dev")
public FilterRegistrationBean corsFilter() {
LOG.warn("Development profile active: CORS filter enabled");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
config.addAllowedMethod(HttpMethod.PUT);
......
package it.inaf.ia2.gms.model.response;
import java.util.List;
public class UserGroup {
private String groupId;
private List<String> groupCompleteName;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public List<String> getGroupCompleteName() {
return groupCompleteName;
}
public void setGroupCompleteName(List<String> groupCompleteName) {
this.groupCompleteName = groupCompleteName;
}
}
package it.inaf.ia2.gms.model.response;
import it.inaf.ia2.gms.model.Permission;
public class UserPermission extends UserGroup {
private Permission permission;
public Permission getPermission() {
return permission;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
}
package it.inaf.ia2.gms.model.response;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import java.util.List;
public class UserSearchResponse {
private List<GroupEntity> groups;
private List<PermissionEntity> permissions;
private List<UserGroup> groups;
private List<UserPermission> permissions;
public List<GroupEntity> getGroups() {
public List<UserGroup> getGroups() {
return groups;
}
public void setGroups(List<GroupEntity> groups) {
public void setGroups(List<UserGroup> groups) {
this.groups = groups;
}
public List<PermissionEntity> getPermissions() {
public List<UserPermission> getPermissions() {
return permissions;
}
public void setPermissions(List<PermissionEntity> permissions) {
public void setPermissions(List<UserPermission> permissions) {
this.permissions = permissions;
}
}
package it.inaf.ia2.gms.service;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Utility class for retrieving the complete names (including parents) from a
* set of group paths.
*/
@Service
public class GroupNameService {
@Autowired
private GroupsDAO groupsDAO;
/**
* @param groupsIdPath map having group id as keys and group paths as values
* @return map having group id as keys and group names as values
*/
public Map<String, List<String>> getNames(List<Map.Entry<String, String>> groupsIdPath) {
Set<String> allIdentifiers = new HashSet<>();
for (Map.Entry<String, String> entry : groupsIdPath) {
allIdentifiers.addAll(getIdentifiers(entry.getValue()));
}
Map<String, String> groupSingleNamesMap = getGroupSingleNamesMap(allIdentifiers);
Map<String, List<String>> groupCompleteNamesMap = new HashMap<>();
for (Map.Entry<String, String> entry : groupsIdPath) {
List<String> groupCompleteName = getGroupCompleteName(groupSingleNamesMap, entry.getValue());
groupCompleteNamesMap.put(entry.getKey(), groupCompleteName);
}
return groupCompleteNamesMap;
}
private Map<String, String> getGroupSingleNamesMap(Set<String> allIdentifiers) {
Map<String, String> groupNamesMap = new HashMap<>();
for (GroupEntity group : groupsDAO.findGroupsByIds(allIdentifiers)) {
groupNamesMap.put(group.getId(), group.getName());
}
return groupNamesMap;
}
private List<String> getGroupCompleteName(Map<String, String> groupNamesMap, String groupPath) {
List<String> names = new ArrayList<>();
if (groupPath.isEmpty()) {
names.add("Root");
} else {
List<String> identifiers = getIdentifiers(groupPath);
for (String groupId : identifiers) {
names.add(groupNamesMap.get(groupId));
}
}
return names;
}
/**
* Returns the list of all identifiers including parent ones.
*/
private List<String> getIdentifiers(String groupPath) {
List<String> identifiers = new ArrayList<>();
if (!groupPath.isEmpty()) {
for (String id : groupPath.split(Pattern.quote("."))) {
identifiers.add(id);
}
}
return identifiers;
}
}
......@@ -4,6 +4,8 @@ import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.response.PaginatedData;
import it.inaf.ia2.gms.model.response.SearchResponseItem;
import it.inaf.ia2.gms.model.response.SearchResponseType;
import it.inaf.ia2.gms.model.response.UserGroup;
import it.inaf.ia2.gms.model.response.UserPermission;
import it.inaf.ia2.gms.model.response.UserSearchResponse;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.MembershipsDAO;
......@@ -11,8 +13,10 @@ 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.rap.RapClient;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -35,6 +39,9 @@ public class SearchService {
@Autowired
private MembershipsDAO membershipsDAO;
@Autowired
private GroupNameService groupNameService;
/**
* Generic search (both groups and users).
*/
......@@ -91,30 +98,66 @@ public class SearchService {
*/
public UserSearchResponse getUserSearchResult(String actorUserId, String targetUserId) {
List<GroupEntity> allGroups = membershipsDAO.getUserMemberships(targetUserId);
// Select only the information visible to the actor user
List<PermissionEntity> actorPermissions = permissionsDAO.findUserPermissions(actorUserId);
// Select only the groups visible to the user
List<PermissionEntity> permissions = permissionsDAO.findUserPermissions(actorUserId);
UserSearchResponse response = new UserSearchResponse();
response.setGroups(getUserGroups(targetUserId, actorPermissions));
response.setPermissions(getUserPermission(targetUserId, actorPermissions));
return response;
}
private List<UserGroup> getUserGroups(String targetUserId, List<PermissionEntity> actorPermissions) {
List<GroupEntity> allGroups = membershipsDAO.getUserMemberships(targetUserId);
List<GroupEntity> visibleGroups = new ArrayList<>();
// Select only groups visible to the actor user
List<Map.Entry<String, String>> visibleGroupsIdPath = new ArrayList<>();
for (GroupEntity group : allGroups) {
PermissionUtils.getGroupPermission(group, permissions).ifPresent(permission -> {
visibleGroups.add(group);
PermissionUtils.getGroupPermission(group, actorPermissions).ifPresent(permission -> {
visibleGroupsIdPath.add(new SimpleEntry<>(group.getId(), group.getPath()));
});
}
UserSearchResponse response = new UserSearchResponse();
response.setGroups(visibleGroups);
return groupNameService.getNames(visibleGroupsIdPath).entrySet().stream()
.map(entry -> {
UserGroup ug = new UserGroup();
ug.setGroupId(entry.getKey());
ug.setGroupCompleteName(entry.getValue());
return ug;
})
.collect(Collectors.toList());
}
private List<UserPermission> getUserPermission(String targetUserId, List<PermissionEntity> actorPermissions) {
List<UserPermission> permissions = new ArrayList<>();
// Super-admin user is able to see also other user permissions
PermissionUtils.getGroupPermission(groupsService.getRoot(), permissions).ifPresent(permission -> {
PermissionUtils.getGroupPermission(groupsService.getRoot(), actorPermissions).ifPresent(permission -> {
if (permission.equals(Permission.ADMIN)) {
List<PermissionEntity> targetUserPermissions = permissionsDAO.findUserPermissions(targetUserId);
response.setPermissions(targetUserPermissions);
Map<String, PermissionEntity> targetUserPermissions
= permissionsDAO.findUserPermissions(targetUserId).stream()
.collect(Collectors.toMap(PermissionEntity::getGroupId, p -> p));
List<Map.Entry<String, String>> groupsIdPath = new ArrayList<>();
for (PermissionEntity p : targetUserPermissions.values()) {
groupsIdPath.add(new SimpleEntry<>(p.getGroupId(), p.getGroupPath()));
}
for (Map.Entry<String, List<String>> entry : groupNameService.getNames(groupsIdPath).entrySet()) {
UserPermission up = new UserPermission();
up.setGroupId(entry.getKey());
up.setGroupCompleteName(entry.getValue());
up.setPermission(targetUserPermissions.get(entry.getKey()).getPermission());
permissions.add(up);
}
}
});
return response;
return permissions;
}
}
package it.inaf.ia2.gms.service;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class GroupNameServiceTest {
@Mock
private GroupsDAO groupsDAO;
@InjectMocks
private GroupNameService groupNameService;
@Test
public void getNamesTest() {
mockGroupsDAO();
List<Map.Entry<String, String>> groupsIdPath = new ArrayList<>();
groupsIdPath.add(new AbstractMap.SimpleEntry<>("def", "abc.def"));
Map<String, List<String>> names = groupNameService.getNames(groupsIdPath);
assertEquals(1, names.size());
assertEquals(2, names.get("def").size());
assertEquals("Group 1", names.get("def").get(0));
assertEquals("Group 2", names.get("def").get(1));
}
public void mockGroupsDAO() {
List<GroupEntity> groups = new ArrayList<>();
GroupEntity group1 = new GroupEntity();
group1.setId("abc");
group1.setName("Group 1");
group1.setPath("abc");
groups.add(group1);
GroupEntity group2 = new GroupEntity();
group2.setId("def");
group2.setName("Group 2");
group2.setPath("abc.def");
groups.add(group2);
when(groupsDAO.findGroupsByIds(any())).thenReturn(groups);
}
@Test
public void getRootTest() {
List<GroupEntity> groups = new ArrayList<>();
GroupEntity root = new GroupEntity();
root.setId("ROOT");
root.setName("Root");
root.setPath("");
groups.add(root);
when(groupsDAO.findGroupsByIds(any())).thenReturn(groups);
List<Map.Entry<String, String>> groupsIdPath = new ArrayList<>();
groupsIdPath.add(new AbstractMap.SimpleEntry<>("ROOT", ""));
Map<String, List<String>> names = groupNameService.getNames(groupsIdPath);
assertEquals(1, names.size());
assertEquals(1, names.get("ROOT").size());
assertEquals("Root", names.get("ROOT").get(0));
}
}
......@@ -16,9 +16,11 @@ import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.rap.RapClient;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any;
......@@ -46,6 +48,9 @@ public class SearchServiceTest {
@Mock
private MembershipsDAO membershipsDAO;
@Mock
private GroupNameService groupNameService;
@InjectMocks
private SearchService searchService;
......@@ -120,14 +125,42 @@ public class SearchServiceTest {
when(permissionsDAO.findUserPermissions(eq("admin_id")))
.thenReturn(Collections.singletonList(adminPermission));
PermissionEntity targetUserPermission = new PermissionEntity();
targetUserPermission.setGroupId("group1_id");
targetUserPermission.setUserId("target_id");
targetUserPermission.setGroupPath("group1_id");
targetUserPermission.setPermission(Permission.MANAGE_MEMBERS);
when(permissionsDAO.findUserPermissions(eq("target_id")))
.thenReturn(Collections.singletonList(targetUserPermission));
GroupEntity root = new GroupEntity();
root.setId("ROOT");
root.setName("Root");
root.setPath("");
when(groupsService.getRoot()).thenReturn(root);
when(groupNameService.getNames(any())).then(invocation -> {
Map<String, List<String>> result = new HashMap<>();
List<Map.Entry<String, String>> arg = invocation.getArgument(0);
for (Entry<String, String> entry : arg) {
List<String> names = new ArrayList<>();
switch (entry.getKey()) {
case "ROOT":
names.add("Root");
break;
case "group1_id":
names.add("Group 1");
break;
}
result.put(entry.getKey(), names);
}
return result;
});
UserSearchResponse response = searchService.getUserSearchResult("admin_id", "target_id");
assertEquals(1, response.getGroups().size());
assertNotNull(response.getPermissions());
assertEquals(1, response.getPermissions().size());
assertEquals(Permission.MANAGE_MEMBERS, response.getPermissions().get(0).getPermission());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment