All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sakaiproject.site.impl.JoinSiteDelegate Maven / Gradle / Ivy

There is a newer version: 23.3
Show newest version
package org.sakaiproject.site.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.sakaiproject.authz.api.SecurityAdvisor;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.api.ResourcePropertiesEdit;
import org.sakaiproject.site.api.AllowedJoinableAccount;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.user.api.UserDirectoryService;

/**
 * Contains methods used to join a site and to check for the different join options and restrictions.
 * @author sfoster
 */
public class JoinSiteDelegate
{
    // apis
    private SiteService             siteService;
    private SecurityService         securityService;
    private UserDirectoryService    userDirectoryService;

    // class members
    private static Log          log                             = LogFactory.getLog(JoinSiteDelegate.class);
    private static final String COMMA_DELIMITER					= ",";										// Comma delimiter (for csv parsing)
    private static final String JOINSITE_GROUP_NO_SELECTION		= "noSelection";							// The value of the joiner group site
	private static final String SAK_PERM_SITE_UPD				= "site.upd";								// The name of the site update permission

    // sakai.properties
    private static final String SAK_PROP_JOIN_GROUP_ENABLED 			= "sitemanage.join.joinerGroup.enabled";
   	private static final String SAK_PROP_JOIN_LIMIT_ACCOUNT_TYPES 		= "sitemanage.join.limitAccountTypes.enabled";
  	private static final String SAK_PROP_JOIN_ACCOUNT_TYPES	 			= "sitemanage.join.allowedJoinableAccountTypes";
	private static final String SAK_PROP_JOIN_ACCOUNT_TYPE_LABELS		= "sitemanage.join.allowedJoinableAccountTypeLabels";
	private static final String SAK_PROP_JOIN_ACCOUNT_TYPE_CATEGORIES	= "sitemanage.join.allowedJoinableAccountTypeCategories";
    private static final String SAK_PROP_JOIN_EXCLUDE_FROM_PUBLIC_LIST 	= "sitemanage.join.excludeFromPublicList.enabled";
    private static final String SAK_PROP_SITE_BROWSER_JOIN_ENABLED		= "sitebrowser.join.enabled";
    
    // site properties
   	private static final String SITE_PROP_JOIN_LIMIT_OFFICIAL 	= "joinLimitByAccountType";					// The name (key) of the join limit official site property
    private static final String SITE_PROP_JOIN_ACCOUNT_TYPES 	= "joinLimitedAccountTypes";				// The name (key) of the limit join to account types site property
    private static final String SITE_PROP_JOINSITE_GROUP_ID 	= "joinerGroup";							// The name (key) of the joiner group site property
    
    // global switches
	private static final boolean GLOBAL_JOIN_GROUP_ENABLED					= ServerConfigurationService.getBoolean( SAK_PROP_JOIN_GROUP_ENABLED, Boolean.FALSE );
	private static final boolean GLOBAL_JOIN_EXCLUDE_FROM_PUBLIC_ENABLED	= ServerConfigurationService.getBoolean( SAK_PROP_JOIN_EXCLUDE_FROM_PUBLIC_LIST, Boolean.FALSE );
	private static       boolean GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED	= ServerConfigurationService.getBoolean( SAK_PROP_JOIN_LIMIT_ACCOUNT_TYPES, Boolean.FALSE );
	private static final boolean GLOBAL_SITE_BROWSER_JOIN_ENABLED			= ServerConfigurationService.getBoolean( SAK_PROP_SITE_BROWSER_JOIN_ENABLED, Boolean.FALSE );
    
