Added VC list and search user-group controllers for system admin.

Change-Id: I6c99443e428c69c6ce3e9c2760b8193ce2613009
diff --git a/full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java b/full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java
index 5abd54c..229eec2 100644
--- a/full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java
+++ b/full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java
@@ -9,7 +9,7 @@
  */
 public enum VirtualCorpusType {
     // available for all
-    PREDEFINED, 
+    SYSTEM, 
     // available to project group members
     PROJECT, 
     // available only for the creator
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
index c0fd186..4b26b2f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
@@ -97,23 +97,51 @@
         entityManager.merge(vc);
     }
 
-    public void deleteVirtualCorpus (int id) throws KustvaktException {
-        VirtualCorpus vc = retrieveVCById(id);
+    public void deleteVirtualCorpus (VirtualCorpus vc) throws KustvaktException {
+        if (!entityManager.contains(vc)){
+            vc = entityManager.merge(vc);
+        }
         entityManager.remove(vc);
+        
     }
 
-    // for admins
-    public List<VirtualCorpus> retrieveVCByType (VirtualCorpusType type)
-            throws KustvaktException {
-        ParameterChecker.checkObjectValue(type, "type");
+    /** System admin function. 
+     * 
+     *  Retrieves virtual corpus by creator and type. If type is not specified, 
+     *  retrieves virtual corpora of all types. If createdBy is not specified,
+     *  retrieves virtual corpora of all users.
+     * 
+     * @param type {@link VirtualCorpusType}
+     * @param createdBy username of the virtual corpus creator
+     * @return a list of {@link VirtualCorpus}
+     * @throws KustvaktException
+     */
+    public List<VirtualCorpus> retrieveVCByType (VirtualCorpusType type,
+            String createdBy) throws KustvaktException {
 
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<VirtualCorpus> query =
                 criteriaBuilder.createQuery(VirtualCorpus.class);
         Root<VirtualCorpus> virtualCorpus = query.from(VirtualCorpus.class);
+
+        Predicate conditions = null;
+        if (createdBy != null && !createdBy.isEmpty()) {
+            conditions = criteriaBuilder.equal(
+                    virtualCorpus.get(VirtualCorpus_.createdBy), createdBy);
+            if (type != null) {
+                conditions = criteriaBuilder.and(conditions, criteriaBuilder
+                        .equal(virtualCorpus.get(VirtualCorpus_.type), type));
+            }
+        }
+        else if (type != null) {
+            conditions = criteriaBuilder
+                    .equal(virtualCorpus.get(VirtualCorpus_.type), type);
+        }
+
         query.select(virtualCorpus);
-        query.where(criteriaBuilder
-                .equal(virtualCorpus.get(VirtualCorpus_.type), type));
+        if (conditions != null) {
+            query.where(conditions);
+        }
         Query q = entityManager.createQuery(query);
         return q.getResultList();
     }
@@ -193,15 +221,16 @@
         Join<VirtualCorpus, VirtualCorpusAccess> access =
                 virtualCorpus.join(VirtualCorpus_.virtualCorpusAccess);
 
-//        Predicate corpusStatus = builder.and(
-//                builder.notEqual(access.get(VirtualCorpusAccess_.status),
-//                        VirtualCorpusAccessStatus.HIDDEN),
-//                builder.notEqual(access.get(VirtualCorpusAccess_.status),
-//                        VirtualCorpusAccessStatus.DELETED));
+        //        Predicate corpusStatus = builder.and(
+        //                builder.notEqual(access.get(VirtualCorpusAccess_.status),
+        //                        VirtualCorpusAccessStatus.HIDDEN),
+        //                builder.notEqual(access.get(VirtualCorpusAccess_.status),
+        //                        VirtualCorpusAccessStatus.DELETED));
 
-        Predicate corpusStatus = builder.notEqual(access.get(VirtualCorpusAccess_.status),
-                VirtualCorpusAccessStatus.DELETED);
-        
+        Predicate corpusStatus =
+                builder.notEqual(access.get(VirtualCorpusAccess_.status),
+                        VirtualCorpusAccessStatus.DELETED);
+
         Predicate userGroupStatus =
                 builder.notEqual(access.get(VirtualCorpusAccess_.userGroup)
                         .get(UserGroup_.status), UserGroupStatus.DELETED);
@@ -235,7 +264,7 @@
                 builder.equal(virtualCorpus.get(VirtualCorpus_.createdBy),
                         userId),
                 builder.equal(virtualCorpus.get(VirtualCorpus_.type),
-                        VirtualCorpusType.PREDEFINED));
+                        VirtualCorpusType.SYSTEM));
 
 
         query.select(virtualCorpus);
