<commit_before>/**
 * $URL$
 * $Id$
 *
 * Copyright (c) 2006-2009 The Sakai Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *             http://www.osedu.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.sakaiproject.basiclti.util;

import java.util.Properties;
import java.util.Map;
import java.net.URL;

import org.imsglobal.basiclti.BasicLTIUtil;
import org.imsglobal.basiclti.BasicLTIConstants;
import org.sakaiproject.linktool.LinkToolUtil;

import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.cover.UserDirectoryService;
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.tool.api.Placement;
import org.sakaiproject.authz.cover.SecurityService;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.cover.SiteService;
import org.sakaiproject.authz.cover.AuthzGroupService;
import org.sakaiproject.authz.api.AuthzGroup;
import org.sakaiproject.authz.api.GroupNotDefinedException;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.Web;

/**
 * Some Sakai Utility code for IMS Basic LTI
 * This is mostly code to support the Sakai conventions for 
 * making and launching BLTI resources within Sakai.
 */
@SuppressWarnings("deprecation")
public class SakaiBLTIUtil {

	public static final boolean verbosePrint = false;

	public static final String BASICLTI_OUTCOMES_ENABLED = "basiclti.outcomes.enabled";
	public static final String BASICLTI_SETTINGS_ENABLED = "basiclti.settings.enabled";
	public static final String BASICLTI_ROSTER_ENABLED = "basiclti.roster.enabled";
	public static final String BASICLTI_CONTENTLINK_ENABLED = "basiclti.contentlink.enabled";

	public static void dPrint(String str)
	{
		if ( verbosePrint ) System.out.println(str);
	}

	// Retrieve the property from the configuration unless it
	// is overridden by the server configurtation (i.e. sakai.properties)
	public static String getCorrectProperty(Properties config,
			String propName, Placement placement)
	{
		// Check for global overrides in properties
		String allowSettings = ServerConfigurationService.getString(BASICLTI_SETTINGS_ENABLED, null);
		if ( "allowsettings".equals(propName) && ! "true".equals(allowSettings) ) return "false";

		String allowRoster = ServerConfigurationService.getString(BASICLTI_ROSTER_ENABLED, null);
		if ( "allowroster".equals(propName) && ! "true".equals(allowRoster) ) return "false";

		String allowContentLink = ServerConfigurationService.getString(BASICLTI_CONTENTLINK_ENABLED, null);
		if ( "contentlink".equals(propName) && ! "true".equals(allowContentLink) ) return null;

		// Check for explicit setting in properties
		String propertyName = placement.getToolId() + "." + propName;
		String propValue = ServerConfigurationService.getString(propertyName,null);
		if ( propValue != null && propValue.trim().length() > 0 ) {
			// System.out.println("Sakai.home "+propName+"="+propValue);
			return propValue;
		}

		// Take it from the placement
		return config.getProperty("imsti."+propName, null);
	}

	// Look at a Placement and come up with the launch urls, and
	// other launch parameters to drive the launch.
	public static boolean loadFromPlacement(Properties info, Properties launch, Placement placement)
	{
		Properties config = placement.getConfig();
		dPrint("Sakai properties=" + config);
		String launch_url = toNull(getCorrectProperty(config,"launch", placement));
		setProperty(info, "launch_url", launch_url);
		if ( launch_url == null ) {
			String xml = toNull(getCorrectProperty(config,"xml", placement));
			if ( xml == null ) return false;
			BasicLTIUtil.parseDescriptor(info, launch, xml);
		}
		setProperty(info, "secret", getCorrectProperty(config,"secret", placement) );
		setProperty(info, "key", getCorrectProperty(config,"key", placement) );
		setProperty(info, "debug", getCorrectProperty(config,"debug", placement) );
		setProperty(info, "frameheight", getCorrectProperty(config,"frameheight", placement) );
		setProperty(info, "newpage", getCorrectProperty(config,"newpage", placement) );
		setProperty(info, "title", getCorrectProperty(config,"tooltitle", placement) );

		// Pull in and parse the custom parameters
		String customstr = toNull(getCorrectProperty(config,"custom", placement) );
		parseCustom(info, customstr);

		if ( info.getProperty("launch_url", null) != null || 
				info.getProperty("secure_launch_url", null) != null ) {
			return true;
		}
		return false;
	}

	public static void parseCustom(Properties info, String customstr)
	{
		if ( customstr != null ) {
			String [] params = customstr.split("[\n;]");
			for (int i = 0 ; i < params.length; i++ ) {
				String param = params[i];
				if ( param == null ) continue;
				if ( param.length() < 1 ) continue;
				int pos = param.indexOf("=");
				if ( pos < 1 ) continue;
				if ( pos+1 > param.length() ) continue;
				String key = BasicLTIUtil.mapKeyName(param.substring(0,pos));
				if ( key == null ) continue;
				String value = param.substring(pos+1);
                if ( value == null ) continue;
				value = value.trim();
				if ( value.length() < 1 ) continue;
				setProperty(info, "custom_"+key, value);
			}
		}
	}