    // account type lists
	private static List 					allowJoinableAccountTypes 			= new ArrayList();
	private static LinkedHashSet 			allowJoinableAccountTypeCategories	= new LinkedHashSet();
	private static List 	allowJoinableAccounts				= new ArrayList();
    private static final List accountTypes			= Arrays.asList(ArrayUtils.nullToEmpty(ServerConfigurationService.getStrings(SAK_PROP_JOIN_ACCOUNT_TYPES)));
    private static final List accountTypeLabels		= Arrays.asList(ArrayUtils.nullToEmpty(ServerConfigurationService.getStrings(SAK_PROP_JOIN_ACCOUNT_TYPE_LABELS)));
    private static final List accountTypeCategories	= Arrays.asList(ArrayUtils.nullToEmpty(ServerConfigurationService.getStrings(SAK_PROP_JOIN_ACCOUNT_TYPE_CATEGORIES)));
    
    /**
     * Default zero-arg constructor; check/verify limit by account type global switch and lists
     * 
     * @author [email protected]
     */
    public JoinSiteDelegate( SiteService siteService, SecurityService securityService, UserDirectoryService userDirectoryService )
    {
    	// Assign the APIs
    	this.siteService 			= siteService;
    	this.securityService 		= securityService;
    	this.userDirectoryService 	= userDirectoryService;
    	
    	// If join limit by account types is enabled globally in sakai.properties, check to make sure the lists are actually valid
    	if( GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED )
    	{
	        // If any of the lists are null, empty or of differing sizes, it is invalid; flip the global switch to disabled
	        if( ( accountTypes == null || accountTypeCategories == null || accountTypeLabels == null ) ||
	        		( accountTypes.isEmpty() || accountTypeCategories.isEmpty() || accountTypeLabels.isEmpty() ) ||
	        		( accountTypeCategories.size() != accountTypes.size() || accountTypeCategories.size() != accountTypeLabels.size() ) )
	        {
	        	GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED = false;
	        	log.warn( "The sakai.properties for allowed joinabel account types are invalid " + 
	                    "(sitmanage.join.allowedJoinableAccountTypeCategories, sitemanage.join.allowedJoinableAccountTypes, " +
	                    "sitemanage.join.allowedJoinableAccountTypeLabels). This option is now disabled globally." );
	        }
    	}
    	
    	// If join limit by account types is still enabled globally, initialize the 'friendly' list
    	if( GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED )
    	{
    		// Initialize the 'friendly' lists
			allowJoinableAccountTypes.addAll( accountTypes );
	        allowJoinableAccountTypeCategories.addAll( accountTypeCategories );
	        for( int i = 0; i < accountTypeCategories.size(); ++i )
            {
	        	allowJoinableAccounts.add( new AllowedJoinableAccount( allowJoinableAccountTypes.get( i ), accountTypeLabels.get( i ), accountTypeCategories.get( i ) ) );
            }
    	}
    }
    
    /**
     * Get the list of allowed account type categories
     * 
     * @author [email protected]
     * @return list of strings (allowed account type categories)
     */
    public LinkedHashSet getAllowedJoinableAccountTypeCategories()
    {
    	return JoinSiteDelegate.allowJoinableAccountTypeCategories;
    }
    
    /**
     * Get the list of (unfriendly) allowed account types
     * 
     * @author [email protected]
     * @return list of strings (allowed account type keys)
     */
    public List getAllowedJoinableAccountTypes()
    {
    	return JoinSiteDelegate.allowJoinableAccountTypes;
    }
    
    /**
     * Get the 'friendly' list of AllowedJoinableAccount objects
     * 
     * @author [email protected]
     * @return
     */
    public List getAllowedJoinableAccounts()
    {
    	return JoinSiteDelegate.allowJoinableAccounts;
    }
    
    /**
     * Get the global joiner group enabled setting
     * 
     * @author [email protected]
     * @return true/false (enabled/disabled)
     */
    public boolean getGlobalJoinGroupEnabled()
    {
    	return JoinSiteDelegate.GLOBAL_JOIN_GROUP_ENABLED;
    }
    
    /**
     * Get the global join exclude from public list enabled setting
     * 
     * @author [email protected]
     * @return true/false (enabled/disabled)
     */
    public boolean getGlobalJoinExcludeFromPublicListEnabled()
    {
    	return JoinSiteDelegate.GLOBAL_JOIN_EXCLUDE_FROM_PUBLIC_ENABLED;
    }
    