@@ -248,7 +277,7 @@
         Set<VirtualCorpus> vcSet = new HashSet<VirtualCorpus>();
         vcSet.addAll(vcList);
         vcSet.addAll(groupVC);
-        
+
         List<VirtualCorpus> merger = new ArrayList<VirtualCorpus>(vcSet.size());
         merger.addAll(vcSet);
         Collections.sort(merger);
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 4450551..e79db77 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
@@ -131,7 +131,8 @@
             List<UserGroupMember> members;
             UserGroupDto groupDto;
             for (UserGroup group : userGroups) {
-                members = groupMemberDao.retrieveMemberByGroupId(group.getId(), true);
+                members = groupMemberDao.retrieveMemberByGroupId(group.getId(),
+                        true);
                 groupDto = converter.createUserGroupDto(group, members, null,
                         null);
                 dtos.add(groupDto);
@@ -478,5 +479,20 @@
         groupMemberDao.deleteMember(member, deletedBy, isSoftDelete);
     }
 
+    public UserGroupDto searchById (String username, int groupId)
+            throws KustvaktException {
+        if (adminDao.isAdmin(username)) {
+            UserGroup userGroup = userGroupDao.retrieveGroupById(groupId, true);
+            UserGroupDto groupDto = converter.createUserGroupDto(userGroup,
+                    userGroup.getMembers(), null, null);
+            return groupDto;
+        }
+        else {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+
+    }
+
 
 }
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 32312cd..429440d 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
@@ -1,6 +1,7 @@
 package de.ids_mannheim.korap.service;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
@@ -19,6 +20,7 @@
 import de.ids_mannheim.korap.dao.AdminDao;
 import de.ids_mannheim.korap.dao.VirtualCorpusAccessDao;
 import de.ids_mannheim.korap.dao.VirtualCorpusDao;
+import de.ids_mannheim.korap.dto.UserGroupDto;
 import de.ids_mannheim.korap.dto.VirtualCorpusAccessDto;
 import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.dto.converter.VirtualCorpusAccessConverter;
@@ -74,12 +76,42 @@
         return createVCDtos(vcList);
     }
 
-    public List<VirtualCorpusDto> listVCByUser (String username)
-            throws KustvaktException {
-        List<VirtualCorpus> vcList = vcDao.retrieveVCByUser(username);
+    public List<VirtualCorpusDto> listVCByUser (String contextUsername,
+            String createdBy) throws KustvaktException {
+
+        boolean isAdmin = adminDao.isAdmin(contextUsername);
+
+        if (createdBy != null) {
+            if (!createdBy.equals(contextUsername) && !isAdmin) {
+                throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                        "Unauthorized operation for user: " + contextUsername,
+                        contextUsername);
+            }
+        }
+        else {
+            createdBy = contextUsername;
+        }
+        List<VirtualCorpus> vcList = vcDao.retrieveVCByUser(createdBy);
         return createVCDtos(vcList);
     }
 
