package org.sakaiproject.delegatedaccess.logic; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import lombok.Getter; import lombok.Setter; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; import org.apache.log4j.Logger; import org.sakaiproject.api.app.scheduler.DelayedInvocation; import org.sakaiproject.api.app.scheduler.ScheduledInvocationManager; import org.sakaiproject.delegatedaccess.dao.DelegatedAccessDao; import org.sakaiproject.delegatedaccess.model.AccessNode; import org.sakaiproject.delegatedaccess.model.AccessSearchResult; import org.sakaiproject.delegatedaccess.model.HierarchyNodeSerialized; import org.sakaiproject.delegatedaccess.model.ListOptionSerialized; import org.sakaiproject.delegatedaccess.model.NodeModel; import org.sakaiproject.delegatedaccess.model.SearchResult; import org.sakaiproject.delegatedaccess.model.SiteSearchResult; import org.sakaiproject.delegatedaccess.model.SiteSerialized; import org.sakaiproject.delegatedaccess.util.DelegatedAccessConstants; import org.sakaiproject.delegatedaccess.util.DelegatedAccessMutableTreeNode; import org.sakaiproject.hierarchy.HierarchyService; import org.sakaiproject.hierarchy.model.HierarchyNode; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SitePage; import org.sakaiproject.site.api.SiteService.SelectionType; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.time.api.TimeService; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.user.api.User; /** * Implementation of {@link ProjectLogic} * * @author Bryan Holladay (holladay@longsight.com) * */ public class ProjectLogicImpl implements ProjectLogic { private static final Logger log = Logger.getLogger(ProjectLogicImpl.class); @Getter @Setter private SakaiProxy sakaiProxy; @Getter @Setter private HierarchyService hierarchyService; @Getter @Setter private DelegatedAccessDao dao; //NodeCache stores HierarchyNodeSerialed nodes for faster lookups @Getter @Setter private Cache nodeCache; //Stores restricted tools map for users when they log back in @Getter @Setter private Cache restrictedAuthToolsCache; @Getter @Setter private ScheduledInvocationManager scheduledInvocationManager; @Getter @Setter private TimeService timeService; @Getter @Setter private Cache restrictedPublicToolsCache; /** * init - perform any actions required here for when this bean starts up */ public void init() { log.info("init"); } /** * returns the node for this id * @param id * @return */ public HierarchyNodeSerialized getNode(String id){ return new HierarchyNodeSerialized(hierarchyService.getNodeById(id)); } /** * {@inheritDoc} */ public void updateNodePermissionsForUser(DefaultMutableTreeNode node, String userId){ updateNodePermissionsForUser((NodeModel) node.getUserObject(), userId); } private void updateNodePermissionsForUser(NodeModel nodeModel, String userId){ //first step, remove all permissions so you can have a clear palet removeAllUserPermissions(nodeModel.getNodeId(), userId); //save access admin setting saveAccessAdmin(nodeModel.isAccessAdmin(), nodeModel.getNodeId(), userId); //save shopping period admin information saveShoppingPeriodAdmin(nodeModel.isShoppingPeriodAdmin(), nodeModel.getNodeId(), userId); if(nodeModel.isDirectAccess()){ //if direct access, add permissions, otherwise, leave it blank //site access permission hierarchyService.assignUserNodePerm(userId, nodeModel.getNodeId(), DelegatedAccessConstants.NODE_PERM_SITE_VISIT, false); //realm & role permissions saveRealmAndRoleAccess(userId, nodeModel.getRealm(), nodeModel.getRole(), nodeModel.getNodeId()); //tool permissions: List<String> restrictedAuthTools = new ArrayList<String>(); for(ListOptionSerialized tool : nodeModel.getRestrictedAuthTools()){ if(tool.isSelected()){ restrictedAuthTools.add(tool.getId()); } } if(!restrictedAuthTools.isEmpty()){ saveRestrictedAuthToolsForUser(userId, nodeModel.getNodeId(), restrictedAuthTools); } //public tool permissions: List<String> restrictedPublicTools = new ArrayList<String>(); for(ListOptionSerialized tool : nodeModel.getRestrictedPublicTools()){ if(tool.isSelected()){ restrictedPublicTools.add(tool.getId()); } } if(!restrictedPublicTools.isEmpty()){ saveRestrictedPublicToolsForUser(userId, nodeModel.getNodeId(), restrictedPublicTools); } if(nodeModel.isInstructorEdited()){ saveInstructorEdited(nodeModel.isInstructorEdited(), userId, nodeModel.getNodeId()); } //save shopping period information if(DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)){ saveShoppingPeriodStartDate(nodeModel.getShoppingPeriodStartDate(), nodeModel.getNodeId()); saveShoppingPeriodEndDate(nodeModel.getShoppingPeriodEndDate(), nodeModel.getNodeId()); saveShoppingPeriodRevokeInstructorEditable(nodeModel.isShoppingPeriodRevokeInstructorEditable(), nodeModel.getNodeId()); saveShoppingPeriodRevokeInstructorPublicOpt(nodeModel.isShoppingPeriodRevokeInstructorPublicOpt(), nodeModel.getNodeId()); }else{ //save non-shopping period user specific data saveAllowBecomeUser(nodeModel.isAllowBecomeUser(), userId, nodeModel.getNodeId()); } } //Modification Date Tracking and Event posting: //if the user still has access of some kind, post a modification event (since only modified nodes get saved) as well as update the modification timestamp if(nodeModel.isDirectAccess() || nodeModel.isShoppingPeriodAdmin() || nodeModel.isAccessAdmin()){ saveModifiedData(userId, nodeModel.getNodeId()); sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_MODIFIED_USER_PERMS, "/user/" + userId + "/node/" + nodeModel.getNodeId() + "/realm/" + nodeModel.getRealm() + "/role/" + nodeModel.getRole(), true); } //if the user added or removed direct access permissions, post an event if(nodeModel.isDirectAccess() != nodeModel.isDirectAccessOrig()){ if(nodeModel.isDirectAccess()){ sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_ADD_USER_PERMS, "/user/" + userId + "/node/" + nodeModel.getNodeId() + "/realm/" + nodeModel.getRealm() + "/role/" + nodeModel.getRole(), true); }else{ sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_DELETE_USER_PERMS, "/user/" + userId + "/node/" + nodeModel.getNodeId(), true); } } //If ths user has been granted or removed shopping admin access, post an event and save the shopping modification timestamp //Theoretically the shopping period user would never be set to be a shopping period admin, but just in case someone tries, check for it if(!DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId) && nodeModel.isShoppingPeriodAdmin() != nodeModel.isShoppingPeriodAdminOrig()){ saveShoppingPeriodAdminModifiedData(userId, nodeModel.getNodeId()); if(nodeModel.isShoppingPeriodAdmin()){ sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_ADD_USER_SHOPPING_ADMIN, "/user/" + userId + "/node/" + nodeModel.getNodeId(), true); }else{ sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_DELETE_USER_SHOPPING_ADMIN, "/user/" + userId + "/node/" + nodeModel.getNodeId(), true); } }else if(!DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId) && nodeModel.getShoppingAdminModified() != null && (nodeModel.isDirectAccess() || nodeModel.isShoppingPeriodAdmin() || nodeModel.isAccessAdmin())){ //If there was no modification to shopping admin permission but there is a timestamp of previous modifications, //we need to resave it so we don't lose this information: hierarchyService.assignUserNodePerm(userId, nodeModel.getNodeId(), DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED + nodeModel.getShoppingAdminModified().getTime(), false); hierarchyService.assignUserNodePerm(userId, nodeModel.getNodeId(), DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED_BY + nodeModel.getShoppingAdminModifiedBy(), false); } if(nodeModel.isAccessAdmin() != nodeModel.isAccessAdminOrig()){ if(nodeModel.isAccessAdmin()){ sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_ADD_USER_ACCESS_ADMIN, "/user/" + userId + "/node/" + nodeModel.getNodeId(), true); }else{ sakaiProxy.postEvent(DelegatedAccessConstants.EVENT_DELETE_USER_ACCESS_ADMIN, "/user/" + userId + "/node/" + nodeModel.getNodeId(), true); } } if(DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)){ // Remove any existing notifications for this node DelayedInvocation[] fdi = scheduledInvocationManager.findDelayedInvocations("org.sakaiproject.delegatedaccess.jobs.DelegatedAccessShoppingPeriodJob", nodeModel.getNode().id); if (fdi != null && fdi.length > 0) { for (DelayedInvocation d : fdi) { scheduledInvocationManager.deleteDelayedInvocation(d.uuid); } } //update the shopping period site settings (realm, site properties, etc) scheduledInvocationManager.createDelayedInvocation(timeService.newTime(), "org.sakaiproject.delegatedaccess.jobs.DelegatedAccessShoppingPeriodJob", nodeModel.getNode().id); } } private void saveShoppingPeriodAdmin(boolean admin, String nodeId, String userId){ //only save shopping period admin flag for real users if(admin && !DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN, false); } } private void saveAccessAdmin(boolean accessAdmin, String nodeId, String userId){ //only save shopping period admin flag for real users if(accessAdmin && !DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_ACCESS_ADMIN, false); } } private void saveShoppingPeriodAdminModifiedData(String userId, String nodeId){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED + new Date().getTime(), false); hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED_BY + sakaiProxy.getCurrentUserId(), false); } private void saveModifiedData(String userId, String nodeId){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_MODIFIED + new Date().getTime(), false); hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_MODIFIED_BY + sakaiProxy.getCurrentUserId(), false); } private void saveShoppingPeriodStartDate(Date startDate, String nodeId){ if(startDate != null){ hierarchyService.assignUserNodePerm(DelegatedAccessConstants.SHOPPING_PERIOD_USER, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_START_DATE + startDate.getTime(), false); } } private void saveShoppingPeriodEndDate(Date endDate, String nodeId){ if(endDate != null){ hierarchyService.assignUserNodePerm(DelegatedAccessConstants.SHOPPING_PERIOD_USER, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_END_DATE + endDate.getTime(), false); } } private void saveShoppingPeriodRevokeInstructorEditable(boolean shoppingPeriodRevokeInstructorEditable, String nodeId){ if(shoppingPeriodRevokeInstructorEditable){ hierarchyService.assignUserNodePerm(DelegatedAccessConstants.SHOPPING_PERIOD_USER, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_REVOKE_INSTRUCTOR_EDITABLE, false); } } private void saveShoppingPeriodRevokeInstructorPublicOpt(boolean bool, String nodeId){ if(bool){ hierarchyService.assignUserNodePerm(DelegatedAccessConstants.SHOPPING_PERIOD_USER, nodeId, DelegatedAccessConstants.NODE_PERM_SHOPPING_REVOKE_INSTRUCTOR_PUBLIC_OPT, false); } } private void saveAllowBecomeUser(boolean bool, String userId, String nodeId){ if(bool){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_ALLOW_BECOME_USER, false); } } private void saveInstructorEdited(boolean bool, String userId, String nodeId){ if(bool){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_INSTRUCTOR_EDITED, false); } } public void saveHierarchyJobLastRunDate(Date runDate, String nodeId){ if(runDate != null){ clearHierarchyJobLastRunDate(nodeId); hierarchyService.assignUserNodePerm(DelegatedAccessConstants.SITE_HIERARCHY_USER, nodeId, DelegatedAccessConstants.NODE_PERM_SITE_HIERARCHY_JOB_LAST_RUN_DATE + runDate.getTime(), false); } } private void clearHierarchyJobLastRunDate(String nodeId){ for(String perm : hierarchyService.getPermsForUserNodes(DelegatedAccessConstants.SITE_HIERARCHY_USER, new String[]{nodeId})){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SITE_HIERARCHY_JOB_LAST_RUN_DATE)){ hierarchyService.removeUserNodePerm(DelegatedAccessConstants.SITE_HIERARCHY_USER, nodeId, perm, false); } } } public Date getHierarchyJobLastRunDate(String nodeId){ Date returnDate = null; for(String perm : hierarchyService.getPermsForUserNodes(DelegatedAccessConstants.SITE_HIERARCHY_USER, new String[]{nodeId})){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SITE_HIERARCHY_JOB_LAST_RUN_DATE)){ try{ returnDate = new Date(Long.parseLong(perm.substring(DelegatedAccessConstants.NODE_PERM_SITE_HIERARCHY_JOB_LAST_RUN_DATE.length()))); }catch (Exception e) { //wrong format, ignore } } } return returnDate; } private void removeAllUserPermissions(String nodeId, String userId){ for(String perm : getPermsForUserNodes(userId, nodeId)){ //Only delete DA permissions for(String daPerm : DelegatedAccessConstants.NODE_PERMS){; //DA permissions are usually prefix's if(perm.startsWith(daPerm)){ hierarchyService.removeUserNodePerm(userId, nodeId, perm, false); break; } } } } /** * returns a list of nodes the user has site.access permission (aka access). Only direct nodes, nothing inherited. * @return */ public Set<HierarchyNodeSerialized> getAllNodesForUser(String userId) { Set<HierarchyNodeSerialized> accessNodes = getAccessNodesForUser(userId); Set<HierarchyNodeSerialized> adminNodes = getShoppingPeriodAdminNodesForUser(userId); Set<HierarchyNodeSerialized> accessAdminNodes = getAccessAdminNodesForUser(userId); accessNodes.addAll(adminNodes); accessNodes.addAll(accessAdminNodes); return accessNodes; } public Set<HierarchyNodeSerialized> getAccessNodesForUser(String userId) { accessNodes = new ArrayList<String>(); Set<HierarchyNodeSerialized> directAccessNodes = convertToSerializedNodeSet(hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_SITE_VISIT)); //set the access and admin noes list for other functions to determine if a node is an access or admin node for(HierarchyNodeSerialized node : directAccessNodes){ accessNodes.add(node.id); } return directAccessNodes; } public Set<HierarchyNodeSerialized> getShoppingPeriodAdminNodesForUser(String userId) { shoppingPeriodAdminNodes = new ArrayList<String>(); Set<HierarchyNodeSerialized> adminNodes = convertToSerializedNodeSet(hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN)); for(HierarchyNodeSerialized node : adminNodes){ shoppingPeriodAdminNodes.add(node.id); } return adminNodes; } public Set<HierarchyNodeSerialized> getAccessAdminNodesForUser(String userId) { accessAdminNodes = new ArrayList<String>(); Set<HierarchyNodeSerialized> adminNodes = convertToSerializedNodeSet(hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_ACCESS_ADMIN)); for(HierarchyNodeSerialized node : adminNodes){ accessAdminNodes.add(node.id); } return adminNodes; } /** * returns a serialized version for Hierarchy nodes. * * @param nodeSet * @return */ private Set<HierarchyNodeSerialized> convertToSerializedNodeSet(Set<HierarchyNode> nodeSet){ Set<HierarchyNodeSerialized> nodesForUserSerialized = new HashSet<HierarchyNodeSerialized>(); if(nodeSet != null){ for(HierarchyNode node : nodeSet){ nodesForUserSerialized.add(new HierarchyNodeSerialized(node)); } } return nodesForUserSerialized; } /** * {@inheritDoc} */ public void initializeDelegatedAccessSession(){ String userId = sakaiProxy.getCurrentUserId(); if(userId != null && !"".equals(userId)){ Session session = sakaiProxy.getCurrentSession(); Set accessNodes = getAccessNodesForUser(userId); if(accessNodes != null && accessNodes.size() > 0){ session.setAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DELEGATED_ACCESS_FLAG, true); //need to clear sakai realm permissions cache for user since Denied Tools list is tied to //session and permissions are a saved in a system cache Element el = restrictedAuthToolsCache.get(userId); if(el != null){ session.setAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DENIED_TOOLS, el.getObjectValue()); } Element elPub = restrictedPublicToolsCache.get(userId); if(elPub != null){ session.setAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DENIED_TOOLS2, elPub.getObjectValue()); } } } } private List<NodeModel> getSiteNodes(DefaultMutableTreeNode treeNode){ List<NodeModel> returnList = new ArrayList<NodeModel>(); if(treeNode != null){ if(((NodeModel) treeNode.getUserObject()).getNode().title.startsWith("/site/")){ returnList.add((NodeModel) treeNode.getUserObject()); } //check the rest of the children: for(int i = 0; i < treeNode.getChildCount(); i++){ returnList.addAll(getSiteNodes((DefaultMutableTreeNode)treeNode.getChildAt(i))); } } return returnList; } private HierarchyNodeSerialized getRootNode(){ return new HierarchyNodeSerialized(hierarchyService.getRootNode(DelegatedAccessConstants.HIERARCHY_ID)); } /** * {@inheritDoc} */ public List<SearchResult> searchUsers(String search) { List<User> searchResult = sakaiProxy.searchUsers(search); List<SearchResult> returnList = new ArrayList<SearchResult>(); for(User user : searchResult){ returnList.add(getSearchResult(user)); } return returnList; } /** * {@inheritDoc} */ private SearchResult getSearchResult(User user){ if(user != null){ return new SearchResult(user); }else{ return null; } } /** * {@inheritDoc} */ private void saveRealmAndRoleAccess(String userId, String realmId, String role, String nodeId){ if(realmId != null && role != null && !"".equals(realmId) && !"".equals(role) && !"null".equals(realmId) && !"null".equals(role)){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_REALM_PREFIX +realmId, false); hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_ROLE_PREFIX +role, false); } } private Set<String> getPermsForUserNodes(String userId, String nodeId){ return hierarchyService.getPermsForUserNodes(userId, new String[]{nodeId}); } /** * returns the user's realm and role information for the given node. Doesn't include inherited information, will return * a "" if not found. * @param userId * @param nodeId * @return */ private String[] getAccessRealmRole(Set<String> perms){ String realmId = ""; String roleId = ""; for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_REALM_PREFIX)){ realmId = perm.substring(DelegatedAccessConstants.NODE_PERM_REALM_PREFIX.length()); }else if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_ROLE_PREFIX)){ roleId = perm.substring(DelegatedAccessConstants.NODE_PERM_ROLE_PREFIX.length()); } } return new String[]{realmId, roleId}; } /** * Returns a list of ToolSerialized that initialized the selected field * @param userId * @param nodeId * @return */ public List<ListOptionSerialized> getRestrictedAuthToolSerializedList(Set<String> perms){ return getRestrictedAuthToolSerializedList(perms, getEntireToolsList()); } public List<ListOptionSerialized> getRestrictedPublicToolSerializedList(Set<String> perms){ return getRestrictedPublicToolSerializedList(perms, getEntireToolsList()); } public List<ListOptionSerialized> getRestrictedAuthToolSerializedList(Set<String> perms, List<ListOptionSerialized> blankList){ List<String> restrictedTools = getRestrictedAuthToolsForUser(perms); for(ListOptionSerialized tool : blankList){ if(restrictedTools.contains(tool.getId())) tool.setSelected(true); } return blankList; } public List<ListOptionSerialized> getRestrictedPublicToolSerializedList(Set<String> perms, List<ListOptionSerialized> blankList){ List<String> restrictedTools = getRestrictedPublicToolsForUser(perms); for(ListOptionSerialized tool : blankList){ if(restrictedTools.contains(tool.getId())) tool.setSelected(true); } return blankList; } public List<ListOptionSerialized> getEntireToolsList(){ List<ListOptionSerialized> returnList = new ArrayList<ListOptionSerialized>(); for(Tool tool : sakaiProxy.getAllTools()){ returnList.add(new ListOptionSerialized(tool.getId(), tool.getTitle(), false)); } //the home tool is special, so add this case String[] homeTools = sakaiProxy.getHomeTools(); if(homeTools != null && homeTools.length > 0){ returnList.add(new ListOptionSerialized("Home", "Home", false)); } Collections.sort(returnList, new Comparator<ListOptionSerialized>() { public int compare(ListOptionSerialized arg0, ListOptionSerialized arg1) { return arg0.getName().compareTo(arg1.getName()); } }); return returnList; } private List<String> getRestrictedAuthToolsForUser(Set<String> userPerms){ List<String> returnList = new ArrayList<String>(); for(String userPerm : userPerms){ if(userPerm.startsWith(DelegatedAccessConstants.NODE_PERM_DENY_TOOL_PREFIX)){ returnList.add(userPerm.substring(DelegatedAccessConstants.NODE_PERM_DENY_TOOL_PREFIX.length())); } } return returnList; } private List<String> getRestrictedPublicToolsForUser(Set<String> userPerms){ List<String> returnList = new ArrayList<String>(); for(String userPerm : userPerms){ if(userPerm.startsWith(DelegatedAccessConstants.NODE_PERM_DENY_TOOL2_PREFIX)){ returnList.add(userPerm.substring(DelegatedAccessConstants.NODE_PERM_DENY_TOOL2_PREFIX.length())); } } return returnList; } private void saveRestrictedAuthToolsForUser(String userId, String nodeId, List<String> toolIds){ //add new tools: for(String newTool : toolIds){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_DENY_TOOL_PREFIX + newTool, false); } } private void saveRestrictedPublicToolsForUser(String userId, String nodeId, List<String> toolIds){ //add new tools: for(String newTool : toolIds){ hierarchyService.assignUserNodePerm(userId, nodeId, DelegatedAccessConstants.NODE_PERM_DENY_TOOL2_PREFIX + newTool, false); } } public List<SiteSearchResult> searchUserSites(String search, Map<String, String> advancedOptions, boolean shoppingPeriod, boolean activeShoppingData){ List<SiteSearchResult> returnList = new ArrayList<SiteSearchResult>(); List<String> resultSiteIds = new ArrayList<String>(); if(search == null){ search = ""; } Collection<SiteSearchResult> siteSubset = null; Map<String, String> userSortNameCache = new HashMap<String, String>(); if(!"".equals(search) || (advancedOptions != null && advancedOptions.size() > 0)){ siteSubset = searchSites(search, advancedOptions, shoppingPeriod); List<String> siteRefs = new ArrayList<String>(); for(SiteSearchResult siteResult : siteSubset){ siteRefs.add(siteResult.getSiteReference()); } Map<String,AccessNode> accessList = grantAccessToSites(siteRefs, shoppingPeriod, activeShoppingData); for(SiteSearchResult siteResult : siteSubset){ AccessNode access = accessList.get(siteResult.getSiteReference()); if(access != null){ siteResult.setAccess(access.getAccess()); siteResult.setShoppingPeriodStartDate(access.getStartDate()); siteResult.setShoppingPeriodEndDate(access.getEndDate()); siteResult.setRestrictedAuthTools(access.getDeniedAuthTools()); siteResult.setRestrictedPublicTools(access.getDeniedPublicTools()); siteResult.setModified(access.getModified()); siteResult.setModifiedBy(access.getModifiedBy()); if(!userSortNameCache.containsKey(access.getModifiedBy())){ User user = sakaiProxy.getUser(access.getModifiedBy()); String sortName = ""; if(user != null){ sortName = user.getSortName(); } userSortNameCache.put(access.getModifiedBy(), sortName); } siteResult.setModifiedBySortName(userSortNameCache.get(access.getModifiedBy())); returnList.add(siteResult); resultSiteIds.add(siteResult.getSiteId()); } } } //only look up the terms for display if the search didn't already look it up //this is done after the subsite search and the access filtering to limit the number //of sites we need to look up if (!(advancedOptions != null && advancedOptions.containsKey(DelegatedAccessConstants.ADVANCED_SEARCH_TERM) && advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_TERM) != null && !"".equals(advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_TERM).trim()))) { String termField = sakaiProxy.getTermField(); Map<String, Map<String, String>> termProps = dao.searchSitesForProp(new String[]{termField}, resultSiteIds.toArray(new String[resultSiteIds.size()])); for(SiteSearchResult result : returnList){ if(termProps.containsKey(result.getSiteId())){ result.getSite().setTerm(termProps.get(result.getSiteId()).get(termField)); } } } return returnList; } public Collection<SiteSearchResult> searchSites(String search, Map<String, String> advancedOptions, boolean publishedSitesOnly){ if("".equals(search)){ search = null; } Map<String, SiteSearchResult> sites = new HashMap<String, SiteSearchResult>(); Site searchByIdSite = sakaiProxy.getSiteById(search); String termField = sakaiProxy.getTermField(); String termValue = ""; //Since we know the hierarchy is site properties, we can use them to speed up our search Map<String,String> propsMap = new HashMap<String, String>(); //add term field restriction if it exist: if (advancedOptions != null && advancedOptions.containsKey(DelegatedAccessConstants.ADVANCED_SEARCH_TERM) && advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_TERM) != null && !"".equals(advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_TERM).trim())) { //add term field to propMap for search termValue = advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_TERM); propsMap.put(termField, termValue); //check if we need to remove the searchByIdSite b/c of the term if(searchByIdSite != null && searchByIdSite.getProperties() != null && searchByIdSite.getProperties().getProperty(termField) != null && searchByIdSite.getProperties().getProperty(termField).toLowerCase().contains(advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_TERM))){ //do nothing, we found it }else{ //doesn't exist in this term, remove it searchByIdSite = null; } } //add instructor restriction Map<String, User> instructorMap = new HashMap<String, User>(); if (advancedOptions != null && advancedOptions.containsKey(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR) && advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR) != null && !"".equals(advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR).trim())) { List<User> searchUsers = sakaiProxy.searchUsers(advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR)); //since we added a site by searching for ID, we need to make sure that at least 1 user is a member, //otherwise, remove it from the results: boolean foundSearchByIdMember = searchByIdSite == null ? true : false; for (User user : searchUsers) { if(!foundSearchByIdMember && searchByIdSite.getMember(user.getId()) != null){ foundSearchByIdMember = true; } instructorMap.put(user.getId(), user); } if(!foundSearchByIdMember && searchByIdSite != null){ //we didn't find any members for this site in the user search, so remove it: searchByIdSite = null; } } // search title, props, or instructors //pass in whether it's an instructor or member search (if exists) String instructorType = ""; if(advancedOptions != null && advancedOptions.containsKey(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE)){ instructorType = advancedOptions.get(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE); } List<String[]> siteResults = dao.searchSites(search, propsMap, instructorMap.keySet().toArray(new String[instructorMap.keySet().size()]), instructorType, publishedSitesOnly); if(siteResults != null && siteResults.size() > 0){ //create an array of the siteIds returned: String[] siteIds = new String[siteResults.size()]; int i = 0; for(String[] site : siteResults){ siteIds[i] = site[0]; i++; } Map<String, Map<String, String>> termProps = dao.searchSitesForProp(new String[]{termField}, siteIds); for(String[] site : siteResults){ List<User> instructors = new ArrayList<User>(); if(site.length == 3){ //this means the results came back with instructor data: instructors.add(instructorMap.get(site[2])); } sites.put(site[0], new SiteSearchResult(new SiteSerialized(site[0], site[1], termValue), instructors, termField)); } } if(searchByIdSite != null && !sites.containsKey(searchByIdSite.getId()) && (!publishedSitesOnly || searchByIdSite.isPublished())){ sites.put(searchByIdSite.getId(), new SiteSearchResult(searchByIdSite, new ArrayList<User>(), termField)); } return sites.values(); } private List<Site> getUserUpdatePermissionMembership(String userId, String search, Map<String, String> propsMap){ String currentUserId = sakaiProxy.getCurrentUserId(); //set session user id to this id: Session sakaiSession = sakaiProxy.getCurrentSession(); sakaiSession.setUserId(userId); sakaiSession.setUserEid(userId); List<Site> siteList = sakaiProxy.getSites(SelectionType.UPDATE, search, propsMap); //return to current user id sakaiSession.setUserId(currentUserId); sakaiSession.setUserEid(currentUserId); return siteList; } private String[] convertToArray(List<String> list){ String[] returnArray = new String[]{}; if(!list.isEmpty()){ returnArray = new String[list.size()]; for(int i = 0; i < list.size(); i++){ returnArray[i] = list.get(i); } } return returnArray; } //TREE MODEL FUNCTIONS: private List<String> accessNodes = new ArrayList<String>(); private List<String> shoppingPeriodAdminNodes = new ArrayList<String>(); private List<String> accessAdminNodes = new ArrayList<String>(); /** * Creates the model that feeds the tree. * * @return New instance of tree model. */ public TreeModel createEntireTreeModelForUser(String userId, boolean addDirectChildren, boolean cascade) { //this is a list of sub-admin access nodes. if the user is a super-admin, then this will be null (as a flag that this is a super admin) List<String> accessAdminNodeIds = null; Set<HierarchyNodeSerialized> accessAdminNodeSet = null; List<String> subAdminsSiteAccessNodes = null; Set<HierarchyNodeSerialized> subAdminSiteAccessNodesSet = null; //check if the user is a super admin, if not, then get the accessAdmin nodes connected to the current user if(!sakaiProxy.isSuperUser()){ //only allow the current user to modify permissions for this user on the nodes that //has been assigned accessAdmin for currentUser accessAdminNodeSet = getAccessAdminNodesForUser(sakaiProxy.getCurrentUserId()); accessAdminNodeIds = new ArrayList<String>(); if(accessAdminNodeSet != null){ for(HierarchyNodeSerialized node : accessAdminNodeSet){ accessAdminNodeIds.add(node.id); } } String[] subAdminOrderedRealmRoles = sakaiProxy.getSubAdminOrderedRealmRoles(); if(subAdminOrderedRealmRoles != null && subAdminOrderedRealmRoles.length > 0){ //we need to restrict sub admin's to only realms&roles they have permissions to set //we do this by finding all the subadmin's access nodes and permissions subAdminSiteAccessNodesSet = getAccessNodesForUser(sakaiProxy.getCurrentUserId()); subAdminsSiteAccessNodes = new ArrayList<String>(); if(subAdminSiteAccessNodesSet != null){ for(HierarchyNodeSerialized node : subAdminSiteAccessNodesSet){ subAdminsSiteAccessNodes.add(node.id); } } } } //these are the nodes that the edit user has permissions in Set<HierarchyNodeSerialized> userNodes = getAllNodesForUser(userId); if(accessAdminNodeSet != null){ //make sure we insert the nodes for access admin so the sub-admin //can modify these nodes if they want to userNodes.addAll(accessAdminNodeSet); } if(subAdminSiteAccessNodesSet != null){ //make sure we process these nodes as well userNodes.addAll(subAdminSiteAccessNodesSet); } //Returns a List that represents the tree/node architecture: // List{ List{node, List<children>}, List{node, List<children>}, ...}. List<List> l1 = getTreeListForUser(userId, addDirectChildren, cascade, userNodes); //order tree model: orderTreeModel(l1); return convertToTreeModel(l1, userId, getEntireToolsList(), addDirectChildren, accessAdminNodeIds, subAdminsSiteAccessNodes, false); } public TreeModel createAccessTreeModelForUser(String userId, boolean addDirectChildren, boolean cascade) { boolean shoppingPeriodTool = DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId); //Returns a List that represents the tree/node architecture: // List{ List{node, List<children>}, List{node, List<children>}, ...}. accessNodes = new ArrayList<String>(); shoppingPeriodAdminNodes = new ArrayList<String>(); accessAdminNodes = new ArrayList<String>(); List<List> l1 = getTreeListForUser(userId, addDirectChildren, cascade, getAccessNodesForUser(userId)); //Remove the shopping period nodes: if(l1 != null){ HierarchyNode hierarchyRoot = hierarchyService.getRootNode(DelegatedAccessConstants.HIERARCHY_ID); String hierarchyRootId = "-1"; if(hierarchyRoot != null){ hierarchyRootId = hierarchyRoot.id; } for (Iterator iterator = l1.iterator(); iterator.hasNext();) { List list = (List) iterator.next(); if(!hierarchyRootId.equals(((HierarchyNodeSerialized) list.get(0)).id)){ iterator.remove(); } } } //order tree model: orderTreeModel(l1); return convertToTreeModel(l1, userId, getEntireToolsList(), addDirectChildren, null, null, shoppingPeriodTool); } //get the entire tree for a user and populates the information that may exist public TreeModel getEntireTreePlusUserPerms(String userId){ //call this to instantiated the accessNodes and shoppingPeriodAdminNodes lists getAllNodesForUser(userId); //just get the root of the tree and then ask for all cascading nodes Set<HierarchyNodeSerialized> rootSet = new HashSet<HierarchyNodeSerialized>(); rootSet.add(getRootNode()); List<List> l1 = getTreeListForUser(userId, false, true, rootSet); //order tree model: orderTreeModel(l1); return convertToTreeModel(l1, userId, getEntireToolsList(), false, null, null, false); } public TreeModel createTreeModelForShoppingPeriod(String userId) { //Returns a List that represents the tree/node architecture: // List{ List{node, List<children>}, List{node, List<children>}, ...}. List<List> l1 = getTreeListForUser(DelegatedAccessConstants.SHOPPING_PERIOD_USER, false, false, getShoppingPeriodAdminNodesForUser(userId)); //order tree model: orderTreeModel(l1); TreeModel treeModel = convertToTreeModel(l1, DelegatedAccessConstants.SHOPPING_PERIOD_USER, getEntireToolsList(), false, null, null, false); if(sakaiProxy.isActiveSiteFlagEnabled()){ if(treeModel != null && treeModel.getRoot() != null){ setActiveFlagForSiteNodes((DefaultMutableTreeNode) treeModel.getRoot()); } } return treeModel; } private void setActiveFlagForSiteNodes(DefaultMutableTreeNode node){ Set<String> siteNodes = new HashSet<String>(); populateSiteNodes(node, siteNodes); List<String> activeSites = dao.findActiveSites(siteNodes.toArray(new String[siteNodes.size()])); setActiveSiteFlag(node, activeSites, siteNodes); } private void populateSiteNodes(DefaultMutableTreeNode node, Set<String> siteNodes){ if(node != null){ if(((NodeModel) node.getUserObject()).isSiteNode()){ siteNodes.add(((NodeModel) node.getUserObject()).getNode().title.substring(6)); } for(int i = 0; i < node.getChildCount(); i++){ populateSiteNodes((DefaultMutableTreeNode) node.getChildAt(i), siteNodes); } } } private void setActiveSiteFlag(DefaultMutableTreeNode node, List<String> activeSites, Set<String> checkSites){ if(node != null){ if(((NodeModel) node.getUserObject()).isSiteNode() && checkSites.contains(((NodeModel) node.getUserObject()).getNode().title.substring(6)) && !activeSites.contains(((NodeModel) node.getUserObject()).getNode().title.substring(6))){ ((NodeModel) node.getUserObject()).setActive(false); } for(int i = 0; i < node.getChildCount(); i++){ setActiveSiteFlag((DefaultMutableTreeNode) node.getChildAt(i), activeSites, checkSites); } } } /** * Takes a list representation of a tree and creates the TreeModel * * @param map * @param userId * @return */ private TreeModel convertToTreeModel(List<List> map, String userId, List<ListOptionSerialized> blankRestrictedTools, boolean addDirectChildren, List<String> accessAdminNodeIds, List<String> subAdminsSiteAccessNodes, boolean shoppingPeriodTool) { TreeModel model = null; if(!map.isEmpty() && map.size() == 1){ DefaultMutableTreeNode rootNode = add(null, map, userId, blankRestrictedTools, addDirectChildren, accessAdminNodeIds, subAdminsSiteAccessNodes, shoppingPeriodTool); model = new DefaultTreeModel(rootNode); } return model; } private Date getShoppingStartDate(Set<String> perms){ Date returnDate = null; for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SHOPPING_START_DATE)){ try{ returnDate = new Date(Long.parseLong(perm.substring(DelegatedAccessConstants.NODE_PERM_SHOPPING_START_DATE.length()))); }catch (Exception e) { //wrong format, ignore } } } return returnDate; } private Date getShoppingEndDate(Set<String> perms){ Date returnDate = null; for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SHOPPING_END_DATE)){ try{ returnDate = new Date(Long.parseLong(perm.substring(DelegatedAccessConstants.NODE_PERM_SHOPPING_END_DATE.length()))); }catch (Exception e) { //wrong format, ignore } } } return returnDate; } private Date getPermDate(Set<String> perms, String permName){ Date returnDate = null; for(String perm : perms){ if(perm.startsWith(permName)){ try{ returnDate = new Date(Long.parseLong(perm.substring(permName.length()))); }catch (Exception e) { //wrong format, ignore } } } return returnDate; } private String getShoppingAdminModifiedBy(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED_BY)){ return perm.substring(DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED_BY.length()); } } return null; } private String getModifiedBy(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_MODIFIED_BY)){ return perm.substring(DelegatedAccessConstants.NODE_PERM_MODIFIED_BY.length()); } } return null; } private boolean isShoppingPeriodAdmin(Set<String> perms){ for(String perm : perms){ if(perm.equals(DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN)){ return true; } } return false; } private boolean isShoppingPeriodRevokeInstructorEditable(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SHOPPING_REVOKE_INSTRUCTOR_EDITABLE)){ return true; } } return false; } private boolean isShoppingPeriodRevokeInstructorPublicOpt(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_SHOPPING_REVOKE_INSTRUCTOR_PUBLIC_OPT)){ return true; } } return false; } private boolean isAllowBecomeUser(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_ALLOW_BECOME_USER)){ return true; } } return false; } private boolean isInstructorEdited(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_INSTRUCTOR_EDITED)){ return true; } } return false; } private boolean getIsDirectAccess(Set<String> perms){ for(String perm : perms){ if(perm.equals(DelegatedAccessConstants.NODE_PERM_SITE_VISIT)){ return true; } } return false; } private boolean getIsAccessAdmin(Set<String> perms){ for(String perm : perms){ if(perm.equals(DelegatedAccessConstants.NODE_PERM_ACCESS_ADMIN)){ return true; } } return false; } private List<ListOptionSerialized> copyListOptions(List<ListOptionSerialized> options){ List<ListOptionSerialized> returnList = new ArrayList<ListOptionSerialized>(); for(ListOptionSerialized option : options){ returnList.add(new ListOptionSerialized(option.getId(), option.getName(), option.isSelected())); } return returnList; } /** * Adds node to parent and creates the NodeModel to store in the tree * @param parent * @param sub * @param userId * @return */ private DefaultMutableTreeNode add(DefaultMutableTreeNode parent, List<List> sub, String userId, List<ListOptionSerialized> blankRestrictedTools, boolean addDirectChildren, List<String> accessAdminNodeIds, List<String> subAdminsSiteAccessNodes, boolean shoppingPeriodTool) { DefaultMutableTreeNode root = null; for (List nodeList : sub) { HierarchyNodeSerialized node = (HierarchyNodeSerialized) nodeList.get(0); List children = (List) nodeList.get(1); String realm = ""; String role = ""; boolean directAccess = false; Date startDate = null; Date endDate = null; Date shoppingAdminModified = null; String shoppingAdminModifiedBy = null; Date modified = null; String modifiedBy = null; boolean shoppingPeriodRevokeInstructorEditable = false; boolean shoppingPeriodRevokeInstructorPublicOpt = false; boolean allowBecomeUser = false; boolean instructorEdited = false; //you must copy in order not to pass changes to other nodes List<ListOptionSerialized> restrictedAuthTools = copyListOptions(blankRestrictedTools); List<ListOptionSerialized> restrictedPublicTools = copyListOptions(blankRestrictedTools); boolean accessAdmin = accessAdminNodes.contains(node.id); boolean shoppingPeriodAdmin = shoppingPeriodAdminNodes.contains(node.id); Set<String> perms = null; if((!shoppingPeriodTool && DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)) || accessNodes.contains(node.id) || shoppingPeriodAdminNodes.contains(node.id)){ perms = getPermsForUserNodes(userId, node.id); String[] realmRole = getAccessRealmRole(perms); realm = realmRole[0]; role = realmRole[1]; startDate = getShoppingStartDate(perms); endDate = getShoppingEndDate(perms); restrictedAuthTools = getRestrictedAuthToolSerializedList(perms, restrictedAuthTools); restrictedPublicTools = getRestrictedPublicToolSerializedList(perms, restrictedPublicTools); directAccess = getIsDirectAccess(perms); shoppingAdminModified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED); shoppingAdminModifiedBy = getShoppingAdminModifiedBy(perms); modified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_MODIFIED); modifiedBy = getModifiedBy(perms); shoppingPeriodRevokeInstructorEditable = isShoppingPeriodRevokeInstructorEditable(perms); shoppingPeriodRevokeInstructorPublicOpt = isShoppingPeriodRevokeInstructorPublicOpt(perms); allowBecomeUser = isAllowBecomeUser(perms); instructorEdited = isInstructorEdited(perms); } NodeModel parentNodeModel = null; if(parent != null){ parentNodeModel = ((NodeModel) parent.getUserObject()); } DefaultMutableTreeNode child = new DelegatedAccessMutableTreeNode(); NodeModel childNodeModel = new NodeModel(node.id, node, directAccess, realm, role, parentNodeModel, restrictedAuthTools, restrictedPublicTools, startDate, endDate, addDirectChildren && !children.isEmpty(), shoppingPeriodAdmin, modifiedBy, modified, shoppingAdminModified, shoppingAdminModifiedBy, accessAdmin, shoppingPeriodRevokeInstructorEditable, shoppingPeriodRevokeInstructorPublicOpt, allowBecomeUser, instructorEdited); //this could be an accessAdmin modifying another user, let's check: if(accessAdminNodeIds != null){ //if accessAdminNodeIds isn't null, this means we need to restrict this tree to these nodes by //setting the editable flag childNodeModel.setEditable(false); boolean found = false; for(String nodeId : accessAdminNodeIds){ if(nodeId.equals(node.id)){ found = true; break; } } if(found){ childNodeModel.setEditable(true); } } if(subAdminsSiteAccessNodes != null && subAdminsSiteAccessNodes.size() > 0){ //we need to make sure we keep track of the subadmin's permissions if subAdminsSiteAccessNodes is set for(String nodeId : subAdminsSiteAccessNodes){ if(childNodeModel.getNodeId().equals(nodeId)){ Set<String> permsSubAdmin = getPermsForUserNodes(sakaiProxy.getCurrentUserId(), nodeId); String[] realmRole = getAccessRealmRole(permsSubAdmin); childNodeModel.setSubAdminSiteAccess(realmRole); } } } child.setUserObject(childNodeModel); if(parent == null){ //we have the root, set it root = child; }else{ if(!(DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId) && shoppingPeriodTool && childNodeModel.getNode().title != null && childNodeModel.isSiteNode() && perms != null && !isShoppingAvailable(perms))){ //add all nodes except shopping period site nodes if the activeOnly flag is true parent.add(child); } } if(!children.isEmpty()){ add(child, children, userId, blankRestrictedTools, addDirectChildren, accessAdminNodeIds, subAdminsSiteAccessNodes, shoppingPeriodTool); } } return root; } /** * takes a list representation of the tree and orders it Alphabetically * @param hierarchy */ private void orderTreeModel(List<List> hierarchy){ if(hierarchy != null){ for(List nodeList : hierarchy){ orderTreeModel((List)nodeList.get(1)); } Collections.sort(hierarchy, new NodeListComparator()); } } /** * This is a simple comparator to order the tree nodes alphabetically * */ private class NodeListComparator implements Comparator<List>{ public int compare(List o1, List o2) { if(((HierarchyNodeSerialized) o1.get(0)).title == null && ((HierarchyNodeSerialized) o2.get(0)).title == null){ //nothing to compare return 0; }else if(((HierarchyNodeSerialized) o1.get(0)).title != null && ((HierarchyNodeSerialized) o2.get(0)).title == null){ return 1; }else if(((HierarchyNodeSerialized) o1.get(0)).title == null && ((HierarchyNodeSerialized) o2.get(0)).title != null){ return -1; }else{ return ((HierarchyNodeSerialized) o1.get(0)).title.compareToIgnoreCase(((HierarchyNodeSerialized) o2.get(0)).title); } } } /** * returns the order of the parent id's from highest to lowest in the hierarchy * @return */ private List<String> getOrderedParentsList(HierarchyNodeSerialized node){ String directParentId = null; if(node.directParentNodeIds != null && node.directParentNodeIds.size() > 0){ directParentId = node.directParentNodeIds.toArray(new String[node.directParentNodeIds.size()])[0]; return getOrderedParentsListHelper(getCachedNode(directParentId)); }else{ List<String> orderedParents = new ArrayList<String>(); return orderedParents; } } private List<String> getOrderedParentsListHelper(HierarchyNodeSerialized node){ if(node.directParentNodeIds == null || node.directParentNodeIds.size() == 0){ List<String> returnList = new ArrayList<String>(); returnList.add(node.id); return returnList; }else{ List<String> parents = getOrderedParentsListHelper(getCachedNode(node.directParentNodeIds.toArray(new String[node.directParentNodeIds.size()])[0])); parents.add(node.id); return parents; } } private List<List> getTreeListForUser(String userId, boolean addDirectChildren, boolean cascade, Set<HierarchyNodeSerialized> nodes){ List<List> l1 = new ArrayList<List>(); List<List> currentLevel = l1; for(HierarchyNodeSerialized node : nodes){ for(String parentId : getOrderedParentsList(node)){ HierarchyNodeSerialized parentNode = getCachedNode(parentId); if(!hasNode(parentNode, currentLevel)){ List newNode = new ArrayList(); newNode.add(parentNode); newNode.add(new ArrayList()); currentLevel.add(newNode); } currentLevel = getChildrenForNode(parentNode.id, currentLevel); if(addDirectChildren){ for(List nodeList : getDirectChildren(parentNode)){ if(!hasNode((HierarchyNodeSerialized) nodeList.get(0), currentLevel)){ currentLevel.add(nodeList); } } } } if(!hasNode(node, currentLevel)){ List child = new ArrayList(); child.add(node); child.add(new ArrayList()); currentLevel.add(child); } if(cascade){ //we need to grab all children (children of children, ect) for this node since this an access node getCascadingChildren(node, getChildrenForNode(node.id, currentLevel)); } currentLevel = l1; } if(l1.isEmpty() && addDirectChildren){ //since we want direct children, include the root's direct children (when the node model is empty) HierarchyNodeSerialized root = getRootNode(); if(root != null && root.id != null && !"".equals(root.id)){ List child = new ArrayList(); child.add(root); child.add(getDirectChildren(root)); l1.add(child); } } return l1; } /** * Checks nodeCache for node with given id. If not found, * looks up the node in the db and saves it in the cache * * @param id * @return */ private HierarchyNodeSerialized getCachedNode(String id){ Element el = nodeCache.get(id); HierarchyNodeSerialized node = null; if(el == null){ node = getNode(id); try{ nodeCache.put(new Element(id, node)); }catch (Exception e) { log.error("getCachedNode: " + id, e); } }else if(el.getObjectValue() instanceof HierarchyNodeSerialized){ node = (HierarchyNodeSerialized) el.getObjectValue(); } return node; } /** * returns the children for this node * * @param id * @param level * @return */ private List<List> getChildrenForNode(String id, List<List> level){ for(List nodeList : level){ HierarchyNodeSerialized n = (HierarchyNodeSerialized) nodeList.get(0); if(n.id.equals(id)){ return (List<List>) nodeList.get(1); } } return null; } /** * returns direct children for the parent. Children will have empty lists. * * @param parent * @return */ private List<List> getDirectChildren(HierarchyNodeSerialized parent){ List<List>returnList = new ArrayList<List>(); if(parent != null){ Set<String> parentChildren = parent.directChildNodeIds; for(String childId : parentChildren){ List child = new ArrayList(); child.add(getCachedNode(childId)); child.add(new ArrayList()); returnList.add(child); } } return returnList; } /** * Finds all children of chilren and returns the hierarchy * * @param parent * @param children * @return */ private List<List> getCascadingChildren(HierarchyNodeSerialized parent, List<List> children){ Set<String> parentChildren = parent.directChildNodeIds; for(String childId : parentChildren){ HierarchyNodeSerialized childNode = getCachedNode(childId); List childMap = getChildrenForNode(childNode.id, children); if(childMap == null){ childMap = new ArrayList(); } childMap = getCascadingChildren(childNode, childMap); if(!hasNode(childNode, children)){ List childList = new ArrayList(); childList.add(childNode); childList.add(childMap); children.add(childList); } } return children; } /** * checks if the node exist in the list * * @param node * @param level * @return */ private boolean hasNode(HierarchyNodeSerialized node, List<List> level){ for(List nodeList : level){ HierarchyNodeSerialized n = (HierarchyNodeSerialized) nodeList.get(0); if(n.id.equals(node.id)){ return true; } } return false; } /** * Adds children node to a node that hasn't had it's children populated. This is used to increase the efficiency * of the tree so you can create the structure on the fly with ajax * * @param node * @param userId * @param blankRestrictedTools * @param onlyAccessNodes * @param accessAdminNodes * @param shopping * @return */ public boolean addChildrenNodes(Object node, String userId, List<ListOptionSerialized> blankRestrictedTools, boolean onlyAccessNodes, List<String> accessAdminNodes, boolean shopping, boolean shoppingPeriodTool){ boolean anyAdded = false; Set<String> addedSites = new HashSet<String>(); DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) node; NodeModel nodeModel = (NodeModel) ((DefaultMutableTreeNode) node).getUserObject(); if(nodeModel.getNode() != null){ List<List> childrenNodes = getDirectChildren(nodeModel.getNode()); Collections.sort(childrenNodes, new NodeListComparator()); for(List childList : childrenNodes){ //check if the user can edit this node: if(accessAdminNodes != null && !((NodeModel) parentNode.getUserObject()).isNodeEditable()){ //if accessAdmin nodes isn't null this means that the user is restricted to edit just those nodes and their children if(!accessAdminNodes.contains(((HierarchyNodeSerialized) childList.get(0)).id)){ //since the parent node isn't editable and this node doesn't show up in the editable nodes list //we will not add this node continue; } } boolean newlyAdded = addChildNodeToTree((HierarchyNodeSerialized) childList.get(0), parentNode, userId, blankRestrictedTools, onlyAccessNodes, shoppingPeriodTool); anyAdded = anyAdded || newlyAdded; if(newlyAdded && ((HierarchyNodeSerialized) childList.get(0)).title.startsWith("/site/")){ addedSites.add(((HierarchyNodeSerialized) childList.get(0)).title.substring(6)); } } } if(shopping && addedSites.size() > 0 && sakaiProxy.isActiveSiteFlagEnabled() ){ List<String> activeSites = dao.findActiveSites(addedSites.toArray(new String[addedSites.size()])); setActiveSiteFlag(parentNode, activeSites, addedSites); } return anyAdded; } /** * This is a helper function for addChildrenNodes. It will add the child nodes to the parent node and create the NodeModel. * * @param childNode * @param parentNode * @param realmMap * @param userId * @return */ private boolean addChildNodeToTree(HierarchyNodeSerialized childNode, DefaultMutableTreeNode parentNode, String userId, List<ListOptionSerialized> blankRestrictedTools, boolean onlyAccessNodes, boolean shoppingPeriodTool){ boolean added = false; if(!doesChildExist(childNode.id, parentNode)){ //just create a blank child since the user should already have all the nodes with information in the db String realm = ""; String role = ""; boolean selected = false; Date startDate = null; Date endDate = null; //you must copy to not pass changes to other nodes List<ListOptionSerialized> restrictedAuthTools = copyListOptions(blankRestrictedTools); List<ListOptionSerialized> restrictedPublicTools = copyListOptions(blankRestrictedTools); boolean shoppingPeriodAdmin = false; boolean directAccess = false; Date shoppingAdminModified = null; String shoppingAdminModifiedBy = null; Date modified = null; String modifiedBy = null; boolean accessAdmin = false; boolean shoppingPeriodRevokeInstructorEditable = false; boolean shoppingPeriodRevokeInstructorPublicOpt = false; boolean allowBecomeUser = false; boolean instructorEdited = false; DefaultMutableTreeNode child = new DelegatedAccessMutableTreeNode(); if(!shoppingPeriodTool && DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)){ Set<String> perms = getPermsForUserNodes(userId, childNode.id); String[] realmRole = getAccessRealmRole(perms); realm = realmRole[0]; role = realmRole[1]; startDate = getShoppingStartDate(perms); endDate = getShoppingEndDate(perms); restrictedAuthTools = getRestrictedAuthToolSerializedList(perms, restrictedAuthTools); restrictedPublicTools = getRestrictedPublicToolSerializedList(perms, restrictedPublicTools); directAccess = getIsDirectAccess(perms); shoppingAdminModified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED); shoppingAdminModifiedBy = getShoppingAdminModifiedBy(perms); modified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_MODIFIED); modifiedBy = getModifiedBy(perms); accessAdmin = getIsAccessAdmin(perms); shoppingPeriodRevokeInstructorEditable = isShoppingPeriodRevokeInstructorEditable(perms); shoppingPeriodRevokeInstructorPublicOpt = isShoppingPeriodRevokeInstructorPublicOpt(perms); allowBecomeUser = isAllowBecomeUser(perms); instructorEdited = isInstructorEdited(perms); } NodeModel node = new NodeModel(childNode.id, childNode, directAccess, realm, role, ((NodeModel) parentNode.getUserObject()), restrictedAuthTools, restrictedPublicTools, startDate, endDate, false, shoppingPeriodAdmin, modifiedBy, modified, shoppingAdminModified, shoppingAdminModifiedBy, accessAdmin, shoppingPeriodRevokeInstructorEditable, shoppingPeriodRevokeInstructorPublicOpt, allowBecomeUser, instructorEdited); child.setUserObject(node); boolean shoppingAvailable = true; if(shoppingPeriodTool && node.isSiteNode() && !isShoppingPeriodOpenForSite(node.getNodeShoppingPeriodStartDate(), node.getNodeShoppingPeriodEndDate(), node.getNodeAccessRealmRole(), node.getNodeRestrictedAuthTools(), node.getNodeRestrictedPublicTools())){ //make sure this node is available shoppingAvailable = false; } if(shoppingAvailable && (!onlyAccessNodes || node.getNodeAccess())){ parentNode.add(child); added = true; } } return added; } /** * Determines if the child exists in the tree structure. This is a helper function for addChildNodeToTree to ensure * the duplicate child nodes aren't added * * @param childNodeId * @param parentNode * @return */ private boolean doesChildExist(String childNodeId, DefaultMutableTreeNode parentNode){ boolean exists = false; for(int i = 0; i < parentNode.getChildCount(); i++){ DefaultMutableTreeNode child = (DefaultMutableTreeNode) parentNode.getChildAt(i); if(childNodeId.equals(((NodeModel) child.getUserObject()).getNodeId())){ exists = true; break; } } return exists; } public NodeModel getNodeModel(String nodeId, String userId){ HierarchyNodeSerialized node = getNode(nodeId); NodeModel parentNodeModel = null; if(node.directParentNodeIds != null && node.directParentNodeIds.size() > 0){ //grad the last parent in the Set (this is the closest parent) List<String> orderedParents = getOrderedParentsList(node); parentNodeModel = getNodeModel(orderedParents.get(orderedParents.size() -1), userId); } Set<String> nodePerms = hierarchyService.getPermsForUserNodes(userId, new String[]{nodeId}); Set<String> perms = getPermsForUserNodes(userId, node.id); String[] realmRole = getAccessRealmRole(perms); String realm = realmRole[0]; String role = realmRole[1]; Date startDate = getShoppingStartDate(perms); Date endDate = getShoppingEndDate(perms); List<ListOptionSerialized> restrictedAuthTools = getRestrictedAuthToolSerializedList(perms, getEntireToolsList()); List<ListOptionSerialized> restrictedPublicTools = getRestrictedPublicToolSerializedList(perms, getEntireToolsList()); boolean direct = getIsDirectAccess(perms); boolean shoppingPeriodAdmin = isShoppingPeriodAdmin(perms); boolean accessAdmin = getIsAccessAdmin(perms); Date shoppingAdminModified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN_MODIFIED); String shoppingAdminModifiedBy = getShoppingAdminModifiedBy(perms); Date modified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_MODIFIED); String modifiedBy = getModifiedBy(perms); boolean shoppingPeriodRevokeInstructorEditable = isShoppingPeriodRevokeInstructorEditable(perms); boolean shoppingPeriodRevokeInstructorPublicOpt = isShoppingPeriodRevokeInstructorPublicOpt(perms); boolean allowBecomeUser = isAllowBecomeUser(perms); boolean instructorEdited = isInstructorEdited(perms); NodeModel nodeModel = new NodeModel(node.id, node, getIsDirectAccess(nodePerms), realm, role, parentNodeModel, restrictedAuthTools, restrictedPublicTools, startDate, endDate, false, shoppingPeriodAdmin, modifiedBy, modified, shoppingAdminModified, shoppingAdminModifiedBy, accessAdmin, shoppingPeriodRevokeInstructorEditable, shoppingPeriodRevokeInstructorPublicOpt, allowBecomeUser, instructorEdited); return nodeModel; } /** * {@inheritDoc} */ public void assignUserNodePerm(String userId, String nodeId, String perm, boolean cascade) { hierarchyService.assignUserNodePerm(userId, nodeId, perm, false); } public void removeNode(String nodeId){ removeNode(hierarchyService.getNodeById(nodeId)); } public void removeNode(HierarchyNode node){ if(node != null){ if(node.childNodeIds != null && !node.childNodeIds.isEmpty()){ //we can delete this, otherwise, delete the children first the children for(String childId : node.childNodeIds){ removeNode(hierarchyService.getNodeById(childId)); } } //all the children nodes have been deleted, now its safe to delete hierarchyService.removeNode(node.id); Set<String> userIds = hierarchyService.getUserIdsForNodesPerm(new String[]{node.id}, DelegatedAccessConstants.NODE_PERM_SITE_VISIT); for(String userId : userIds){ removeAllUserPermissions(node.id, userId); } //since the hierarchy service doesn't really delete the nodes, //we need to distinguish between deleted nodes hierarchyService.setNodeDisabled(node.id, true); } } public void deleteEmptyNonSiteNodes(String hierarchyId){ List<String> emptyNodes = dao.getEmptyNonSiteNodes(hierarchyId); //I don't like loops, loops shouldn't happen but never say never int loopProtection = 1; while(emptyNodes != null && emptyNodes.size() > 0 && loopProtection < 1000000){ for(String id : emptyNodes){ removeNode(hierarchyService.getNodeById(id)); } //check again emptyNodes = dao.getEmptyNonSiteNodes(hierarchyId); loopProtection++; } } public Map<String, String> getRealmRoleDisplay(boolean shopping){ if(shopping){ return convertRealmRoleToSingleList(sakaiProxy.getShoppingRealmOptions()); }else{ return convertRealmRoleToSingleList(sakaiProxy.getDelegatedAccessRealmOptions()); } } private Map<String, String> convertRealmRoleToSingleList(Map<String, List<String>> realmMap){ //First get a list of all roles: List<String> allRoles = new ArrayList<String>(); for(Entry<String, List<String>> entry : realmMap.entrySet()){ for(String role : entry.getValue()){ allRoles.add(role); } } //convert this map to a single role dropdown representation: Map<String, String> returnMap = new HashMap<String, String>(); for(Entry<String, List<String>> entry : realmMap.entrySet()){ String realm = entry.getKey(); for(String role : entry.getValue()){ String roleTitle = role; if(countNumOfOccurances(allRoles, role) > 1){ roleTitle += " (" + realm + ")"; } returnMap.put(realm + ":" + role, roleTitle); } } return returnMap; } private int countNumOfOccurances(List<String> list, String str){ int i = 0; for(String check : list){ if(check.equals(str)){ i++; } } return i; } public boolean hasShoppingPeriodAdminNodes(String userId){ if(userId == null || "".equals(userId)){ return false; } Set<HierarchyNode> shoppingAdminNodes = hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_SHOPPING_ADMIN); return shoppingAdminNodes != null && shoppingAdminNodes.size() > 0; } public boolean hasDelegatedAccessNodes(String userId){ if(userId == null || "".equals(userId)){ return false; } Set<HierarchyNode> delegatedAccessNodes = hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_SITE_VISIT); return delegatedAccessNodes != null && delegatedAccessNodes.size() > 0; } public boolean hasAccessAdminNodes(String userId){ if(userId == null || "".equals(userId)){ return false; } Set<HierarchyNode> accessAdminNodes = hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_ACCESS_ADMIN); return accessAdminNodes != null && accessAdminNodes.size() > 0; } public boolean hasAllowBecomeUserPerm(String userId){ if(userId == null || "".equals(userId)){ return false; } Set<HierarchyNode> accessAdminNodes = hierarchyService.getNodesForUserPerm(userId, DelegatedAccessConstants.NODE_PERM_ALLOW_BECOME_USER); return accessAdminNodes != null && accessAdminNodes.size() > 0; } public Map<String, List<String>> getNodesBySiteRef(String[] siteRefs, String hierarchyId){ return dao.getNodesBySiteRef(siteRefs, hierarchyId); } public void clearNodeCache(){ nodeCache.removeAll(); } public String[] getCurrentUsersAccessToSite(String siteRef){ String currentUserId = sakaiProxy.getCurrentUserId(); if(currentUserId == null || "".equals(currentUserId)){ return null; } //check the session first: if(sakaiProxy.getCurrentSession().getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_ACCESS_MAP) != null && ((Map) sakaiProxy.getCurrentSession().getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_ACCESS_MAP)).containsKey(siteRef)){ return (String[]) ((Map) sakaiProxy.getCurrentSession().getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_ACCESS_MAP)).get(siteRef); }else{ List<String> siteRefs = new ArrayList<String>(); siteRefs.add(siteRef); Map<String, AccessNode> accessNodes = grantAccessToSites(siteRefs, false, false); if(accessNodes != null && accessNodes.containsKey(siteRef) && accessNodes.get(siteRef) != null){ return accessNodes.get(siteRef).getAccess(); }else{ return null; } } } private Map<String, AccessNode> grantAccessToSites(List<String> siteRefs, boolean shoppingPeriod, boolean activeShoppingData){ String userId = sakaiProxy.getCurrentUserId(); if(shoppingPeriod){ userId = DelegatedAccessConstants.SHOPPING_PERIOD_USER; } return grantAccessToSites(siteRefs, shoppingPeriod, activeShoppingData, userId); } private Map<String, AccessNode> grantAccessToSites(List<String> siteRefs, boolean shoppingPeriod, boolean activeShoppingData, String userId){ Map<String, AccessNode> returnNodes = new HashMap<String, AccessNode>(); if(!shoppingPeriod && (userId == null || "".equals(userId))){ //skip since the user id is empty return returnNodes; } //we don't want to use the session if it's the shopping period user or we are looking up info for a different user //otherwise, use the session boolean useSession = userId != null && userId.equals(sakaiProxy.getCurrentUserId()); Session session = null;; if(useSession){ session = sakaiProxy.getCurrentSession(); } Map<String, String[]> deniedAuthToolsMap = new HashMap<String, String[]>(); if(useSession){ //only worry about the session for non shopping period queries Object sessionDeniedToolsMap = session.getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DENIED_TOOLS); if(sessionDeniedToolsMap != null){ deniedAuthToolsMap = (Map<String, String[]>) sessionDeniedToolsMap; } } Map<String, String[]> deniedPublicToolsMap = new HashMap<String, String[]>(); if(useSession){ //only worry about the session for non shopping period queries Object sessionDeniedTools2Map = session.getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DENIED_TOOLS2); if(sessionDeniedTools2Map != null){ deniedPublicToolsMap = (Map<String, String[]>) sessionDeniedTools2Map; } } Map<String, String[]> accessMap = new HashMap<String, String[]>(); if(useSession){ //only worry about the session for non shopping period queries Object sessionaccessMap = session.getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_ACCESS_MAP); if(sessionaccessMap != null){ accessMap = (Map<String, String[]>) sessionaccessMap; } } for (Iterator iterator = siteRefs.iterator(); iterator.hasNext();) { String siteRef = (String) iterator.next(); if(!shoppingPeriod && accessMap.containsKey(siteRef) && accessMap.get(siteRef) == null){ //we already know this result is null, so return null returnNodes.put(siteRef, null); iterator.remove(); }else{ //set default to no access and override it if the user does have access //this is so we don't have to keep looking up their access for the same site: deniedAuthToolsMap.put(siteRef, null); deniedPublicToolsMap.put(siteRef, null); accessMap.put(siteRef, null); } } //Set user Id and hierarchy id String hierarchyId = DelegatedAccessConstants.HIERARCHY_ID; if(shoppingPeriod){ userId = DelegatedAccessConstants.SHOPPING_PERIOD_USER; } //this is a simple flag set in the delegated access login observer which //determines if there is a need to lookup access information for this user. //if it's not set, then don't worry about looking up anything Object dAMapFlag = null; if(useSession){ dAMapFlag = session.getAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DELEGATED_ACCESS_FLAG); } if(dAMapFlag != null || !useSession){ //get list of all site ref nodes: Map<String, List<String>> siteRefToNodeMap = getNodesBySiteRef(siteRefs.toArray(new String[siteRefs.size()]), hierarchyId); if(siteRefToNodeMap != null){ Set<String> nodeIds = new HashSet<String>(); for(List<String> nodeIdsList : siteRefToNodeMap.values()){ nodeIds.addAll(nodeIdsList); } Map<String, HierarchyNode> siteNodes = hierarchyService.getNodesByIds(nodeIds.toArray(new String[nodeIds.size()])); //create a set of parent ID's and lookup the user's permissions for this sub-set: Set<String> subSetNodeIds = new HashSet<String>(); if(siteNodes != null){ for(HierarchyNode node : siteNodes.values()){ subSetNodeIds.add(node.id); if(node.parentNodeIds != null){ for(String pId : node.parentNodeIds){ subSetNodeIds.add(pId); } } } } //find the node for the site Map<String, Set<String>> userNodesAndPerms = dao.getNodesAndPermsForUser(userId, subSetNodeIds.toArray(new String[subSetNodeIds.size()])); Map<String, String> memberRoles = new HashMap<String, String>(); if(!shoppingPeriod){ memberRoles = sakaiProxy.isUserMember(userId, siteRefs); } if(userNodesAndPerms != null){ for(String siteRef : siteRefs){ if(siteRefToNodeMap != null && siteRefToNodeMap.containsKey(siteRef) && siteRefToNodeMap.get(siteRef) != null && siteRefToNodeMap.get(siteRef).size() > 0){ //find the first access node for this user, if none found, then that means they don't have access String nodeId = siteRefToNodeMap.get(siteRef).get(0); while(nodeId != null && !"".equals(nodeId)){ Set<String> perms = userNodesAndPerms.get(nodeId); if(perms != null && getIsDirectAccess(perms)){ //check first that the user's isn't a member of the site, if so, return null: //don't waste time checking until we get to this level (for bulk searching speed) if(!shoppingPeriod && memberRoles.get(siteRef) != null){ returnNodes.put(siteRef, null); }else{ if(shoppingPeriod && activeShoppingData){ //do substring(6) b/c we need site ID and what is stored is a ref: /site/1231231 String siteId = siteRef.substring(6); if(!isShoppingAvailable(perms)){ //check that shopping period is still available unless activeShoppingData is false break; } } //Access Map: String[] access = getAccessRealmRole(perms); if (access == null || access.length != 2 || access[0] == null || access[1] == null || "".equals(access[0]) || "".equals(access[1]) || "null".equals(access[0]) || "null".equals(access[1])) { access = new String[]{"", ""}; } accessMap.put(siteRef, access); //Denied Auth Tools List List<String> deniedAuthTools = getRestrictedAuthToolsForUser(perms); String[] deniedAuthToolsArr = (String[]) deniedAuthTools.toArray(new String[deniedAuthTools.size()]); if(deniedAuthToolsArr != null){ deniedAuthToolsMap.put(siteRef, deniedAuthToolsArr); }else{ deniedAuthToolsMap.put(siteRef, new String[0]); } //Denied Public List List<String> deniedPublicTools = getRestrictedPublicToolsForUser(perms); String[] deniedPublicToolsArr = (String[]) deniedPublicTools.toArray(new String[deniedPublicTools.size()]); if(deniedPublicToolsArr != null){ deniedPublicToolsMap.put(siteRef, deniedPublicToolsArr); }else{ deniedPublicToolsMap.put(siteRef, new String[0]); } Date startDate = getShoppingStartDate(perms); Date endDate = getShoppingEndDate(perms); Date modified = getPermDate(perms, DelegatedAccessConstants.NODE_PERM_MODIFIED); String modifiedBy = getModifiedBy(perms); //set returnNode AccessNode returnNode = new AccessNode(userId, siteRef, access, deniedAuthToolsArr, deniedPublicToolsArr, startDate, endDate, modified, modifiedBy); returnNodes.put(siteRef, returnNode); } //break out of loop nodeId = null; break; }else{ Set<String> parentIds = null; if(siteNodes != null && siteNodes.containsKey(nodeId)){ //we've already spent the time looking this up in bulk parentIds = siteNodes.get(nodeId).parentNodeIds; }else{ parentIds = getCachedNode(nodeId).parentNodeIds; } nodeId = getFirstAccessParent(parentIds, userNodesAndPerms); } } } } } } } if(useSession){ //we want to set the session map no matter what so we don't have to look it up again: session.setAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DENIED_TOOLS, deniedAuthToolsMap); session.setAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_DENIED_TOOLS2, deniedPublicToolsMap); session.setAttribute(DelegatedAccessConstants.SESSION_ATTRIBUTE_ACCESS_MAP, accessMap); //update restrictedToolsCache try{ restrictedAuthToolsCache.put(new Element(userId, deniedAuthToolsMap)); }catch (Exception e) { log.error("grantAccessToSite: " + userId, e); } try{ restrictedPublicToolsCache.put(new Element(userId, deniedPublicToolsMap)); }catch (Exception e) { log.error("grantAccessToSite: " + userId, e); } } return returnNodes; } private String getFirstAccessParent(Set<String> parentIds, Map<String, Set<String>> userNodesAndPerms){ String accessParent = null; List<String> accessParents = new ArrayList<String>(); for(String parent: parentIds){ for(Entry<String, Set<String>> entry : userNodesAndPerms.entrySet()){ if(parent.equals(entry.getKey()) && getIsDirectAccess(entry.getValue())){ accessParents.add(parent); } } } if(accessParents.size() == 1){ //there is only one parent which is an access node, so lets set it to that: accessParent = accessParents.get(0); }else if(accessParents.size() > 1){ //there are more than 1 parents with access, we need to find out which one is the closest to this node //reverse order since most of the time (not guaranteed) parents are ordered from top to bottom, //so by starting at the bottom we have a better chance of using less cylces Collections.reverse(accessParents); for(String parent: accessParents){ HierarchyNodeSerialized pNode = getCachedNode(parent); boolean foundAccessChild = false; for(String child : pNode.childNodeIds){ for(String childCheck: accessParents){ if(childCheck.equals(child)){ //there is a parent with access permissions at a lower level, //skip this parent and go to the next one foundAccessChild = true; break; } } if(foundAccessChild){ break; } } if(!foundAccessChild){ accessParent = parent; break; } } } return accessParent; } private boolean isShoppingAvailable(Set<String> perms){ Date startDate = getShoppingStartDate(perms); Date endDate = getShoppingEndDate(perms); String[] nodeAccessRealmRole = getAccessRealmRole(perms); List<String> restrictedAuthTools = getRestrictedAuthToolsForUser(perms); String[] restrictedAuthToolsArr = null; if(restrictedAuthTools != null){ restrictedAuthToolsArr = restrictedAuthTools.toArray(new String[restrictedAuthTools.size()]); } List<String> restrictedPublicTools = getRestrictedPublicToolsForUser(perms); String[] restrictedPublicToolsArr = null; if(restrictedPublicTools != null){ restrictedPublicToolsArr = restrictedPublicTools.toArray(new String[restrictedPublicTools.size()]); } return isShoppingPeriodOpenForSite(startDate, endDate, nodeAccessRealmRole, restrictedAuthToolsArr, restrictedPublicToolsArr); } public boolean isShoppingPeriodOpenForSite(Date startDate, Date endDate, String[] nodeAccessRealmRole, String[] restrictedAuthTools, String[] restrictedPublicTools){ Date now = new Date(); boolean isOpen = false; if(startDate != null && endDate != null){ isOpen = startDate.before(now) && endDate.after(now); }else if(startDate != null){ isOpen = startDate.before(now); }else if(endDate != null){ isOpen = endDate.after(now); } if(nodeAccessRealmRole != null && nodeAccessRealmRole.length == 2 && !"".equals(nodeAccessRealmRole[0]) && !"".equals(nodeAccessRealmRole[1]) && !"null".equals(nodeAccessRealmRole[0]) && !"null".equals(nodeAccessRealmRole[1])){ isOpen = isOpen && true; }else{ isOpen = false; } if((restrictedAuthTools == null || restrictedAuthTools.length == 0) && (restrictedPublicTools == null || restrictedPublicTools.length == 0)){ isOpen = false; }else{ isOpen = isOpen && true; } return isOpen; } @Override public void syncMyworkspaceToolForUser(String userId) { if(sakaiProxy.getSyncMyworkspaceTool()){ String currentUserId = sakaiProxy.getCurrentUserId(); Site workspace = null; try{ //trick the session into thinking you are the user who's workspace this is for. This way, //SiteService will create the workspace if its missing sakaiProxy.setSessionUserId(userId); workspace = sakaiProxy.getSiteById("~" + userId); }catch (Exception e) { log.error(e); }finally{ sakaiProxy.setSessionUserId(currentUserId); } if(workspace != null){ boolean hasAnyAccess = false; //check if user has any access at all to determine if we need to add or remove the tool hasAnyAccess = hasDelegatedAccessNodes(userId); boolean hasAllowBecomeUserPerm = false; if(hasAnyAccess){ //we know the user has at least one site.visit permission, let's see if they have any //allowBecomeUser perms hasAllowBecomeUserPerm = hasAllowBecomeUserPerm(userId); } if(!hasAnyAccess) hasAnyAccess = hasShoppingPeriodAdminNodes(userId); if(!hasAnyAccess) hasAnyAccess = hasAccessAdminNodes(userId); //Check for Delegated Access Tool ToolConfiguration tool = workspace.getToolForCommonId("sakai.delegatedaccess"); if(hasAnyAccess && tool == null){ //user has access but doesn't have the DA tool, we need to add it SitePage page = workspace.addPage(); page.addTool("sakai.delegatedaccess"); sakaiProxy.saveSite(workspace); }else if(!hasAnyAccess && tool != null){ //user doesn't have any access in DA but their MyWorkspace still has the DA tool, remove it: workspace.removePage(tool.getContainingPage()); sakaiProxy.saveSite(workspace); } //Check for Become User tool ToolConfiguration becomeUserTool = workspace.getToolForCommonId("sakai.su"); if(hasAnyAccess && hasAllowBecomeUserPerm && becomeUserTool == null){ //user has access and allowBecomeUser perm but doesn't have the become user tool, we need to add it SitePage page = workspace.addPage(); page.addTool("sakai.su"); sakaiProxy.saveSite(workspace); }else if((!hasAnyAccess || !hasAllowBecomeUserPerm) && becomeUserTool != null){ //user doesn't have any access or allowBecomeUser perm in DA but their MyWorkspace still has the become user tool, remove it: workspace.removePage(becomeUserTool.getContainingPage()); sakaiProxy.saveSite(workspace); } } } } public Map<String, AccessNode> getUserAccessForSite(String siteRef){ Map<String, AccessNode> returnMap = new HashMap<String, AccessNode>(); Map<String, List<String>> siteNodeMap = getNodesBySiteRef(new String[]{siteRef}, DelegatedAccessConstants.HIERARCHY_ID); if(siteNodeMap != null && siteNodeMap.containsKey(siteRef) && siteNodeMap.get(siteRef) != null && siteNodeMap.get(siteRef).size() > 0){ //there should only be 1 node with a siteRef like this, so just grab the first HierarchyNodeSerialized node = getCachedNode(siteNodeMap.get(siteRef).get(0)); Set<String> nodeIds = node.parentNodeIds; nodeIds.add(node.id); Map<String, Map<String, Set<String>>> userPerms = hierarchyService.getUsersAndPermsForNodes(nodeIds.toArray(new String[nodeIds.size()])); List<String> siteRefs = new ArrayList<String>(); siteRefs.add(siteRef); Set<String> usersWithAccess = new HashSet<String>(); //map returns nodeId -> {userId -> {perms}}, so lets just grab all the user Ids and look up their //permissions later for(Map<String, Set<String>> nodeUsers : userPerms.values()){ for(String userId : nodeUsers.keySet()){ if(!DelegatedAccessConstants.SHOPPING_PERIOD_USER.equals(userId)) usersWithAccess.add(userId); } } for(String userId : usersWithAccess){ Map<String, AccessNode> userAccess = grantAccessToSites(siteRefs, false, false, userId); if(userAccess != null && userAccess.containsKey(siteRef) && userAccess.get(siteRef) != null){ returnMap.put(userId, userAccess.get(siteRef)); } } } return returnMap; } public Map<String, String> updateShoppingPeriodSettings(DefaultMutableTreeNode node){ Map<String, String> errors = new HashMap<String, String>(); List<String> removeAnonAuthRefs = new ArrayList<String>(); Map<String, Map<String, List<String>>> realmRoleCopy = new HashMap<String, Map<String, List<String>>>(); List<String> removeAuthToolsSiteProp = new ArrayList<String>(); List<String> removePublicToolsSiteProp = new ArrayList<String>(); Map<String, List<String>> updateAuthToolsSiteProp = new HashMap<String, List<String>>(); Map<String, List<String>> updatePublicToolsSiteProp = new HashMap<String, List<String>>(); updateShoppingPeriodSettingsHelper(node, getEntireToolsList(), errors, removeAnonAuthRefs, realmRoleCopy, removeAuthToolsSiteProp, removePublicToolsSiteProp, updateAuthToolsSiteProp, updatePublicToolsSiteProp); if(removeAnonAuthRefs.size() > 0){ //remove all .anon and .auth roles for these sites dao.removeAnonAndAuthRoles(removeAnonAuthRefs.toArray(new String[removeAnonAuthRefs.size()])); } if(realmRoleCopy.size() > 0){ for(Entry<String, Map<String, List<String>>> e : realmRoleCopy.entrySet()){ String[] realmRole = e.getKey().split(":"); if(realmRole.length == 2){ for(Entry<String, List<String>> e2 : e.getValue().entrySet()){ dao.copyRole(realmRole[0], realmRole[1], e2.getValue().toArray(new String[e2.getValue().size()]), e2.getKey()); } } } } if(removeAuthToolsSiteProp.size() > 0){ dao.removeSiteProperty(removeAuthToolsSiteProp.toArray(new String[removeAuthToolsSiteProp.size()]), DelegatedAccessConstants.SITE_PROP_AUTH_TOOLS); } if(removePublicToolsSiteProp.size() > 0){ dao.removeSiteProperty(removePublicToolsSiteProp.toArray(new String[removePublicToolsSiteProp.size()]), DelegatedAccessConstants.SITE_PROP_PUBLIC_TOOLS); } for(Entry<String, List<String>> e : updateAuthToolsSiteProp.entrySet()){ dao.updateSiteProperty(e.getValue().toArray(new String[e.getValue().size()]), DelegatedAccessConstants.SITE_PROP_AUTH_TOOLS, e.getKey()); } for(Entry<String, List<String>> e : updatePublicToolsSiteProp.entrySet()){ dao.updateSiteProperty(e.getValue().toArray(new String[e.getValue().size()]), DelegatedAccessConstants.SITE_PROP_PUBLIC_TOOLS, e.getKey()); } return errors; } private void updateShoppingPeriodSettingsHelper(DefaultMutableTreeNode node, List<ListOptionSerialized> blankRestrictedTools, Map<String, String> errors, List<String> removeAnonAuthRefs, Map<String, Map<String, List<String>>> realmRoleCopy, List<String> removeAuthToolsSiteProp, List<String> removePublicToolsSiteProp, Map<String, List<String>> updateAuthToolsSiteProp, Map<String, List<String>> updatePublicToolsSiteProp){ if(node != null){ NodeModel nodeModel = (NodeModel) node.getUserObject(); if(nodeModel.isSiteNode()){ try{ ShoppingPeriodUpdateStruct struct = updateShoppingPeriodSettings(nodeModel); removeAnonAuthRefs.add(nodeModel.getNode().title); if(struct != null && struct.getRealmRole() != null && struct.getRealmRole().length == 2 && (struct.isAnon() || struct.isAuth())){ String fromRealmRole = struct.getRealmRole()[0] + ":" + struct.getRealmRole()[1]; Map<String, List<String>> copyTo = realmRoleCopy.get(fromRealmRole); if(copyTo == null){ copyTo = new HashMap<String, List<String>>(); } if(struct.isAuth()){ List<String> siteRefs = copyTo.get(".auth"); if(siteRefs == null){ siteRefs = new ArrayList<String>(); } siteRefs.add(struct.getSiteRef()); copyTo.put(".auth", siteRefs); } if(struct.isAnon()){ List<String> siteRefs = copyTo.get(".anon"); if(siteRefs == null){ siteRefs = new ArrayList<String>(); } siteRefs.add(struct.getSiteRef()); copyTo.put(".anon", siteRefs); } realmRoleCopy.put(fromRealmRole, copyTo); } if(struct.getRestrictedAuthToolsList() == null || "".equals(struct.getRestrictedAuthToolsList()) || ";".equals(struct.getRestrictedAuthToolsList())){ removeAuthToolsSiteProp.add(struct.getSiteRef().substring(6)); }else{ List<String> siteRefs = updateAuthToolsSiteProp.get(struct.getRestrictedAuthToolsList()); if(siteRefs == null){ siteRefs = new ArrayList<String>(); } siteRefs.add(struct.getSiteRef().substring(6)); updateAuthToolsSiteProp.put(struct.getRestrictedAuthToolsList(), siteRefs); } if(struct.getRestrictedPublicToolsList() == null || "".equals(struct.getRestrictedPublicToolsList()) || ";".equals(struct.getRestrictedPublicToolsList())){ removePublicToolsSiteProp.add(struct.getSiteRef().substring(6)); }else{ List<String> siteRefs = updatePublicToolsSiteProp.get(struct.getRestrictedPublicToolsList()); if(siteRefs == null){ siteRefs = new ArrayList<String>(); } siteRefs.add(struct.getSiteRef().substring(6)); updatePublicToolsSiteProp.put(struct.getRestrictedPublicToolsList(), siteRefs); } }catch(Exception e){ log.error(e.getMessage(), e); StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); errors.put(nodeModel.getNode().title, sw.toString()); } } if(!nodeModel.isAddedDirectChildrenFlag()){ addChildrenNodes(node, DelegatedAccessConstants.SHOPPING_PERIOD_USER, blankRestrictedTools, false, null, true, false); nodeModel.setAddedDirectChildrenFlag(true); } for(int i = 0; i < node.getChildCount(); i++){ updateShoppingPeriodSettingsHelper((DefaultMutableTreeNode) node.getChildAt(i), blankRestrictedTools, errors, removeAnonAuthRefs, realmRoleCopy, removeAuthToolsSiteProp, removePublicToolsSiteProp, updateAuthToolsSiteProp, updatePublicToolsSiteProp); } } } private ShoppingPeriodUpdateStruct updateShoppingPeriodSettings(NodeModel node) { ShoppingPeriodUpdateStruct returnStruct = null; boolean auth = false; boolean anon = false; Date startDate = null; Date endDate = null; Date now = new Date(); startDate = node.getNodeShoppingPeriodStartDate(); endDate = node.getNodeShoppingPeriodEndDate(); String[] nodeAccessRealmRole = node.getNodeAccessRealmRole(); String[] restrictedAuthcTools = node.getNodeRestrictedAuthTools(); String[] restrictedPublicTools = node.getNodeRestrictedPublicTools(); //do substring(6) b/c we need site ID and what is stored is a ref: /site/1231231 String siteId = node.getNode().title.substring(6); boolean addAuth = isShoppingPeriodOpenForSite(startDate, endDate, nodeAccessRealmRole, restrictedAuthcTools, restrictedPublicTools); String restrictedAuthToolsList = ""; String restrictedPublicToolsList = ""; if(addAuth){ //update the restricted tools list, otherwise it will be cleared: //set the restricted tools list to a non empty string, otherwise, the site property won't be saved //when the string is empty (no tools allowed to view). restrictedAuthToolsList = ";"; for(String tool : node.getNodeRestrictedAuthTools()){ if("Home".equals(tool)){ String homeToolsVal = ""; String[] homeTools = sakaiProxy.getHomeTools(); for(String toolId : homeTools){ if(!"".equals(homeToolsVal)){ homeToolsVal += ";"; } homeToolsVal += toolId; } restrictedAuthToolsList += homeToolsVal; }else{ restrictedAuthToolsList += tool; } restrictedAuthToolsList += ";"; } restrictedPublicToolsList = ";"; for(String tool : node.getNodeRestrictedPublicTools()){ if(!"".equals(restrictedPublicToolsList)){ restrictedPublicToolsList += ";"; } if("Home".equals(tool)){ String homeToolsVal = ""; String[] homeTools = sakaiProxy.getHomeTools(); for(String toolId : homeTools){ if(!"".equals(homeToolsVal)){ homeToolsVal += ";"; } homeToolsVal += toolId; } restrictedPublicToolsList += homeToolsVal; }else{ restrictedPublicToolsList += tool; } } //add either .anon or .auth role: auth = restrictedAuthcTools != null && restrictedAuthcTools.length > 0; anon = restrictedPublicTools != null && restrictedPublicTools.length > 0; } // if(restrictedAuthToolsList == null || "".equals(restrictedAuthToolsList) || ";".equals(restrictedAuthToolsList)){ // //no need for property if null or blank, just remove it in case it existed before // dao.removeSiteProperty(siteId, DelegatedAccessConstants.SITE_PROP_AUTH_TOOLS); // }else{ // String sitePropRestrictedTools = dao.getSiteProperty(DelegatedAccessConstants.SITE_PROP_AUTH_TOOLS, siteId); // if(sitePropRestrictedTools != null){ // dao.updateSiteProperty(siteId, DelegatedAccessConstants.SITE_PROP_AUTH_TOOLS, restrictedAuthToolsList); // }else{ // dao.addSiteProperty(siteId, DelegatedAccessConstants.SITE_PROP_AUTH_TOOLS, restrictedAuthToolsList); // } // } // // if(restrictedPublicToolsList == null || "".equals(restrictedPublicToolsList) || ";".equals(restrictedPublicToolsList)){ // //no need for property if null or blank, just remove it in case it existed before // dao.removeSiteProperty(siteId, DelegatedAccessConstants.SITE_PROP_PUBLIC_TOOLS); // }else{ // String sitePropRestrictedTools = dao.getSiteProperty(DelegatedAccessConstants.SITE_PROP_PUBLIC_TOOLS, siteId); // if(sitePropRestrictedTools != null){ // dao.updateSiteProperty(siteId, DelegatedAccessConstants.SITE_PROP_PUBLIC_TOOLS, restrictedPublicToolsList); // }else{ // dao.addSiteProperty(siteId, DelegatedAccessConstants.SITE_PROP_PUBLIC_TOOLS, restrictedPublicToolsList); // } // } returnStruct = new ShoppingPeriodUpdateStruct(auth, anon, nodeAccessRealmRole, node.getNode().title, restrictedPublicToolsList, restrictedAuthToolsList); return returnStruct; } private class ShoppingPeriodUpdateStruct{ private boolean auth = false; private boolean anon = true; private String[] realmRole; private String siteRef; private String restrictedPublicToolsList; private String restrictedAuthToolsList; public ShoppingPeriodUpdateStruct(boolean auth, boolean anon, String[] realmRole, String siteRef, String restrictedPublicToolsList, String restrictedAuthToolsList){ this.anon = anon; this.auth = auth; this.realmRole = realmRole; this.siteRef = siteRef; this.restrictedAuthToolsList = restrictedAuthToolsList; this.restrictedPublicToolsList = restrictedPublicToolsList; } public boolean isAuth() { return auth; } public void setAuth(boolean auth) { this.auth = auth; } public boolean isAnon() { return anon; } public void setAnon(boolean anon) { this.anon = anon; } public String[] getRealmRole() { return realmRole; } public void setRealmRole(String[] realmRole) { this.realmRole = realmRole; } public String getSiteRef() { return siteRef; } public void setSiteRef(String siteRef) { this.siteRef = siteRef; } public String getRestrictedPublicToolsList() { return restrictedPublicToolsList; } public void setRestrictedPublicToolsList(String restrictedPublicToolsList) { this.restrictedPublicToolsList = restrictedPublicToolsList; } public String getRestrictedAuthToolsList() { return restrictedAuthToolsList; } public void setRestrictedAuthToolsList(String restrictedAuthToolsList) { this.restrictedAuthToolsList = restrictedAuthToolsList; } } // private void removeAnonAndAuthRoles(String siteRef){ // AuthzGroup ag = sakaiProxy.getAuthzGroup(siteRef); // if(ag != null){ // log.debug("Removing .auth and.anon roles for " + siteRef); // for (Role role: ag.getRoles()){ // if (role.getId().equals(".auth") || role.getId().equals(".anon")){ // sakaiProxy.removeRoleFromAuthzGroup(ag, role); // } // } // } // } private void copyNewRole(String siteRef, String copyRealm, String copyRole, boolean auth, boolean anon){ if(auth){ log.debug("Copying " + copyRole + " to .auth for " + siteRef); sakaiProxy.copyNewRole(siteRef, copyRealm, copyRole, ".auth"); } if(anon){ log.debug("Copying " + copyRole + " to .anon for " + siteRef); sakaiProxy.copyNewRole(siteRef, copyRealm, copyRole, ".anon"); } } public String getAddDAMyworkspaceJobStatus(){ HierarchyNode root = hierarchyService.getRootNode(DelegatedAccessConstants.HIERARCHY_ID); if(root != null){ Set<String> perms = hierarchyService.getPermsForUserNodes(DelegatedAccessConstants.SITE_HIERARCHY_USER, new String[]{root.id}); return getAddDAMyworkspaceJobStatus(perms); } return null; } private String getAddDAMyworkspaceJobStatus(Set<String> perms){ for(String perm : perms){ if(perm.startsWith(DelegatedAccessConstants.NODE_PERM_MYWORKSPACE_JOB_STATUS)){ return perm.substring(DelegatedAccessConstants.NODE_PERM_MYWORKSPACE_JOB_STATUS.length()); } } return null; } public void updateAddDAMyworkspaceJobStatus(String status){ //first find the old status and remove it if it exist: HierarchyNode root = hierarchyService.getRootNode(DelegatedAccessConstants.HIERARCHY_ID); if(root != null){ String currentStatus = getAddDAMyworkspaceJobStatus(); if(currentStatus != null){ hierarchyService.removeUserNodePerm(DelegatedAccessConstants.SITE_HIERARCHY_USER, root.id, DelegatedAccessConstants.NODE_PERM_MYWORKSPACE_JOB_STATUS + currentStatus, false); } //add new status: hierarchyService.assignUserNodePerm(DelegatedAccessConstants.SITE_HIERARCHY_USER, root.id, DelegatedAccessConstants.NODE_PERM_MYWORKSPACE_JOB_STATUS + status, false); } } public void scheduleAddDAMyworkspaceJobStatus(){ // Remove any existing notifications for this node DelayedInvocation[] fdi = scheduledInvocationManager.findDelayedInvocations("org.sakaiproject.delegatedaccess.jobs.DelegatedAccessAddToolToMyWorkspacesJob", ""); if (fdi != null && fdi.length > 0) { for (DelayedInvocation d : fdi) { scheduledInvocationManager.deleteDelayedInvocation(d.uuid); } } //update the shopping period site settings (realm, site properties, etc) scheduledInvocationManager.createDelayedInvocation(timeService.newTime(), "org.sakaiproject.delegatedaccess.jobs.DelegatedAccessAddToolToMyWorkspacesJob", ""); updateAddDAMyworkspaceJobStatus("0"); } public boolean isUserAllowBecomeUser(String userId, String siteRef){ Map<String, List<String>> nodeIds = getNodesBySiteRef(new String[]{siteRef}, DelegatedAccessConstants.HIERARCHY_ID); if(nodeIds != null && nodeIds.containsKey(siteRef) && nodeIds.get(siteRef) != null && nodeIds.get(siteRef).size() == 1){ //we found the site, now look up this user's permission for this node String nodeId = nodeIds.get(siteRef).get(0); NodeModel model = getNodeModel(nodeId, userId); if(model != null){ return model.getNodeAccess() && model.getNodeAllowBecomeUser(); }else{ return false; } }else{ return false; } } public HierarchyNodeSerialized getRootNodeId(){ return new HierarchyNodeSerialized(hierarchyService.getRootNode(DelegatedAccessConstants.HIERARCHY_ID)); } public Set<HierarchyNodeSerialized> getDirectNodes(String nodeId){ HierarchyNodeSerialized node = getCachedNode(nodeId); Set<HierarchyNodeSerialized> returnSet = new HashSet<HierarchyNodeSerialized>(); if(node != null && node.directChildNodeIds != null){ for(String id : node.directChildNodeIds){ returnSet.add(getCachedNode(id)); } } return returnSet; } public List<AccessSearchResult> getAccessForUser(User user){ List<AccessSearchResult> returnSet = new ArrayList<AccessSearchResult>(); if(user != null){ boolean isAdmin = sakaiProxy.isSuperUser(); Set<String> accessAdminNodesArr = new HashSet<String>(); if(!isAdmin){ Set<HierarchyNodeSerialized> accessAdminNodes = getAccessAdminNodesForUser(sakaiProxy.getCurrentUserId()); for(HierarchyNodeSerialized n : accessAdminNodes){ accessAdminNodesArr.add(n.id); accessAdminNodesArr.addAll(n.childNodeIds); } } //Access Nodes Set<HierarchyNodeSerialized> accessNodes = getAccessNodesForUser(user.getId()); for(HierarchyNodeSerialized n : accessNodes){ boolean canEdit = false; if(isAdmin || accessAdminNodesArr.contains(n.id)){ canEdit = true; } AccessSearchResult r = new AccessSearchResult(); r.setId(user.getId()); r.setEid(user.getEid()); r.setSortName(user.getDisplayName()); r.setType(DelegatedAccessConstants.TYPE_ACCESS); int level = 0; if(n.parentNodeIds != null){ level = n.parentNodeIds.size(); } r.setLevel(level); r.setHierarchyNodes(getHierarchyForNode(n)); r.setNodeId(n.id); r.setCanEdit(canEdit); Set<String> perms = getPermsForUserNodes(user.getId(), n.id); r.setAccess(getAccessRealmRole(perms)); r.setRestrictedTools(getRestrictedAuthToolsForUser(perms)); returnSet.add(r); } //Shoppinger period nodes Set<HierarchyNodeSerialized> shoppingAdminNodes = getShoppingPeriodAdminNodesForUser(user.getId()); for(HierarchyNodeSerialized n : shoppingAdminNodes){ boolean canEdit = false; if(isAdmin || accessAdminNodesArr.contains(n.id)){ canEdit = true; } AccessSearchResult r = new AccessSearchResult(); r.setId(user.getId()); r.setEid(user.getEid()); r.setSortName(user.getDisplayName()); r.setType(DelegatedAccessConstants.TYPE_ACCESS_SHOPPING_PERIOD_USER); int level = 0; if(n.parentNodeIds != null){ level = n.parentNodeIds.size(); } r.setLevel(level); r.setHierarchyNodes(getHierarchyForNode(n)); r.setNodeId(n.id); r.setCanEdit(canEdit); returnSet.add(r); } //Access Admin nodes Set<HierarchyNodeSerialized> accessAdminNodes = getAccessAdminNodesForUser(user.getId()); for(HierarchyNodeSerialized n : accessAdminNodes){ boolean canEdit = false; if(isAdmin || accessAdminNodesArr.contains(n.id)){ canEdit = true; } AccessSearchResult r = new AccessSearchResult(); r.setId(user.getId()); r.setEid(user.getEid()); r.setDisplayName(user.getDisplayName()); r.setSortName(user.getSortName()); r.setType(DelegatedAccessConstants.TYPE_ACCESS_ADMIN); int level = 0; if(n.parentNodeIds != null){ level = n.parentNodeIds.size(); } r.setLevel(level); r.setHierarchyNodes(getHierarchyForNode(n)); r.setNodeId(n.id); r.setCanEdit(canEdit); returnSet.add(r); } } return returnSet; } private List<String> getHierarchyForNode(HierarchyNodeSerialized node){ List<String> returnList = new ArrayList<String>(); for(String parentId : getOrderedParentsList(node)){ HierarchyNodeSerialized parentNode = getCachedNode(parentId); returnList.add(parentNode.description); } returnList.add(node.description); return returnList; } @Override public List<AccessSearchResult> getAccessAtLevel(List<String> nodeSelectOrder, boolean includeLowerPerms) { boolean isAdmin = sakaiProxy.isSuperUser(); Set<String> accessAdminNodesArr = new HashSet<String>(); if(!isAdmin){ Set<HierarchyNodeSerialized> accessAdminNodes = getAccessAdminNodesForUser(sakaiProxy.getCurrentUserId()); for(HierarchyNodeSerialized n : accessAdminNodes){ accessAdminNodesArr.add(n.id); accessAdminNodesArr.addAll(n.childNodeIds); } } List<AccessSearchResult> returnSet = new ArrayList<AccessSearchResult>(); if((isAdmin || accessAdminNodesArr.size() > 0) && nodeSelectOrder != null && nodeSelectOrder.size() > 0){ Set<String> searchNodes = new HashSet<String>(); if(includeLowerPerms){ //we want to look at the lowest level and find all users who have access at that level or below HierarchyNode searchNode = hierarchyService.getNodeById(nodeSelectOrder.get(nodeSelectOrder.size() - 1)); searchNodes.add(searchNode.id); searchNodes.addAll(searchNode.childNodeIds); } //we also want to audit as well, so include the hierarchy node ids above the last searchNodes.addAll(nodeSelectOrder); Map<String, Map<String, Set<String>>> usersAndPerms = hierarchyService.getUsersAndPermsForNodes(searchNodes.toArray(new String[searchNodes.size()])); if(usersAndPerms != null){ for(Entry<String, Map<String, Set<String>>> usersAndPermsForNode : usersAndPerms.entrySet()){ String nodeId = usersAndPermsForNode.getKey(); boolean canEdit = false; if(isAdmin || accessAdminNodesArr.contains(nodeId)){ canEdit = true; } for(Entry<String, Set<String>> userAndPerms : usersAndPermsForNode.getValue().entrySet()){ User u = sakaiProxy.getUser(userAndPerms.getKey()); if(u != null){ boolean hasAccess = getIsDirectAccess(userAndPerms.getValue()); boolean hasShoppingAdmin = isShoppingPeriodAdmin(userAndPerms.getValue()); boolean hasAccessAdmin = getIsAccessAdmin(userAndPerms.getValue()); if(hasAccess || hasShoppingAdmin || hasAccessAdmin){ String id = u.getId(); String eid = u.getEid(); String displayName = u.getDisplayName(); String sortName = u.getSortName(); HierarchyNodeSerialized node = getCachedNode(nodeId); int level = 0; if(node.parentNodeIds != null){ level = node.parentNodeIds.size(); } List<String> hierarchy = getHierarchyForNode(node); if(hasAccess){ AccessSearchResult r = new AccessSearchResult(); r.setId(id); r.setEid(eid); r.setDisplayName(displayName); r.setSortName(sortName); r.setType(DelegatedAccessConstants.TYPE_ACCESS); r.setLevel(level); r.setHierarchyNodes(hierarchy); r.setNodeId(nodeId); r.setCanEdit(canEdit); r.setAccess(getAccessRealmRole(userAndPerms.getValue())); r.setRestrictedTools(getRestrictedAuthToolsForUser(userAndPerms.getValue())); returnSet.add(r); } if(hasShoppingAdmin){ AccessSearchResult r = new AccessSearchResult(); r.setId(id); r.setEid(eid); r.setDisplayName(displayName); r.setSortName(sortName); r.setType(DelegatedAccessConstants.TYPE_ACCESS_SHOPPING_PERIOD_USER); r.setLevel(level); r.setHierarchyNodes(hierarchy); r.setNodeId(nodeId); r.setCanEdit(canEdit); returnSet.add(r); } if(hasAccessAdmin){ AccessSearchResult r = new AccessSearchResult(); r.setId(id); r.setEid(eid); r.setDisplayName(displayName); r.setSortName(sortName); r.setType(DelegatedAccessConstants.TYPE_ACCESS_ADMIN); r.setLevel(level); r.setHierarchyNodes(hierarchy); r.setNodeId(nodeId); r.setCanEdit(canEdit); returnSet.add(r); } } } } } } } return returnSet; } public void removeAccess(String nodeId, String userId, int accessType){ NodeModel model = getNodeModel(nodeId, userId); if(model != null){ switch (accessType) { case DelegatedAccessConstants.TYPE_ACCESS: model.setDirectAccess(false); break; case DelegatedAccessConstants.TYPE_ACCESS_SHOPPING_PERIOD_USER: model.setShoppingPeriodAdmin(false); break; case DelegatedAccessConstants.TYPE_ACCESS_ADMIN: model.setAccessAdmin(false); break; } updateNodePermissionsForUser(model, userId); syncMyworkspaceToolForUser(userId); } } public void removeAllPermsForUser(String userId){ boolean updated = false; for(HierarchyNodeSerialized n : getAllNodesForUser(userId)){ NodeModel model = getNodeModel(n.id, userId); if(model != null){ model.setDirectAccess(false); model.setShoppingPeriodAdmin(false); model.setAccessAdmin(false); updateNodePermissionsForUser(model, userId); updated = true; } } syncMyworkspaceToolForUser(userId); } }