diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index fdc85e20f..66e38316c 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -206,9 +206,9 @@ public EntityDescriptorConversionUtils EntityDescriptorConverstionUtilsInit(Enti } @Bean - public GroupUpdatedEntityListener groupUpdatedEntityListener(OwnershipRepository repo) { + public GroupUpdatedEntityListener groupUpdatedEntityListener(OwnershipRepository repo, GroupsRepository groupsRepository) { GroupUpdatedEntityListener listener = new GroupUpdatedEntityListener(); - listener.init(repo); + listener.init(repo, groupsRepository); return listener; } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Approvers.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Approvers.java index 811e4ffc6..dd0c4bec4 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Approvers.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Approvers.java @@ -22,6 +22,6 @@ public class Approvers { @Column(name = "resource_id") private String resourceId = UUID.randomUUID().toString(); - @OneToMany + @ManyToMany private List approverGroups = new ArrayList<>(); } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Group.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Group.java index ac02c5067..14597deb2 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Group.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Group.java @@ -33,6 +33,9 @@ public class Group implements Owner { @JsonIgnore public static Group ADMIN_GROUP; + @Transient + List approveForList = new ArrayList<>(); + @Column(name = "group_description") String description; @@ -97,4 +100,11 @@ public int hashCode() { public boolean equals(Object o) { return o instanceof Group && this.resourceId.equals(((Group)o).resourceId); } + + public List getApproveForList() { + if (lazyLoaderHelper != null) { + lazyLoaderHelper.loadApproveForList(this); + } + return approveForList; + } } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/GroupUpdatedEntityListener.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/GroupUpdatedEntityListener.java index d477ae78c..5fa01c570 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/GroupUpdatedEntityListener.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/GroupUpdatedEntityListener.java @@ -2,6 +2,7 @@ import edu.internet2.tier.shibboleth.admin.ui.security.model.Group; import edu.internet2.tier.shibboleth.admin.ui.security.model.Ownership; +import edu.internet2.tier.shibboleth.admin.ui.security.repository.GroupsRepository; import edu.internet2.tier.shibboleth.admin.ui.security.repository.OwnershipRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -9,17 +10,20 @@ import javax.persistence.PostPersist; import javax.persistence.PostRemove; import javax.persistence.PostUpdate; +import java.util.List; import java.util.Set; public class GroupUpdatedEntityListener implements ILazyLoaderHelper { + private static GroupsRepository groupsRepository; private static OwnershipRepository ownershipRepository; /** * @see https://stackoverflow.com/questions/12155632/injecting-a-spring-dependency-into-a-jpa-entitylistener */ @Autowired - public static void init(OwnershipRepository repo) { - GroupUpdatedEntityListener.ownershipRepository = repo; + public static void init(OwnershipRepository ownershipRepository, GroupsRepository groupsRepository) { + GroupUpdatedEntityListener.ownershipRepository = ownershipRepository; + GroupUpdatedEntityListener.groupsRepository = groupsRepository; } @PostPersist @@ -38,4 +42,14 @@ public void loadOwnedItems(Group group) { group.setOwnedItems(ownedItems); } + @Override + public void loadApproveForList(Group group) { + List result = group.getResourceId().equals(Group.ADMIN_GROUP.getResourceId()) ? + groupsRepository.findAllGroupIds() : + groupsRepository.getGroupIdsOfGroupsToApproveFor(group.getResourceId()); + if (result != null) { + group.setApproveForList(result); + } + } + } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/ILazyLoaderHelper.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/ILazyLoaderHelper.java index 689306932..b669845aa 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/ILazyLoaderHelper.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/listener/ILazyLoaderHelper.java @@ -4,6 +4,8 @@ import edu.internet2.tier.shibboleth.admin.ui.security.model.User; public interface ILazyLoaderHelper { + default void loadApproveForList(Group group) { } + default void loadOwnedItems(Group g) { } default void loadGroups(User u) { } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepository.java index daf3ce265..7d92d3c18 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepository.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepository.java @@ -5,9 +5,22 @@ import org.springframework.data.jpa.repository.JpaRepository; import edu.internet2.tier.shibboleth.admin.ui.security.model.Group; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface GroupsRepository extends JpaRepository { void deleteByResourceId(String resourceId); Group findByResourceId(String id); + + @Query(nativeQuery = true, + value = "SELECT DISTINCT user_groups_resource_id " + + " FROM user_groups_approvers " + + " WHERE approvers_list_resource_id IN (SELECT approvers_resource_id " + + " FROM approvers_user_groups " + + " WHERE approver_groups_resource_id = :resourceId)") + List getGroupIdsOfGroupsToApproveFor(@Param("resourceId") String resourceId); + + @Query(nativeQuery = true, value = "SELECT resource_id FROM user_groups") + List findAllGroupIds(); } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/GroupServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/GroupServiceImpl.java index 6eac2fde7..a9607534f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/GroupServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/GroupServiceImpl.java @@ -37,11 +37,6 @@ public class GroupServiceImpl implements IGroupService { @Autowired protected OwnershipRepository ownershipRepository; -// public GroupServiceImpl(GroupsRepository repo, OwnershipRepository ownershipRepository) { -// this.groupRepository = repo; -// this.ownershipRepository = ownershipRepository; -// } - @Override @Transactional public Group createGroup(Group group) throws GroupExistsConflictException, InvalidGroupRegexException { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java index 25f152a90..873ba3df6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java @@ -144,6 +144,10 @@ public Group getCurrentUserGroup() { } } + public List getGroupsCurrentUserCanApprove() { + return getCurrentUserGroup().getApproveForList(); + } + public Set getUserRoles(String username) { Optional user = userRepository.findByUsername(username); HashSet result = new HashSet<>(); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/AbstractBaseDataJpaTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/AbstractBaseDataJpaTest.groovy index 85859855c..65195d7ae 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/AbstractBaseDataJpaTest.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/AbstractBaseDataJpaTest.groovy @@ -87,7 +87,7 @@ abstract class AbstractBaseDataJpaTest extends Specification implements ResetsDa } createAdminUser() - GroupUpdatedEntityListener.init(ownershipRepository) + GroupUpdatedEntityListener.init(ownershipRepository, groupRepository) UserUpdatedEntityListener.init(ownershipRepository, groupRepository) } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy index 2c246889a..b8baf83f8 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy @@ -54,9 +54,9 @@ class BaseDataJpaTestConfiguration { } @Bean - GroupUpdatedEntityListener groupUpdatedEntityListener(OwnershipRepository ownershipRepository) { + GroupUpdatedEntityListener groupUpdatedEntityListener(OwnershipRepository ownershipRepository, GroupsRepository groupsRepository) { GroupUpdatedEntityListener listener = new GroupUpdatedEntityListener() - listener.init(ownershipRepository) + listener.init(ownershipRepository, groupsRepository) return listener } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepositoryTests.groovy index f0dcfa68d..b341d0ab7 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/repository/GroupsRepositoryTests.groovy @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.security.repository import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest +import edu.internet2.tier.shibboleth.admin.ui.security.model.Approvers import edu.internet2.tier.shibboleth.admin.ui.security.model.Group import edu.internet2.tier.shibboleth.admin.ui.security.model.Ownership import org.springframework.beans.factory.annotation.Autowired @@ -205,4 +206,52 @@ class GroupsRepositoryTests extends AbstractBaseDataJpaTest { then: nothingThere == null } + + def "get list of groups that a group can approve for"() { + when: + groupService.clearAllForTesting() + List apprGroups = new ArrayList<>() + String[] groupNames = ['BBB', 'CCC', 'EEE', 'AAA'] + groupNames.each {name -> { + Group group = new Group().with({ + it.name = name + it.description = name + it.resourceId = name + it + }) + if (name != "AAA") { + apprGroups.add(groupRepository.save(group)) + } else { + Approvers approvers = new Approvers() + approvers.setApproverGroups(apprGroups) + List apprList = new ArrayList<>() + apprList.add(approversRepository.save(approvers)) + group.setApproversList(apprList) + groupRepository.save(group) + } + }} + Group group = new Group().with({ + it.name = 'DDD' + it.description = 'DDD' + it.resourceId = 'DDD' + it + }) + Approvers approvers = new Approvers() + apprGroups = new ArrayList<>() + apprGroups.add(groupRepository.findByResourceId('BBB')) + approvers.setApproverGroups(apprGroups) + List apprList = new ArrayList<>() + apprList.add(approversRepository.save(approvers)) + group.setApproversList(apprList) + groupRepository.save(group) + entityManager.flush() + entityManager.clear() + + then: + def result = groupRepository.getGroupIdsOfGroupsToApproveFor('BBB') + result.size() == 2 + result.contains('AAA') + result.contains('DDD') + groupRepository.findAllGroupIds().size() == 6 + } } \ No newline at end of file