Update share query and list query access (#763).

Change-Id: I8a06df4749f844f224b2b5cfcc10404000874f71
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 5448b49..59e2a2b 100644
--- a/src/main/java/de/ids_mannheim/korap/dao/QueryAccessDao.java
+++ b/src/main/java/de/ids_mannheim/korap/dao/QueryAccessDao.java
@@ -13,18 +13,24 @@
 import jakarta.persistence.criteria.Predicate;
 import jakarta.persistence.criteria.Root;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
+import de.ids_mannheim.korap.constant.PredefinedRole;
+import de.ids_mannheim.korap.constant.PrivilegeType;
 import de.ids_mannheim.korap.constant.QueryAccessStatus;
 import de.ids_mannheim.korap.entity.UserGroup;
+import de.ids_mannheim.korap.entity.UserGroupMember;
 import de.ids_mannheim.korap.entity.UserGroup_;
 import de.ids_mannheim.korap.entity.QueryAccess;
 import de.ids_mannheim.korap.entity.QueryAccess_;
 import de.ids_mannheim.korap.entity.QueryDO;
 import de.ids_mannheim.korap.entity.QueryDO_;
+import de.ids_mannheim.korap.entity.Role;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.service.UserGroupService;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
 /**
@@ -43,6 +49,11 @@
 
     @PersistenceContext
     private EntityManager entityManager;
+    
+    @Autowired
+    private RoleDao roleDao;
+    @Autowired
+    private UserGroupMemberDao memberDao;
 
     public QueryAccess retrieveAccessById (int accessId)
             throws KustvaktException {
@@ -231,14 +242,26 @@
         }
     }
 
-    public void createAccessToQuery (QueryDO query, UserGroup userGroup,
-            String createdBy, QueryAccessStatus status) {
-        QueryAccess queryAccess = new QueryAccess();
-        queryAccess.setQuery(query);
-        queryAccess.setUserGroup(userGroup);
-        queryAccess.setCreatedBy(createdBy);
-        queryAccess.setStatus(status);
-        entityManager.persist(queryAccess);
+    public void createAccessToQuery (QueryDO query, UserGroup userGroup)
+            throws KustvaktException {
+    
+        List<UserGroupMember> members = memberDao
+                .retrieveMemberByGroupId(userGroup.getId());
+
+        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);
+        }
+//        QueryAccess queryAccess = new QueryAccess();
+//        queryAccess.setQuery(query);
+//        queryAccess.setUserGroup(userGroup);
+//        queryAccess.setCreatedBy(createdBy);
+//        queryAccess.setStatus(status);
+//        entityManager.persist(queryAccess);
     }
 
     public void deleteAccess (QueryAccess access, String deletedBy) {
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 f432ece..bc0c16a 100644
--- a/src/main/java/de/ids_mannheim/korap/dao/RoleDao.java
+++ b/src/main/java/de/ids_mannheim/korap/dao/RoleDao.java
@@ -4,24 +4,25 @@
 import java.util.List;
 import java.util.Set;
 
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.PersistenceContext;
-import jakarta.persistence.Query;
-import jakarta.persistence.criteria.CriteriaBuilder;
-import jakarta.persistence.criteria.CriteriaQuery;
-import jakarta.persistence.criteria.ListJoin;
-import jakarta.persistence.criteria.Root;
-
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
 import de.ids_mannheim.korap.constant.PredefinedRole;
-import de.ids_mannheim.korap.constant.PrivilegeType;
+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 jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.Query;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Join;
+import jakarta.persistence.criteria.JoinType;
+import jakarta.persistence.criteria.ListJoin;
+import jakarta.persistence.criteria.Root;
 
 /**
  * Manages database queries and transactions regarding {@link Role}
@@ -54,6 +55,8 @@
         entityManager.flush();
     }
     
+    
+    
     public Role retrieveRoleByName (PredefinedRole role) {
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<Role> query = criteriaBuilder.createQuery(Role.class);
@@ -66,19 +69,6 @@
         return (Role) q.getSingleResult();
     }
 
-    @Deprecated
-    public Role retrieveRoleByName (String roleName) {
-        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
-        CriteriaQuery<Role> query = criteriaBuilder.createQuery(Role.class);
-
-        Root<Role> root = query.from(Role.class);
-//        root.fetch(Role_.privileges);
-        query.select(root);
-        query.where(criteriaBuilder.equal(root.get(Role_.name), roleName));
-        Query q = entityManager.createQuery(query);
-        return (Role) q.getSingleResult();
-    }
-
     public Set<Role> retrieveRoleByGroupMemberId (int userId) {
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<Role> query = criteriaBuilder.createQuery(Role.class);
@@ -90,8 +80,54 @@
         query.select(root);
         query.where(criteriaBuilder.equal(memberRole.get(UserGroupMember_.id),
                 userId));
-        Query q = entityManager.createQuery(query);
-        @SuppressWarnings("unchecked")
+        TypedQuery<Role> q= entityManager.createQuery(query);
+        List<Role> resultList = q.getResultList();
+        return new HashSet<Role>(resultList);
+    }
+    
+    public Set<Role> retrieveRoleByGroupId (int groupId, boolean hasQuery) {
+        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+        CriteriaQuery<Role> query = cb.createQuery(Role.class);
+
+        Root<Role> role = query.from(Role.class);
+        role.fetch("userGroup", JoinType.INNER);
+        role.fetch("query", JoinType.INNER);
+        
+        query.select(role);
+        if (hasQuery) {
+            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)
+            );
+        }
+
+        TypedQuery<Role> q = entityManager.createQuery(query);
+        List<Role> resultList = q.getResultList();
+        return new HashSet<Role>(resultList);
+    }
+    
+    public Set<Role> retrieveRoleByQueryIdAndUsername (int queryId, String username) {
+        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+        CriteriaQuery<Role> query = cb.createQuery(Role.class);
+
+        Root<Role> role = query.from(Role.class);
+        role.fetch(Role_.query, JoinType.INNER);
+
+        Join<Role, UserGroupMember> members = role.join("userGroupMembers",
+                JoinType.INNER);
+        
+        query.select(role);
+        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);
     }
diff --git a/src/main/java/de/ids_mannheim/korap/dto/QueryAccessDto.java b/src/main/java/de/ids_mannheim/korap/dto/QueryAccessDto.java
index 84b8b3f..f6e1173 100644
--- a/src/main/java/de/ids_mannheim/korap/dto/QueryAccessDto.java
+++ b/src/main/java/de/ids_mannheim/korap/dto/QueryAccessDto.java
@@ -1,5 +1,8 @@
 package de.ids_mannheim.korap.dto;
 
+import java.util.List;
+
+import de.ids_mannheim.korap.entity.UserGroupMember;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -13,18 +16,18 @@
 @Getter
 @Setter
 public class QueryAccessDto {
-    private int accessId;
-    private String createdBy;
+    private int roleId;
     private int queryId;
     private String queryName;
     private int userGroupId;
     private String userGroupName;
+    private List<String> members;
 
     @Override
     public String toString () {
-        return "accessId=" + accessId + ", createdBy=" + createdBy
-                + " , queryId=" + queryId + ", queryName=" + queryName
-                + ", userGroupId=" + userGroupId + ", userGroupName="
-                + userGroupName;
+        return "roleId=" + roleId + " , queryId=" + queryId + ", queryName="
+                + queryName + ", userGroupId=" + userGroupId
+                + ", userGroupName=" + userGroupName 
+                +", members=" + members;
     }
 }
diff --git a/src/main/java/de/ids_mannheim/korap/dto/converter/QueryAccessConverter.java b/src/main/java/de/ids_mannheim/korap/dto/converter/QueryAccessConverter.java
index 5dfad63..2ecfa38 100644
--- a/src/main/java/de/ids_mannheim/korap/dto/converter/QueryAccessConverter.java
+++ b/src/main/java/de/ids_mannheim/korap/dto/converter/QueryAccessConverter.java
@@ -2,11 +2,14 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 import org.springframework.stereotype.Component;
 
 import de.ids_mannheim.korap.dto.QueryAccessDto;
 import de.ids_mannheim.korap.entity.QueryAccess;
+import de.ids_mannheim.korap.entity.Role;
+import de.ids_mannheim.korap.entity.UserGroupMember;
 
 /**
  * QueryAccessConverter prepares data transfer objects (DTOs)
@@ -25,8 +28,8 @@
         List<QueryAccessDto> dtos = new ArrayList<>(accessList.size());
         for (QueryAccess access : accessList) {
             QueryAccessDto dto = new QueryAccessDto();
-            dto.setAccessId(access.getId());
-            dto.setCreatedBy(access.getCreatedBy());
+//            dto.setAccessId(access.getId());
+//            dto.setCreatedBy(access.getCreatedBy());
 
             dto.setQueryId(access.getQuery().getId());
             dto.setQueryName(access.getQuery().getName());
@@ -39,4 +42,25 @@
         return dtos;
     }
 
+    public List<QueryAccessDto> createRoleDto (Set<Role> roles) {
+        List<QueryAccessDto> dtos = new ArrayList<>(roles.size());
+        for (Role role : roles) {
+            QueryAccessDto dto = new QueryAccessDto();
+            dto.setRoleId(role.getId());
+//            dto.setCreatedBy(role.getCreatedBy());
+            dto.setQueryId(role.getQuery().getId());
+            dto.setQueryName(role.getQuery().getName());
+            dto.setUserGroupId(role.getUserGroup().getId());
+            dto.setUserGroupName(role.getUserGroup().getName());
+            List<String> members = new ArrayList<>(
+                    role.getUserGroupMembers().size());
+            for (UserGroupMember m : role.getUserGroupMembers()) {
+                members.add(m.getUserId());
+            }
+            dto.setMembers(members);
+            dtos.add(dto);
+        }
+        return dtos;
+    }
+
 }
diff --git a/src/main/java/de/ids_mannheim/korap/entity/QueryAccess.java b/src/main/java/de/ids_mannheim/korap/entity/QueryAccess.java
index 42c7968..1e0c3ea 100644
--- a/src/main/java/de/ids_mannheim/korap/entity/QueryAccess.java
+++ b/src/main/java/de/ids_mannheim/korap/entity/QueryAccess.java
@@ -25,6 +25,7 @@
  * @see QueryDO
  * @see UserGroup
  */
+@Deprecated
 @Setter
 @Getter
 @Entity
diff --git a/src/main/java/de/ids_mannheim/korap/entity/Role.java b/src/main/java/de/ids_mannheim/korap/entity/Role.java
index 434ab82..65568bf 100644
--- a/src/main/java/de/ids_mannheim/korap/entity/Role.java
+++ b/src/main/java/de/ids_mannheim/korap/entity/Role.java
@@ -56,7 +56,7 @@
 //    )
 //    private Set<UserRole> user_roles;
     
-    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
+    @ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER)
     private List<UserGroupMember> userGroupMembers;
 //
 //    @OneToMany(mappedBy = "role", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