	public static boolean sakaiInfo(Properties props, Placement placement, ResourceLoader rb)
	{
		dPrint("placement="+ placement.getId());
		dPrint("placement title=" + placement.getTitle());
		String context = placement.getContext();
		dPrint("ContextID="+context);

		return sakaiInfo(props, context, placement.getId(), rb);
	}

	public static void addSiteInfo(Properties props, Site site)
	{
		if ( site != null ) {
			String context_type = site.getType();
			if ( context_type != null && context_type.toLowerCase().contains("course") ){
				setProperty(props,BasicLTIConstants.CONTEXT_TYPE,BasicLTIConstants.CONTEXT_TYPE_COURSE_SECTION);
			}
			setProperty(props,BasicLTIConstants.CONTEXT_ID,site.getId());
			setProperty(props,BasicLTIConstants.CONTEXT_LABEL,site.getTitle());
			setProperty(props,BasicLTIConstants.CONTEXT_TITLE,site.getTitle());
			String courseRoster = getExternalRealmId(site.getId());
			if ( courseRoster != null ) 
			{
				setProperty(props,BasicLTIConstants.LIS_COURSE_OFFERING_SOURCEDID,courseRoster);
			}
		}
	}

	public static void addRoleInfo(Properties props, String context)
	{
		String theRole = "Learner";
		if ( SecurityService.isSuperUser() )
		{
			theRole = "Instructor";
		}
		else if ( SiteService.allowUpdateSite(context) ) 
		{
			theRole = "Instructor";
		}
		setProperty(props,"roles",theRole);
	}

