diff --git a/gms-ui/src/components/GenericSearchResults.vue b/gms-ui/src/components/GenericSearchResults.vue index 27d9199a627a9fa0d2fdfb176e06fc2eb69797d1..ea3ae44138f97111ef163e58ed40e8ef705518a8 100644 --- a/gms-ui/src/components/GenericSearchResults.vue +++ b/gms-ui/src/components/GenericSearchResults.vue @@ -39,10 +39,7 @@ export default { this.$store.commit('openGroup', result.id); break; case 'USER': - client.openUserSearchResult(result.id) - .then(model => { - this.$store.commit('displayUserSearchResults', [result.label, model]); - }); + this.$store.dispatch('openUserPage', result.id); break; } }, diff --git a/gms-ui/src/components/Main.vue b/gms-ui/src/components/Main.vue index 115922fcc9f2d5e354b546a0edde62ae4ee00d31..055309c5adfa9708c4bef8c90a0c85b75fd01009 100644 --- a/gms-ui/src/components/Main.vue +++ b/gms-ui/src/components/Main.vue @@ -54,6 +54,8 @@ export default { }), methods: { tabChanged: function(tabIndex) { + // reset paginator + this.input.paginatorPage = 1; switch (tabIndex) { case 0: client.fetchGroupsTab(this.input) diff --git a/gms-ui/src/components/MembersPanel.vue b/gms-ui/src/components/MembersPanel.vue index b8d27362d57c4cac9fb2390d5e52f6660af030dc..30ea021ede92c526fde3b37728cacbd9a6a1ce3f 100644 --- a/gms-ui/src/components/MembersPanel.vue +++ b/gms-ui/src/components/MembersPanel.vue @@ -2,9 +2,9 @@ <b-tab title="Members" v-if="model.permission === 'ADMIN' || model.permission === 'MANAGE_MEMBERS' || model.permission === 'VIEW_MEMBERS'"> <div v-if="model.membersPanel !== null"> <b-list-group v-for="member in model.membersPanel.items" id="members-list"> - <b-list-group-item href="#"> + <b-list-group-item href="#" @click="openUser(member)"> <div class="float-left"> - <User v-bind:user="member" /> + <User :user="member" :anchor="false" /> </div> <span v-if="model.permission === 'ADMIN' || model.permission === 'MANAGE_MEMBERS'" class="float-right"> <a href="#" v-on:click.stop="openRemoveMemberModal(member)" class="text-danger" title="Remove member"> @@ -52,6 +52,9 @@ export default { .then(panel => { this.$store.commit('updateMembersPanel', panel); }); + }, + openUser(member) { + this.$store.dispatch('openUserPage', member.id); } } } diff --git a/gms-ui/src/components/PermissionsPanel.vue b/gms-ui/src/components/PermissionsPanel.vue index 95f67a85482b26af71217444972ff91fcbe136c0..a8537deb8cc620069042a85c846d0a55483a307f 100644 --- a/gms-ui/src/components/PermissionsPanel.vue +++ b/gms-ui/src/components/PermissionsPanel.vue @@ -12,7 +12,7 @@ <tbody> <tr v-for="up in model.permissionsPanel.items"> <td> - <User v-bind:user="up.user" /> + <User :user="up.user" :anchor="true" /> </td> <td>{{up.permission}}</td> <td> diff --git a/gms-ui/src/components/User.vue b/gms-ui/src/components/User.vue index d12e873ba36b7ad8ac7745a8bbc77fbe6c920c14..2c6c16e33099570e38ebe6e5c49533fa8b2162af 100644 --- a/gms-ui/src/components/User.vue +++ b/gms-ui/src/components/User.vue @@ -1,12 +1,12 @@ <template> <div :id="'user-name-' + user.id"> - <span>{{user.displayName}}</span> + <component :is="anchor ? 'a' : 'span'" :href="anchor ? '#' : false" @click="openUser">{{user.displayName}}</component> <b-tooltip ref="user-tooltip" :target="'user-name-' + user.id" placement="bottom"> <div class="text-left"> <p><strong>User id</strong>: {{user.id}}</p> <p><strong>Identities</strong>:</p> <ul> - <li v-for="identity in user.identities"> + <li v-for="identity in user.identities" v-bind:key="identity.typedId"> {{identity.email}} ({{identity.type}}) </li> </ul> @@ -19,7 +19,13 @@ export default { name: 'User', props: { - user: Object + user: Object, + anchor: Boolean + }, + methods: { + openUser() { + this.$store.dispatch('openUserPage', this.user.id); + } } } </script> diff --git a/gms-ui/src/components/UserSearchResult.vue b/gms-ui/src/components/UserSearchResult.vue index a2b87c8e95c78ec826a8a454295e44475522cfd4..c648affff26627b0c80ac7e54b244f7a0e1fff31 100644 --- a/gms-ui/src/components/UserSearchResult.vue +++ b/gms-ui/src/components/UserSearchResult.vue @@ -1,9 +1,12 @@ <template> -<div class="mt-sm-3" v-if="userLabel !== null"> +<div class="mt-sm-3" v-if="user !== null"> <b-button variant="primary" class="float-right" v-on:click="back()">Back</b-button> - <h5>Results for <strong>{{userLabel}}</strong>:</h5> + <h5><strong>{{user.displayName}}</strong>:</h5> <b-container class="mt-sm-5"> + <b-row> + + </b-row> <b-row> <b-col class="text-left"> <h5>Is member of</h5> @@ -19,6 +22,24 @@ </li> </ul> </div> + + <h5 class="mt-5 mb-3">User info</h5> + <p><strong>User id</strong>: {{user.id}}</p> + <p><strong>Identities ({{user.identities.length}})</strong>:</p> + <b-row> + <b-col lg="10"> + <b-list-group> + <b-list-group-item v-for="identity in user.identities" v-bind:key="identity.typedId"> + <dl class="mb-0 ml-0 row"> + <dt class="col-3">Type</dt><dd class="col-9">{{identity.type}}</dd> + <dt class="col-3">Email</dt><dd class="col-9">{{identity.email}}</dd> + <dt class="col-3" v-if="identity.type === 'eduGAIN'"><abbr title="EduPerson Principal Name, an unique identifier used into federations.">EPPN</abbr></dt> + <dd class="col-9" v-if="identity.type === 'eduGAIN'">{{identity.typedId}}</dd> + </dl> + </b-list-group-item> + </b-list-group> + </b-col> + </b-row> </b-col> <b-col v-if="permissions.length > 0"> <h5>Permissions</h5> @@ -55,13 +76,13 @@ import { export default { name: 'UserSearchResult', computed: mapState({ - userLabel: state => state.model.userSearchResults.userLabel, + user: state => state.model.userSearchResults.user, groups: state => state.model.userSearchResults.groups, permissions: state => state.model.userSearchResults.permissions }), methods: { back() { - this.$store.commit('displaySearchResults'); + this.$store.commit('backFromUserPage'); }, openGroup(groupId) { this.$store.commit('openGroup', groupId); diff --git a/gms-ui/src/store.js b/gms-ui/src/store.js index 0a44fd6c5430410cd38888ef953a7ac53e908b1f..f175ec5b8f55d8b9deb22e316ff920b9d3e64486 100644 --- a/gms-ui/src/store.js +++ b/gms-ui/src/store.js @@ -38,6 +38,7 @@ export default new Vuex.Store({ } }, loading: false, + previousPage: null, page: 'main' }, mutations: { @@ -100,11 +101,20 @@ export default new Vuex.Store({ 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; + backFromUserPage(state) { + state.page = state.previousPage; + } + }, + actions: { + openUserPage({ state }, userId) { + state.previousPage = state.page; + client.openUserSearchResult(userId) + .then(model => { + state.page = 'userSearch'; + state.model.userSearchResults.user = model.user; + state.model.userSearchResults.groups = model.groups; + state.model.userSearchResults.permissions = model.permissions; + }); } }, getters: { diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java index 77469ed03cc8e42b5be01d970119611d9e9b6089..792e2d521e5e141437181aad7b7ce5cfa2b7b51f 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java @@ -1,17 +1,17 @@ package it.inaf.ia2.gms.controller; -import it.inaf.ia2.gms.authn.SessionData; import it.inaf.ia2.gms.manager.MembershipManager; import it.inaf.ia2.gms.manager.PermissionsManager; import it.inaf.ia2.gms.model.request.AddMemberRequest; -import it.inaf.ia2.gms.model.request.MemberRequest; import it.inaf.ia2.gms.model.response.PaginatedData; import it.inaf.ia2.gms.model.Permission; import it.inaf.ia2.gms.model.RapUser; +import it.inaf.ia2.gms.model.request.PaginatedModelRequest; import it.inaf.ia2.gms.model.request.RemoveMemberRequest; import it.inaf.ia2.gms.model.request.TabRequest; import it.inaf.ia2.gms.persistence.model.GroupEntity; import it.inaf.ia2.gms.service.GroupsService; +import java.util.Collections; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -36,18 +36,17 @@ public class MembersController { @Autowired private PermissionsManager permissionsManager; - @GetMapping(value = "/members", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @GetMapping(value = "/members", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<PaginatedData<RapUser>> getMembersTab(TabRequest request) { GroupEntity group = groupsService.getGroupById(request.getGroupId()); - List<RapUser> members = membershipManager.getMembers(group); - PaginatedData<RapUser> membersPanel = new PaginatedData<>(members, request.getPaginatorPage(), request.getPaginatorPageSize()); + PaginatedData<RapUser> membersPanel = getMembersPanel(group, request); return ResponseEntity.ok(membersPanel); } - @PostMapping(value = "/member", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @PostMapping(value = "/member", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<PaginatedData<RapUser>> addMember(@Valid @RequestBody AddMemberRequest request) { GroupEntity group = groupsService.getGroupById(request.getGroupId()); @@ -64,10 +63,10 @@ public class MembersController { permissionsManager.addPermission(group, request.getUserId(), request.getPermission()); } - return new ResponseEntity<>(getMembersPanel(request, group), HttpStatus.CREATED); + return new ResponseEntity<>(getMembersPanel(group, request), HttpStatus.CREATED); } - @DeleteMapping(value = "/member", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @DeleteMapping(value = "/member", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<PaginatedData<RapUser>> removeMember(@Valid RemoveMemberRequest request) { GroupEntity group = groupsService.getGroupById(request.getGroupId()); @@ -91,11 +90,14 @@ public class MembersController { permissionsManager.removePermission(group, request.getUserId()); } - return ResponseEntity.ok(getMembersPanel(request, group)); + return ResponseEntity.ok(getMembersPanel(group, request)); } - private PaginatedData<RapUser> getMembersPanel(MemberRequest request, GroupEntity group) { + private PaginatedData<RapUser> getMembersPanel(GroupEntity group, PaginatedModelRequest request) { List<RapUser> members = membershipManager.getMembers(group); + Collections.sort(members, (m1, m2) -> { + return m1.getDisplayName().compareTo(m2.getDisplayName()); + }); return new PaginatedData<>(members, request.getPaginatorPage(), request.getPaginatorPageSize()); } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java index 3f7d8e8d643dc06b3f94776319cf3497098da667..5840978ae51c9bba38628e74e546dd944d46621e 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java @@ -10,6 +10,7 @@ import it.inaf.ia2.gms.model.Permission; import it.inaf.ia2.gms.model.UserPermission; import it.inaf.ia2.gms.model.request.TabRequest; import it.inaf.ia2.gms.persistence.model.GroupEntity; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,8 +39,7 @@ public class PermissionsController { public ResponseEntity<PaginatedData<UserPermission>> getPermissionsTab(TabRequest request) { GroupEntity group = groupsManager.getGroupById(request.getGroupId()); - List<UserPermission> permissions = permissionsManager.getAllPermissions(group); - PaginatedData<UserPermission> permissionsPanel = new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize()); + PaginatedData<UserPermission> permissionsPanel = getPermissionsPanel(group, request); return ResponseEntity.ok(permissionsPanel); } @@ -79,6 +79,9 @@ public class PermissionsController { private PaginatedData<UserPermission> getPermissionsPanel(GroupEntity group, PaginatedModelRequest request) { List<UserPermission> permissions = permissionsManager.getAllPermissions(group); + Collections.sort(permissions, (p1, p2) -> { + return p1.getUser().getDisplayName().compareTo(p2.getUser().getDisplayName()); + }); return new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize()); } } 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 6920999521a8b4162d658c06f27170a474f63190..c612e9c4baba290bcdcd75c8641cc88da7c38b30 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,6 +1,7 @@ package it.inaf.ia2.gms.controller; import it.inaf.ia2.gms.authn.SessionData; +import it.inaf.ia2.gms.model.RapUser; import it.inaf.ia2.gms.model.response.PaginatedData; import it.inaf.ia2.gms.model.response.SearchResponseItem; import it.inaf.ia2.gms.model.response.UserSearchResponse; @@ -22,7 +23,7 @@ public class SearchController { @Autowired private SearchService searchService; - @GetMapping(value = "/search", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @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) { @@ -30,7 +31,7 @@ public class SearchController { return ResponseEntity.ok(response); } - @GetMapping(value = "/search/user/{userId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @GetMapping(value = "/search/user/{userId}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<UserSearchResponse> getSearchResultUser(@PathVariable("userId") String userId) { UserSearchResponse response = searchService.getUserSearchResult(sessionData.getUserId(), userId); diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java index 54577f6dbff66bb4f1f72142752471edcab39b0d..595b1e48d7181d184bfb5826ed7b3f06ea244d31 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java @@ -16,7 +16,7 @@ public class UsersController { @Autowired private RapClient rapClient; - @GetMapping(value = "users", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @GetMapping(value = "users", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<RapUser>> searchUsers(@RequestParam("search") String searchText) { return ResponseEntity.ok(rapClient.searchUsers(searchText)); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java index 7d08b2e53ad149681912c5806a54ade2db04e245..a1503f09b8d467433ef88e219ff8bd6cb07bb3f0 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java +++ b/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java @@ -63,7 +63,7 @@ public class PermissionsManager extends UserAwareComponent { public Permission getDirectUserPermission(GroupEntity group, String userId) { verifyUserCanManagePermissions(group); - List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, getCurrentUserId()); + List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, userId); for (PermissionEntity permission : permissions) { if (permission.getGroupId().equals(group.getId())) { return permission.getPermission(); @@ -74,7 +74,7 @@ public class PermissionsManager extends UserAwareComponent { public Permission getUserPermission(GroupEntity group, String userId) { verifyUserCanManagePermissions(group); - List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, getCurrentUserId()); + List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, userId); return PermissionUtils.getGroupPermission(group, permissions).orElse(null); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/response/UserSearchResponse.java b/gms/src/main/java/it/inaf/ia2/gms/model/response/UserSearchResponse.java index 0ec85677813660bfb8f900ef7b3aeafce120e59a..4d00c2489b6ff8f8c25f1aaf328e2b0aff2145b9 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/model/response/UserSearchResponse.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/response/UserSearchResponse.java @@ -1,12 +1,22 @@ package it.inaf.ia2.gms.model.response; +import it.inaf.ia2.gms.model.RapUser; import java.util.List; public class UserSearchResponse { + private RapUser user; private List<UserGroup> groups; private List<UserPermission> permissions; + public RapUser getUser() { + return user; + } + + public void setUser(RapUser user) { + this.user = user; + } + public List<UserGroup> getGroups() { return groups; } diff --git a/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java b/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java index b13b1de5eb82782eb85650bfb63ec82705587db7..ddb51dbb0ab8c84f14e503a6259df0f5fff38cb5 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java +++ b/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java @@ -57,6 +57,16 @@ public class RapClient { this.refreshTokenRestTemplate = new RestTemplate(); } + public RapUser getUser(String userId) { + + String url = rapBaseUrl + "/user/" + userId; + + return httpCall(entity -> { + return rapRestTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<RapUser>() { + }).getBody(); + }); + } + public List<RapUser> getUsers(Set<String> identifiers) { if (identifiers.isEmpty()) { 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 ac6b72ad8944b1764c0ce6dac98ee811d43a8d89..9f59907cc51db024182baba78611e6c58b902135 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 @@ -119,6 +119,8 @@ public class SearchService { sortByGroupCompleteName(permissions); response.setPermissions(permissions); + response.setUser(rapClient.getUser(targetUserId)); + return response; } diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/JWTWebServiceControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/JWTWebServiceControllerTest.java index a665c24173767d3cfb66f11b2a8c562b57fc8e35..e47104e8d6dcac617f2d8d173876e1b8d7b768dc 100644 --- a/gms/src/test/java/it/inaf/ia2/gms/controller/JWTWebServiceControllerTest.java +++ b/gms/src/test/java/it/inaf/ia2/gms/controller/JWTWebServiceControllerTest.java @@ -16,7 +16,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import static org.mockito.ArgumentMatchers.any; @@ -141,17 +140,15 @@ public class JWTWebServiceControllerTest { } @Test - @Ignore public void testDeleteGroupByPath() throws Exception { - List<String> names = Arrays.asList("LBT", "INAF"); - - when(groupsService.findGroupByNames(names)).thenReturn(Optional.of(inaf)); + when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt)); + when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf)); - mockMvc.perform(delete("/ws/jwt/group/LBT.INAF")) + mockMvc.perform(delete("/ws/jwt/LBT.INAF")) .andExpect(status().isNoContent()); - verify(groupsService, times(1)).deleteGroup(eq(inaf)); + verify(groupsDAO, times(1)).deleteGroupById(eq(inaf.getId())); } @Test @@ -176,19 +173,17 @@ public class JWTWebServiceControllerTest { } @Test - @Ignore public void testRemoveMember() throws Exception { List<String> names = Arrays.asList("LBT", "INAF"); - GroupEntity inaf = getInafGroup(); - - when(groupsService.findGroupByNames(names)).thenReturn(Optional.of(inaf)); - - mockMvc.perform(delete("/ws/jwt/membership/LBT.INAF?userId=user_id")) + when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt)); + when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf)); + + mockMvc.perform(delete("/ws/jwt/membership/LBT.INAF?user_id=userId")) .andExpect(status().isNoContent()); - verify(membershipManager, times(1)).removeMember(eq(inaf), eq("user_id")); + verify(membershipManager, times(1)).removeMember(eq(inaf), eq("userId")); } @Test @@ -220,17 +215,18 @@ public class JWTWebServiceControllerTest { } @Test - @Ignore public void testRemovePermission() throws Exception { List<String> names = Arrays.asList("LBT", "INAF"); - GroupEntity inaf = getInafGroup(); - when(groupsService.findGroupByNames(names)).thenReturn(Optional.of(inaf)); + + //when(groupsService.findGroupByNames(names)).thenReturn(Optional.of(inaf)); + when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt)); + when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf)); - mockMvc.perform(delete("/ws/jwt/permission?LBT.INAF?userId=user_id&permission=ADMIN")) + mockMvc.perform(delete("/ws/jwt/permission/LBT.INAF?user_id=userId&permission=ADMIN")) .andExpect(status().isNoContent()); - verify(permissionsManager, times(1)).removePermission(eq(inaf), eq("user_id")); + verify(permissionsManager, times(1)).removePermission(eq(inaf), eq("userId")); } private GroupEntity getRoot() {