Added list group controller for system admin & status to user-group DTO.

Change-Id: I628008322472c3910088ea7c17db137d7b3aec87
diff --git a/full/Changes b/full/Changes
index 24636ce..c7aea38 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,8 +1,14 @@
 version 0.60.1
-14/03/2018
+20/03/2018
 	- added admin-related SQL codes (margaretha)
 	- updated AdminDao (margaretha)
 	- added optional username query parameter to group list controller (margaretha) 
+	- fixed non hierarchical URI of kustvakt conf files (margaretha)
+	- added delete group member triggers (margaretha)
+	- added list user-group by username and status for system admin (margaretha)
+	- added user-group status in user-group DTO (margaretha)
+	- added check for hidden groups in user-group tests (margaretha)
+	- added database trigger test on deleting members when deleting group (margaretha)
 	
 version 0.60 release
 14/03/2018
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
index 43eee36..bee11e3 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
@@ -259,6 +259,60 @@
 
     }
 
+    /** This is an admin function. It retrieves all groups given the userId 
+     * and status.
+     * 
+     * @param userId
+     * @param status
+     * @return a list of {@link UserGroup}s
+     * @throws KustvaktException
+     */
+    public List<UserGroup> retrieveGroupByStatus (String userId,
+            UserGroupStatus status) throws KustvaktException {
+
+        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
+        CriteriaQuery<UserGroup> query =
+                criteriaBuilder.createQuery(UserGroup.class);
+
+        Root<UserGroup> root = query.from(UserGroup.class);
+
+        Predicate restrictions = null;
+
+        if (userId != null && !userId.isEmpty()) {
+
+            ListJoin<UserGroup, UserGroupMember> members =
+                    root.join(UserGroup_.members);
+            restrictions = criteriaBuilder.and(
+                    criteriaBuilder.equal(members.get(UserGroupMember_.userId),
+                            userId));
+            
+            if (status != null){
+                restrictions = criteriaBuilder.and(restrictions, criteriaBuilder
+                        .equal(root.get(UserGroup_.status), status));
+            }
+        }
+        else if (status != null) {
+                restrictions = criteriaBuilder
+                        .equal(root.get(UserGroup_.status), status);
+                
+        }
+
+        query.select(root);
+        if (restrictions!=null){
+            query.where(restrictions);
+        }
+        Query q = entityManager.createQuery(query);
+
+        try {
+            return q.getResultList();
+        }
+        catch (NoResultException e) {
+            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
+                    "No group found for status " + status, status.toString());
+        }
+
+    }
+
     public void addVCToGroup (VirtualCorpus virtualCorpus, String createdBy,
             VirtualCorpusAccessStatus status, UserGroup group) {
         VirtualCorpusAccess accessGroup = new VirtualCorpusAccess();
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
index ae58ec6..b4f2227 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
@@ -143,17 +143,25 @@
 
     public List<UserGroupMember> retrieveMemberByGroupId (int groupId)
             throws KustvaktException {
+        return retrieveMemberByGroupId(groupId, false);
+    }
+
+    public List<UserGroupMember> retrieveMemberByGroupId (int groupId,
+            boolean isAdmin) throws KustvaktException {
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<UserGroupMember> query =
                 criteriaBuilder.createQuery(UserGroupMember.class);
 
         Root<UserGroupMember> root = query.from(UserGroupMember.class);
 
-        Predicate predicate = criteriaBuilder.and(
-                criteriaBuilder.equal(root.get(UserGroupMember_.group),
-                        groupId),
-                criteriaBuilder.notEqual(root.get(UserGroupMember_.status),
-                        GroupMemberStatus.DELETED));
+        Predicate predicate = criteriaBuilder.and(criteriaBuilder
+                .equal(root.get(UserGroupMember_.group), groupId));
+
+        if (!isAdmin) {
+            predicate = criteriaBuilder.and(predicate,
+                    criteriaBuilder.notEqual(root.get(UserGroupMember_.status),
+                            GroupMemberStatus.DELETED));
+        }
 
         query.select(root);
         query.where(predicate);
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/UserGroupDto.java b/full/src/main/java/de/ids_mannheim/korap/dto/UserGroupDto.java
index 8d64c09..69900d8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/UserGroupDto.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/UserGroupDto.java
@@ -5,6 +5,7 @@
 import com.fasterxml.jackson.annotation.JsonInclude;
 
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
+import de.ids_mannheim.korap.constant.UserGroupStatus;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -21,6 +22,7 @@
     private int id;
     private String name;
     private String owner;
+    private UserGroupStatus status;
     
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
     private List<UserGroupMemberDto> members;
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/converter/UserGroupConverter.java b/full/src/main/java/de/ids_mannheim/korap/dto/converter/UserGroupConverter.java
index 9dd4df9..0ee2912 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/converter/UserGroupConverter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/converter/UserGroupConverter.java
@@ -29,14 +29,17 @@
         UserGroupDto dto = new UserGroupDto();
         dto.setId(group.getId());
         dto.setName(group.getName());
+        dto.setStatus(group.getStatus());
         dto.setOwner(group.getCreatedBy());
         dto.setUserMemberStatus(userMemberStatus);
 
-        List<String> roles = new ArrayList<>(userRoles.size());
-        for (Role r : userRoles) {
-            roles.add(r.getName());
+        if (userRoles != null) {
+            List<String> roles = new ArrayList<>(userRoles.size());
+            for (Role r : userRoles) {
+                roles.add(r.getName());
+            }
+            dto.setUserRoles(roles);
         }
-        dto.setUserRoles(roles);
 
         if (members != null) {
             ArrayList<UserGroupMemberDto> memberDtos =
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
index 147be56..4450551 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
@@ -67,21 +67,8 @@
      * 
      * @see {@link PredefinedRole}
      */
-    public List<UserGroupDto> retrieveUserGroup (String username,
-            String contextUsername) throws KustvaktException {
-
-        boolean isAdmin = adminDao.isAdmin(contextUsername);
-
-        if (username != null) {
-            if (!username.equals(contextUsername) && !isAdmin) {
-                throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
-                        "Unauthorized operation for user: " + contextUsername,
-                        contextUsername);
-            }
-        }
-        else {
-            username = contextUsername;
-        }
+    public List<UserGroupDto> retrieveUserGroup (String username)
+            throws KustvaktException {
 
         List<UserGroup> userGroups =
                 userGroupDao.retrieveGroupByUserId(username);
@@ -124,10 +111,40 @@
         return userGroupDao.retrieveGroupById(groupId);
     }
 
-    public UserGroup retrieveHiddenGroup (int vcId) throws KustvaktException {
+    public UserGroup retrieveHiddenUserGroupByVC (int vcId)
+            throws KustvaktException {
         return userGroupDao.retrieveHiddenGroupByVC(vcId);
     }
 
+    public List<UserGroupDto> retrieveUserGroupByStatus (String username,
+            String contextUsername, UserGroupStatus status)
+            throws KustvaktException {
+
+        boolean isAdmin = adminDao.isAdmin(contextUsername);
+
+        if (isAdmin) {
+            List<UserGroup> userGroups =
+                    userGroupDao.retrieveGroupByStatus(username, status);
+            Collections.sort(userGroups);
+            ArrayList<UserGroupDto> dtos = new ArrayList<>(userGroups.size());
+
+            List<UserGroupMember> members;
+            UserGroupDto groupDto;
+            for (UserGroup group : userGroups) {
+                members = groupMemberDao.retrieveMemberByGroupId(group.getId(), true);
+                groupDto = converter.createUserGroupDto(group, members, null,
+                        null);
+                dtos.add(groupDto);
+            }
+            return dtos;
+        }
+        else {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + contextUsername,
+                    contextUsername);
+        }
+    }
+
     public List<UserGroupMember> retrieveVCAccessAdmins (UserGroup userGroup)
             throws KustvaktException {
         List<UserGroupMember> groupAdmins = groupMemberDao.retrieveMemberByRole(
@@ -460,4 +477,6 @@
 
         groupMemberDao.deleteMember(member, deletedBy, isSoftDelete);
     }
+
+
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
index 6ea1002..32312cd 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
@@ -383,7 +383,7 @@
             else if (VirtualCorpusType.PUBLISHED.equals(type)) {
                 // add user in the VC's auto group 
                 UserGroup userGroup =
-                        userGroupService.retrieveHiddenGroup(vcId);
+                        userGroupService.retrieveHiddenUserGroupByVC(vcId);
                 try {
                     userGroupService.inviteGroupMember(username, userGroup,
                             "system", GroupMemberStatus.ACTIVE);
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
index a838c13..b4a5fc7 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
@@ -20,6 +20,7 @@
 
 import com.sun.jersey.spi.container.ResourceFilters;
 
+import de.ids_mannheim.korap.constant.UserGroupStatus;
 import de.ids_mannheim.korap.dto.UserGroupDto;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.service.UserGroupService;
@@ -55,19 +56,21 @@
     private UserGroupService service;
 
     /** Returns all user-groups in which a user is an active or a pending member.
+     *  Not suitable for system-admin, instead use {@link UserGroupController#
+     *  getUserGroupBySystemAdmin(SecurityContext, String, UserGroupStatus)} 
      * 
      * @param securityContext
      * @return a list of user-groups
+     * 
      */
     @GET
     @Path("list")
-    public Response getUserGroup (@Context SecurityContext securityContext,
-            @QueryParam("username") String username) {
+    public Response getUserGroup (@Context SecurityContext securityContext) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
             List<UserGroupDto> dtos =
-                    service.retrieveUserGroup(username, context.getUsername());
+                    service.retrieveUserGroup(context.getUsername());
             String result = JsonUtils.toJSON(dtos);
             return Response.ok(result).build();
         }
@@ -76,6 +79,34 @@
         }
     }
 
+    
+    /** Lists user-groups for system-admin purposes. If username parameter 
+     *  is not specified, list user-groups of all users. If status is not
+     *  specified, list user-groups of all statuses.
+     * 
+     * @param securityContext
+     * @param username username
+     * @param status {@link UserGroupStatus}
+     * @return a list of user-groups
+     */
+    @GET
+    @Path("list/system-admin")
+    public Response getUserGroupBySystemAdmin (
+            @Context SecurityContext securityContext,
+            @QueryParam("username") String username,
+            @QueryParam("status") UserGroupStatus status) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            List<UserGroupDto> dtos = service.retrieveUserGroupByStatus(
+                    username, context.getUsername(), status);
+            String result = JsonUtils.toJSON(dtos);
+            return Response.ok(result).build();
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+    }
 
     /** Creates a user group where the user in token context is the 
      * group owner, and assigns the listed group members with status 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
index 265a173..a80397c 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
@@ -37,28 +37,52 @@
                 .queryParam("username", username)
                 .header(Attributes.AUTHORIZATION,
                         handler.createBasicAuthorizationHeaderValue(
+                                testUsername, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .get(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        return node;
+    }
+
+    @Test
+    public void testListDoryGroups () throws KustvaktException {
+        ClientResponse response = resource().path("group").path("list")
+                .path("system-admin").queryParam("username", "dory")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
                                 adminUsername, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .get(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         String entity = response.getEntity(String.class);
-                System.out.println(entity);
+//        System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
-
-        return node;
+        assertEquals(3, node.size());
     }
 
     @Test
-    public void testListDoryGroups () throws KustvaktException {
-        JsonNode node = listGroup("dory");
-        JsonNode group = node.get(1);
-        assertEquals(2, group.at("/id").asInt());
-        assertEquals("dory group", group.at("/name").asText());
-        assertEquals("dory", group.at("/owner").asText());
-        assertEquals(3, group.at("/members").size());
-    }
+    public void testListDoryActiveGroups () throws KustvaktException {
+        ClientResponse response = resource().path("group").path("list")
+                .path("system-admin").queryParam("username", "dory")
+                .queryParam("status", "ACTIVE")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
+                                adminUsername, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .get(ClientResponse.class);
 
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        String entity = response.getEntity(String.class);
+//        System.out.println(entity);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(2, node.size());
+    }
+    
+    
     // same as list user-groups of the admin
     @Test
     public void testListWithoutUsername () throws UniformInterfaceException,
@@ -76,7 +100,43 @@
     }
 
     @Test
-    public void testCreateUserGroup () throws UniformInterfaceException,
+    public void testListByStatusAll () throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
+        ClientResponse response =
+                resource().path("group").path("list").path("system-admin")
+                        .header(Attributes.AUTHORIZATION,
+                                handler.createBasicAuthorizationHeaderValue(
+                                        adminUsername, "pass"))
+                        .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                        .get(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        String entity = response.getEntity(String.class);
+
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(4, node.size());
+    }
+
+    @Test
+    public void testListByStatusHidden () throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
+        ClientResponse response = resource().path("group").path("list")
+                .path("system-admin").queryParam("status", "HIDDEN")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
+                                adminUsername, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .get(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(1, node.size());
+        assertEquals(3, node.at("/0/id").asInt());
+    }
+
+    @Test
+    public void testUserGroup () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
 
         UserGroupJson json = new UserGroupJson();
@@ -100,8 +160,8 @@
         assertEquals("admin test group", node.get("name").asText());
 
         String groupId = node.get("id").asText();
-//        testInviteMember(groupId);
-//        testDeleteMember(groupId);
+        testInviteMember(groupId);
+        testDeleteMember(groupId);
         testDeleteGroup(groupId);
     }
 
@@ -120,8 +180,8 @@
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         // check group
-//        JsonNode node = listGroup(testUsername);
-//        assertEquals(0, node.size());
+        JsonNode node = listGroup(testUsername);
+        assertEquals(0, node.size());
     }
 
     private void testDeleteMember (String groupId)
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
index f748b69..89d7ecd 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
@@ -31,6 +31,7 @@
     @Autowired
     private HttpAuthorizationHandler handler;
     private String username = "UserGroupControllerTest";
+    private String admin = "admin";
 
     private JsonNode retrieveUserGroups (String username)
             throws UniformInterfaceException, ClientHandlerException,
@@ -122,25 +123,6 @@
         assertEquals("Unauthorized operation for user: guest",
                 node.at("/errors/0/1").asText());
     }
-    
-    @Test
-    public void testListGroupOtherUser() throws KustvaktException {
-        ClientResponse response = resource().path("group").path("list")
-                .queryParam("username", "dory")
-                .header(Attributes.AUTHORIZATION,
-                        handler.createBasicAuthorizationHeaderValue("marlin",
-                                "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-                .get(ClientResponse.class);
-        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
-        
-        String entity = response.getEntity(String.class);
-        JsonNode node = JsonUtils.readTree(entity);
-        assertEquals(StatusCodes.AUTHORIZATION_FAILED,
-                node.at("/errors/0/0").asInt());
-        assertEquals("Unauthorized operation for user: marlin",
-                node.at("/errors/0/1").asText());
-    }
 
     @Test
     public void testCreateUserGroup () throws UniformInterfaceException,
@@ -319,14 +301,25 @@
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         // check group
-        response = resource().path("group").path("list")
+        response = resource().path("group").path("list").path("system-admin")
+                .queryParam("username", username)
+                .queryParam("status", "DELETED")
                 .header(Attributes.AUTHORIZATION,
-                        handler.createBasicAuthorizationHeaderValue(username,
+                        handler.createBasicAuthorizationHeaderValue(admin,
                                 "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .get(ClientResponse.class);
         String entity = response.getEntity(String.class);
-        assertEquals("[]", entity);
+
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(1, node.size());
+        assertEquals(groupId, node.at("/0/id").asText());
+
+        // check group members
+        for (int i=0; i< node.at("/0/members").size(); i++){
+            assertEquals(GroupMemberStatus.DELETED.name(),
+                    node.at("/0/members/"+i+"/status").asText());    
+        }
     }
 
     @Test