/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.portfolio.manager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.olat.basesecurity.Group;
import org.olat.basesecurity.GroupRoles;
import org.olat.basesecurity.Invitation;
import org.olat.basesecurity.manager.GroupDAO;
import org.olat.core.commons.persistence.DB;
import org.olat.core.id.Identity;
import org.olat.group.BusinessGroup;
import org.olat.group.manager.BusinessGroupDAO;
import org.olat.portfolio.model.structel.EPMapShort;
import org.olat.portfolio.model.structel.EPStructureElement;
import org.olat.portfolio.model.structel.EPStructureElementToGroupRelation;
import org.olat.portfolio.model.structel.PortfolioStructureMap;
import org.olat.portfolio.model.structel.PortfolioStructureMapRef;
import org.olat.resource.OLATResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Description:<br>
* manager for all map share and policy handling
*
* <P>
* Initial Date: 30.11.2010 <br>
* @author Roman Haag, roman.haag@frentix.com, http://www.frentix.com
*/
@Service("epPolicyManager")
public class EPPolicyManager {
@Autowired
private DB dbInstance;
@Autowired
private GroupDAO groupDao;
@Autowired
private InvitationDAO invitationDao;
@Autowired
private BusinessGroupDAO businessGroupDao;
public List<Identity> getOwners(PortfolioStructureMapRef map) {
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(EPMapShort.class.getName()).append(" as map")
.append(" inner join map.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup ")
.append(" inner join baseGroup.members as members on members.role='").append(GroupRoles.owner.name()).append("'")
.append(" inner join members.identity as ident")
.append(" where map.key=:mapKey");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("mapKey", map.getKey()).getResultList();
}
public boolean isMapShared(OLATResource resource) {
StringBuilder sb = new StringBuilder();
sb.append("select count(relGroup) from ").append(EPMapShort.class.getName()).append(" as map")
.append(" inner join map.groups as relGroup on relGroup.defaultGroup=false")
.append(" where map.olatResource=:resource");
Number count = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Number.class)
.setParameter("resource", resource)
.getSingleResult();
return count == null ? false : count.intValue() > 0;
}
/**
* Return a list of wrapper containing the read policies of the map
* @param map
*/
public List<EPMapPolicy> getMapPolicies(PortfolioStructureMapRef mapRef) {
EPMapShort map = dbInstance.getCurrentEntityManager().find(EPMapShort.class, mapRef.getKey());
List<EPMapPolicy> policies = new ArrayList<EPMapPolicy>();
Set<EPStructureElementToGroupRelation> relations = map.getGroups();
for(EPStructureElementToGroupRelation relation:relations) {
if(relation.isDefaultGroup()) {
continue;
}
EPMapPolicy policy = getEquivalentWrapper(relation, policies);
if(policy == null) {
policy = new EPMapPolicy();
policy.setTo(relation.getValidTo());
policy.setFrom(relation.getValidFrom());
policies.add(policy);
}
String role = relation.getRole();
if(role.startsWith(EPMapPolicy.Type.user.name())) {
List<Identity> identities = groupDao.getMembers(relation.getGroup(), GroupRoles.participant.name());
policy.addRelation(relation);
policy.setType(EPMapPolicy.Type.user);
policy.addIdentities(identities);
} else if (role.startsWith(EPMapPolicy.Type.group.name())) {
policy.addRelation(relation);
BusinessGroup group = businessGroupDao.findBusinessGroup(relation.getGroup());
policy.addGroup(group);
policy.setType(EPMapPolicy.Type.group);
} else if (role.startsWith(EPMapPolicy.Type.invitation.name())) {
policy.addRelation(relation);
Invitation invitation = invitationDao.findInvitation(relation.getGroup());
policy.setInvitation(invitation);
policy.setType(EPMapPolicy.Type.invitation);
} else if (role.startsWith(EPMapPolicy.Type.allusers.name())) {
policy.addRelation(relation);
policy.setType(EPMapPolicy.Type.allusers);
}
}
return policies;
}
private EPMapPolicy getEquivalentWrapper(EPStructureElementToGroupRelation relation, List<EPMapPolicy> policies) {
Date to = relation.getValidTo();
Date from = relation.getValidFrom();
String role = relation.getRole();
a_a:
for(EPMapPolicy policy:policies) {
for(EPStructureElementToGroupRelation p:policy.getRelations()) {
if(!role.equals(p.getRole())) {
continue a_a;
}
if(from == null && p.getValidFrom() == null || (from != null && p.getValidFrom() != null && from.equals(p.getValidFrom()))) {
if(to == null && p.getValidTo() == null || (to != null && p.getValidTo() != null && to.equals(p.getValidTo()))) {
return policy;
}
}
}
}
return null;
}
/**
* Update the map policies of a map. The missing policies are deleted!
* @param map
* @param policies
*/
public PortfolioStructureMap updateMapPolicies(PortfolioStructureMap map, List<EPMapPolicy> policies) {
map = dbInstance.getCurrentEntityManager().merge(map);
List<EPStructureElementToGroupRelation> savedPolicies = new ArrayList<EPStructureElementToGroupRelation>();
for(EPMapPolicy wrapper:policies) {
savedPolicies.addAll(applyPolicy(wrapper, map));
}
Collection<EPStructureElementToGroupRelation> currentRelations = new ArrayList<>(map.getGroups());
for(EPStructureElementToGroupRelation currentRelation:currentRelations) {
if(currentRelation.isDefaultGroup()) {
continue;
}
boolean inUse = savedPolicies.contains(currentRelation);
if(!inUse) {
map.getGroups().remove(currentRelation);
}
}
return dbInstance.getCurrentEntityManager().merge(map);
}
private List<EPStructureElementToGroupRelation> applyPolicy(EPMapPolicy policy, PortfolioStructureMap map) {
List<EPStructureElementToGroupRelation> savedPolicies = new ArrayList<EPStructureElementToGroupRelation>();
switch(policy.getType()) {
case user:
savedPolicies.add(applyPolicyToUsers(policy, map));
break;
case group:
for(BusinessGroup group:policy.getGroups()) {
savedPolicies.add(applyPolicyToGroup(group.getBaseGroup(), policy, map));
}
break;
case invitation:
Invitation invitation = policy.getInvitation();
EPStructureElementToGroupRelation invitationPolicy = applyPolicyToInvitation(invitation, policy, map);
savedPolicies.add(invitationPolicy);
break;
case allusers:
EPStructureElementToGroupRelation allUsersPolicy = applyPolicyToAllUsers(policy, map);
savedPolicies.add(allUsersPolicy);
break;
}
return savedPolicies;
}
private EPStructureElementToGroupRelation applyPolicyToAllUsers(EPMapPolicy wrapper, PortfolioStructureMap map) {
List<EPStructureElementToGroupRelation> currentRelations = wrapper.getRelations();
if(!currentRelations.isEmpty()) {
EPStructureElementToGroupRelation currentRelation = currentRelations.get(0);
updatePolicy(currentRelation, wrapper.getFrom(), wrapper.getTo());
return currentRelation;
}
return createBaseRelation(map, null, EPMapPolicy.Type.allusers.name(), wrapper.getFrom(), wrapper.getTo());
}
private EPStructureElementToGroupRelation applyPolicyToUsers(EPMapPolicy policy, PortfolioStructureMap map) {
List<EPStructureElementToGroupRelation> currentRelations = policy.getRelations();
EPStructureElementToGroupRelation relation = (currentRelations == null || currentRelations.isEmpty()) ? null : currentRelations.get(0);
if(relation == null) {
Group secGroup = groupDao.createGroup();
relation = createBaseRelation(map, secGroup, EPMapPolicy.Type.user.name(), policy.getFrom(), policy.getTo());
for(Identity identity:policy.getIdentities()) {
groupDao.addMembershipTwoWay(secGroup, identity, GroupRoles.participant.name());
}
} else {
EPStructureElementToGroupRelation currentPolicy = reusePolicyInSession(relation, map);
updatePolicy(currentPolicy, policy.getFrom(), policy.getTo());
Group secGroup = relation.getGroup();
List<Identity> currentMembers = groupDao.getMembers(secGroup, GroupRoles.participant.name());
List<Identity> newMembers = new ArrayList<>(policy.getIdentities());
for (Identity newMember:policy.getIdentities()) {
if(currentMembers.contains(newMember)) {
newMembers.remove(newMember);
currentMembers.remove(newMember);
}
}
//re-attach the session to lazy load the members
secGroup = dbInstance.getCurrentEntityManager().merge(secGroup);
for(Identity currentMember:currentMembers) {
groupDao.removeMembership(secGroup, currentMember);
}
for(Identity newMember:newMembers) {
groupDao.addMembershipTwoWay(secGroup, newMember, GroupRoles.participant.name());
}
}
return relation;
}
private EPStructureElementToGroupRelation applyPolicyToInvitation(Invitation invitation, EPMapPolicy policy, PortfolioStructureMap map) {
invitation = dbInstance.getCurrentEntityManager().merge(invitation);
Group secGroup = invitation.getBaseGroup();
Collection<EPStructureElementToGroupRelation> currentRelations = map.getGroups();
for(EPStructureElementToGroupRelation currentRelation:currentRelations) {
if(secGroup.equals(currentRelation.getGroup())) {
updatePolicy(currentRelation, policy.getFrom(), policy.getTo());
return currentRelation;
}
}
return createBaseRelation(map, secGroup, EPMapPolicy.Type.invitation.name(), policy.getFrom(), policy.getTo());
}
/**
* Hibernate doesn't allow to update an object if the same object is already in the current
* hibernate session.
* @param policy
* @param currentPolicies
* @return
*/
private EPStructureElementToGroupRelation reusePolicyInSession(EPStructureElementToGroupRelation relation, PortfolioStructureMap map) {
Collection<EPStructureElementToGroupRelation> currentRelations = map.getGroups();
for(EPStructureElementToGroupRelation currentRelation:currentRelations) {
if(relation.equalsByPersistableKey(currentRelation)) {
return currentRelation;
}
}
return relation;
}
private EPStructureElementToGroupRelation applyPolicyToGroup(Group group, EPMapPolicy policy, PortfolioStructureMap map) {
Collection<EPStructureElementToGroupRelation> currentRelations = map.getGroups();
for(EPStructureElementToGroupRelation currentRelation:currentRelations) {
if(currentRelation.getGroup() != null && currentRelation.getGroup().equals(group)) {
updatePolicy(currentRelation, policy.getFrom(), policy.getTo());
return currentRelation;
}
}
return createBaseRelation(map, group, EPMapPolicy.Type.group.name(), policy.getFrom(), policy.getTo());
}
private void updatePolicy(EPStructureElementToGroupRelation relation, Date from, Date to) {
relation.setValidFrom(from);
relation.setValidTo(to);
}
private EPStructureElementToGroupRelation createBaseRelation(PortfolioStructureMap map, Group group, String role, Date from, Date to) {
//create security group
EPStructureElementToGroupRelation relation = new EPStructureElementToGroupRelation();
relation.setDefaultGroup(false);
relation.setCreationDate(new Date());
relation.setGroup(group);
relation.setStructureElement((EPStructureElement)map);
relation.setRole(role);
relation.setValidFrom(from);
relation.setValidTo(to);
map.getGroups().add(relation);
return relation;
}
}