Added virtual corpus edit service.

Change-Id: I9e030930c3fb0118086ae6359cf192157ea73098
diff --git a/full/src/main/java/de/ids_mannheim/korap/constant/PredefinedUserGroup.java b/full/src/main/java/de/ids_mannheim/korap/constant/PredefinedUserGroup.java
new file mode 100644
index 0000000..78b39cf
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/constant/PredefinedUserGroup.java
@@ -0,0 +1,15 @@
+package de.ids_mannheim.korap.constant;
+
+public enum PredefinedUserGroup {
+    ALL("all users");
+    
+    private String value;
+
+    PredefinedUserGroup (String value) {
+        this.value = value;
+    }
+    
+    public String getValue () {
+        return value;
+    }
+}
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 b02dd57..a1f74e6 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
@@ -202,16 +202,43 @@
         return q.getResultList();
     }
 
-    public void retrieveGroupByVCId (String vcId) {
+    public UserGroup retrieveGroupByName (String groupName)
+            throws KustvaktException {
+        ParameterChecker.checkStringValue(groupName, "groupName");
+
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
-        CriteriaQuery<VirtualCorpusAccess> query =
-                criteriaBuilder.createQuery(VirtualCorpusAccess.class);
+        CriteriaQuery<UserGroup> query =
+                criteriaBuilder.createQuery(UserGroup.class);
 
-        Root<VirtualCorpusAccess> root = query.from(VirtualCorpusAccess.class);
+        Root<UserGroup> root = query.from(UserGroup.class);
+        query.select(root);
+        query.where(
+                criteriaBuilder.equal(root.get(UserGroup_.name), groupName));
+        Query q = entityManager.createQuery(query);
 
-
+        UserGroup userGroup;
+        try {
+            userGroup = (UserGroup) q.getSingleResult();
+        }
+        catch (NoResultException e) {
+            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
+                    "No result found for query: retrieve group by name "
+                            + groupName,
+                    groupName, e);
+        }
+        return userGroup;
     }
 
+    //    public void retrieveGroupByVCId (String vcId) {
+    //        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
+    //        CriteriaQuery<VirtualCorpusAccess> query =
+    //                criteriaBuilder.createQuery(VirtualCorpusAccess.class);
+    //
+    //        Root<VirtualCorpusAccess> root = query.from(VirtualCorpusAccess.class);
+    //
+    //
+    //    }
+
     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/VirtualCorpusDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
index a57ae75..936c56f 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
@@ -49,8 +49,9 @@
     private EntityManager entityManager;
 
     public int createVirtualCorpus (String name, VirtualCorpusType type,
-            CorpusAccess requiredAccess, String collectionQuery, String definition,
-            String description, String status, String createdBy) {
+            CorpusAccess requiredAccess, String collectionQuery,
+            String definition, String description, String status,
+            String createdBy) throws KustvaktException {
 
         VirtualCorpus vc = new VirtualCorpus();
         vc.setName(name);
@@ -61,11 +62,40 @@
         vc.setDescription(description);
         vc.setStatus(status);
         vc.setCreatedBy(createdBy);
-        
+
         entityManager.persist(vc);
         return vc.getId();
     }
 
+    public void editVirtualCorpus (VirtualCorpus vc, String name,
+            VirtualCorpusType type, CorpusAccess requiredAccess,
+            String collectionQuery, String definition, String description,
+            String status) throws KustvaktException {
+
+        if (name != null && !name.isEmpty()) {
+            vc.setName(name);
+        }
+        if (type != null) {
+            vc.setType(type);
+        }
+        if (requiredAccess != null) {
+            vc.setRequiredAccess(requiredAccess);
+        }
+        if (collectionQuery != null) {
+            vc.setCollectionQuery(collectionQuery);
+        }
+        if (definition != null && !definition.isEmpty()) {
+            vc.setDefinition(definition);
+        }
+        if (description != null && !description.isEmpty()) {
+            vc.setDescription(description);
+        }
+        if (status != null && !status.isEmpty()) {
+            vc.setStatus(status);
+        }
+        entityManager.merge(vc);
+    }
+
     public void deleteVirtualCorpus (int id) throws KustvaktException {
         VirtualCorpus vc = retrieveVCById(id);
         entityManager.remove(vc);
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 5ff4ef9..7751988 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
@@ -8,6 +8,7 @@
 
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
 import de.ids_mannheim.korap.constant.PredefinedRole;
+import de.ids_mannheim.korap.constant.PredefinedUserGroup;
 import de.ids_mannheim.korap.constant.UserGroupStatus;
 import de.ids_mannheim.korap.dao.RoleDao;
 import de.ids_mannheim.korap.dao.UserGroupDao;
@@ -129,6 +130,14 @@
         }
     }
 
