From f29db93fdb724bb7d25c11cdd211dc86a63b3349 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Mon, 4 Nov 2019 15:25:52 +0100
Subject: [PATCH] Handled is leaf field also in UI

---
 gms-ui/src/api/mock/data/groups.json          |  3 +-
 gms-ui/src/api/server/index.js                | 10 +--
 gms-ui/src/components/GroupsBreadcrumb.vue    |  2 +-
 gms-ui/src/components/GroupsPanel.vue         |  2 +-
 gms-ui/src/components/Main.vue                | 47 +++++--------
 .../src/components/modals/AddGroupModal.vue   |  6 +-
 .../components/modals/RenameGroupModal.vue    |  7 +-
 gms-ui/src/store.js                           |  9 +--
 .../BasicAuthWebServiceController.java        |  2 +-
 .../ia2/gms/controller/GroupsController.java  |  4 +-
 .../controller/GroupsTabResponseBuilder.java  |  2 +
 .../java/it/inaf/ia2/gms/model/Identity.java  |  9 +++
 .../java/it/inaf/ia2/gms/model/RapUser.java   |  9 ++-
 .../gms/model/request/RenameGroupRequest.java | 10 +++
 .../gms/model/response/GroupsTabResponse.java | 10 +++
 .../inaf/ia2/gms/persistence/GroupsDAO.java   |  8 ++-
 .../inaf/ia2/gms/service/GroupsService.java   | 70 ++++++++++---------
 .../BasicAuthWebServiceControllerTest.java    |  3 +-
 .../NestedGroupsIntegrationTest.java          | 12 ++--
 19 files changed, 130 insertions(+), 95 deletions(-)

diff --git a/gms-ui/src/api/mock/data/groups.json b/gms-ui/src/api/mock/data/groups.json
index a5f3d20..c99769e 100644
--- a/gms-ui/src/api/mock/data/groups.json
+++ b/gms-ui/src/api/mock/data/groups.json
@@ -28,5 +28,6 @@
     "hasPreviousPages": false,
     "hasFollowingPages": false
   },
-  "permission": "ADMIN"
+  "permission": "ADMIN",
+  "leaf": false
 }
