Update delete query access and role.

Change-Id: I0efeb6e38365bb975d8708c9d4d252fb3979cdc4
diff --git a/src/main/java/de/ids_mannheim/korap/dao/QueryAccessDao.java b/src/main/java/de/ids_mannheim/korap/dao/QueryAccessDao.java
index 59e2a2b..1d5ce75 100644
--- a/src/main/java/de/ids_mannheim/korap/dao/QueryAccessDao.java
+++ b/src/main/java/de/ids_mannheim/korap/dao/QueryAccessDao.java
@@ -43,6 +43,7 @@
  * @see QueryAccess
  * @see Query
  */
+@Deprecated
 @Transactional
 @Repository
 public class QueryAccessDao {
diff --git a/src/main/java/de/ids_mannheim/korap/dao/RoleDao.java b/src/main/java/de/ids_mannheim/korap/dao/RoleDao.java
index bc0c16a..2ded95c 100644
--- a/src/main/java/de/ids_mannheim/korap/dao/RoleDao.java
+++ b/src/main/java/de/ids_mannheim/korap/dao/RoleDao.java
@@ -8,16 +8,21 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import de.ids_mannheim.korap.constant.PredefinedRole;
+import de.ids_mannheim.korap.entity.QueryAccess;
 import de.ids_mannheim.korap.entity.QueryDO_;
 import de.ids_mannheim.korap.entity.Role;
 import de.ids_mannheim.korap.entity.Role_;
 import de.ids_mannheim.korap.entity.UserGroupMember;
 import de.ids_mannheim.korap.entity.UserGroupMember_;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
 import jakarta.persistence.EntityManager;
+import jakarta.persistence.NoResultException;
 import jakarta.persistence.PersistenceContext;
 import jakarta.persistence.Query;
 import jakarta.persistence.TypedQuery;
 import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaDelete;
 import jakarta.persistence.criteria.CriteriaQuery;
 import jakarta.persistence.criteria.Join;
 import jakarta.persistence.criteria.JoinType;
@@ -38,31 +43,47 @@
     @PersistenceContext
     private EntityManager entityManager;
 
-//    public void deleteRole (int roleId) {
-//        Role r = retrieveRoleById(roleId);
-//        entityManager.remove(r);
-//    }
-//
-//    public void editRoleName (int roleId, PredefinedRole name) {
-//        Role r = retrieveRoleById(roleId);
-//        r.setName(name);
-//        entityManager.persist(r);
-//    }
-
+    //    public void deleteRole (Role role) {
+    //        entityManager.remove(role);
+    //        entityManager.flush();
+    //    }
+    //
+    //    public void editRoleName (int roleId, PredefinedRole name) {
+    //        Role r = retrieveRoleById(roleId);
+    //        r.setName(name);
+    //        entityManager.persist(r);
+    //    }
 
     public void addRole (Role newRole) {
         entityManager.persist(newRole);
         entityManager.flush();
     }
-    
-    
-    
+
+    public Role retrieveRoleById (int roleId) throws KustvaktException {
+        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
+        CriteriaQuery<Role> query = criteriaBuilder.createQuery(Role.class);
+
+        Root<Role> root = query.from(Role.class);
+        root.fetch(Role_.userGroup);
+        query.select(root);
+        query.where(criteriaBuilder.equal(root.get(Role_.id), roleId));
+        Query q = entityManager.createQuery(query);
+        
+        try {
+            return (Role) q.getSingleResult();
+        }
+        catch (NoResultException e) {
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Role is not found", String.valueOf(roleId));
+        }
+    }
+
     public Role retrieveRoleByName (PredefinedRole role) {
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<Role> query = criteriaBuilder.createQuery(Role.class);
 
         Root<Role> root = query.from(Role.class);
-//        root.fetch(Role_.privileges);
+        //        root.fetch(Role_.privileges);
         query.select(root);
         query.where(criteriaBuilder.equal(root.get(Role_.name), role));
         Query q = entityManager.createQuery(query);
@@ -80,7 +101,7 @@
         query.select(root);
         query.where(criteriaBuilder.equal(memberRole.get(UserGroupMember_.id),
                 userId));
-        TypedQuery<Role> q= entityManager.createQuery(query);
+        TypedQuery<Role> q = entityManager.createQuery(query);
         List<Role> resultList = q.getResultList();
         return new HashSet<Role>(resultList);
     }
@@ -95,23 +116,20 @@
         
         query.select(role);
         if (hasQuery) {
-            query.where(
-                cb.equal(role.get("userGroup").get("id"), groupId),
-                cb.isNotNull(role.get("query").get("id"))
-            );
+            query.where(cb.equal(role.get("userGroup").get("id"), groupId),
+                    cb.isNotNull(role.get("query").get("id")));
         }
-        else {  
-            query.where(
-                cb.equal(role.get("userGroup").get("id"), groupId)
-            );
+        else {
+            query.where(cb.equal(role.get("userGroup").get("id"), groupId));
         }
 
         TypedQuery<Role> q = entityManager.createQuery(query);
         List<Role> resultList = q.getResultList();
         return new HashSet<Role>(resultList);
     }
-    
-    public Set<Role> retrieveRoleByQueryIdAndUsername (int queryId, String username) {
+
+    public Set<Role> retrieveRoleByQueryIdAndUsername (int queryId,
+            String username) {
         CriteriaBuilder cb = entityManager.getCriteriaBuilder();
         CriteriaQuery<Role> query = cb.createQuery(Role.class);
 
@@ -122,14 +140,31 @@
                 JoinType.INNER);
         
         query.select(role);
-        query.where(
-            cb.equal(role.get(Role_.query).get(QueryDO_.id), queryId),
-            cb.equal(members.get(UserGroupMember_.userId), username)
-        );
-        
+        query.where(cb.equal(role.get(Role_.query).get(QueryDO_.id), queryId),
+                cb.equal(members.get(UserGroupMember_.userId), username));
+
         TypedQuery<Role> q = entityManager.createQuery(query);
         List<Role> resultList = q.getResultList();
         return new HashSet<Role>(resultList);
     }
 
+    public void deleteRole (int roleId) throws KustvaktException {
+
+        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+        CriteriaDelete<Role> delete = cb.createCriteriaDelete(Role.class);
+        Root<Role> role = delete.from(Role.class);
+
+        delete.where(
+                cb.equal(role.get("id"), roleId));
+        
+        try {
+            entityManager.createQuery(delete).executeUpdate();
+        }
+        catch (NoResultException e) {
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Role is not found", String.valueOf(roleId));
+        }
+        
+    }
+
 }