	// Retrieve the Sakai information about users, etc.
	public static boolean sakaiInfo(Properties props, String context, String placementId, ResourceLoader rb)
	{

		Site site = null;
		try {
			site = SiteService.getSite(context);
		} catch (Exception e) {
			dPrint("No site/page associated with Launch context="+context);
			return false;
		}<commit_msg>BLTI-131 BLTI-145<commit_after>/**
 * $URL$
 * $Id$
 *
 * Copyright (c) 2006-2009 The Sakai Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *             http://www.osedu.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.sakaiproject.basiclti.util;

import java.util.Properties;
import java.util.Map;
import java.net.URL;

import org.imsglobal.basiclti.BasicLTIUtil;
import org.imsglobal.basiclti.BasicLTIConstants;
import org.sakaiproject.linktool.LinkToolUtil;

import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.cover.UserDirectoryService;
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.tool.api.Placement;
import org.sakaiproject.authz.cover.SecurityService;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.cover.SiteService;
import org.sakaiproject.authz.cover.AuthzGroupService;
import org.sakaiproject.authz.api.AuthzGroup;
import org.sakaiproject.authz.api.Role;
import org.sakaiproject.authz.api.GroupNotDefinedException;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.Web;

/**
 * Some Sakai Utility code for IMS Basic LTI
 * This is mostly code to support the Sakai conventions for 
 * making and launching BLTI resources within Sakai.
 */
@SuppressWarnings("deprecation")
public class SakaiBLTIUtil {

	public static final boolean verbosePrint = false;

	public static final String BASICLTI_OUTCOMES_ENABLED = "basiclti.outcomes.enabled";
	public static final String BASICLTI_SETTINGS_ENABLED = "basiclti.settings.enabled";
	public static final String BASICLTI_ROSTER_ENABLED = "basiclti.roster.enabled";
	public static final String BASICLTI_CONTENTLINK_ENABLED = "basiclti.contentlink.enabled";

	public static void dPrint(String str)
	{
		if ( verbosePrint ) System.out.println(str);
	}

	// Retrieve the property from the configuration unless it
	// is overridden by the server configurtation (i.e. sakai.properties)
	public static String getCorrectProperty(Properties config,
			String propName, Placement placement)
	{
		// Check for global overrides in properties
		String allowSettings = ServerConfigurationService.getString(BASICLTI_SETTINGS_ENABLED, null);
		if ( "allowsettings".equals(propName) && ! "true".equals(allowSettings) ) return "false";

		String allowRoster = ServerConfigurationService.getString(BASICLTI_ROSTER_ENABLED, null);
		if ( "allowroster".equals(propName) && ! "true".equals(allowRoster) ) return "false";

		String allowContentLink = ServerConfigurationService.getString(BASICLTI_CONTENTLINK_ENABLED, null);
		if ( "contentlink".equals(propName) && ! "true".equals(allowContentLink) ) return null;

		// Check for explicit setting in properties
		String propertyName = placement.getToolId() + "." + propName;
		String propValue = ServerConfigurationService.getString(propertyName,null);
		if ( propValue != null && propValue.trim().length() > 0 ) {
			// System.out.println("Sakai.home "+propName+"="+propValue);
			return propValue;
		}

		// Take it from the placement
		return config.getProperty("imsti."+propName, null);
	}

	// Look at a Placement and come up with the launch urls, and
	// other launch parameters to drive the launch.
	public static boolean loadFromPlacement(Properties info, Properties launch, Placement placement)
	{
		Properties config = placement.getConfig();
		dPrint("Sakai properties=" + config);
		String launch_url = toNull(getCorrectProperty(config,"launch", placement));
		setProperty(info, "launch_url", launch_url);
		if ( launch_url == null ) {
			String xml = toNull(getCorrectProperty(config,"xml", placement));
			if ( xml == null ) return false;
			BasicLTIUtil.parseDescriptor(info, launch, xml);
		}
		setProperty(info, "secret", getCorrectProperty(config,"secret", placement) );
		setProperty(info, "key", getCorrectProperty(config,"key", placement) );
		setProperty(info, "debug", getCorrectProperty(config,"debug", placement) );
		setProperty(info, "frameheight", getCorrectProperty(config,"frameheight", placement) );
		setProperty(info, "newpage", getCorrectProperty(config,"newpage", placement) );
		setProperty(info, "title", getCorrectProperty(config,"tooltitle", placement) );

		// Pull in and parse the custom parameters
		String customstr = toNull(getCorrectProperty(config,"custom", placement) );
		parseCustom(info, customstr);

		if ( info.getProperty("launch_url", null) != null || 
				info.getProperty("secure_launch_url", null) != null ) {
			return true;
		}
		return false;
	}

	public static void parseCustom(Properties info, String customstr)
	{
		if ( customstr != null ) {
			String [] params = customstr.split("[\n;]");
			for (int i = 0 ; i < params.length; i++ ) {
				String param = params[i];
				if ( param == null ) continue;
				if ( param.length() < 1 ) continue;
				int pos = param.indexOf("=");
				if ( pos < 1 ) continue;
				if ( pos+1 > param.length() ) continue;
				String key = BasicLTIUtil.mapKeyName(param.substring(0,pos));
				if ( key == null ) continue;
				String value = param.substring(pos+1);
                if ( value == null ) continue;
				value = value.trim();
				if ( value.length() < 1 ) continue;
				setProperty(info, "custom_"+key, value);
			}
		}
	}

	public static boolean sakaiInfo(Properties props, Placement placement, ResourceLoader rb)
	{
		dPrint("placement="+ placement.getId());
		dPrint("placement title=" + placement.getTitle());
		String context = placement.getContext();
		dPrint("ContextID="+context);

		return sakaiInfo(props, context, placement.getId(), rb);
	}

	public static void addSiteInfo(Properties props, Site site)
	{
		if ( site != null ) {
			String context_type = site.getType();
			if ( context_type != null && context_type.toLowerCase().contains("course") ){
				setProperty(props,BasicLTIConstants.CONTEXT_TYPE,BasicLTIConstants.CONTEXT_TYPE_COURSE_SECTION);
			}
			setProperty(props,BasicLTIConstants.CONTEXT_ID,site.getId());
			setProperty(props,BasicLTIConstants.CONTEXT_LABEL,site.getTitle());
			setProperty(props,BasicLTIConstants.CONTEXT_TITLE,site.getTitle());
			String courseRoster = getExternalRealmId(site.getId());
			if ( courseRoster != null ) 
			{
				setProperty(props,BasicLTIConstants.LIS_COURSE_OFFERING_SOURCEDID,courseRoster);
			}
		}
	}

	public static void addRoleInfo(Properties props, String context)
	{
		String theRole = "Learner";
		if ( SecurityService.isSuperUser() )
		{
			theRole = "Instructor,Administrator";
		}
		else if ( SiteService.allowUpdateSite(context) ) 
		{
			theRole = "Instructor";
		}
		setProperty(props,BasicLTIConstants.ROLES,theRole);

		String realmId = SiteService.siteReference(context);
		try {
			User user = UserDirectoryService.getCurrentUser();
			if ( user != null ) {
				Role role = null;
				String roleId = null;
				AuthzGroup realm = AuthzGroupService.getAuthzGroup(realmId);
				if ( realm != null ) role = realm.getUserRole(user.getId());
				if ( role != null ) roleId = role.getId();
				if ( roleId != null && roleId.length() > 0 ) setProperty(props, "ext_sakai_role", roleId);
			}
		} catch (GroupNotDefinedException e) {
			dPrint("SiteParticipantHelper.getExternalRealmId: site realm not found"+e.getMessage());
		}
	}

	// Retrieve the Sakai information about users, etc.
	public static boolean sakaiInfo(Properties props, String context, String placementId, ResourceLoader rb)
	{

		Site site = null;
		try {
			site = SiteService.getSite(context);
		} catch (Exception e) {
			dPrint("No site/page associated with Launch context="+context);
			return false;
		}
{'fraction_non_alphanumeric': 0.11494763567121549, 'fraction_numerical': 0.0029831799428752777, 'mean_word_length': 4.811877535964589, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5714813', 'n_tokens_mistral': 5169, 'n_tokens_neox': 4755, 'n_words': 1176}