Implemented share VC and list VC-access tasks.

Change-Id: I91fb838d8875317bfc98b29a11dc3d76ef5109c2
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 3b4e355..35bc6cc 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
@@ -110,6 +110,9 @@
 
     public List<UserGroupMember> retrieveMemberByRole (int groupId, int roleId)
             throws KustvaktException {
+        ParameterChecker.checkIntegerValue(roleId, "roleId");
+        ParameterChecker.checkIntegerValue(groupId, "groupId");
+
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<UserGroupMember> query =
                 criteriaBuilder.createQuery(UserGroupMember.class);
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusAccessDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusAccessDao.java
index 98e7990..7db9a28 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusAccessDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusAccessDao.java
@@ -1,5 +1,6 @@
 package de.ids_mannheim.korap.dao;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -17,6 +18,7 @@
 
 import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
 import de.ids_mannheim.korap.entity.UserGroup;
+import de.ids_mannheim.korap.entity.UserGroup_;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.entity.VirtualCorpusAccess;
 import de.ids_mannheim.korap.entity.VirtualCorpusAccess_;
@@ -49,6 +51,25 @@
         Query q = entityManager.createQuery(query);
         return q.getResultList();
     }
+    
+    public List<VirtualCorpusAccess> retrieveAccessByGroup (int groupId)
+            throws KustvaktException {
+        ParameterChecker.checkIntegerValue(groupId, "groupId");
+
+        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
+        CriteriaQuery<VirtualCorpusAccess> query =
+                builder.createQuery(VirtualCorpusAccess.class);
+
+        Root<VirtualCorpusAccess> access =
+                query.from(VirtualCorpusAccess.class);
+        Join<VirtualCorpusAccess, UserGroup> accessVC =
+                access.join(VirtualCorpusAccess_.userGroup);
+
+        query.select(access);
+        query.where(builder.equal(accessVC.get(UserGroup_.id), groupId));
+        Query q = entityManager.createQuery(query);
+        return q.getResultList();
+    }
 
     /** Hidden accesses are only created for published or system VC. 
      * 
@@ -58,7 +79,8 @@
      * @return true if there is a hidden access, false otherwise
      * @throws KustvaktException
      */
-    public boolean hasHiddenAccess (int vcId) throws KustvaktException {
+    public List<VirtualCorpusAccess> retrieveHiddenAccess (int vcId)
+            throws KustvaktException {
         ParameterChecker.checkIntegerValue(vcId, "vcId");
 
         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
@@ -79,22 +101,17 @@
 
         query.select(access);
         query.where(p);
+
         try {
             Query q = entityManager.createQuery(query);
-            List<VirtualCorpusAccess> resultList = q.getResultList();
-            if (resultList.isEmpty()) {
-                return false;
-            }
-            else {
-                return true;
-            }
+            return q.getResultList();
         }
         catch (NoResultException e) {
-            return false;
+            return new ArrayList<>();
         }
     }
-
-    public void addAccessToVC (VirtualCorpus virtualCorpus, UserGroup userGroup,
+    
+    public void createAccessToVC (VirtualCorpus virtualCorpus, UserGroup userGroup,
             String createdBy, VirtualCorpusAccessStatus status) {
         VirtualCorpusAccess vca = new VirtualCorpusAccess();
         vca.setVirtualCorpus(virtualCorpus);
diff --git a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
index 2cc465c..7f7370a 100644
--- a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
+++ b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
@@ -145,6 +145,7 @@
                     avalabilityCopy, userAvailabilities, false);
             if (!userAvailabilities.isEmpty()) {
                 builder.with(buildAvailability(avalabilityCopy));
+                jlog.debug("corpus query: " +builder.toString());
                 builder.setBaseQuery(builder.toJSON());
                 rewrittesNode = builder.mergeWith(jsonNode).at("/collection");
                 node.set("collection", rewrittesNode, identifier);
@@ -152,12 +153,13 @@
         }
         else {
             builder.with(buildAvailability(userAvailabilities));
+            jlog.debug("corpus query: " +builder.toString());
             rewrittesNode =
                     JsonUtils.readTree(builder.toJSON()).at("/collection");
             node.set("collection", rewrittesNode, identifier);
         }
 
-        jlog.info("REWRITES: " + node.at("/collection").toString());
+        jlog.debug("REWRITES: " + node.at("/collection").toString());
         return node.rawNode();
     }
 
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 77c6554..642d038 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
@@ -77,16 +77,31 @@
 
         return dtos;
     }