+    public List<VirtualCorpusDto> listVCByType (String username,
+            String createdBy, VirtualCorpusType type) throws KustvaktException {
+
+        boolean isAdmin = adminDao.isAdmin(username);
+
+        if (isAdmin) {
+            List<VirtualCorpus> virtualCorpora =
+                    vcDao.retrieveVCByType(type, createdBy);
+            Collections.sort(virtualCorpora);
+            return createVCDtos(virtualCorpora);
+        }
+        else {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+    }
+
     private ArrayList<VirtualCorpusDto> createVCDtos (
             List<VirtualCorpus> vcList) throws KustvaktException {
         ArrayList<VirtualCorpusDto> dtos = new ArrayList<>(vcList.size());
@@ -108,7 +140,15 @@
         VirtualCorpus vc = vcDao.retrieveVCById(vcId);
 
         if (vc.getCreatedBy().equals(username) || adminDao.isAdmin(username)) {
-            vcDao.deleteVirtualCorpus(vcId);
+
+            if (vc.getType().equals(VirtualCorpusType.PUBLISHED)) {
+                VirtualCorpusAccess access =
+                        accessDao.retrieveHiddenAccess(vcId);
+                accessDao.deleteAccess(access, "system");
+                userGroupService.deleteAutoHiddenGroup(
+                        access.getUserGroup().getId(), "system");
+            }
+            vcDao.deleteVirtualCorpus(vc);
         }
         else {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
@@ -187,7 +227,7 @@
         ParameterChecker.checkStringValue(vc.getCreatedBy(), "createdBy");
 
 
-        if (vc.getType().equals(VirtualCorpusType.PREDEFINED)
+        if (vc.getType().equals(VirtualCorpusType.SYSTEM)
                 && !adminDao.isAdmin(username)) {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                     "Unauthorized operation for user: " + username, username);
@@ -393,7 +433,7 @@
                     // skip adding user to hidden group
                 }
             }
-            // else VirtualCorpusType.PREDEFINED
+            // else VirtualCorpusType.SYSTEM
         }
 
         String json = vc.getCorpusQuery();
@@ -414,4 +454,6 @@
         }
         return false;
     }
+
+
 }
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 b4a5fc7..6157b24 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
@@ -8,6 +8,7 @@
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
@@ -22,6 +23,7 @@
 
 import de.ids_mannheim.korap.constant.UserGroupStatus;
 import de.ids_mannheim.korap.dto.UserGroupDto;
+import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.service.UserGroupService;
 import de.ids_mannheim.korap.user.TokenContext;
@@ -108,6 +110,30 @@
         }
     }
 
+    /** Searches for a specific user-group for system admins.
+     * 
+     * @param securityContext
+     * @param groupId group id
+     * @return a user-group
+     */
+    @GET
+    @Path("search/{groupId}")
+    public Response searchUserGroup (@Context SecurityContext securityContext,
+            @PathParam("groupId") int groupId) {
+        String result;
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            UserGroupDto dto =
+                    service.searchById(context.getUsername(), groupId);
+            result = JsonUtils.toJSON(dto);
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        return Response.ok(result).build();
+    }
+    
     /** Creates a user group where the user in token context is the 
      * group owner, and assigns the listed group members with status 
      * GroupMemberStatus.PENDING. 
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
index ef012d6..94cc93d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
@@ -24,6 +24,7 @@
 import com.sun.jersey.spi.container.ResourceFilters;
 
 import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
+import de.ids_mannheim.korap.constant.VirtualCorpusType;
 import de.ids_mannheim.korap.dto.VirtualCorpusAccessDto;
 import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -65,7 +66,9 @@
     @Autowired
     private VirtualCorpusService service;
 
-    /** Creates a user VC, also for system admins
+    /** Creates a user virtual corpus, also for system admins
+     * 
+     *  EM: should system admins be able to create VC for other users?
      * 
      * @param securityContext
      * @param vc a JSON object describing the virtual corpus
@@ -91,7 +94,8 @@
         return Response.ok().build();
     }
 
-    /** Only the VC owner and system admins can edit VC.
+    /** Only the virtual corpus owner and system admins can edit 
+     * a virtual corpus.
      * 
      * @param securityContext
      * @param vc a JSON object describing the virtual corpus
@@ -115,11 +119,11 @@
         return Response.ok().build();
     }
 
-    /** Searches for a specific VC.
+    /** Searches for a specific virtual corpus.
      * 
      * @param securityContext
      * @param vcId a virtual corpus id
-     * @return a list of VC
+     * @return a list of virtual corpora
      */
     @GET
     @Path("search/{vcId}")