diff --git a/src/main/java/de/ids_mannheim/korap/service/QueryService.java b/src/main/java/de/ids_mannheim/korap/service/QueryService.java
index b242ba5..8d9482d 100644
--- a/src/main/java/de/ids_mannheim/korap/service/QueryService.java
+++ b/src/main/java/de/ids_mannheim/korap/service/QueryService.java
@@ -19,6 +19,7 @@
 import de.ids_mannheim.korap.cache.VirtualCorpusCache;
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
+import de.ids_mannheim.korap.constant.PredefinedRole;
 import de.ids_mannheim.korap.constant.PrivilegeType;
 import de.ids_mannheim.korap.constant.QueryType;
 import de.ids_mannheim.korap.constant.ResourceType;
@@ -26,6 +27,7 @@
 import de.ids_mannheim.korap.dao.QueryAccessDao;
 import de.ids_mannheim.korap.dao.QueryDao;
 import de.ids_mannheim.korap.dao.RoleDao;
+import de.ids_mannheim.korap.dao.UserGroupMemberDao;
 import de.ids_mannheim.korap.dto.QueryAccessDto;
 import de.ids_mannheim.korap.dto.QueryDto;
 import de.ids_mannheim.korap.dto.converter.QueryAccessConverter;
@@ -79,6 +81,9 @@
     @Autowired
     private RoleDao roleDao;
     @Autowired
+    private UserGroupMemberDao memberDao;
+
+    @Autowired
     private QueryAccessDao accessDao;
     @Autowired
     private AdminDao adminDao;
@@ -488,7 +493,7 @@
         }
         else {
             try {
-                accessDao.createAccessToQuery(query, userGroup);
+                createAccessToQuery(query, userGroup);
             }
             catch (Exception e) {
                 Throwable cause = e;
@@ -501,42 +506,29 @@
                     lastCause = cause;
                 }
                 throw new KustvaktException(StatusCodes.DB_INSERT_FAILED,
-                        cause.getMessage());
+                        e.getMessage());
             }
 
             queryDao.editQuery(query, null, ResourceType.PROJECT, null, null,
                     null, null, null, query.isCached(), null, null);
         }
     }
-
-    @Deprecated
-    private boolean isQueryAccessAdmin (UserGroup userGroup, String username)
+    
+    public void createAccessToQuery (QueryDO query, UserGroup userGroup)
             throws KustvaktException {
-        List<UserGroupMember> accessAdmins = userGroupService
-                .retrieveQueryAccessAdmins(userGroup);
-        for (UserGroupMember m : accessAdmins) {
-            if (username.equals(m.getUserId())) {
-                return true;
-            }
-        }
-        return false;
-    }
+    
+        List<UserGroupMember> members = memberDao
+                .retrieveMemberByGroupId(userGroup.getId());
 