-    
+
     public UserGroup retrieveUserGroupById (int groupId)
             throws KustvaktException {
         return userGroupDao.retrieveGroupById(groupId);
     }
-    
+
     public UserGroup retrieveAllUserGroup () {
         return userGroupDao.retrieveAllUserGroup();
     }
 
+    public List<UserGroupMember> retrieveVCAccessAdmins (UserGroup userGroup)
+            throws KustvaktException {
+        List<UserGroupMember> groupAdmins = groupMemberDao.retrieveMemberByRole(
+                userGroup.getId(), PredefinedRole.VC_ACCESS_ADMIN.getId());
+        return groupAdmins;
+    }
+    
+    public List<UserGroupMember> retrieveUserGroupAdmins (UserGroup userGroup)
+            throws KustvaktException {
+        List<UserGroupMember> groupAdmins = groupMemberDao.retrieveMemberByRole(
+                userGroup.getId(), PredefinedRole.USER_GROUP_ADMIN.getId());
+        return groupAdmins;
+    }
+
+
     /** Group owner is automatically added when creating a group. 
      *  Do not include owners in group members. 
      *  
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 5f8bed0..8d11bf3 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
@@ -15,14 +15,15 @@
 import com.fasterxml.jackson.databind.JsonNode;
 
 import de.ids_mannheim.korap.config.FullConfiguration;
-import de.ids_mannheim.korap.constant.PredefinedUserGroup;
 import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
 import de.ids_mannheim.korap.constant.VirtualCorpusType;
 import de.ids_mannheim.korap.dao.VirtualCorpusAccessDao;
 import de.ids_mannheim.korap.dao.VirtualCorpusDao;
 import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.dto.converter.VirtualCorpusConverter;
+import de.ids_mannheim.korap.entity.Role;
 import de.ids_mannheim.korap.entity.UserGroup;
+import de.ids_mannheim.korap.entity.UserGroupMember;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.entity.VirtualCorpusAccess;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -66,6 +67,91 @@
     @Autowired
     private VirtualCorpusConverter converter;
 
+    public List<VirtualCorpusDto> listOwnerVC (String username)
+            throws KustvaktException {
+        List<VirtualCorpus> vcList = vcDao.retrieveOwnerVC(username);
+        return createVCDtos(vcList);
+    }
+
+    public List<VirtualCorpusDto> listVCByUser (String username)
+            throws KustvaktException {
+        Set<VirtualCorpus> vcSet = vcDao.retrieveVCByUser(username);
+        return createVCDtos(vcSet);
+    }
+
+    private ArrayList<VirtualCorpusDto> createVCDtos (
+            Collection<VirtualCorpus> vcList) throws KustvaktException {
+        ArrayList<VirtualCorpusDto> dtos = new ArrayList<>(vcList.size());
+        VirtualCorpus vc;
+        Iterator<VirtualCorpus> i = vcList.iterator();
+        while (i.hasNext()) {
+            vc = i.next();
+            String json = vc.getCorpusQuery();
+            String statistics = krill.getStatistics(json);
+            VirtualCorpusDto vcDto =
+                    converter.createVirtualCorpusDto(vc, statistics);
+            dtos.add(vcDto);
+        }
+        return dtos;
+    }
+
+    /** Only admin and the owner of the virtual corpus are allowed to 
+     *  delete a virtual corpus.
+     *  
+     * @param username username
+     * @param vcId virtual corpus id
+     * @throws KustvaktException
+     */
+    public void deleteVC (String username, int vcId) throws KustvaktException {
+
+        User user = authManager.getUser(username);
+        VirtualCorpus vc = vcDao.retrieveVCById(vcId);
+
+        if (vc.getCreatedBy().equals(username) || user.isAdmin()) {
+            vcDao.deleteVirtualCorpus(vcId);
+        }
+        else {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+    }
+
+    public void editVC (VirtualCorpusJson vcJson, String username)
+            throws KustvaktException {
+
+        VirtualCorpus vc = vcDao.retrieveVCById(vcJson.getId());
+        editVC(vc, vcJson, username);
+    }
+
+    public void editVC (VirtualCorpus vc, VirtualCorpusJson vcJson,
+            String username) throws KustvaktException {
+        ParameterChecker.checkIntegerValue(vcJson.getId(), "id");
+        User user = authManager.getUser(username);
+
+        if (!username.equals(vc.getCreatedBy()) || !user.isAdmin()) {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+
+        String koralQuery = null;
+        CorpusAccess requiredAccess = null;
+        if (vcJson.getCorpusQuery() != null
+                && vcJson.getCorpusQuery().isEmpty()) {
+            koralQuery = serializeCorpusQuery(vcJson.getCorpusQuery());
+            requiredAccess = determineRequiredAccess(koralQuery);
+        }
+
+        vcDao.editVirtualCorpus(vc, vcJson.getName(), vcJson.getType(),
+                requiredAccess, koralQuery, vcJson.getDefinition(),
+                vcJson.getDescription(), vcJson.getStatus());
+
+        if (!vc.getType().equals(VirtualCorpusType.PUBLISHED)
+                && vcJson.getType() != null
+                && vcJson.getType().equals(VirtualCorpusType.PUBLISHED)) {
+            publishVC(vcJson.getId());
+        }
+    }
+
     public int storeVC (VirtualCorpusJson vc, String username)
             throws KustvaktException {
 
@@ -96,61 +182,6 @@
         return vcId;
     }
 
-    public void editVC (VirtualCorpusJson vcJson, String username)
-            throws KustvaktException {
-
-        ParameterChecker.checkIntegerValue(vcJson.getId(), "id");
-        VirtualCorpus vc = vcDao.retrieveVCById(vcJson.getId());
-
-        User user = authManager.getUser(username);
-
-        if (!username.equals(vc.getCreatedBy()) && !user.isAdmin()) {
-            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
-                    "Unauthorized operation for user: " + username, username);
-        }
-
-        String koralQuery = null;
-        CorpusAccess requiredAccess = null;
-        if (vcJson.getCorpusQuery() != null
-                && vcJson.getCorpusQuery().isEmpty()) {
-            koralQuery = serializeCorpusQuery(vcJson.getCorpusQuery());
-            requiredAccess = determineRequiredAccess(koralQuery);
-        }
-
-        vcDao.editVirtualCorpus(vc, vcJson.getName(), vcJson.getType(),
-                requiredAccess, koralQuery, vcJson.getDefinition(),
-                vcJson.getDescription(), vcJson.getStatus());
-
-        if (!vc.getType().equals(VirtualCorpusType.PUBLISHED)
-                && vcJson.getType() != null
-                && vcJson.getType().equals(VirtualCorpusType.PUBLISHED)) {
-            publishVC(vcJson.getId());
-        }
-    }
-
-    private void publishVC (int vcId) throws KustvaktException {
-
-        // check if hidden access exists
-        if (!accessDao.hasHiddenAccess(vcId)) {
-            // assign hidden access for all users
-            VirtualCorpus vc = vcDao.retrieveVCById(vcId);
-            UserGroup all = userGroupService.retrieveAllUserGroup();
-            accessDao.addAccessToVC(vc, all, "system",
-                    VirtualCorpusAccessStatus.HIDDEN);
-
-            // create and assign a hidden group
-            int groupId = userGroupService.createAutoHiddenGroup(vcId);
-            UserGroup autoHidden =
-                    userGroupService.retrieveUserGroupById(groupId);
-            accessDao.addAccessToVC(vc, autoHidden, "system",
-                    VirtualCorpusAccessStatus.HIDDEN);
-        }
-        else {
-            jlog.error("Cannot publish VC with id: " + vcId
-                    + ". There have been hidden accesses for the VC already.");
-        }
-    }
-
     private String serializeCorpusQuery (String corpusQuery)
             throws KustvaktException {
         QuerySerializer serializer = new QuerySerializer();
@@ -195,57 +226,141 @@
         return (numberOfDoc > 0) ? true : false;
     }
 
-    public List<VirtualCorpusDto> listOwnerVC (String username)
-            throws KustvaktException {
-        List<VirtualCorpus> vcList = vcDao.retrieveOwnerVC(username);
-        return createVCDtos(vcList);
-    }
+    private void publishVC (int vcId) throws KustvaktException {
 
-    public List<VirtualCorpusDto> listVCByUser (String username)
-            throws KustvaktException {
-        Set<VirtualCorpus> vcSet = vcDao.retrieveVCByUser(username);
-        return createVCDtos(vcSet);
-    }
+        List<VirtualCorpusAccess> hiddenAccess =
+                accessDao.retrieveHiddenAccess(vcId);
 
-    private ArrayList<VirtualCorpusDto> createVCDtos (
-            Collection<VirtualCorpus> vcList) throws KustvaktException {
-        ArrayList<VirtualCorpusDto> dtos = new ArrayList<>(vcList.size());
-        VirtualCorpus vc;
-        Iterator<VirtualCorpus> i = vcList.iterator();
-        while (i.hasNext()) {
-            vc = i.next();
-            String json = vc.getCorpusQuery();
-            String statistics = krill.getStatistics(json);
-            VirtualCorpusDto vcDto =
-                    converter.createVirtualCorpusDto(vc, statistics);
-            dtos.add(vcDto);
-        }
-        return dtos;
-    }
+        // check if hidden access exists
+        if (hiddenAccess.isEmpty()) {
+            // assign hidden access for all users
+            VirtualCorpus vc = vcDao.retrieveVCById(vcId);
+            UserGroup all = userGroupService.retrieveAllUserGroup();
+            accessDao.createAccessToVC(vc, all, "system",
+                    VirtualCorpusAccessStatus.HIDDEN);
 
-    /** Only admin and the owner of the virtual corpus are allowed to 
-     *  delete a virtual corpus.
-     *  
-     * @param username username
-     * @param vcId virtual corpus id
-     * @throws KustvaktException
-     */
-    public void deleteVC (String username, int vcId) throws KustvaktException {
-
-        User user = authManager.getUser(username);
-        VirtualCorpus vc = vcDao.retrieveVCById(vcId);
-
-        if (user.isAdmin() || vc.getCreatedBy().equals(username)) {
-            vcDao.deleteVirtualCorpus(vcId);
+            // create and assign a hidden group
+            int groupId = userGroupService.createAutoHiddenGroup(vcId);
+            UserGroup autoHidden =
+                    userGroupService.retrieveUserGroupById(groupId);
+            accessDao.createAccessToVC(vc, autoHidden, "system",
+                    VirtualCorpusAccessStatus.HIDDEN);
         }
         else {
+            jlog.error("Cannot publish VC with id: " + vcId
+                    + ". There have been hidden accesses for the VC already.");
+        }
+    }
+
+
+    //    public void concealVC (String username, int vcId) throws KustvaktException {
+    //
+    //        VirtualCorpus vc = vcDao.retrieveVCById(vcId);
+    //        if (vc.getType().equals(VirtualCorpusType.PUBLISHED)) {
+    //            throw new KustvaktException(StatusCodes.NOTHING_CHANGED,
+    //                    "Virtual corpus is not published.");
+    //        }
+    //
+    //        VirtualCorpusJson vcJson = new VirtualCorpusJson();
+    //        // EM: a published VC may originate from a project or a private VC. 
+    //        // This origin is not saved in the DB. To be on the safe side, 
+    //        // VirtualCorpusType is changed into PROJECT so that any groups 
+    //        // associated with the VC can access it.
+    //        vcJson.setType(VirtualCorpusType.PROJECT);
+    //        editVC(vc, vcJson, username);
+    //
+    //        List<VirtualCorpusAccess> hiddenAccess =
+    //                accessDao.retrieveHiddenAccess(vcId);
+    //        for (VirtualCorpusAccess access : hiddenAccess){
+    //            access.setDeletedBy(username);
+    //            editVCAccess(access,username);
+    //        }
+    //
+    //    }
+
+    public List<VirtualCorpusAccess> retrieveVCAccess (int vcId)
+            throws KustvaktException {
+        return accessDao.retrieveAccessByVC(vcId);
+    }
+
+    public void shareVC (String username, int vcId, int groupId)
+            throws KustvaktException {
+
+        User user = authManager.getUser(username);
+
+        VirtualCorpus vc = vcDao.retrieveVCById(vcId);
+        if (!username.equals(vc.getCreatedBy()) || !user.isAdmin()) {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+
+        UserGroup userGroup = userGroupService.retrieveUserGroupById(groupId);
+
+        if (!user.isAdmin() && !isVCAccessAdmin(userGroup, username)) {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+        else {
+            accessDao.createAccessToVC(vc, userGroup, username,
+                    VirtualCorpusAccessStatus.ACTIVE);
+        }
+    }
+
+    private boolean isVCAccessAdmin (UserGroup userGroup, String username)
+            throws KustvaktException {
+        List<UserGroupMember> accessAdmins =
+                userGroupService.retrieveVCAccessAdmins(userGroup);
+        for (UserGroupMember m : accessAdmins) {
+            if (username.equals(m.getUserId())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void editVCAccess (VirtualCorpusAccess access, String username)
+            throws KustvaktException {
+
+        // get all the VCA admins
+        UserGroup userGroup = access.getUserGroup();
+        List<UserGroupMember> accessAdmins =
+                userGroupService.retrieveVCAccessAdmins(userGroup);
+
+        User user = authManager.getUser(username);
+        if (!user.isAdmin()) {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                     "Unauthorized operation for user: " + username, username);
         }
     }
 
-    public List<VirtualCorpusAccess> retrieveVCAccess (int vcId)
-            throws KustvaktException {
-        return accessDao.retrieveAccessByVC(vcId);
+    public List<VirtualCorpusAccess> listVCAccessByVC (String username,
+            int vcId) throws KustvaktException {
+
+        List<VirtualCorpusAccess> accessList =
+                accessDao.retrieveAccessByVC(vcId);
+        User user = authManager.getUser(username);
+        if (user.isAdmin()){
+            return accessList;
+        }
+
+        List<VirtualCorpusAccess> filteredAccessList = new ArrayList<>();
+        for (VirtualCorpusAccess access : accessList){
+            UserGroup userGroup = access.getUserGroup();
+            if (isVCAccessAdmin(userGroup, username)){
+                filteredAccessList.add(access);
+            }
+        }
+        return filteredAccessList;
+    }
+
+    public List<VirtualCorpusAccess> listVCAccessByGroup (String username,
+            int groupId) throws KustvaktException {
+        User user = authManager.getUser(username);
+        UserGroup userGroup = userGroupService.retrieveUserGroupById(groupId);
+        if (!user.isAdmin() && !isVCAccessAdmin(userGroup, username)) {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+        return accessDao.retrieveAccessByGroup(groupId);
     }
 }
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 2e018fe..3914ac7 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
@@ -126,7 +126,7 @@
         }
         return Response.ok(result).build();
     }
-    
+
     /** Lists all VCs created by a user
      * 
      * @param securityContext
@@ -171,4 +171,73 @@
         }
         return Response.ok().build();
     }
+
+    //  @POST
+    //  @Path("conceal")
+    //  public Response concealPublishedVC (@Context SecurityContext securityContext,
+    //          @QueryParam("vcId") int vcId) {
+    //      TokenContext context =
+    //              (TokenContext) securityContext.getUserPrincipal();
+    //      try {
+    //          service.concealVC(context.getUsername(), vcId);
+    //      }
+    //      catch (KustvaktException e) {
+    //          throw responseHandler.throwit(e);
+    //      }
+    //      return Response.ok().build();
+    //  }
+
+    /** VC can only be shared with a group, not individuals. 
+     *  Only VC Access Admins are allowed to share VCs and 
+     *  the VCs must have been created by themselves.
+     * 
+     * @param securityContext
+     * @param vcId a virtual corpus id
+     * @param groupId a user group id
+     * @return HTTP status 200, if successful
+     */
+    @POST
+    @Path("access/share")
+    public Response shareVC (@Context SecurityContext securityContext,
+            @QueryParam("vcId") int vcId, @QueryParam("groupId") int groupId) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            service.shareVC(context.getUsername(), vcId, groupId);
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("access/list")
+    public Response listVCAccess (@Context SecurityContext securityContext,
+            @QueryParam("vcId") int vcId) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            service.listVCAccessByVC(context.getUsername(), vcId);
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        return Response.ok().build();
+    }
+    
+    @GET
+    @Path("access/list/byGroup")
+    public Response listVCAccessByGroup (@Context SecurityContext securityContext,
+            @QueryParam("groupId") int groupId) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            service.listVCAccessByGroup(context.getUsername(), groupId);
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        return Response.ok().build();
+    }
 }
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
index 2f2eb57..8d36bd8 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
@@ -150,7 +150,7 @@
                 response.getStatus());
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
-        System.out.println(entity);
+//        System.out.println(entity);
         assertNotNull(node);
         assertNotEquals(0, node.path("matches").size());
         assertEquals("koral:docGroup", node.at("/collection/@type").asText());
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
index 32fa94a..252e39e 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
@@ -27,6 +27,7 @@
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.config.AuthenticationScheme;
 import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.constant.VirtualCorpusType;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.JsonUtils;
@@ -92,49 +93,6 @@
     }
 
     @Test
-    public void testCreatePublishVC () throws KustvaktException {
-        String json =
-                "{\"name\": \"new published vc\",\"type\": \"PUBLISHED\",\"createdBy\": "
-                        + "\"test class\",\"corpusQuery\": \"corpusSigle=GOE\"}";
-        ClientResponse response = resource().path("vc").path("create")
-                .header(Attributes.AUTHORIZATION,
-                        handler.createBasicAuthorizationHeaderValue(
-                                "test class", "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
-                .post(ClientResponse.class, json);
-        
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        
-        // test list owner vc
-        response = resource().path("vc").path("list").path("user")
-                .header(Attributes.AUTHORIZATION,
-                        handler.createBasicAuthorizationHeaderValue(
-                                "test class", "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-
-                .get(ClientResponse.class);
-        
-        String entity = response.getEntity(String.class);
-        System.out.println(entity);
-        JsonNode node = JsonUtils.readTree(entity);
-        assertEquals(1, node.size());
-        assertEquals("new published vc", node.get(0).get("name").asText());
-        // cannot explicitly checked hidden groups here
-        
-        String vcId = node.get(0).get("id").asText();
-        
-        // delete vc
-        resource().path("vc").path("delete").queryParam("vcId", vcId)
-        .header(Attributes.AUTHORIZATION,
-                handler.createBasicAuthorizationHeaderValue(
-                        "test class", "pass"))
-        .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-
-        .delete(ClientResponse.class);
-    }
-    
-    @Test
     public void testCreateDeleteVC () throws KustvaktException {
         String json =
                 "{\"name\": \"new vc\",\"type\": \"PRIVATE\",\"createdBy\": "
@@ -195,6 +153,51 @@
     }
 
     @Test
+    public void testCreatePublishVC () throws KustvaktException {
+        String json =
+                "{\"name\": \"new published vc\",\"type\": \"PUBLISHED\",\"createdBy\": "
+                        + "\"test class\",\"corpusQuery\": \"corpusSigle=GOE\"}";
+        ClientResponse response = resource().path("vc").path("create")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
+                                "test class", "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .post(ClientResponse.class, json);
+        
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        
+        // test list owner vc
+        response = resource().path("vc").path("list").path("user")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
+                                "test class", "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+
+                .get(ClientResponse.class);
+        
+        String entity = response.getEntity(String.class);
+        System.out.println(entity);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(1, node.size());
+        assertEquals("new published vc", node.get(0).get("name").asText());
+        //EM: cannot explicitly checked hidden groups here
+        
+        String vcId = node.get(0).get("id").asText();
+        
+        //EM: delete vc
+        resource().path("vc").path("delete").queryParam("vcId", vcId)
+        .header(Attributes.AUTHORIZATION,
+                handler.createBasicAuthorizationHeaderValue(
+                        "test class", "pass"))
+        .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+
+        .delete(ClientResponse.class);
+        
+        //EM: have to delete the hidden groups as well (admin)
+    }
+    
+    @Test
     public void testCreateVCWithExpiredToken ()
             throws IOException, KustvaktException {
         String json =
@@ -393,7 +396,7 @@
         
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
-     // check VC
+        // check VC
         response = resource().path("vc").path("list")
                 .header(Attributes.AUTHORIZATION,
                         handler.createBasicAuthorizationHeaderValue("dory",
@@ -417,6 +420,45 @@
     }
     
     @Test
+    public void testEditPublishVC () throws KustvaktException {
+        
+        String json =
+                "{\"id\": \"1\", \"name\": \"dory pubished vc\", \"type\": \"PUBLISHED\"}";
+
+        ClientResponse response = resource().path("vc").path("edit")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
+                                "dory", "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .post(ClientResponse.class, json);
+        
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        // check VC
+        response = resource().path("vc").path("list").path("user")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue("dory",
+                                "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+
+                .get(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        JsonNode node = JsonUtils.readTree(entity);
+        
+        for (int i=0; i<node.size(); i++){
+            JsonNode n = node.get(i);
+            if (n.get("id").asInt() == 1){
+                assertEquals("dory pubished vc", n.get("name").asText());
+                assertEquals(VirtualCorpusType.PUBLISHED.displayName(), n.get("type").asText());
+                break;
+            }
+        }
+    }
+    
+    @Test
     public void testEditVCNotOwner () throws KustvaktException {
         String json =
                 "{\"id\": \"1\", \"name\": \"edited vc\"}";
@@ -439,4 +481,5 @@
 
         checkWWWAuthenticateHeader(response);
     }
+    
 }
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index 082817d..7ec4381 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -1,5 +1,5 @@
 ## index dir
-krill.indexDir = /home/elma/git/Kustvakt-new/sample-index
+krill.indexDir = ../sample-index
 
 krill.index.commit.count = 134217000
 krill.index.commit.log = log/krill.commit.log