@@ -139,20 +143,27 @@
         return Response.ok(result).build();
     }
 
-    /** Lists not only private VC but all VC available to a user.
+    /** Lists not only private virtual corpora but all virtual corpora 
+     *  available to a user.
+     *  
+     *  Users, except system admins, cannot list virtual corpora of 
+     *  other users. Thus, createdBy parameter is only relevant for 
+     *  requests from system admins.
      * 
      * @param securityContext
-     * @return a list of VC
+     * @param createdBy username of virtual corpus creator (optional)
+     * @return a list of virtual corpora
      */
     @GET
     @Path("list")
-    public Response listVCByUser (@Context SecurityContext securityContext) {
+    public Response listVCByUser (@Context SecurityContext securityContext,
+            @QueryParam("createdBy") String createdBy) {
         String result;
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
             List<VirtualCorpusDto> dtos =
-                    service.listVCByUser(context.getUsername());
+                    service.listVCByUser(context.getUsername(), createdBy);
             result = JsonUtils.toJSON(dtos);
         }
         catch (KustvaktException e) {
@@ -161,10 +172,11 @@
         return Response.ok(result).build();
     }
 
-    /** Lists all VC created by a user
+    /** Lists all virtual corpora created by a user
      * 
      * @param securityContext
-     * @return a list of VC created by the user in the security context.
+     * @return a list of virtual corpora created by the user 
+     * in the security context.
      */
     @GET
     @Path("list/user")
@@ -183,6 +195,37 @@
         return Response.ok(result).build();
     }
 
+    /** Lists virtual corpora by creator and type. This is a controller for 
+     *  system admin requiring valid system admin authentication. 
+     *  
+     *  If type is not specified, retrieves virtual corpora of all types. 
+     *  If createdBy is not specified, retrieves virtual corpora of all 
+     *  users.
+     *  
+     * @param securityContext
+     * @param createdBy username of virtual corpus creator
+     * @param type {@link VirtualCorpusType}
+     * @return a list of virtual corpora
+     */
+    @GET
+    @Path("list/system-admin")
+    public Response listVCByStatus (@Context SecurityContext securityContext,
+            @QueryParam("createdBy") String createdBy,
+            @QueryParam("type") VirtualCorpusType type) {
+        String result;
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            List<VirtualCorpusDto> dtos = service
+                    .listVCByType(context.getUsername(), createdBy, type);
+            result = JsonUtils.toJSON(dtos);
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        return Response.ok(result).build();
+    }
+
     /** Only the VC owner and system admins can delete VC. VCA admins 
      *  can delete VC-accesses e.g. of project VC, but not the VC 
      *  themselves. 
diff --git a/full/src/main/resources/db/insert/V3.1__insert_virtual_corpus.sql b/full/src/main/resources/db/insert/V3.1__insert_virtual_corpus.sql
index e09d2fb..7d11ce6 100644
--- a/full/src/main/resources/db/insert/V3.1__insert_virtual_corpus.sql
+++ b/full/src/main/resources/db/insert/V3.1__insert_virtual_corpus.sql
@@ -70,7 +70,7 @@
 	'{"collection": { "@type": "koral:docGroup", "operands": [ { "@type": "koral:doc", "key": "corpusSigle", "match": "match:eq", "value": "GOE" }, { "@type": "koral:doc", "key": "creationDate", "match": "match:leq", "type": "type:date", "value": "1810" } ], "operation": "operation:and" }}');
 
 INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("system VC", "PREDEFINED", "ALL", "system", "test vc", "experimental",
+	VALUES ("system VC", "SYSTEM", "ALL", "system", "test vc", "experimental",
 	'{"collection":{"@type":"koral:doc","value":"GOE","match":"match:eq","key":"corpusSigle"}}');
 
 INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query)