+    public int createAutoHiddenGroup (int vcId) throws KustvaktException {
+        String groupName = "auto-group-VC" + vcId;
+        int groupId = userGroupDao.createGroup(groupName, "system",
+                UserGroupStatus.HIDDEN);
+
+        return groupId;
+    }
+
     /** Updates the {@link GroupMemberStatus} of a pending member 
      * to {@link GroupMemberStatus#ACTIVE}.
      * 
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 921ee60..dee1da7 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
@@ -13,10 +13,12 @@
 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.VirtualCorpusType;
 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.UserGroup;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -47,6 +49,8 @@
     @Autowired
     private VirtualCorpusDao dao;
     @Autowired
+    private UserGroupService userGroupService;
+    @Autowired
     private SearchKrill krill;
     @Autowired
     private FullConfiguration config;
@@ -55,31 +59,72 @@
     @Autowired
     private VirtualCorpusConverter converter;
 
-    public void createVC (VirtualCorpusJson vc, String username)
+    public void storeVC (VirtualCorpusJson vc, String username)
             throws KustvaktException {
-        
+
+        ParameterChecker.checkStringValue(vc.getName(), "name");
         ParameterChecker.checkObjectValue(vc.getType(), "type");
-        
+        ParameterChecker.checkStringValue(vc.getCollectionQuery(),
+                "collectionQuery");
+        ParameterChecker.checkStringValue(vc.getCreatedBy(), "createdBy");
+
         User user = authManager.getUser(username);
-        // EM: how about VirtualCorpusType.PUBLISHED?
-        
+
         if (vc.getType().equals(VirtualCorpusType.PREDEFINED)
                 && !user.isAdmin()) {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
-                    "Unauthorized operation for user: " + user.getUsername(),
-                    user.getUsername());
+                    "Unauthorized operation for user: " + username, username);
         }
 
         String koralQuery = serializeCollectionQuery(vc.getCollectionQuery());
         CorpusAccess requiredAccess = determineRequiredAccess(koralQuery);
 
-        dao.createVirtualCorpus(vc.getName(), vc.getType(), requiredAccess,
-                koralQuery, vc.getDefinition(), vc.getDescription(),
-                vc.getStatus(), vc.getCreatedBy());
+        int vcId = dao.createVirtualCorpus(vc.getName(), vc.getType(),
+                requiredAccess, koralQuery, vc.getDefinition(),
+                vc.getDescription(), vc.getStatus(), vc.getCreatedBy());
+
+        // EM: how about VirtualCorpusType.PUBLISHED?
+        //        if (vc.getType() != null
+        //                && vc.getType().equals(VirtualCorpusType.PUBLISHED)) {
+        //            int groupId = userGroupService.createAutoHiddenGroup(vcId);
+        //            UserGroup allUserGroup = userGroupDao
+        //                    .retrieveGroupByName(PredefinedUserGroup.ALL.getValue());
+        //            int allUserGroupId = allUserGroup.getId();
+        //            // add access to VC for all and auto-group
+        //        }
 
         // EM: should this return anything?
     }
 
+    public void editVC (VirtualCorpusJson vcJson, String username)
+            throws KustvaktException {
+
+        ParameterChecker.checkIntegerValue(vcJson.getId(), "id");
+        VirtualCorpus vc = dao.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.getCollectionQuery() != null
+                && vcJson.getCollectionQuery().isEmpty()) {
+            koralQuery = serializeCollectionQuery(vcJson.getCollectionQuery());
+            requiredAccess = determineRequiredAccess(koralQuery);
+        }
+
+        dao.editVirtualCorpus(vc, vcJson.getName(), vcJson.getType(), requiredAccess,
+                koralQuery, vcJson.getDefinition(), vcJson.getDescription(),
+                vcJson.getStatus());
+        
+        vc = dao.retrieveVCById(vcJson.getId());
+
+    }
+
     private String serializeCollectionQuery (String collectionQuery)
             throws KustvaktException {
         QuerySerializer serializer = new QuerySerializer();
@@ -149,8 +194,7 @@
      * @param vcId virtual corpus id
      * @throws KustvaktException
      */