diff --git a/gms-ui/src/api/server/index.js b/gms-ui/src/api/server/index.js
index b05cca5..aabf500 100644
--- a/gms-ui/src/api/server/index.js
+++ b/gms-ui/src/api/server/index.js
@@ -2,7 +2,7 @@ const BASE_API_URL = process.env.VUE_APP_API_BASE_URL;
 
 function apiRequest(url, options) {
   loading(true);
-  return new Promise((resolve, reject) => {
+  return new Promise((resolve) => {
     fetch(url, options)
       .then(response => {
         loading(false);
@@ -123,7 +123,7 @@ export default {
       }
     });
   },
-  addGroup(newGroupName, input) {
+  addGroup(newGroupName, leaf, input) {
     let url = BASE_API_URL + 'group';
     return apiRequest(url, {
       method: 'POST',
@@ -138,11 +138,12 @@ export default {
         parentGroupId: input.selectedGroupId,
         paginatorPageSize: input.paginatorPageSize,
         paginatorPage: input.paginatorPage,
-        searchFilter: input.searchFilter
+        searchFilter: input.searchFilter,
+        leaf: leaf
       })
     });
   },
-  renameGroup(groupId, newGroupName, input) {
+  renameGroup(groupId, newGroupName, leaf, input) {
     let url = BASE_API_URL + 'group/' + groupId;
     return apiRequest(url, {
       method: 'PUT',
@@ -154,6 +155,7 @@ export default {
       },
       body: JSON.stringify({
         newGroupName: newGroupName,
+        leaf: leaf,
         paginatorPageSize: input.paginatorPageSize,
         paginatorPage: input.paginatorPage,
         searchFilter: input.searchFilter
diff --git a/gms-ui/src/components/GroupsBreadcrumb.vue b/gms-ui/src/components/GroupsBreadcrumb.vue
index 291ce46..629059b 100644
--- a/gms-ui/src/components/GroupsBreadcrumb.vue
+++ b/gms-ui/src/components/GroupsBreadcrumb.vue
@@ -43,7 +43,7 @@ export default {
     changeBreadcrumb: function(groupId) {
       this.input.selectedGroupId = groupId;
       this.input.searchFilter = null;
-      if (this.input.selectedTab === 'groups') {
+      if (this.input.tabIndex === 0) {
         client.fetchGroupsTab(this.input)
           .then(model => {
             this.$store.commit('updateGroups', model);
diff --git a/gms-ui/src/components/GroupsPanel.vue b/gms-ui/src/components/GroupsPanel.vue
index 038978e..f7aea61 100644
--- a/gms-ui/src/components/GroupsPanel.vue
+++ b/gms-ui/src/components/GroupsPanel.vue
@@ -1,5 +1,5 @@
 <template>
-<b-tab title="Groups" active>
+<b-tab title="Groups" :title-link-class="{ 'd-none': model.leaf }">
   <b-row>
     <b-col xs="12">
       <b-form-input placeholder="Search group" v-model="input.searchFilter" v-on:input="filterGroups"></b-form-input>
diff --git a/gms-ui/src/components/Main.vue b/gms-ui/src/components/Main.vue
index fe477da..115922f 100644
--- a/gms-ui/src/components/Main.vue
+++ b/gms-ui/src/components/Main.vue
@@ -47,48 +47,33 @@ export default {
   computed: mapState({
     model: state => state.model,
     input: state => state.input,
-    showAddMemberBtn: state => state.model.permission === 'ADMIN' && state.input.selectedTab === 'members',
-    showAddCollaboratorBtn: state => state.model.permission === 'MANAGE_MEMBERS' && state.input.selectedTab === 'members',
-    showAddGroupBtn: state => state.model.permission === 'ADMIN' && state.input.selectedTab === 'groups',
-    showAddPermissionBtn: state => state.model.permission === 'ADMIN' && state.input.selectedTab === 'permissions'
+    showAddMemberBtn: state => state.model.permission === 'ADMIN' && state.input.tabIndex === 1,
+    showAddCollaboratorBtn: state => state.model.permission === 'MANAGE_MEMBERS' && state.input.tabIndex === 1,
+    showAddGroupBtn: state => state.model.permission === 'ADMIN' && state.input.tabIndex === 0,
+    showAddPermissionBtn: state => state.model.permission === 'ADMIN' && state.input.tabIndex === 2
   }),
   methods: {
     tabChanged: function(tabIndex) {
-      let tab;
       switch (tabIndex) {
         case 0:
-          tab = 'groups';
+          client.fetchGroupsTab(this.input)
+            .then(model => {
+              this.$store.commit('updateGroups', model);
+            });
           break;
         case 1:
-          tab = 'members';
+          client.fetchMembersPanel(this.input)
+            .then(panel => {
+              this.$store.commit('updateMembersPanel', panel);
+            });
           break;
         case 2:
-          tab = 'permissions';
+          client.fetchPermissionsPanel(this.input)
+            .then(panel => {
+              this.$store.commit('updatePermissionsPanel', panel);
+            });
           break;
       }
-      if (this.input.selectedTab !== tab) {
-        this.input.selectedTab = tab;
-        switch (this.input.selectedTab) {
-          case 'groups':
-            client.fetchGroupsTab(this.input)
-              .then(model => {
-                this.$store.commit('updateGroups', model);
-              });
-            break;
-          case 'members':
-            client.fetchMembersPanel(this.input)
-              .then(panel => {
-                this.$store.commit('updateMembersPanel', panel);
-              });
-            break;
-          case 'permissions':
-            client.fetchPermissionsPanel(this.input)
-              .then(panel => {
-                this.$store.commit('updatePermissionsPanel', panel);
-              });
-            break;
-        }
-      }
     },
     openAddGroupModal: function() {
       this.$bvModal.show('add-group-modal');
diff --git a/gms-ui/src/components/modals/AddGroupModal.vue b/gms-ui/src/components/modals/AddGroupModal.vue
index 09e1f5a..1e7d32b 100644
--- a/gms-ui/src/components/modals/AddGroupModal.vue
+++ b/gms-ui/src/components/modals/AddGroupModal.vue
@@ -5,6 +5,7 @@
     <b-form-input v-model="newGroupName" id="new-group-name-input" ref="newGroupNameInput" class="w-75" aria-describedby="new-group-name-input-feedback" :state="newGroupNameState" v-on:input="resetError" @keydown.native.enter="addGroup">
     </b-form-input>
     <b-form-invalid-feedback id="new-group-name-input-feedback">{{newGroupNameError}}</b-form-invalid-feedback>
+    <b-form-checkbox class="mt-3 ml-3" v-model="leaf">is leaf</b-form-checkbox>
   </b-form>
 </b-modal>
 </template>
@@ -24,7 +25,8 @@ export default {
   data: function() {
     return {
       newGroupName: null,
-      newGroupNameError: null
+      newGroupNameError: null,
+      leaf: false
     };
   },
   methods: {
@@ -45,7 +47,7 @@ export default {
       if (!this.newGroupName) {
         this.newGroupNameError = "Group name is required";
       } else {
-        client.addGroup(this.newGroupName, this.$store.state.input)
+        client.addGroup(this.newGroupName, this.leaf, this.$store.state.input)
           .then(res => {
             if (res.status === 400) {
               this.newGroupNameError = res.message;
diff --git a/gms-ui/src/components/modals/RenameGroupModal.vue b/gms-ui/src/components/modals/RenameGroupModal.vue
index 3ee6f6a..a3a79d9 100644
--- a/gms-ui/src/components/modals/RenameGroupModal.vue
+++ b/gms-ui/src/components/modals/RenameGroupModal.vue
@@ -5,6 +5,7 @@
     <b-form-input v-model="newGroupName" id="new-group-name-input" class="w-75" aria-describedby="new-group-name-input-feedback" :state="newGroupNameState" v-on:input="resetError">
     </b-form-input>
     <b-form-invalid-feedback id="new-group-name-input-feedback">{{newGroupNameError}}</b-form-invalid-feedback>
+    <b-form-checkbox class="mt-3 ml-3" v-model="leaf">is leaf</b-form-checkbox>
   </b-form>
 </b-modal>
 </template>
@@ -26,7 +27,8 @@ export default {
       groupId: null,
       oldGroupName: null,
       newGroupName: null,
-      newGroupNameError: null
+      newGroupNameError: null,
+      leaf: false
     };
   },
   methods: {
@@ -36,6 +38,7 @@ export default {
     openRenameGroupModal: function(group) {
       this.newGroupName = group.groupName;
       this.groupId = group.groupId;
+      this.leaf = group.leaf;
       this.$bvModal.show('rename-group-modal');
     },
     renameGroup: function(event) {
@@ -53,7 +56,7 @@ export default {
       }
 
       let parent = this.$store.getters.selectedGroupId;
-      client.renameGroup(this.groupId, this.newGroupName, this.$store.state.input)
+      client.renameGroup(this.groupId, this.newGroupName, this.leaf, this.$store.state.input)
         .then(res => {
           if (res.status === 400) {
             this.newGroupNameError = res.message;
diff --git a/gms-ui/src/store.js b/gms-ui/src/store.js
index 00e3cd7..ff7e99d 100644
--- a/gms-ui/src/store.js
+++ b/gms-ui/src/store.js
@@ -15,6 +15,7 @@ export default new Vuex.Store({
       permissionsPanel: null,
       membersPanel: null,
       permission: null,
+      leaf: false,
       user: null,
       genericSearchResults: [],
       userSearchResults: {
@@ -28,7 +29,6 @@ export default new Vuex.Store({
       selectedGroupId: 'ROOT',
       paginatorPageSize: 20,
       paginatorPage: 1,
-      selectedTab: 'groups',
       tabIndex: 0,
       searchFilter: '',
       genericSearch: {
@@ -54,11 +54,11 @@ export default new Vuex.Store({
       client.fetchGroupsTab(input)
         .then(model => {
           this.commit('updateGroups', model);
-          if (model.groupsPanel.items.length > 0) {
-            this.commit('setTabIndex', 0);
-          } else {
+          if (model.leaf) {
             // If there are no subgroups show the members panel
             this.commit('setTabIndex', 1);
+          } else {
+            this.commit('setTabIndex', 0);
           }
           this.commit('showMainPage');
         });
@@ -67,6 +67,7 @@ export default new Vuex.Store({
       this.state.model.breadcrumbs = model.breadcrumbs;
       this.state.model.groupsPanel = model.groupsPanel;
       this.state.model.permission = model.permission;
+      this.state.model.leaf = model.leaf;
     },
     updateGroupsPanel(state, groupsPanel) {
       this.state.model.groupsPanel = groupsPanel;
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceController.java
index 54af876..49530ba 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceController.java
@@ -55,7 +55,7 @@ public class BasicAuthWebServiceController {
             if (optGroup.isPresent()) {
                 group = optGroup.get();
             } else {
-                group = groupsService.addGroup(group, name);
+                group = groupsService.addGroup(group, name, false);
             }
         }
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
index cb7fb79..c3d42f9 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
@@ -67,7 +67,7 @@ public class GroupsController {
             throw new UnauthorizedException("Missing admin permission");
         }
 
-        groupsService.addGroup(parent, request.getNewGroupName());
+        groupsService.addGroup(parent, request.getNewGroupName(), request.isLeaf());
 
         PaginatedData<GroupNode> groupsPanel = getGroupsPanel(parent, request);
 
@@ -83,7 +83,7 @@ public class GroupsController {
             throw new UnauthorizedException("Missing admin permission");
         }
 
-        GroupEntity renamedGroup = groupsService.renameGroup(group, request.getNewGroupName());
+        GroupEntity renamedGroup = groupsService.renameGroup(group, request.getNewGroupName(), request.isLeaf());
 
         GroupEntity parent = groupsService.getGroupByPath(renamedGroup.getParentPath());
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsTabResponseBuilder.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsTabResponseBuilder.java
index 0b0dd8a..30d8463 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsTabResponseBuilder.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsTabResponseBuilder.java
@@ -39,6 +39,8 @@ public class GroupsTabResponseBuilder {
 
         response.setGroupsPanel(groupsListBuilder.listSubGroups(group, request, session.getUserId()));
 
+        response.setLeaf(group.isLeaf());
+
         return response;
     }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java b/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java
index 12d99a2..c879da9 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java
@@ -3,6 +3,7 @@ package it.inaf.ia2.gms.model;
 public class Identity {
 
     private IdentityType type;
+    private String typedId;
     private String email;
     private String name;
     private String surname;
@@ -16,6 +17,14 @@ public class Identity {
         this.type = type;
     }
 
+    public String getTypedId() {
+        return typedId;
+    }
+
+    public void setTypedId(String typedId) {
+        this.typedId = typedId;
+    }
+
     public String getEmail() {
         return email;
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java b/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java
index c3854ec..5ef0ac4 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java
@@ -46,8 +46,13 @@ public class RapUser {
         }
 
         // Adding types
-        Set<String> types = identities.stream().map(i -> i.getType().getValue()).collect(Collectors.toSet());
-        displayName += String.format(" (%s)", String.join(",", types));
+        Set<String> types = identities.stream().map(i -> {
+            if (i.getType() == IdentityType.EDU_GAIN && i.getTypedId().endsWith("@ia2.inaf.it")) {
+                return "IA2";
+            }
+            return i.getType().getValue();
+        }).collect(Collectors.toSet());
+        displayName += String.format(" (%s)", String.join(", ", types));
 
         return displayName;
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/request/RenameGroupRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/request/RenameGroupRequest.java
index 8137728..9bd325e 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/request/RenameGroupRequest.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/request/RenameGroupRequest.java
@@ -9,6 +9,8 @@ public class RenameGroupRequest extends PaginatedModelRequest implements SearchF
     @Size(min = 1)
     private String newGroupName;
 
+    private boolean leaf;
+
     private String searchFilter;
 
     public String getNewGroupName() {
@@ -28,4 +30,12 @@ public class RenameGroupRequest extends PaginatedModelRequest implements SearchF
     public void setSearchFilter(String searchFilter) {
         this.searchFilter = searchFilter;
     }
+
+    public boolean isLeaf() {
+        return leaf;
+    }
+
+    public void setLeaf(boolean leaf) {
+        this.leaf = leaf;
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/response/GroupsTabResponse.java b/gms/src/main/java/it/inaf/ia2/gms/model/response/GroupsTabResponse.java
index 4df4cb5..0eb8665 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/response/GroupsTabResponse.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/response/GroupsTabResponse.java
@@ -12,6 +12,8 @@ public class GroupsTabResponse {
     // current group permissions
     private Permission permission;
 
+    private boolean leaf;
+
     public List<GroupBreadcrumb> getBreadcrumbs() {
         return breadcrumbs;
     }
@@ -35,4 +37,12 @@ public class GroupsTabResponse {
     public void setPermission(Permission permission) {
         this.permission = permission;
     }
+
+    public boolean isLeaf() {
+        return leaf;
+    }
+
+    public void setLeaf(boolean leaf) {
+        this.leaf = leaf;
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java
index 32bc241..301ebd8 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java
@@ -30,13 +30,14 @@ public class GroupsDAO {
 
     public GroupEntity createGroup(GroupEntity group) {
 
-        String sql = "INSERT INTO gms_group (id, name, path) VALUES (?, ?, ?)";
+        String sql = "INSERT INTO gms_group (id, name, path, is_leaf) VALUES (?, ?, ?, ?)";
 
         jdbcTemplate.update(conn -> {
             PreparedStatement ps = conn.prepareStatement(sql);
             ps.setString(1, group.getId());
             ps.setString(2, group.getName());
             ps.setObject(3, group.getPath(), Types.OTHER);
+            ps.setBoolean(4, group.isLeaf());
             return ps;
         });
 
@@ -45,13 +46,14 @@ public class GroupsDAO {
 
     public GroupEntity updateGroup(GroupEntity group) {
 
-        String sql = "UPDATE gms_group SET name = ?, path = ? WHERE id = ?";
+        String sql = "UPDATE gms_group SET name = ?, path = ?, is_leaf = ? WHERE id = ?";
 
         jdbcTemplate.update(conn -> {
             PreparedStatement ps = conn.prepareStatement(sql);
             ps.setString(1, group.getName());
             ps.setObject(2, group.getPath(), Types.OTHER);
-            ps.setString(3, group.getId());
+            ps.setBoolean(3, group.isLeaf());
+            ps.setString(4, group.getId());
             return ps;
         });
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
index 8ea1979..8889c1b 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
@@ -16,13 +16,13 @@ import java.util.stream.Collectors;
 
 @Service
 public class GroupsService {
-
+    
     public static final String ROOT = "ROOT";
-
+    
     private final GroupsDAO groupsDAO;
     private final PermissionsDAO permissionsDAO;
     private final MembershipsDAO membershipsDAO;
-
+    
     @Autowired
     public GroupsService(GroupsDAO groupsDAO,
             PermissionsDAO permissionsDAO, MembershipsDAO membershipsDAO) {
@@ -31,7 +31,7 @@ public class GroupsService {
         this.membershipsDAO = membershipsDAO;
         createRootIfNecessary();
     }
-
+    
     private void createRootIfNecessary() {
         if (groupsDAO.count() == 0) {
             GroupEntity root = new GroupEntity();
@@ -41,88 +41,90 @@ public class GroupsService {
             groupsDAO.createGroup(root);
         }
     }
-
-    public GroupEntity addGroup(GroupEntity parent, String groupName) {
-
+    
+    public GroupEntity addGroup(GroupEntity parent, String groupName, boolean leaf) {
+        
         if (groupsDAO.getDirectSubGroups(parent.getPath()).stream()
                 .anyMatch(g -> g.getName().equals(groupName))) {
             throw new BadRequestException("There is already a group named " + groupName);
         }
-
+        
         String newGroupId = UUID.randomUUID().toString().replaceAll("-", "");
-
+        
         String path = parent.getPath();
         if (!path.isEmpty()) {
             path += ".";
         }
         path += newGroupId;
-
+        
         GroupEntity group = new GroupEntity();
         group.setId(newGroupId);
         group.setName(groupName);
         group.setPath(path);
-
+        group.setLeaf(leaf);
+        
         groupsDAO.createGroup(group);
-
+        
         return group;
     }
-
-    public GroupEntity renameGroup(GroupEntity group, String newGroupName) {
-
+    
+    public GroupEntity renameGroup(GroupEntity group, String newGroupName, boolean leaf) {
+        
         if (groupsDAO.getDirectSubGroups(group.getPath()).stream()
                 .anyMatch(g -> g.getName().equals(newGroupName))) {
             throw new BadRequestException("There is already a group named " + newGroupName);
         }
-
+        
         group.setName(newGroupName);
-
+        group.setLeaf(leaf);
+        
         return groupsDAO.updateGroup(group);
     }
-
+    
     public GroupEntity deleteGroup(GroupEntity group) {
-
+        
         if (ROOT.equals(group.getId())) {
             throw new UnauthorizedException("It is not possible to remove the ROOT");
         }
-
+        
         String parentPath = group.getParentPath();
         GroupEntity parent = groupsDAO.findGroupByPath(parentPath)
                 .orElseThrow(() -> new BadRequestException("No group found at path " + parentPath));
-
+        
         List<GroupEntity> groupsToDelete = groupsDAO.getAllChildren(group.getPath());
         groupsToDelete.add(group);
-
+        
         List<String> groupsToDeleteIds = groupsToDelete.stream()
                 .map(g -> g.getId()).collect(Collectors.toList());
-
+        
         membershipsDAO.deleteAllGroupsMembership(groupsToDeleteIds);
         permissionsDAO.deleteAllGroupsPermissions(groupsToDeleteIds);
-
+        
         for (String groupId : groupsToDeleteIds) {
             groupsDAO.deleteGroupById(groupId);
         }
-
+        
         return parent;
     }
-
+    
     public GroupEntity getRoot() {
         return getGroupById(ROOT);
     }
-
+    
     public GroupEntity getGroupById(String groupId) {
         return groupsDAO.findGroupById(groupId)
                 .orElseThrow(() -> new BadRequestException("Group " + groupId + " not found"));
     }
-
+    
     public GroupEntity getGroupByPath(String path) {
         return groupsDAO.findGroupByPath(path)
                 .orElseThrow(() -> new BadRequestException("Group not found at path " + path));
     }
-
+    
     public List<GroupBreadcrumb> getBreadcrumbs(String path) {
         return groupsDAO.getBreadcrumbs(path);
     }
-
+    
     public Optional<GroupEntity> findGroupByParentAndName(GroupEntity parent, String childName) {
         return groupsDAO.findGroupByParentAndName(parent.getPath(), childName);
     }
@@ -137,7 +139,7 @@ public class GroupsService {
         // after retrieving this list it is necessary to match for the correct
         // group
         List<GroupEntity> groups = groupsDAO.findGroupsByNames(names);
-
+        
         String parentPath = "";
         GroupEntity group = null;
         for (String name : names) {
@@ -148,10 +150,10 @@ public class GroupsService {
                 parentPath = group.getPath();
             }
         }
-
+        
         return Optional.ofNullable(group);
     }
-
+    
     private GroupEntity findGroup(List<GroupEntity> groups, String parentPath, String groupName) {
         for (GroupEntity group : groups) {
             if (parentPath.equals(group.getParentPath()) && groupName.equals(group.getName())) {
@@ -160,7 +162,7 @@ public class GroupsService {
         }
         return null;
     }
-
+    
     public List<GroupEntity> searchGroups(String searchText) {
         return groupsDAO.searchGroups(searchText);
     }
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceControllerTest.java
index bca8fe9..0061ca3 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/BasicAuthWebServiceControllerTest.java
@@ -19,6 +19,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import static org.mockito.Mockito.times;
@@ -74,7 +75,7 @@ public class BasicAuthWebServiceControllerTest {
 
         when(groupsService.getRoot()).thenReturn(root);
         when(groupsService.findGroupByParentAndName(eq(root), eq("LBT"))).thenReturn(Optional.of(lbt));
-        when(groupsService.addGroup(eq(lbt), eq("INAF"))).thenReturn(inaf);
+        when(groupsService.addGroup(eq(lbt), eq("INAF"), anyBoolean())).thenReturn(inaf);
 
         List<String> names = Arrays.asList("LBT", "INAF");
 
diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
index 9d9fb6e..7db372b 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
@@ -47,12 +47,12 @@ public class NestedGroupsIntegrationTest {
 
         // Setup groups
         GroupEntity root = groupsService.getRoot();
-        GroupEntity lbt = groupsService.addGroup(root, "LBT");
-        GroupEntity tng = groupsService.addGroup(root, "TNG");
-        GroupEntity radio = groupsService.addGroup(root, "Radio");
-        GroupEntity lbtInaf = groupsService.addGroup(lbt, "INAF");
-        GroupEntity lbtInafProgram1 = groupsService.addGroup(lbtInaf, "P1");
-        GroupEntity lbtInafProgram2 = groupsService.addGroup(lbtInaf, "P2");
+        GroupEntity lbt = groupsService.addGroup(root, "LBT", false);
+        GroupEntity tng = groupsService.addGroup(root, "TNG", false);
+        GroupEntity radio = groupsService.addGroup(root, "Radio", false);
+        GroupEntity lbtInaf = groupsService.addGroup(lbt, "INAF", false);
+        GroupEntity lbtInafProgram1 = groupsService.addGroup(lbtInaf, "P1", false);
+        GroupEntity lbtInafProgram2 = groupsService.addGroup(lbtInaf, "P2", false);
 
         GroupsRequest request = new GroupsRequest();
         request.setPaginatorPage(1);
-- 
GitLab