-    // 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.isSystemAdmin()) {
-    // throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
-    // "Unauthorized operation for user: " + username, username);
-    // }
-    // }
+        Role r1 = new Role(PredefinedRole.QUERY_ACCESS,
+                PrivilegeType.READ_QUERY, userGroup, query);
+        roleDao.addRole(r1);
+        
+        for (UserGroupMember member : members) {
+            member.getRoles().add(r1);
+            memberDao.updateMember(member);
+        }
+    }
 
     public List<QueryAccessDto> listQueryAccessByUsername (String username)
             throws KustvaktException {
@@ -599,14 +591,14 @@
         return accessConverter.createRoleDto(accessList);
     }
 
-    public void deleteQueryAccess (int accessId, String username)
+    public void deleteQueryAccess (int roleId, String username)
             throws KustvaktException {
 
-        QueryAccess access = accessDao.retrieveAccessById(accessId);
-        UserGroup userGroup = access.getUserGroup();
+        Role role = roleDao.retrieveRoleById(roleId);
+        UserGroup userGroup = role.getUserGroup();
         if (userGroupService.isUserGroupAdmin(username, userGroup)
                 || adminDao.isAdmin(username)) {
-            accessDao.deleteAccess(access, username);
+            roleDao.deleteRole(roleId);
         }
         else {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
diff --git a/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusAccessTest.java b/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusAccessTest.java
index 4bdc837..311ceca 100644
--- a/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusAccessTest.java
+++ b/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusAccessTest.java
@@ -2,19 +2,21 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import jakarta.ws.rs.ProcessingException;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.Status;
-
 import org.apache.http.HttpStatus;
 import org.junit.jupiter.api.Test;
+
 import com.fasterxml.jackson.databind.JsonNode;
+
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
-import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.constant.PredefinedRole;
 import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.JsonUtils;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.Form;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
 
 public class VirtualCorpusAccessTest extends VirtualCorpusTestBase {
 
@@ -22,11 +24,13 @@
 
     @Test
     public void testlistAccessByNonVCAAdmin () throws KustvaktException {
+        createDoryGroup();
         JsonNode node = listAccessByGroup("nemo", "dory-group");
         assertEquals(StatusCodes.AUTHORIZATION_FAILED,
                 node.at("/errors/0/0").asInt());
         assertEquals(node.at("/errors/0/1").asText(),
                 "Unauthorized operation for user: nemo");
+        deleteGroupByName(doryGroupName, "dory");
     }
 
     // @Test
@@ -49,25 +53,20 @@
     // node.at("/errors/0/0").asInt());
     // assertEquals("vcId", node.at("/errors/0/1").asText());
     // }
-    @Test
-    public void testlistAccessByGroup () throws KustvaktException {
-        Response response = target().path(API_VERSION).path("vc").path("access")
-                .queryParam("groupName", "dory-group").request()
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue("dory", "pass"))
-                .get();
-        String entity = response.readEntity(String.class);
-        // System.out.println(entity);
-        JsonNode node = JsonUtils.readTree(entity);
-        assertEquals(1, node.at("/0/accessId").asInt());
-        assertEquals(2, node.at("/0/queryId").asInt());
-        assertEquals(node.at("/0/queryName").asText(), "group-vc");
-        assertEquals(2, node.at("/0/userGroupId").asInt());
-        assertEquals(node.at("/0/userGroupName").asText(), "dory-group");
+    private void testlistAccessByGroup (JsonNode node, String vcName,
+            String groupName) throws KustvaktException {
+        //        System.out.println(node.toPrettyString());
+        //        assertEquals(1, node.at("/0/accessId").asInt());
+        //        assertEquals(2, node.at("/0/queryId").asInt());
+        assertEquals(node.at("/0/queryName").asText(), vcName);
+        //        assertEquals(2, node.at("/0/userGroupId").asInt());
+        assertEquals(node.at("/0/userGroupName").asText(), groupName);
     }
 
     @Test
     public void testDeleteSharedVC () throws KustvaktException {
+        createDoryGroup();
+
         String json = "{\"type\": \"PROJECT\""
                 + ",\"queryType\": \"VIRTUAL_CORPUS\""
                 + ",\"corpusQuery\": \"corpusSigle=GOE\"}";
@@ -76,19 +75,27 @@
         String authHeader = HttpAuthorizationHandler
                 .createBasicAuthorizationHeaderValue(username, "pass");
         createVC(authHeader, username, vcName, json);
+
         String groupName = "dory-group";
         testShareVCByCreator(username, vcName, groupName);
+
         JsonNode node = listAccessByGroup(username, groupName);
-        assertEquals(2, node.size());
+        assertEquals(1, node.size());
+        testlistAccessByGroup(node, vcName, groupName);
+
         // delete project VC
         deleteVC(vcName, username, username);
         node = listAccessByGroup(username, groupName);
-        assertEquals(1, node.size());
+        assertEquals(0, node.size());
+
+        deleteGroupByName(doryGroupName, "dory");
     }
 
     @Test
     public void testCreateDeleteAccess ()
             throws ProcessingException, KustvaktException {
+        createMarlinGroup();
+
         String vcName = "marlin-vc";
         String groupName = "marlin-group";
         // check the vc type
@@ -103,31 +110,51 @@
         assertEquals(node.at("/type").asText(), "project");
         // list vc access by marlin
         node = listAccessByGroup("marlin", groupName);
-        assertEquals(2, node.size());
+        assertEquals(1, node.size());
+
         // get access id
-        node = node.get(1);
+        node = node.get(0);
         assertEquals(5, node.at("/queryId").asInt());
         assertEquals(vcName, node.at("/queryName").asText());
-        assertEquals(1, node.at("/userGroupId").asInt());
+        //        assertEquals(1, node.at("/userGroupId").asInt());
         assertEquals(groupName, node.at("/userGroupName").asText());
-        String accessId = node.at("/accessId").asText();
-        testShareVC_nonUniqueAccess("marlin", vcName, groupName);
+        assertEquals(1, node.at("/members").size());
+
+        String roleId = node.at("/roleId").asText();
+        // EM: TODO
+        //        testShareVC_nonUniqueAccess("marlin", vcName, groupName);
+
         // delete unauthorized
-        response = testDeleteAccess(testUser, accessId);
+        response = deleteAccess(testUser, roleId);
         testResponseUnauthorized(response, testUser);
-        // delete access by vc-admin
-        // dory is a vc-admin in marlin group
-        response = testDeleteAccess("dory", accessId);
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        // list vc access by dory
-        node = listAccessByGroup("dory", groupName);
-        assertEquals(1, node.size());
+
+        testDeleteAccessByAdmin(roleId, groupName);
+
         // edit VC back to private
         String json = "{\"type\": \"" + ResourceType.PRIVATE + "\"}";
         editVC("marlin", "marlin", vcName, json);
         node = retrieveVCInfo("marlin", "marlin", vcName);
         assertEquals(ResourceType.PRIVATE.displayName(),
                 node.at("/type").asText());
+
+        deleteGroupByName(marlinGroupName, "marlin");
+    }
+
+    private void testDeleteAccessByAdmin (String roleId, String groupName)
+            throws KustvaktException {
+        inviteMember(marlinGroupName, "marlin", "nemo");
+        subscribe(marlinGroupName, "nemo");
+
+        Form form = new Form();
+        form.param("memberUsername", "nemo");
+        form.param("role", PredefinedRole.GROUP_ADMIN.name());
+        addMemberRole(marlinGroupName, "marlin", form);
+
+        Response response = deleteAccess("nemo", roleId);
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        JsonNode node = listAccessByGroup("nemo", groupName);
+        assertEquals(0, node.size());
     }
 
     private void testShareVC_nonUniqueAccess (String vcCreator, String vcName,
@@ -143,20 +170,10 @@
         // .startsWith("[SQLITE_CONSTRAINT_UNIQUE]"));
     }
 
-    private Response testDeleteAccess (String username, String accessId)
-            throws ProcessingException, KustvaktException {
-        Response response = target().path(API_VERSION).path("vc").path("access")
-                .path(accessId).request()
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .delete();
-        return response;
-    }
-
     @Test
     public void testDeleteNonExistingAccess ()
             throws ProcessingException, KustvaktException {
-        Response response = testDeleteAccess("dory", "100");
+        Response response = deleteAccess("dory", "100");
         assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
         JsonNode node = JsonUtils.readTree(response.readEntity(String.class));
         assertEquals(StatusCodes.NO_RESOURCE_FOUND,
diff --git a/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusTestBase.java b/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusTestBase.java
index 7ef5f0d..3a0d385 100644
--- a/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusTestBase.java
+++ b/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusTestBase.java
@@ -187,4 +187,26 @@
             }
         }
     }
+    
+    protected void createAccess (String vcCreator, String vcName,
+            String groupName, String username)
+            throws ProcessingException, KustvaktException {
+        Response response = target().path(API_VERSION).path("vc")
+                .path("~" + vcCreator).path(vcName).path("share")
+                .path("@" + groupName).request()
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .post(Entity.form(new Form()));
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+    }
+    
+    protected Response deleteAccess (String username, String accessId)
+            throws ProcessingException, KustvaktException {
+        Response response = target().path(API_VERSION).path("vc").path("access")
+                .path(accessId).request()
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .delete();
+        return response;
+    }
 }