-    public void deleteVC (String username, int vcId)
-            throws KustvaktException {
+    public void deleteVC (String username, int vcId) throws KustvaktException {
 
         User user = authManager.getUser(username);
         VirtualCorpus vc = dao.retrieveVCById(vcId);
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 8cab1af..ada1c8f 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
@@ -55,6 +55,12 @@
     @Autowired
     private VirtualCorpusService service;
 
+    /** Creates a user VC, also for admins
+     * 
+     * @param securityContext
+     * @param vc a JSON object describing the virtual corpus
+     * @return HTTP Response OK if successful
+     */
     @POST
     @Path("create")
     @Consumes("application/json")
@@ -67,7 +73,7 @@
             TokenContext context =
                     (TokenContext) securityContext.getUserPrincipal();
 
-            service.createVC(vc, context.getUsername());
+            service.storeVC(vc, context.getUsername());
         }
         catch (KustvaktException e) {
             throw responseHandler.throwit(e);
@@ -75,9 +81,37 @@
         return Response.ok().build();
     }
 
-    // EM: nicer URL with username?
+    /** Only the VC owner and system admins can edit VCs.
+     * 
+     * @param securityContext
+     * @param vc a JSON object describing the virtual corpus
+     * @return HTTP Response OK if successful
+     * @throws KustvaktException
+     */
+    @POST
+    @Path("edit")
+    @Consumes("application/json")
+    public Response editVC (@Context SecurityContext securityContext,
+            VirtualCorpusJson vc) throws KustvaktException {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+
+        try {
+            service.editVC(vc, context.getUsername());
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+        return Response.ok().build();
+    }
+
+    /** Lists not only private VCs but all VCs available to a user.
+     * 
+     * @param securityContext
+     * @return a list of VCs
+     */
     @GET
-    @Path("user")
+    @Path("list")
     public Response getUserVC (@Context SecurityContext securityContext) {
         String result;
         TokenContext context =
@@ -93,28 +127,12 @@
         return Response.ok(result).build();
     }
 
-    //    @POST
-    //    @Path("edit")
-    //    public Response editVC (@Context SecurityContext securityContext,
-    //            String json) throws KustvaktException {
-    //        TokenContext context =
-    //                (TokenContext) securityContext.getUserPrincipal();
-    //        if (context.isDemo()) {
-    //            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
-    //                    "Operation is not permitted for user: "
-    //                            + context.getUsername(),
-    //                    context.getUsername());
-    //        }
-    //
-    //        return Response.ok().build();
-    //    }
-
-    /** Only VC owner and system admin can delete VCs. VC-access admins 
+    /** Only the VC owner and system admins can delete VCs. VC-access admins 
      *  can delete VC-accesses e.g. of project VCs, but not the VCs 
      *  themselves. 
      * 
      * @param securityContext
-     * @param vcId
+     * @param vcId the id of the virtual corpus
      * @return HTTP status 200, if successful
      */
     @DELETE
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java b/full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java
index 76a55ac..7038690 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java
@@ -10,45 +10,34 @@
 import lombok.Setter;
 
 /** Java POJO of JSON input of the virtual corpus service for 
- * creating virtual corpora.
+ * creating and editing virtual corpora.
  * 
  * @author margaretha
- * @see VirtualCorpusController#createVC(javax.ws.rs.core.SecurityContext, VirtualCorpusJson)
- * @see VirtualCorpusService#createVC(VirtualCorpusJson, String)
+ * @see VirtualCorpusController
+ * @see VirtualCorpusService
  */
 @Getter
 @Setter
 public class VirtualCorpusJson {
 
-    // required
+    // required in creating VCs
     private String name;
     private VirtualCorpusType type;
-    private String createdBy;
     private String collectionQuery;
-
+    private String createdBy;
+    
+    // required in editing VCs
+    private int id;
+    
     // optional
     private String definition;
     private String description;
     private String status;
 
-    public void setType (VirtualCorpusType type) throws KustvaktException {
-        ParameterChecker.checkObjectValue(type, "VirtualCorpusType");
-        this.type = type;
-    }
-
-    public void setName (String name) throws KustvaktException {
-        ParameterChecker.checkStringValue(name, "name");
-        this.name = name;
-    }
-
-    public void setCreatedBy (String createdBy) throws KustvaktException {
-        ParameterChecker.checkStringValue(createdBy, "createdBy");
-        this.createdBy = createdBy;
-    }
 
     public void setCollectionQuery (String collectionQuery)
             throws KustvaktException {
-        ParameterChecker.checkStringValue(collectionQuery, "collectionQuery");
+        
         this.collectionQuery = collectionQuery;
     }
 }
\ No newline at end of file
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 70becc8..d613460 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
@@ -7,8 +7,8 @@
 INSERT INTO user_group(name,status,created_by) 
 	VALUES ("auto group","HIDDEN","system");
 
-INSERT INTO user_group(name,status,created_by) 
-	VALUES ("all users","HIDDEN","system");
+--INSERT INTO user_group(name,status,created_by) 
+--	VALUES ("all users","HIDDEN","system");
 
 INSERT INTO user_group(name,status,created_by) 
 	VALUES ("deleted group","DELETED","dory");
@@ -77,7 +77,7 @@
 	SELECT 
 		(SELECT id from virtual_corpus where name = "published VC"),
 		(SELECT id from user_group where name = "all users"),
-		"HIDDEN", "marlin";
+		"HIDDEN", "system";
 
 INSERT INTO virtual_corpus_access(virtual_corpus_id, user_group_id, status, created_by) 
 	SELECT 
diff --git a/full/src/main/resources/db/insert/V3.3__insert_member_roles.sql b/full/src/main/resources/db/insert/V3.3__insert_member_roles.sql
index 459b5e2..202ff50 100644
--- a/full/src/main/resources/db/insert/V3.3__insert_member_roles.sql
+++ b/full/src/main/resources/db/insert/V3.3__insert_member_roles.sql
@@ -2,27 +2,27 @@
 -- dory group
 INSERT INTO group_member_role(group_member_id,role_id)
 SELECT
-	(SELECT id FROM user_group_member WHERE user_id="dory" AND group_id=1),
+	(SELECT id FROM user_group_member WHERE user_id="dory" AND group_id=2),
 	(SELECT id FROM role WHERE name = "group admin");
 	
 INSERT INTO group_member_role(group_member_id,role_id)
 SELECT
-	(SELECT id FROM user_group_member WHERE user_id="dory" AND group_id=1),
+	(SELECT id FROM user_group_member WHERE user_id="dory" AND group_id=2),
 	(SELECT id FROM role WHERE name = "vc admin");
 	
 INSERT INTO group_member_role(group_member_id,role_id)
 SELECT
-	(SELECT id FROM user_group_member WHERE user_id="nemo" AND group_id=1),
+	(SELECT id FROM user_group_member WHERE user_id="nemo" AND group_id=2),
 	(SELECT id FROM role WHERE name = "group member");
 	
 INSERT INTO group_member_role(group_member_id,role_id)
 SELECT
-	(SELECT id FROM user_group_member WHERE user_id="nemo" AND group_id=1),
+	(SELECT id FROM user_group_member WHERE user_id="nemo" AND group_id=2),
 	(SELECT id FROM role WHERE name = "vc member");
 
 -- auto group
 INSERT INTO group_member_role(group_member_id,role_id)
 SELECT
-	(SELECT id FROM user_group_member WHERE user_id="pearl" AND group_id=2),
+	(SELECT id FROM user_group_member WHERE user_id="pearl" AND group_id=3),
 	(SELECT id FROM role WHERE name = "vc member");
 
diff --git a/full/src/main/resources/db/predefined/V3.0__insert_predefined_user_groups.sql b/full/src/main/resources/db/predefined/V3.0__insert_predefined_user_groups.sql
new file mode 100644
index 0000000..ba34c4e
--- /dev/null
+++ b/full/src/main/resources/db/predefined/V3.0__insert_predefined_user_groups.sql
@@ -0,0 +1,3 @@
+
+INSERT INTO user_group(name,status,created_by) 
+	VALUES ("all users","HIDDEN","system");
\ No newline at end of file
diff --git a/full/src/main/resources/jdbc.properties b/full/src/main/resources/jdbc.properties
index 9b888f0..fb06a12 100644
--- a/full/src/main/resources/jdbc.properties
+++ b/full/src/main/resources/jdbc.properties
@@ -22,4 +22,4 @@
 jdbc.username=pc
 jdbc.password=pc
 # db.insert contains test data, omit it in production setting
-jdbc.schemaPath=db.new-sqlite, db.insert, db.predefined
+jdbc.schemaPath=db.new-sqlite, db.predefined, db.insert
diff --git a/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java b/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java
index 66e2b79..8753259 100644
--- a/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java
@@ -86,8 +86,9 @@
 
     @Test
     public void retrieveGroupWithMembers () throws KustvaktException {
+        // dory group
         List<UserGroupMember> members =
-                userGroupDao.retrieveGroupWithMemberById(1).getMembers();
+                userGroupDao.retrieveGroupWithMemberById(2).getMembers();
         assertEquals(4, members.size());
 
         UserGroupMember m = members.get(1);
@@ -123,7 +124,7 @@
     @Test
     public void addVCToGroup () throws KustvaktException {
         // dory group
-        int groupId = 1;
+        int groupId = 2;
 
         UserGroup group = userGroupDao.retrieveGroupById(groupId);
         String createdBy = "dory";
diff --git a/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java b/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
index 06da873..4ec7314 100644
--- a/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
@@ -29,13 +29,25 @@
     @Rule
     public ExpectedException thrown = ExpectedException.none();
 
+    @Test
+    public void testListVCByType () throws KustvaktException {
+        List<VirtualCorpus> vcList =
+                dao.retrieveVCByType(VirtualCorpusType.PUBLISHED);
+        assertEquals(1, vcList.size());
+        
+        VirtualCorpus vc = vcList.get(0);
+        assertEquals(4, vc.getId());
+        assertEquals("published VC", vc.getName());
+        assertEquals("marlin", vc.getCreatedBy());
+    }
 
     @Test
     public void testPredefinedVC () throws KustvaktException {
         // insert vc
-        int id = dao.createVirtualCorpus("predefined VC", VirtualCorpusType.PREDEFINED,
-                User.CorpusAccess.FREE, "corpusSigle=GOE", "definition",
-                "description", "experimental", "test class");
+        int id = dao.createVirtualCorpus("predefined VC",
+                VirtualCorpusType.PREDEFINED, User.CorpusAccess.FREE,
+                "corpusSigle=GOE", "definition", "description", "experimental",
+                "test class");
 
         // select vc
         List<VirtualCorpus> vcList =
@@ -68,10 +80,10 @@
         Set<VirtualCorpus> virtualCorpora = dao.retrieveVCByUser("dory");
         assertEquals(3, virtualCorpora.size());
         // order is random
-//        Iterator<VirtualCorpus> i = virtualCorpora.iterator();
-//        assertEquals("dory VC", i.next().getName());
-//        assertEquals("system VC", i.next().getName());
-//        assertEquals("group VC", i.next().getName());
+        //        Iterator<VirtualCorpus> i = virtualCorpora.iterator();
+        //        assertEquals("dory VC", i.next().getName());
+        //        assertEquals("system VC", i.next().getName());
+        //        assertEquals("group VC", i.next().getName());
     }
 
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/service/full/UserGroupServiceTest.java b/full/src/test/java/de/ids_mannheim/korap/web/service/full/UserGroupServiceTest.java
index 7f1d390..5a975a6 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/service/full/UserGroupServiceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/service/full/UserGroupServiceTest.java
@@ -40,7 +40,7 @@
         //        System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
 
-        assertEquals(1, node.at("/0/id").asInt());
+        assertEquals(2, node.at("/0/id").asInt());
         assertEquals("dory group", node.at("/0/name").asText());
         assertEquals("dory", node.at("/0/owner").asText());
         assertEquals(3, node.at("/0/members").size());
@@ -60,7 +60,7 @@
         //        System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
 
-        assertEquals(1, node.at("/0/id").asInt());
+        assertEquals(2, node.at("/0/id").asInt());
         assertEquals("dory group", node.at("/0/name").asText());
         assertEquals("dory", node.at("/0/owner").asText());
         // group members are not allowed to see other members
@@ -103,7 +103,7 @@
     @Test
     public void testSubscribeMarlinToDoryGroup () throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("groupId", "1");
+        form.add("groupId", "2");
 
         ClientResponse response = resource().path("group").path("subscribe")
                 .type(MediaType.APPLICATION_FORM_URLENCODED)
@@ -127,7 +127,7 @@
         
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(1, node.size());
-        assertEquals(1, node.at("/0/id").asInt());
+        assertEquals(2, node.at("/0/id").asInt());
         assertEquals("dory group", node.at("/0/name").asText());
         assertEquals("dory", node.at("/0/owner").asText());
         // group members are not allowed to see other members
@@ -138,7 +138,7 @@
     @Test
     public void testSubscribePearlToDoryGroup () throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("groupId", "1");
+        form.add("groupId", "2");
 
         ClientResponse response = resource().path("group").path("subscribe")
                 .type(MediaType.APPLICATION_FORM_URLENCODED)
@@ -153,7 +153,7 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         assertEquals(StatusCodes.NOTHING_CHANGED,
                 node.at("/errors/0/0").asInt());
-        assertEquals("Username pearl had been deleted in group 1",
+        assertEquals("Username pearl had been deleted in group 2",
                 node.at("/errors/0/1").asText());
     }
     
@@ -177,7 +177,7 @@
     @Test
     public void testSubscribeNonExistentMember () throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("groupId", "1");
+        form.add("groupId", "2");
 
         ClientResponse response = resource().path("group").path("subscribe")
                 .type(MediaType.APPLICATION_FORM_URLENCODED)
@@ -193,7 +193,7 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         assertEquals(StatusCodes.NO_RESULT_FOUND,
                 node.at("/errors/0/0").asInt());
-        assertEquals("Username bruce is not found in group 1",
+        assertEquals("Username bruce is not found in group 2",
                 node.at("/errors/0/1").asText());
     }
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java b/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
index 3b3bc6e..0e02f2b 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/service/full/VirtualCorpusServiceTest.java
@@ -27,6 +27,8 @@
 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.dao.VirtualCorpusDao;
+import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.JsonUtils;
@@ -35,7 +37,7 @@
 
     @Autowired
     private HttpAuthorizationHandler handler;
-
+    
     private void checkWWWAuthenticateHeader (ClientResponse response) {
         Set<Entry<String, List<String>>> headers =
                 response.getHeaders().entrySet();
@@ -55,9 +57,9 @@
     }
 
     @Test
-    public void testRetrieveUserVC () throws UniformInterfaceException,
+    public void tesListVC () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        ClientResponse response = resource().path("vc").path("user")
+        ClientResponse response = resource().path("vc").path("list")
                 .header(Attributes.AUTHORIZATION,
                         handler.createBasicAuthorizationHeaderValue("dory",
                                 "pass"))
@@ -66,16 +68,16 @@
                 .get(ClientResponse.class);
         String entity = response.getEntity(String.class);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-                System.out.println(entity);
+        //                System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(3, node.size());
     }
 
     @Test
-    public void testRetrieveUserVCUnauthorized ()
+    public void testListVCUnauthorized ()
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        ClientResponse response = resource().path("vc").path("user")
+        ClientResponse response = resource().path("vc").path("list")
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
 
                 .get(ClientResponse.class);
@@ -105,11 +107,11 @@
                 .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
                 .post(ClientResponse.class, json);
         String entity = response.getEntity(String.class);
-//        System.out.println(entity);
+        //        System.out.println(entity);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         // retrieve user VC
-        response = resource().path("vc").path("user")
+        response = resource().path("vc").path("list")
                 .header(Attributes.AUTHORIZATION,
                         handler.createBasicAuthorizationHeaderValue(
                                 "test class", "pass"))
@@ -136,8 +138,8 @@
         //        entity = response.getEntity(String.class);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
-        // retrieve user VC
-        response = resource().path("vc").path("user")
+        // list VC
+        response = resource().path("vc").path("list")
                 .header(Attributes.AUTHORIZATION,
                         handler.createBasicAuthorizationHeaderValue(
                                 "test class", "pass"))
@@ -206,10 +208,10 @@
     }
 
     @Test
-    public void testCreateVCWithoutType () throws KustvaktException {
+    public void testCreateVCWithoutCollectionQuery () throws KustvaktException {
         String json =
-                "{\"name\": \"new vc\",\"createdBy\": "
-                        + "\"test class\",\"collectionQuery\": \"creationDate since 1820\"}";
+                "{\"name\": \"new vc\",\"type\": \"PRIVATE\",\"createdBy\": "
+                        + "\"test class\"}";
 
         ClientResponse response = resource().path("vc").path("create")
                 .header(Attributes.AUTHORIZATION,
@@ -218,16 +220,38 @@
                 .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
                 .entity(json).post(ClientResponse.class);
         String entity = response.getEntity(String.class);
-//        System.out.println(entity);
+        //        System.out.println(entity);
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(StatusCodes.INVALID_ARGUMENT,
                 node.at("/errors/0/0").asInt());
-        assertEquals("type",node.at("/errors/0/1").asText());
-        assertEquals("null",node.at("/errors/0/2").asText());
+        assertEquals("collectionQuery", node.at("/errors/0/1").asText());
+        assertEquals("null", node.at("/errors/0/2").asText());
     }
-    
+
+    @Test
+    public void testCreateVCWithoutType () throws KustvaktException {
+        String json = "{\"name\": \"new vc\",\"createdBy\": "
+                + "\"test class\",\"collectionQuery\": \"creationDate since 1820\"}";
+
+        ClientResponse response = resource().path("vc").path("create")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue(
+                                "test class", "pass"))
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .entity(json).post(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+        //        System.out.println(entity);
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.INVALID_ARGUMENT,
+                node.at("/errors/0/0").asInt());
+        assertEquals("type", node.at("/errors/0/1").asText());
+        assertEquals("null", node.at("/errors/0/2").asText());
+    }
+
     @Test
     public void testCreateVCWithWrongType () throws KustvaktException {
         String json =
@@ -241,7 +265,7 @@
                 .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
                 .entity(json).post(ClientResponse.class);
         String entity = response.getEntity(String.class);
-//        System.out.println(entity);
+        //        System.out.println(entity);
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
@@ -275,4 +299,103 @@
 
         checkWWWAuthenticateHeader(response);
     }
+
+    @Test
+    public void testEditVC () throws KustvaktException {
+        
+        // 1st edit
+        String json =
+                "{\"id\": \"1\", \"name\": \"edited vc\"}";
+
+        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")
+                .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("edited vc", n.get("name").asText());
+                break;
+            }
+        }
+        
+        // 2nd edit
+        json =
+                "{\"id\": \"1\", \"name\": \"dory VC\"}";
+
+        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")
+                .header(Attributes.AUTHORIZATION,
+                        handler.createBasicAuthorizationHeaderValue("dory",
+                                "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+
+                .get(ClientResponse.class);
+        
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        
+        entity = response.getEntity(String.class);
+        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 VC", n.get("name").asText());
+                break;
+            }
+        }
+    }
+    
+    @Test
+    public void testEditVCNotOwner () throws KustvaktException {
+        String json =
+                "{\"id\": \"1\", \"name\": \"edited vc\"}";
+
+        ClientResponse response = resource().path("vc").path("edit")
+                .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);
+        String entity = response.getEntity(String.class);
+//        System.out.println(entity);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+        assertEquals(StatusCodes.AUTHORIZATION_FAILED,
+                node.at("/errors/0/0").asInt());
+        assertEquals("Unauthorized operation for user: test class",
+                node.at("/errors/0/1").asText());
+
+        checkWWWAuthenticateHeader(response);
+    }
 }