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