    /**
     * Get the global join limit by account type enabled setting
     * 
     * @author [email protected]
     * @return true/false (enabled/disabled)
     */
    public boolean getGlobalJoinLimitByAccountTypeEnabled()
    {
    	return JoinSiteDelegate.GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED;
    }
    
    /**
     * Get the global site browser join enabled setting
     * 
     * @author [email protected]
     * @return true/false (enabled/disabled)
     */
    public boolean getGlobalSiteBrowserJoinEnabled()
    {
    	return JoinSiteDelegate.GLOBAL_SITE_BROWSER_JOIN_ENABLED;
    }
    
    /** 
     * Check if the system has restricted account types enabled as a joining option. If so,
     * check if the current user has allowed account type to join the worksite.
     * 
     * @param site 
     * 		The worksite to check the current user's ability to join against
     * @return true if either restricted account type join option is disabled at the system level, or if user has one of the site's allowed account type 
     */
    public boolean isAllowedToJoin(Site site)
    {
        // get current user
        User user = userDirectoryService.getCurrentUser();
        if(user == null || site == null)
        {
            return false;
        }
        
        // check first if account types are limited; if not, user is allowed (that is, user isn't being restricted)
    	// otherwise, check if the user's account type is an allowed joinable account type for the site
        return !isLimitByAccountTypeEnabled(site.getId()) || hasAllowedAccountTypeToJoin(user, site);
    }
    
    /**
     * Checks if the system and the provided site allows account types of joining users to be limited
     * 
     * @param siteID 
     * 		The site to check if the join system will limit users to allowed account types
     * @return true if the join site is limiting account types
     */
	public boolean isLimitByAccountTypeEnabled(String siteID)
	{
		if(siteID == null || StringUtils.isBlank(siteID))
		{
			return false;
		}
		
        // if the system allows joinable systems to limit on account type and the account types lists are valid
		if(GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED)
        {
            // get the site's property to determine if the site is restricted by account type
            return getBooleanSiteProperty(siteID, SITE_PROP_JOIN_LIMIT_OFFICIAL);
        }
		else
        {
			return false;
        }
	}
    
    /**
     * Get a site's group id for the group that a joiner will be added to upon joining a site, if enabled
     * 
     * @author [email protected], [email protected]
     * @param site 
     * 		Site to get current joiner group from
     * @return joinGroupId string representing the group id of the group that a joining user will be added to upon joining a site; the string "noSelection" represents no joiner group
     */
    public String getJoinGroupId(Site site)
    {
        // set group id to default no selection string
        String joinGroupId = JOINSITE_GROUP_NO_SELECTION;

        if(site != null)
        {
            // get the site's properties
            ResourceProperties rp = site.getProperties();
            
            // get the group id property
            if(rp != null)
            {
            	joinGroupId = rp.getProperty(SITE_PROP_JOINSITE_GROUP_ID);
            }
            
            // If the group was not found or the group id is null or empty (and the joiner group ID is not the 'noSelection' string), 
            // revert the site property to the "noSelection" setting
            if(!JOINSITE_GROUP_NO_SELECTION.equals(joinGroupId) && site.getGroup(joinGroupId) == null)
            {
                ResourcePropertiesEdit rpe = site.getPropertiesEdit();
                rpe.addProperty(SITE_PROP_JOINSITE_GROUP_ID, JOINSITE_GROUP_NO_SELECTION);
                joinGroupId = JOINSITE_GROUP_NO_SELECTION;

                try
                {
                    siteService.save(site);
                }
                catch(Exception e)
                {
                    log.error("Site " + site.getId() + " could not be saved during adding joiner to join group: " + e.getMessage(), e);
                }
            }
        }

        return joinGroupId;
    }
    