@@ -69,9 +69,19 @@
         setPrivilege(privilege);
         setUserGroup(group);
     }
+    
+    public Role (PredefinedRole name, PrivilegeType privilege, UserGroup group,
+                 QueryDO query) {
+        setName(name);
+        setPrivilege(privilege);
+        setUserGroup(group);
+        setQuery(query);
+    }
 
     public String toString () {
-        return "id=" + id + ", name=" + name;
+        return "id=" + id + ", name=" + name + ", privilege=" + privilege
+                + ", usergroup=" + userGroup.getId() + ", members=" + userGroupMembers + ", query="
+                + ((query!=null) ? query.getId() : query);
     }
 
     @Override
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 7e45d30..b242ba5 100644
--- a/src/main/java/de/ids_mannheim/korap/service/QueryService.java
+++ b/src/main/java/de/ids_mannheim/korap/service/QueryService.java
@@ -5,6 +5,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 import org.apache.logging.log4j.LogManager;
@@ -18,18 +19,20 @@
 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.QueryAccessStatus;
+import de.ids_mannheim.korap.constant.PrivilegeType;
 import de.ids_mannheim.korap.constant.QueryType;
 import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.dao.AdminDao;
 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.dto.QueryAccessDto;
 import de.ids_mannheim.korap.dto.QueryDto;
 import de.ids_mannheim.korap.dto.converter.QueryAccessConverter;
 import de.ids_mannheim.korap.dto.converter.QueryConverter;
 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.UserGroup;
 import de.ids_mannheim.korap.entity.UserGroupMember;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -74,6 +77,8 @@
     @Autowired
     private QueryDao queryDao;
     @Autowired
+    private RoleDao roleDao;
+    @Autowired
     private QueryAccessDao accessDao;
     @Autowired
     private AdminDao adminDao;
@@ -254,8 +259,8 @@
             int groupId = userGroupService.createAutoHiddenGroup();
             UserGroup autoHidden = userGroupService
                     .retrieveUserGroupById(groupId);
-            accessDao.createAccessToQuery(query, autoHidden, "system",
-                    QueryAccessStatus.HIDDEN);
+            accessDao.createAccessToQuery(query, autoHidden);
+//                    , "system", QueryAccessStatus.HIDDEN);
         }
         else {
             // should not happened
@@ -476,15 +481,14 @@
         UserGroup userGroup = userGroupService
                 .retrieveUserGroupByName(groupName);
 
-        if (!isQueryAccessAdmin(userGroup, username)
+        if (!userGroupService.isUserGroupAdmin(username,userGroup)
                 && !adminDao.isAdmin(username)) {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                     "Unauthorized operation for user: " + username, username);
         }
         else {
             try {
-                accessDao.createAccessToQuery(query, userGroup, username,
-                        QueryAccessStatus.ACTIVE);
+                accessDao.createAccessToQuery(query, userGroup);
             }
             catch (Exception e) {
                 Throwable cause = e;
@@ -505,6 +509,7 @@
         }
     }
 
+    @Deprecated
     private boolean isQueryAccessAdmin (UserGroup userGroup, String username)
             throws KustvaktException {
         List<UserGroupMember> accessAdmins = userGroupService
@@ -543,7 +548,7 @@
             List<UserGroup> groups = userGroupService
                     .retrieveUserGroup(username);
             for (UserGroup g : groups) {
-                if (isQueryAccessAdmin(g, username)) {
+                if (userGroupService.isUserGroupAdmin(username, g)) {
                     accessList.addAll(
                             accessDao.retrieveActiveAccessByGroup(g.getId()));
                 }
@@ -566,7 +571,7 @@
             List<QueryAccess> filteredAccessList = new ArrayList<>();
             for (QueryAccess access : accessList) {
                 UserGroup userGroup = access.getUserGroup();
-                if (isQueryAccessAdmin(userGroup, username)) {
+                if (userGroupService.isUserGroupAdmin(username, userGroup)) {
                     filteredAccessList.add(access);
                 }
             }
@@ -575,44 +580,23 @@
         return accessConverter.createQueryAccessDto(accessList);
     }
 
-    @Deprecated
-    public List<QueryAccessDto> listVCAccessByGroup (String username,
-            int groupId) throws KustvaktException {
-        UserGroup userGroup = userGroupService.retrieveUserGroupById(groupId);
-
-        List<QueryAccess> accessList;
-        if (adminDao.isAdmin(username)) {
-            accessList = accessDao.retrieveAllAccessByGroup(groupId);
-        }
-        else if (isQueryAccessAdmin(userGroup, username)) {
-            accessList = accessDao.retrieveActiveAccessByGroup(groupId);
-        }
-        else {
-            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
-                    "Unauthorized operation for user: " + username, username);
-        }
-
-        return accessConverter.createQueryAccessDto(accessList);
-    }
-
     public List<QueryAccessDto> listQueryAccessByGroup (String username,
             String groupName) throws KustvaktException {
         UserGroup userGroup = userGroupService
                 .retrieveUserGroupByName(groupName);
 
-        List<QueryAccess> accessList;
-        if (adminDao.isAdmin(username)) {
-            accessList = accessDao.retrieveAllAccessByGroup(userGroup.getId());
-        }
-        else if (isQueryAccessAdmin(userGroup, username)) {
-            accessList = accessDao
-                    .retrieveActiveAccessByGroup(userGroup.getId());
+        Set<Role> accessList;
+        if (adminDao.isAdmin(username)
+                || userGroupService.isUserGroupAdmin(username, userGroup)) {
+            //            accessList = accessDao.retrieveAllAccessByGroup(userGroup.getId());
+            accessList = roleDao.retrieveRoleByGroupId(userGroup.getId(), false);
+
         }
         else {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                     "Unauthorized operation for user: " + username, username);
         }
-        return accessConverter.createQueryAccessDto(accessList);
+        return accessConverter.createRoleDto(accessList);
     }
 
     public void deleteQueryAccess (int accessId, String username)
@@ -620,7 +604,7 @@
 
         QueryAccess access = accessDao.retrieveAccessById(accessId);
         UserGroup userGroup = access.getUserGroup();
-        if (isQueryAccessAdmin(userGroup, username)
+        if (userGroupService.isUserGroupAdmin(username, userGroup)
                 || adminDao.isAdmin(username)) {
             accessDao.deleteAccess(access, username);
         }
@@ -713,7 +697,7 @@
                 && !username.equals(query.getCreatedBy())) {
             if (type.equals(ResourceType.PRIVATE)
                     || (type.equals(ResourceType.PROJECT)
-                            && !hasAccess(username, query.getId()))) {
+                            && !hasReadAccess(username, query.getId()))) {
                 throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                         "Unauthorized operation for user: " + username,
                         username);
@@ -738,16 +722,13 @@
         }
     }
 
-    private boolean hasAccess (String username, int queryId)
+    private boolean hasReadAccess (String username, int queryId)
             throws KustvaktException {
-        UserGroup userGroup;
-        List<QueryAccess> accessList = accessDao
-                .retrieveActiveAccessByQuery(queryId);
-        for (QueryAccess access : accessList) {
-            userGroup = access.getUserGroup();
-            if (userGroupService.isMember(username, userGroup)) {
+        Set<Role> roles = roleDao.retrieveRoleByQueryIdAndUsername(queryId,
+                username);
+        for (Role r :roles) {
+            if (r.getPrivilege().equals(PrivilegeType.READ_QUERY))
                 return true;
-            }
         }
         return false;
     }
diff --git a/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java b/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java
index 8799ad7..cd846d9 100644
--- a/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java
+++ b/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java
@@ -61,7 +61,7 @@
         int size = accesses.size();
         QueryAccessDto dto = accesses.get(accesses.size() - 1);
         assertEquals(vcName, dto.getQueryName());
-        assertEquals(dto.getCreatedBy(), "system");
+//        assertEquals(dto.getCreatedBy(), "system");
         assertTrue(dto.getUserGroupName().startsWith("auto"));
         // check hidden group
         int groupId = dto.getUserGroupId();
@@ -100,7 +100,7 @@
         int size = accesses.size();
         QueryAccessDto dto = accesses.get(accesses.size() - 1);
         assertEquals(vcName, dto.getQueryName());
-        assertEquals(dto.getCreatedBy(), "system");
+//        assertEquals(dto.getCreatedBy(), "system");
         assertTrue(dto.getUserGroupName().startsWith("auto"));
         // check auto hidden group
         int groupId = dto.getUserGroupId();
diff --git a/src/test/java/de/ids_mannheim/korap/web/controller/usergroup/UserGroupTestBase.java b/src/test/java/de/ids_mannheim/korap/web/controller/usergroup/UserGroupTestBase.java
index cebb710..d07fad2 100644
--- a/src/test/java/de/ids_mannheim/korap/web/controller/usergroup/UserGroupTestBase.java
+++ b/src/test/java/de/ids_mannheim/korap/web/controller/usergroup/UserGroupTestBase.java
@@ -7,17 +7,17 @@
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.SpringJerseyTest;
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.controller.OAuth2TestBase;
 import jakarta.ws.rs.ProcessingException;
 import jakarta.ws.rs.client.Entity;
 import jakarta.ws.rs.core.Form;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
 
-public class UserGroupTestBase extends SpringJerseyTest {
+public abstract class UserGroupTestBase extends OAuth2TestBase {
 
     protected String doryGroupName = "dory-group";
     protected String marlinGroupName = "marlin-group";
diff --git a/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusSharingTest.java b/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusSharingTest.java
index bd15a76..8a03ce1 100644
--- a/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusSharingTest.java
+++ b/src/test/java/de/ids_mannheim/korap/web/controller/vc/VirtualCorpusSharingTest.java
@@ -47,9 +47,8 @@
     }
 
     @Test
-    public void testShareVC_notOwner ()
+    public void testShareVC_Unauthorized ()
             throws ProcessingException, KustvaktException {
-        // dory is VCA in marlin group
         Response response = target().path(API_VERSION).path("vc")
                 .path("~marlin").path("marlin-vc").path("share")
                 .path("@marlin group").request()
@@ -62,13 +61,29 @@
     @Test
     public void testShareVC_byMember ()
             throws ProcessingException, KustvaktException {
-        // nemo is not VCA in marlin group
-        Response response = target().path(API_VERSION).path("vc").path("~nemo")
-                .path("nemo-vc").path("share").path("@marlin-group").request()
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue("nemo", "pass"))
-                .post(Entity.form(new Form()));
+        createMarlinGroup();
+        inviteMember(marlinGroupName, "marlin", "nemo");
+        subscribe(marlinGroupName, "nemo");
+        
+        JsonNode node = listAccessByGroup("marlin", marlinGroupName);
+        assertEquals(0, node.size());
+        
+        Response response = testShareVCByCreator("nemo", "nemo-vc",
+                marlinGroupName);
         testResponseUnauthorized(response, "nemo");
+        
+        
+        Form form = new Form();
+        form.param("memberUsername", "nemo");
+        form.param("role", PredefinedRole.GROUP_ADMIN.name());
+        addMemberRole(marlinGroupName, "marlin", form);
+
+        response = testShareVCByCreator("nemo", "nemo-vc", marlinGroupName);
+        
+        node = listAccessByGroup("marlin", marlinGroupName);
+        assertEquals(1, node.size());
+        System.out.println(node.toPrettyString());
+        deleteGroupByName(marlinGroupName, "marlin");
     }
 
     @Test
@@ -93,15 +108,19 @@
         // create user group
         String groupName = "owidGroup";
         String memberName = "darla";
-        response = createUserGroup(testUser, groupName, "Owid users");
+        response = createUserGroup(groupName, "Owid users", testUser);
         assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
         listUserGroup(testUser, groupName);
-        testInviteMember(testUser, groupName, "darla");
+        testInviteMember(groupName, testUser, "darla");
         subscribeToGroup(memberName, groupName);
         checkMemberInGroup(memberName, testUser, groupName);
         // share vc to group
         testShareVCByCreator(testUser, vcName, groupName);
+        
+        // check member roles
         node = listAccessByGroup(testUser, groupName);
+        assertEquals(1, node.size());
+        
         // search by member
         response = searchWithVCRef(memberName, testUser, vcName);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -120,18 +139,6 @@
                 node.at("/errors/0/0").asInt());
     }
 
-    private Response createUserGroup (String username, String groupName,
-            String description) throws ProcessingException, KustvaktException {
-        Form form = new Form();
-        form.param("description", description);
-        Response response = target().path(API_VERSION).path("group")
-                .path("@" + groupName).request()
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .put(Entity.form(form));
-        return response;
-    }
-
     private JsonNode listUserGroup (String username, String groupName)
             throws KustvaktException {
         Response response = target().path(API_VERSION).path("group").request()
@@ -144,26 +151,6 @@
         return node;
     }
 
-    private void testInviteMember (String username, String groupName,
-            String memberName) throws ProcessingException, KustvaktException {
-        Form form = new Form();
-        form.param("members", memberName);
-        Response response = target().path(API_VERSION).path("group")
-                .path("@" + groupName).path("invite").request()
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .post(Entity.form(form));
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        // list group
-        JsonNode node = listUserGroup(username, groupName);
-        node = node.get(0);
-        assertEquals(2, node.get("members").size());
-        assertEquals(memberName, node.at("/members/1/userId").asText());
-        assertEquals(GroupMemberStatus.PENDING.name(),
-                node.at("/members/1/status").asText());
-        assertEquals(0, node.at("/members/1/roles").size());
-    }
-
     private void subscribeToGroup (String username, String groupName)
             throws KustvaktException {
         Response response = target().path(API_VERSION).path("group")
@@ -181,9 +168,7 @@
         assertEquals(memberName, node.at("/members/1/userId").asText());
         assertEquals(GroupMemberStatus.ACTIVE.name(),
                 node.at("/members/1/status").asText());
-        assertEquals(PredefinedRole.QUERY_ACCESS,
-                node.at("/members/1/roles/1").asText());
-        assertEquals(PredefinedRole.GROUP_MEMBER,
+        assertEquals(PredefinedRole.GROUP_MEMBER.name(),
                 node.at("/members/1/roles/0").asText());
     }
 
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 f2f8afb..7ef5f0d 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
@@ -9,12 +9,6 @@
 import java.util.Map.Entry;
 import java.util.Set;
 
-import jakarta.ws.rs.ProcessingException;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.core.Form;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.Status;
-
 import org.apache.http.entity.ContentType;
 import org.glassfish.jersey.server.ContainerRequest;
 
@@ -26,9 +20,14 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.web.controller.OAuth2TestBase;
+import de.ids_mannheim.korap.web.controller.usergroup.UserGroupTestBase;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Form;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
 
-public abstract class VirtualCorpusTestBase extends OAuth2TestBase {
+public abstract class VirtualCorpusTestBase extends UserGroupTestBase {
 
     protected JsonNode retrieveVCInfo (String username, String vcCreator,
             String vcName) throws ProcessingException, KustvaktException {
@@ -124,6 +123,16 @@
                         .createBasicAuthorizationHeaderValue(vcCreator, "pass"))
                 .post(Entity.form(new Form()));
     }
+    
+    protected Response shareVC (String vcCreator, String vcName,
+            String groupName, String username) throws ProcessingException, KustvaktException {
+
+        return 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()));
+    }
 
     protected JsonNode listAccessByGroup (String username, String groupName)
             throws KustvaktException {