From 0922b0322284457580c6e162765eccc4c7323526 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Thu, 18 Mar 2021 18:30:20 +0100
Subject: [PATCH] API endpoints refactoring

---
 .../ia2/gms/client/call/AddMemberCall.java    | 13 ++-
 .../gms/client/call/AddPermissionCall.java    | 12 ++-
 .../ia2/gms/client/call/DeleteGroupCall.java  |  5 +-
 .../client/call/GetGroupPermissionsCall.java  |  7 +-
 .../gms/client/call/GetUserGroupsCall.java    | 14 ++--
 .../client/call/GetUserPermissionsCall.java   |  3 +-
 .../ia2/gms/client/call/ListGroupsCall.java   | 18 ++--
 .../ia2/gms/client/call/RemoveMemberCall.java | 12 ++-
 .../gms/client/call/RemovePermissionCall.java | 12 ++-
 .../gms/client/call/SetPermissionCall.java    | 12 +--
 .../ia2/gms/client/call/AddMemberTest.java    |  2 +-
 .../gms/client/call/AddPermissionTest.java    |  2 +-
 .../ia2/gms/client/call/CreateGroupTest.java  |  2 +-
 .../ia2/gms/client/call/DeleteGroupTest.java  |  2 +-
 .../gms/client/call/GetUserGroupsTest.java    |  4 +-
 .../ia2/gms/client/call/RemoveMemberTest.java |  2 +-
 .../gms/client/call/RemovePermissionTest.java |  2 +-
 .../ia2/gms/controller/GroupsController.java  | 31 +++++--
 .../controller/JWTWebServiceController.java   | 10 ++-
 .../ia2/gms/controller/MembersController.java | 24 ++++++
 .../gms/controller/PermissionsController.java | 56 ++++++++++++-
 .../inaf/ia2/gms/manager/GroupsManager.java   | 20 +++++
 .../ia2/gms/manager/PermissionsManager.java   |  4 +
 .../inaf/ia2/gms/service/GroupsService.java   |  8 ++
 .../ia2/gms/service/PermissionsService.java   |  4 +
 .../gms/controller/ControllersMockData.java   | 64 +++++++++++++++
 .../gms/controller/GroupsControllerTest.java  | 40 ++++-----
 .../JWTWebServiceControllerTest.java          |  2 +-
 .../gms/controller/MembersControllerTest.java | 54 ++++++++++--
 .../controller/PermissionsControllerTest.java | 82 +++++++++++++++++++
 30 files changed, 436 insertions(+), 87 deletions(-)
 create mode 100644 gms/src/test/java/it/inaf/ia2/gms/controller/ControllersMockData.java

diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddMemberCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddMemberCall.java
index 70bb477..a6294f3 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddMemberCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddMemberCall.java
@@ -2,9 +2,11 @@ package it.inaf.ia2.gms.client.call;
 
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpRequest.BodyPublishers;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 
 public class AddMemberCall extends BaseCall<GmsClient> {
 
@@ -14,15 +16,18 @@ public class AddMemberCall extends BaseCall<GmsClient> {
 
     public boolean addMember(String completeGroupName, String userId) {
 
-        String endpoint = "ws/jwt/membership";
-        if (completeGroupName != null && !completeGroupName.isBlank()) {
-            endpoint += "/" + completeGroupName;
+        String endpoint = "membership";
+
+        if (completeGroupName == null) {
+            completeGroupName = "";
         }
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
                 .header("Content-Type", "application/x-www-form-urlencoded")
-                .POST(BodyPublishers.ofString("user_id=" + userId))
+                .POST(BodyPublishers.ofString(
+                        "group=" + URLEncoder.encode(completeGroupName, StandardCharsets.UTF_8)
+                        + "&user_id=" + userId))
                 .build();
 
         return client.call(groupsRequest, BodyHandlers.ofInputStream(), 200, res -> true);
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddPermissionCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddPermissionCall.java
index ace30ec..f9977ea 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddPermissionCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/AddPermissionCall.java
@@ -3,10 +3,12 @@ package it.inaf.ia2.gms.client.call;
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
 import it.inaf.ia2.gms.client.model.Permission;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpRequest.BodyPublisher;
 import java.net.http.HttpRequest.BodyPublishers;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 
 public class AddPermissionCall extends BaseCall<GmsClient> {
 
@@ -16,13 +18,15 @@ public class AddPermissionCall extends BaseCall<GmsClient> {
 
     public String addPermission(String completeGroupName, String userId, Permission permission) {
 
-        String endpoint = "ws/jwt/permission";
-        if (completeGroupName != null && !completeGroupName.isBlank()) {
-            endpoint += "/" + completeGroupName;
+        String endpoint = "permission";
+
+        if (completeGroupName == null) {
+            completeGroupName = "";
         }
 
         BodyPublisher requestBody = BodyPublishers.ofString(
-                "user_id=" + userId + "&permission=" + permission);
+                "group=" + URLEncoder.encode(completeGroupName, StandardCharsets.UTF_8)
+                + "&user_id=" + userId + "&permission=" + permission);
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/DeleteGroupCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/DeleteGroupCall.java
index bbde41d..4e1b763 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/DeleteGroupCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/DeleteGroupCall.java
@@ -2,8 +2,10 @@ package it.inaf.ia2.gms.client.call;
 
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 
 public class DeleteGroupCall extends BaseCall<GmsClient> {
 
@@ -13,7 +15,8 @@ public class DeleteGroupCall extends BaseCall<GmsClient> {
 
     public boolean deleteGroup(String completeGroupName) {
 
-        HttpRequest groupsRequest = client.newRequest("ws/jwt/" + completeGroupName)
+        HttpRequest groupsRequest = client.newRequest("group?name="
+                + URLEncoder.encode(completeGroupName, StandardCharsets.UTF_8))
                 .header("Accept", "text/plain")
                 .DELETE()
                 .build();
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetGroupPermissionsCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetGroupPermissionsCall.java
index 5e782d1..94edece 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetGroupPermissionsCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetGroupPermissionsCall.java
@@ -4,8 +4,10 @@ import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
 import it.inaf.ia2.gms.client.model.GroupPermission;
 import it.inaf.ia2.gms.client.model.Permission;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Scanner;
@@ -16,12 +18,11 @@ public class GetGroupPermissionsCall extends BaseCall<GmsClient> {
         super(client);
     }
 
-    public List<GroupPermission> getGroupPermissions(String groupId) {
+    public List<GroupPermission> getGroupPermissions(String groupName) {
 
         List<GroupPermission> groupPermissions = new ArrayList<>();
 
-        String endpoint = "ws/jwt/permission";
-        endpoint += "/" + groupId;
+        String endpoint = "permission?group=" + URLEncoder.encode(groupName, StandardCharsets.UTF_8);
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserGroupsCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserGroupsCall.java
index a6a4b66..1b504cb 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserGroupsCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserGroupsCall.java
@@ -2,8 +2,10 @@ package it.inaf.ia2.gms.client.call;
 
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Scanner;
@@ -48,15 +50,17 @@ public class GetUserGroupsCall extends BaseCall<GmsClient> {
                 });
     }
 
-    public List<String> getUserGroups(String userId, String prefix) {
+    public List<String> getUserGroups(String userId, String groupName) {
 
         List<String> groups = new ArrayList<>();
 
-        String endpoint = "ws/jwt/membership";
-        if (prefix != null && !prefix.isBlank()) {
-            endpoint += "/" + prefix;
+        if (groupName == null) {
+            groupName = "";
         }
-        endpoint += "?user_id=" + userId;
+
+        String endpoint = "membership?group="
+                + URLEncoder.encode(groupName, StandardCharsets.UTF_8)
+                + "&user_id=" + userId;
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserPermissionsCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserPermissionsCall.java
index 8f4e9ed..ab15574 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserPermissionsCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/GetUserPermissionsCall.java
@@ -20,8 +20,7 @@ public class GetUserPermissionsCall extends BaseCall<GmsClient> {
 
         List<UserPermission> userPermissions = new ArrayList<>();
 
-        String endpoint = "ws/jwt/permission";
-        endpoint += "?user_id=" + userId;
+        String endpoint = "permission?user_id=" + userId;
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/ListGroupsCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/ListGroupsCall.java
index f032d9c..7cb26a8 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/ListGroupsCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/ListGroupsCall.java
@@ -2,8 +2,10 @@ package it.inaf.ia2.gms.client.call;
 
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Scanner;
@@ -16,18 +18,20 @@ public class ListGroupsCall extends BaseCall<GmsClient> {
 
     /**
      * Returns the list of the groups in a given parent group (if the user has
-     * the privileges to see that information). The prefix is removed by the
-     * service.
+     * the privileges to see that information). The parent group name is removed
+     * by the service.
      */
-    public List<String> listGroups(String prefix, boolean recursive) {
+    public List<String> listGroups(String parentGroup, boolean recursive) {
 
         List<String> groups = new ArrayList<>();
 
-        String uri = "list";
-        if (prefix != null && !prefix.isBlank()) {
-            uri += "/" + prefix;
+        if (parentGroup == null) {
+            parentGroup = "";
         }
-        uri += "?recursive=" + recursive;
+
+        String uri = "groups?parent="
+                + URLEncoder.encode(parentGroup, StandardCharsets.UTF_8)
+                + "&recursive=" + recursive;
 
         HttpRequest groupsRequest = client.newRequest(uri)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemoveMemberCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemoveMemberCall.java
index 7daf15e..31fb348 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemoveMemberCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemoveMemberCall.java
@@ -2,8 +2,10 @@ package it.inaf.ia2.gms.client.call;
 
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 
 public class RemoveMemberCall extends BaseCall<GmsClient> {
 
@@ -13,11 +15,13 @@ public class RemoveMemberCall extends BaseCall<GmsClient> {
 
     public boolean removeMember(String completeGroupName, String userId) {
 
-        String endpoint = "ws/jwt/membership";
-        if (completeGroupName != null && !completeGroupName.isBlank()) {
-            endpoint += "/" + completeGroupName;
+        if (completeGroupName == null) {
+            completeGroupName = "";
         }
-        endpoint += "?user_id=" + userId;
+
+        String endpoint = "membership?group="
+                + URLEncoder.encode(completeGroupName, StandardCharsets.UTF_8)
+                + "&user_id=" + userId;
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemovePermissionCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemovePermissionCall.java
index 3602a55..6faf01c 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemovePermissionCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/RemovePermissionCall.java
@@ -2,8 +2,10 @@ package it.inaf.ia2.gms.client.call;
 
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 
 public class RemovePermissionCall extends BaseCall<GmsClient> {
 
@@ -13,11 +15,13 @@ public class RemovePermissionCall extends BaseCall<GmsClient> {
 
     public boolean removePermission(String completeGroupName, String userId) {
 
-        String endpoint = "ws/jwt/permission";
-        if (completeGroupName != null && !completeGroupName.isBlank()) {
-            endpoint += "/" + completeGroupName;
+        if (completeGroupName == null) {
+            completeGroupName = "";
         }
-        endpoint += "?user_id=" + userId;
+
+        String endpoint = "permission?group="
+                + URLEncoder.encode(completeGroupName, StandardCharsets.UTF_8)
+                + "&user_id=" + userId;
 
         HttpRequest groupsRequest = client.newRequest(endpoint)
                 .header("Accept", "text/plain")
diff --git a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/SetPermissionCall.java b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/SetPermissionCall.java
index 97ceb21..67c1b91 100644
--- a/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/SetPermissionCall.java
+++ b/gms-client/gms-client/src/main/java/it/inaf/ia2/gms/client/call/SetPermissionCall.java
@@ -3,8 +3,10 @@ package it.inaf.ia2.gms.client.call;
 import it.inaf.ia2.client.BaseCall;
 import it.inaf.ia2.gms.client.GmsClient;
 import it.inaf.ia2.gms.client.model.Permission;
+import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 
 public class SetPermissionCall extends BaseCall<GmsClient> {
 
@@ -14,15 +16,15 @@ public class SetPermissionCall extends BaseCall<GmsClient> {
 
     public String setPermission(String completeGroupName, String userId, Permission permission) {
 
-        String endpoint = "ws/jwt/permission";
-        if (completeGroupName != null && !completeGroupName.isBlank()) {
-            endpoint += "/" + completeGroupName;
+        if (completeGroupName == null) {
+            completeGroupName = "";
         }
 
         HttpRequest.BodyPublisher requestBody = HttpRequest.BodyPublishers.ofString(
-                "user_id=" + userId + "&permission=" + permission);
+                "group=" + URLEncoder.encode(completeGroupName, StandardCharsets.UTF_8)
+                + "&user_id=" + userId + "&permission=" + permission);
 
-        HttpRequest groupsRequest = client.newRequest(endpoint)
+        HttpRequest groupsRequest = client.newRequest("permission")
                 .header("Accept", "text/plain")
                 .header("Content-Type", "application/x-www-form-urlencoded")
                 .PUT(requestBody)
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddMemberTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddMemberTest.java
index 268b2f0..5148831 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddMemberTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddMemberTest.java
@@ -28,6 +28,6 @@ public class AddMemberTest extends BaseGmsClientTest {
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
         gmsClient.addMember("LBT.INAF", "user");
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "ws/jwt/membership/LBT.INAF"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "membership"), any());
     }
 }
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddPermissionTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddPermissionTest.java
index 4c68372..3887282 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddPermissionTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/AddPermissionTest.java
@@ -29,6 +29,6 @@ public class AddPermissionTest extends BaseGmsClientTest {
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
         gmsClient.addPermission("LBT.INAF", "user", Permission.ADMIN);
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "ws/jwt/permission/LBT.INAF"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "permission"), any());
     }
 }
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/CreateGroupTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/CreateGroupTest.java
index 8c62a3f..7968694 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/CreateGroupTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/CreateGroupTest.java
@@ -28,6 +28,6 @@ public class CreateGroupTest extends BaseGmsClientTest {
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
         gmsClient.createGroup("LBT.INAF", false);
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "ws/jwt/LBT.INAF"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "group"), any());
     }
 }
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/DeleteGroupTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/DeleteGroupTest.java
index e5b1161..c27bd57 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/DeleteGroupTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/DeleteGroupTest.java
@@ -28,6 +28,6 @@ public class DeleteGroupTest extends BaseGmsClientTest {
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
         gmsClient.deleteGroup("LBT.INAF");
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "ws/jwt/LBT.INAF"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "group?name=LBT.INAF"), any());
     }
 }
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/GetUserGroupsTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/GetUserGroupsTest.java
index d7cde9f..e2b3ea5 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/GetUserGroupsTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/GetUserGroupsTest.java
@@ -50,9 +50,9 @@ public class GetUserGroupsTest extends BaseGmsClientTest {
         CompletableFuture response = CompletableFuture.completedFuture(getMockedStreamResponse(200, body));
 
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
-        List<String> groups = gmsClient.listGroups("LBT.", false);
+        List<String> groups = gmsClient.listGroups("LBT", false);
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("GET", "list/LBT.?recursive=false"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("GET", "groups?parent=LBT&recursive=false"), any());
 
         assertEquals(2, groups.size());
         assertEquals("INAF", groups.get(0));
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemoveMemberTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemoveMemberTest.java
index 845dbb2..ede76ac 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemoveMemberTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemoveMemberTest.java
@@ -28,6 +28,6 @@ public class RemoveMemberTest extends BaseGmsClientTest {
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
         gmsClient.removeMember("LBT.INAF", "user");
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "ws/jwt/membership/LBT.INAF?user_id=user"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "membership?group=LBT.INAF&user_id=user"), any());
     }
 }
diff --git a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemovePermissionTest.java b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemovePermissionTest.java
index c1a86b0..cc49686 100644
--- a/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemovePermissionTest.java
+++ b/gms-client/gms-client/src/test/java/it/inaf/ia2/gms/client/call/RemovePermissionTest.java
@@ -28,6 +28,6 @@ public class RemovePermissionTest extends BaseGmsClientTest {
         when(httpClient.sendAsync(any(), any())).thenReturn(response);
         gmsClient.removePermission("LBT.INAF", "user");
 
-        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "ws/jwt/permission/LBT.INAF?user_id=user"), any());
+        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "permission?group=LBT.INAF&user_id=user"), any());
     }
 }
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 e806e75..c4ec0fb 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
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.security.Principal;
 import java.util.List;
 import java.util.Optional;
 import javax.servlet.http.HttpServletRequest;
@@ -146,20 +147,33 @@ public class GroupsController {
         return groupsTreeBuilder.listSubGroups(parentGroup, request, servletRequest.getUserPrincipal().getName());
     }
 
+    @GetMapping(value = "/groups", produces = MediaType.TEXT_PLAIN_VALUE)
+    public void listChildGroups(@RequestParam("parent") Optional<String> groupNames,
+            @RequestParam(value = "recursive", defaultValue = "false") boolean recursive,
+            Principal principal, HttpServletResponse response) throws IOException {
+
+        GroupEntity parentGroup = groupNameService.getGroupFromNames(groupNames);
+
+        List<GroupEntity> visibleSubgroups = groupsManager.getChildGroups(parentGroup, recursive);
+
+        try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+            for (String groupName : groupNameService.getGroupsNames(visibleSubgroups)) {
+                pw.println(groupNameService.getShortGroupName(groupName, groupNames));
+            }
+        }
+    }
+
     /**
      * Creates a group and its ancestors if they are missing. It doesn't fail if
-     * the last group already exists.
+     * the last group already exists. For CLI/API usage.
      */
     @PostMapping(value = "/group", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
     public void createGroup(@RequestParam("name") String groupParam,
             @RequestParam(value = "leaf", required = false, defaultValue = "false") boolean leaf,
-            HttpServletRequest request, HttpServletResponse response) throws IOException {
+            HttpServletResponse response) throws IOException {
 
         List<String> groupNames = groupNameService.extractGroupNames(groupParam);
 
-        String leafParam = request.getParameter("leaf");
-        //boolean leaf = leafParam == null ? false : Boolean.valueOf(leafParam);
-
         GroupEntity group = groupsManager.getRoot();
         for (int i = 0; i < groupNames.size(); i++) {
             String name = groupNames.get(i);
@@ -176,4 +190,11 @@ public class GroupsController {
             pw.println(groupParam);
         }
     }
+
+    @DeleteMapping(value = "/group", produces = MediaType.TEXT_PLAIN_VALUE)
+    public ResponseEntity<?> deleteGroup(@RequestParam("name") String groupParam) {
+        GroupEntity group = groupNameService.getGroupFromNames(Optional.of(groupParam));
+        groupsManager.deleteGroup(group.getId());
+        return ResponseEntity.noContent().build();
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
index 38f1e4f..da64a1a 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
@@ -200,13 +200,15 @@ public class JWTWebServiceController {
         }
     }
 
+    @Deprecated
     @DeleteMapping(value = "/ws/jwt/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE)
     public void deleteGroup(@PathVariable("group") String groupParam, HttpServletResponse response) {
         GroupEntity group = groupNameService.getGroupFromNames(Optional.of(groupParam));
-        groupsDAO.deleteGroup(group);
+        groupsManager.deleteGroup(group.getId());
         response.setStatus(HttpServletResponse.SC_NO_CONTENT);
     }
 
+    @Deprecated
     @GetMapping(value = {"/ws/jwt/membership/{group:.+}", "/ws/jwt/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
     public void getMembership(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId, HttpServletResponse response) throws IOException {
 
@@ -221,6 +223,7 @@ public class JWTWebServiceController {
         }
     }
 
+    @Deprecated
     @PostMapping(value = {"/ws/jwt/membership/{group:.+}", "/ws/jwt/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
     public void addMember(@PathVariable("group") Optional<String> groupNames, HttpServletRequest request, HttpServletResponse response) throws IOException {
 
@@ -235,6 +238,7 @@ public class JWTWebServiceController {
         membershipManager.addMember(groupEntity, targetUserId);
     }
 
+    @Deprecated
     @DeleteMapping(value = {"/ws/jwt/membership/{group:.+}", "/ws/jwt/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
     public void removeMember(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId,
             HttpServletRequest request, HttpServletResponse response) throws IOException {
@@ -245,6 +249,7 @@ public class JWTWebServiceController {
         response.setStatus(HttpServletResponse.SC_NO_CONTENT);
     }
 
+    @Deprecated
     @GetMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission"}, produces = MediaType.TEXT_PLAIN_VALUE)
     public void getUserPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") Optional<String> userId, HttpServletRequest request, HttpServletResponse response) throws IOException {
 
@@ -265,18 +270,21 @@ public class JWTWebServiceController {
         }
     }
 
+    @Deprecated
     @PostMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
     public void addPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException {
         GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
         permissionsManager.addPermission(groupEntity, targetUserId, permission);
     }
 
+    @Deprecated
     @PutMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
     public void setPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException {
         GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
         permissionsManager.createOrUpdatePermission(groupEntity, targetUserId, permission);
     }
 
+    @Deprecated
     @DeleteMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE)
     public void removePermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId,
             HttpServletRequest request, HttpServletResponse response) throws IOException {
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 3db24db..def7eed 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
@@ -8,10 +8,12 @@ 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.GroupNameService;
 import it.inaf.ia2.gms.service.GroupsService;
 import it.inaf.ia2.rap.data.RapUser;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import javax.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -21,6 +23,7 @@ import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
@@ -35,6 +38,9 @@ public class MembersController {
     @Autowired
     private PermissionsManager permissionsManager;
 
+    @Autowired
+    protected GroupNameService groupNameService;
+
     @GetMapping(value = "/members", produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<PaginatedData<RapUser>> getMembersTab(TabRequest request) {
 
@@ -77,4 +83,22 @@ public class MembersController {
         });
         return new PaginatedData<>(members, request.getPaginatorPage(), request.getPaginatorPageSize());
     }
+
+    @PostMapping(value = "/membership", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    public void addMember(@RequestParam("group") Optional<String> groupNames,
+            @RequestParam("user_id") String targetUserId) {
+
+        GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
+
+        membershipManager.addMember(groupEntity, targetUserId);
+    }
+
+    @DeleteMapping(value = "/membership", produces = MediaType.TEXT_PLAIN_VALUE)
+    public ResponseEntity<?> removeMember(@RequestParam("group") Optional<String> groupNames, @RequestParam("user_id") String userId) {
+
+        GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
+        membershipManager.removeMember(groupEntity, userId);
+
+        return ResponseEntity.noContent().build();
+    }
 }
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 84e3faf..80942ea 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
@@ -1,6 +1,5 @@
 package it.inaf.ia2.gms.controller;
 
-import it.inaf.ia2.gms.exception.BadRequestException;
 import it.inaf.ia2.gms.manager.GroupsManager;
 import it.inaf.ia2.gms.manager.PermissionsManager;
 import it.inaf.ia2.gms.model.request.AddPermissionRequest;
@@ -15,13 +14,16 @@ import it.inaf.ia2.gms.model.response.UserPermission;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.persistence.model.PermissionEntity;
 import it.inaf.ia2.gms.service.GroupNameService;
+import it.inaf.ia2.gms.service.SearchService;
+import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -29,6 +31,7 @@ import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -44,6 +47,12 @@ public class PermissionsController {
     @Autowired
     private PermissionsManager permissionsManager;
 
+    @Autowired
+    protected GroupNameService groupNameService;
+
+    @Autowired
+    private SearchService searchService;
+
     @GetMapping(value = "/permissions", produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<PaginatedData<RapUserPermission>> getPermissionsTab(TabRequest request) {
 
@@ -109,4 +118,45 @@ public class PermissionsController {
         });
         return new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize());
     }
+
+    @GetMapping(value = "/permission", produces = MediaType.TEXT_PLAIN_VALUE)
+    public void getUserPermission(@RequestParam("group") Optional<String> groupNames, @RequestParam("user_id") Optional<String> userId, HttpServletRequest request, HttpServletResponse response) throws IOException {
+
+        GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
+        if (userId.isPresent()) {
+            try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+                for (UserPermission userPermission : searchService.getUserPermission(groupEntity, userId.get(), permissionsManager.getCurrentUserPermissions(groupEntity))) {
+                    String group = String.join(".", userPermission.getGroupCompleteName());
+                    pw.println(group + " " + userPermission.getPermission());
+                }
+            }
+        } else {
+            try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+                for (it.inaf.ia2.gms.model.RapUserPermission up : permissionsManager.getAllPermissions(groupEntity)) {
+                    pw.println(up.getUser().getId() + " " + up.getPermission());
+                }
+            }
+        }
+    }
+
+    @PostMapping(value = "/permission", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    public void addPermission(@RequestParam("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException {
+        GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
+        permissionsManager.addPermission(groupEntity, targetUserId, permission);
+    }
+
+    @PutMapping(value = "/permission", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    public void setPermission(@RequestParam("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException {
+        GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
+        permissionsManager.createOrUpdatePermission(groupEntity, targetUserId, permission);
+    }
+
+    @DeleteMapping(value = "/permission", produces = MediaType.TEXT_PLAIN_VALUE)
+    public ResponseEntity<?> removePermission(@RequestParam("group") Optional<String> groupNames, @RequestParam("user_id") String userId) {
+
+        GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
+        permissionsManager.removePermission(groupEntity, userId);
+
+        return ResponseEntity.noContent().build();
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/GroupsManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/GroupsManager.java
index f2a2d8d..fa2e475 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/manager/GroupsManager.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/manager/GroupsManager.java
@@ -5,7 +5,11 @@ import it.inaf.ia2.gms.exception.UnauthorizedException;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.persistence.LoggingDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.persistence.model.PermissionEntity;
 import it.inaf.ia2.gms.service.GroupsService;
+import it.inaf.ia2.gms.service.PermissionUtils;
+import java.util.ArrayList;
+import java.util.List;
 import org.springframework.stereotype.Service;
 
 @Service
@@ -37,6 +41,22 @@ public class GroupsManager extends UserAwareComponent {
         return group;
     }
 
+    public List<GroupEntity> getChildGroups(GroupEntity parentGroup, boolean recursive) {
+        List<GroupEntity> allSubGroups = groupsService.getChildGroups(parentGroup, recursive);
+
+        // Select only the groups visible to the user
+        List<PermissionEntity> permissions = permissionsManager.getCurrentUserPermissions();
+        List<GroupEntity> visibleSubgroups = new ArrayList<>();
+
+        for (GroupEntity subgroup : allSubGroups) {
+            PermissionUtils.getGroupPermission(subgroup, permissions).ifPresent(permission -> {
+                visibleSubgroups.add(subgroup);
+            });
+        }
+
+        return visibleSubgroups;
+    }
+
     public GroupEntity createGroup(GroupEntity parent, String childGroupName, boolean leaf) {
 
         if (parent.isLeaf()) {
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 eab8686..d4568f3 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
@@ -148,6 +148,10 @@ public class PermissionsManager extends UserAwareComponent {
         return () -> new UnauthorizedException("You don't have the privileges for managing the requested permission");
     }
 
+    public List<PermissionEntity> getCurrentUserPermissions() {
+        return permissionsService.findUserPermissions(getCurrentUserId());
+    }
+
     public List<PermissionEntity> getCurrentUserPermissions(GroupEntity group) {
         return permissionsService.findUserPermissions(group, getCurrentUserId());
     }
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 e585896..e39e285 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
@@ -184,4 +184,12 @@ public class GroupsService {
     public List<GroupEntity> searchGroups(String searchText) {
         return groupsDAO.searchGroups(searchText);
     }
+    
+    public List<GroupEntity> getChildGroups(GroupEntity parentGroup, boolean recursive) {
+        if (recursive) {
+            return groupsDAO.getAllChildren(parentGroup.getPath());
+        } else {
+            return groupsDAO.getDirectSubGroups(parentGroup.getPath());
+        }
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
index d953563..6457571 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
@@ -26,6 +26,10 @@ public class PermissionsService {
         return permissionsDAO.getGroupsPermissions(group.getId());
     }
 
+    public List<PermissionEntity> findUserPermissions(String userId) {
+        return permissionsDAO.findUserPermissions(userId);
+    }
+
     public List<PermissionEntity> findUserPermissions(GroupEntity group, String userId) {
         return permissionsDAO.findUserPermissions(userId, group.getPath());
     }
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/ControllersMockData.java b/gms/src/test/java/it/inaf/ia2/gms/controller/ControllersMockData.java
new file mode 100644
index 0000000..0201297
--- /dev/null
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/ControllersMockData.java
@@ -0,0 +1,64 @@
+package it.inaf.ia2.gms.controller;
+
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.service.GroupsService;
+import it.inaf.ia2.rap.data.RapUser;
+import java.security.Principal;
+
+public class ControllersMockData {
+
+    public static GroupEntity getRoot() {
+        GroupEntity root = new GroupEntity();
+        root.setId(GroupsService.ROOT);
+        root.setName(GroupsService.ROOT);
+        root.setPath("");
+        return root;
+    }
+
+    public static GroupEntity getLbtGroup() {
+        GroupEntity lbt = new GroupEntity();
+        lbt.setId("lbt_id");
+        lbt.setName("LBT");
+        lbt.setPath("lbt_id");
+        return lbt;
+    }
+
+    public static GroupEntity getInafGroup() {
+        GroupEntity inaf = new GroupEntity();
+        inaf.setId("inaf_id");
+        inaf.setName("INAF");
+        inaf.setPath("lbt_id.inaf_id");
+        return inaf;
+    }
+
+    public static GroupEntity getPeopleGroup() {
+        GroupEntity lbt = new GroupEntity();
+        lbt.setId("people_id");
+        lbt.setName("people");
+        lbt.setPath("people_id");
+        return lbt;
+    }
+
+    public static GroupEntity getNameSurnameGroup() {
+        GroupEntity inaf = new GroupEntity();
+        inaf.setId("user_group_id");
+        inaf.setName("name.surname");
+        inaf.setPath("people_id.user_group_id");
+        return inaf;
+    }
+
+    public static RapUser getRapUser() {
+        RapUser user = new RapUser();
+        user.setId("rap_user");
+        return user;
+    }
+
+    public static Principal getPrincipal() {
+        return new Principal() {
+            @Override
+            public String getName() {
+                return "TEST_PRINCIPAL";
+            }
+        };
+    }
+}
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java
index 369a8ed..29afb8a 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java
@@ -2,6 +2,7 @@ package it.inaf.ia2.gms.controller;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import it.inaf.ia2.gms.GmsTestUtils;
+import static it.inaf.ia2.gms.controller.ControllersMockData.*;
 import it.inaf.ia2.gms.manager.GroupsManager;
 import it.inaf.ia2.gms.manager.PermissionsManager;
 import it.inaf.ia2.gms.model.GroupNode;
@@ -17,6 +18,7 @@ import it.inaf.ia2.gms.service.GroupsService;
 import it.inaf.ia2.gms.service.GroupsTreeBuilder;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import javax.servlet.http.HttpServletRequest;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
@@ -122,7 +124,7 @@ public class GroupsControllerTest {
     }
 
     @Test
-    public void testDeleteGroup() throws Exception {
+    public void testDeleteGroupPaginated() throws Exception {
 
         mockMvc.perform(delete("/group/id?paginatorPageSize=20&paginatorPage=1&searchFilter="))
                 .andDo(print())
@@ -132,7 +134,7 @@ public class GroupsControllerTest {
     }
 
     @Test
-    public void testAddGroupTextPlain() throws Exception {
+    public void testAddGroupWs() throws Exception {
 
         GroupEntity peopleGroup = getPeopleGroup();
 
@@ -152,31 +154,21 @@ public class GroupsControllerTest {
         verify(groupsManager, times(1)).createGroup(argGroupIdEq("people_id"), eq("name.surname"), eq(true));
     }
 
-    private GroupEntity argGroupIdEq(String groupId) {
-        return argThat(g -> g.getId().equals(groupId));
-    }
+    @Test
+    public void testDeleteGroupWs() throws Exception {
 
-    private GroupEntity getRoot() {
-        GroupEntity root = new GroupEntity();
-        root.setId(GroupsService.ROOT);
-        root.setName(GroupsService.ROOT);
-        root.setPath("");
-        return root;
-    }
+        GroupEntity inafGroup = getInafGroup();
 
-    private GroupEntity getPeopleGroup() {
-        GroupEntity lbt = new GroupEntity();
-        lbt.setId("people_id");
-        lbt.setName("people");
-        lbt.setPath("people_id");
-        return lbt;
+        when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(getLbtGroup()));
+        when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inafGroup));
+
+        mockMvc.perform(delete("/group?name=LBT.INAF"))
+                .andExpect(status().isNoContent());
+
+        verify(groupsManager, times(1)).deleteGroup(eq(inafGroup.getId()));
     }
 
-    private GroupEntity getNameSurnameGroup() {
-        GroupEntity inaf = new GroupEntity();
-        inaf.setId("user_group_id");
-        inaf.setName("name.surname");
-        inaf.setPath("people_id.user_group_id");
-        return inaf;
+    private GroupEntity argGroupIdEq(String groupId) {
+        return argThat(g -> g.getId().equals(groupId));
     }
 }
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 9df44f3..952f33d 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
@@ -152,7 +152,7 @@ public class JWTWebServiceControllerTest {
         mockMvc.perform(delete("/ws/jwt/LBT.INAF"))
                 .andExpect(status().isNoContent());
 
-        verify(groupsDAO, times(1)).deleteGroup(eq(inaf));
+        verify(groupsManager, times(1)).deleteGroup(eq(inaf.getId()));
     }
 
     @Test
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
index be3de51..4d7c75f 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
@@ -1,12 +1,18 @@
 package it.inaf.ia2.gms.controller;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import static it.inaf.ia2.gms.controller.ControllersMockData.getInafGroup;
+import static it.inaf.ia2.gms.controller.ControllersMockData.getLbtGroup;
 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.Permission;
+import it.inaf.ia2.gms.persistence.GroupsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.persistence.model.MembershipEntity;
+import it.inaf.ia2.gms.service.GroupNameService;
 import it.inaf.ia2.gms.service.GroupsService;
+import java.util.Optional;
 import static org.hamcrest.CoreMatchers.is;
 import org.junit.Before;
 import org.junit.Test;
@@ -39,6 +45,9 @@ public class MembersControllerTest {
     @Mock
     private MembershipManager membershipManager;
 
+    @Mock
+    private GroupsDAO groupsDAO;
+
     @InjectMocks
     private MembersController controller;
 
@@ -46,23 +55,25 @@ public class MembersControllerTest {
 
     private final ObjectMapper mapper = new ObjectMapper();
 
+    private GroupEntity lbt = getLbtGroup();
+    private GroupEntity inaf = getInafGroup();
+
     @Before
     public void init() {
+        controller.groupNameService = new GroupNameService(groupsDAO);
         mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
 
-        GroupEntity group = new GroupEntity();
-        group.setId("group_id");
-        group.setName("GroupName");
-        group.setPath("parent_id.group_id");
+        when(groupsService.getGroupById(eq("lbt_id"))).thenReturn(lbt);
 
-        when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
+        when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt));
+        when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf));
     }
 
     @Test
     public void testAddMember() throws Exception {
 
         AddMemberRequest request = new AddMemberRequest();
-        request.setGroupId("group_id");
+        request.setGroupId("lbt_id");
         request.setUserId("user_id");
         request.setPaginatorPage(1);
         request.setPaginatorPageSize(10);
@@ -86,4 +97,35 @@ public class MembersControllerTest {
 
         verify(membershipManager, times(1)).removeMember(any(), eq("user_id"));
     }
+
+    @Test
+    public void testAddMemberWs() throws Exception {
+
+        when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt));
+        when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf));
+
+        String userId = "target_user";
+
+        MembershipEntity membership = new MembershipEntity();
+        membership.setGroupId(lbt.getId());
+        membership.setUserId(userId);
+
+        mockMvc.perform(post("/membership")
+                .param("group", "LBT.INAF")
+                .param("user_id", userId)
+                .accept(MediaType.TEXT_PLAIN)
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED))
+                .andExpect(status().isOk());
+
+        verify(membershipManager, times(1)).addMember(eq(inaf), eq(userId));
+    }
+
+    @Test
+    public void testRemoveMemberWs() throws Exception {
+
+        mockMvc.perform(delete("/membership?group=LBT.INAF&user_id=userId"))
+                .andExpect(status().isNoContent());
+
+        verify(membershipManager, times(1)).removeMember(eq(inaf), eq("userId"));
+    }
 }
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
index 6c8334d..d4b8f9f 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
@@ -1,15 +1,24 @@
 package it.inaf.ia2.gms.controller;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import static it.inaf.ia2.gms.controller.ControllersMockData.*;
 import it.inaf.ia2.gms.manager.GroupsManager;
 import it.inaf.ia2.gms.manager.PermissionsManager;
 import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.model.RapUserPermission;
 import it.inaf.ia2.gms.model.request.AddPermissionRequest;
+import it.inaf.ia2.gms.persistence.GroupsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.persistence.model.PermissionEntity;
+import it.inaf.ia2.gms.service.GroupNameService;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
 import static org.hamcrest.CoreMatchers.is;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
@@ -22,6 +31,7 @@ import org.springframework.test.web.servlet.MockMvc;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@@ -35,6 +45,9 @@ public class PermissionsControllerTest {
     @Mock
     private PermissionsManager permissionsManager;
 
+    @Mock
+    private GroupsDAO groupsDAO;
+
     @InjectMocks
     private PermissionsController controller;
 
@@ -46,6 +59,7 @@ public class PermissionsControllerTest {
 
     @Before
     public void init() {
+        controller.groupNameService = new GroupNameService(groupsDAO);
         mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
 
         group = new GroupEntity();
@@ -103,4 +117,72 @@ public class PermissionsControllerTest {
 
         verify(permissionsManager, times(1)).removePermission(eq(group), eq("user_id"));
     }
+
+    @Test
+    public void testGetGroupPermissions() throws Exception {
+
+        when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(getLbtGroup()));
+        when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(getInafGroup()));
+
+        List<RapUserPermission> permissions = new ArrayList<>();
+        RapUserPermission up = new RapUserPermission();
+        up.setUser(getRapUser());
+        up.setPermission(Permission.ADMIN);
+        permissions.add(up);
+        when(permissionsManager.getAllPermissions(any())).thenReturn(permissions);
+
+        mockMvc.perform(get("/permission?group=LBT.INAF").principal(getPrincipal())
+                .accept(MediaType.TEXT_PLAIN))
+                .andExpect(status().isOk())
+                .andExpect(content().string("rap_user ADMIN\n"));
+    }
+
+    @Test
+    public void testAddPermissionWs() throws Exception {
+
+        String userId = "target_user";
+        Permission permission = Permission.ADMIN;
+
+        GroupEntity lbt = getLbtGroup();
+        GroupEntity inaf = getInafGroup();
+
+        when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt));
+        when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf));
+
+        PermissionEntity permissionEntity = new PermissionEntity();
+        permissionEntity.setGroupId(inaf.getId());
+        permissionEntity.setUserId(userId);
+        permissionEntity.setPermission(permission);
+        permissionEntity.setGroupPath(inaf.getPath());
+
+        when(permissionsManager.addPermission(eq(inaf), eq(userId),
+                eq(permission))).thenReturn(permissionEntity);
+
+        mockMvc.perform(post("/permission")
+                .param("group", "LBT.INAF")
+                .param("user_id", userId)
+                .param("permission", permission.toString())
+                .accept(MediaType.TEXT_PLAIN)
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED))
+                .andExpect(status().isOk());
+
+        verify(permissionsManager, times(1))
+                .addPermission(eq(inaf), eq(userId), eq(permission));
+    }
+
+    @Test
+    public void testRemovePermissionWs() throws Exception {
+
+        GroupEntity lbt = getLbtGroup();
+        GroupEntity inaf = getInafGroup();
+
+        when(groupsDAO.findGroupByParentAndName("", "LBT")).thenReturn(Optional.of(lbt));
+        when(groupsDAO.findGroupByParentAndName("lbt_id", "INAF")).thenReturn(Optional.of(inaf));
+
+        mockMvc.perform(delete("/permission?group=LBT.INAF&user_id=userId")
+                .accept(MediaType.TEXT_PLAIN))
+                .andExpect(status().isNoContent());
+
+        verify(permissionsManager, times(1)).removePermission(eq(inaf), eq("userId"));
+    }
 }
-- 
GitLab