    /** 
     * Adds current user to provided site
     * 
     * @param site 
     * 		Site to add current user to
     */
    public void addJoinerToGroup(Site site)
    {
    	// can't add joiner to a site that doesn't exist
        if(site == null)
        {
        	return;
        }
    	
    	// can't add joiner to a group if they're not a member of the site
        if(!siteService.isCurrentUserMemberOfSite(site.getId()))
        {
        	return;
        }
        
        // Create the SecurityAdvisor (elevated permissions needed to use add members)
        SecurityAdvisor yesMan = new SecurityAdvisor()
        {
            @Override
            public SecurityAdvice isAllowed(String userID, String function, String reference)
            {
                // get permission to update the site
                if(SAK_PERM_SITE_UPD.equalsIgnoreCase(function))
                {
                    return SecurityAdvice.ALLOWED;
                }
                else
                {
                    return SecurityAdvice.PASS;
                }
            }
        };

        try
        {
            // Push the security advisor onto the stack
            securityService.pushAdvisor(yesMan);

            // check if the site has the join group property enabled
            if(GLOBAL_JOIN_GROUP_ENABLED);
            {
                //get joiner group id
                String joinerGroupId = getJoinGroupId(site);

                // if the joiner group is found
                if(joinerGroupId != null && !JOINSITE_GROUP_NO_SELECTION.equals(joinerGroupId))
                {
                    try 
                    {
                    	User user = userDirectoryService.getCurrentUser();
                    	if( user == null )
                    	{
                    		throw new UserNotDefinedException( "No user is logged in" );
                    	}
                    	
                    	// try adding the user to the group
                        site.getGroup(joinerGroupId).addMember(user.getId(), site.getJoinerRole(), true, false);
                        siteService.saveGroupMembership(site);
                    }
                    catch(Exception e)
                    {
                        log.error("Join group not found during site join: " + e.getMessage(), e);
                    }
                }
            }
        }
        finally
        {
            // pop the Security Advisor off no matter what happens
            securityService.popAdvisor(yesMan);
        }
    }    
    
    /**
     * Helper method to get the value of a boolean property
     * 
     * @param siteID 
     * 		The site to retrieve the property from
     * @param propertyName 
     * 		The boolean property name to retrieve
     * @return true if the boolean property is found and is set to true
     */
    private boolean getBooleanSiteProperty(String siteID, String propertyName)
    {
        try 
        {
            // for example, return the site property called 'joinLimitOfficial' (boolean)
            Site site = siteService.getSite(siteID);
            ResourceProperties props = site.getProperties();
            return props.getBooleanProperty(propertyName);
        }
        catch(Exception e)
        {
            log.debug(String.format("Error retrieving property %s from site %s ", propertyName, siteID), e);
        }
        return false;
    }
        
    /**
     * Check if the user's account type is an allowed joinable account type for the site
     * 
     * @param user 
     * 		User to check account type
     * @param site 
     * 		Site to check for account types
     * @return true if user's account type matches one of the site's allowed account types
     */
	private boolean hasAllowedAccountTypeToJoin(User user, Site site)
	{
		if(user == null || site == null)
		{
			return false;
		}
		
		if(!GLOBAL_JOIN_LIMIT_BY_ACCOUNT_TYPE_ENABLED)
		{
			return true;
		}
		
        try 
        { 
            // checks to see if the user's account type is in the allowed joinable account types for this site
            ResourceProperties rp = site.getProperties();
            String csv = rp.getProperty(SITE_PROP_JOIN_ACCOUNT_TYPES);

            if(csv != null)
            {
                List accntTypes = Arrays.asList(csv.split(COMMA_DELIMITER));
                
                // if the current user has an allowed user types to join this site, as chosen by the site maintainer
                return accntTypes.contains(user.getType());
            }
        }
        catch( Exception e ) 
        { 
            log.error( "Error occurred when checking if user has the allowed account type: " + e.getMessage(), e ); 
        }

        return false;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy