/**
* $URL: https://source.sakaiproject.org/svn/basiclti/trunk/basiclti-portlet/src/java/org/sakaiproject/portlets/IMSBLTIPortlet.java $
* $Id: IMSBLTIPortlet.java 132825 2013-12-19 21:22:20Z csev@umich.edu $
*
* Copyright (c) 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.opensource.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.portlets;
import org.imsglobal.basiclti.BasicLTIUtil;
import java.lang.Integer;
import java.io.PrintWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URI;
import java.util.UUID;
import java.util.Properties;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Date;
import java.text.SimpleDateFormat;
import javax.portlet.GenericPortlet;
import javax.portlet.RenderRequest;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.RenderResponse;
import javax.portlet.PortletRequest;
import javax.portlet.PortletException;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletContext;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletConfig;
import javax.portlet.PortletMode;
import javax.portlet.PortletSession;
import javax.portlet.ReadOnlyException;
import javax.servlet.ServletRequest;
import org.sakaiproject.thread_local.cover.ThreadLocalManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.portlet.util.PortletHelper;
// Sakai APIs
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.tool.cover.ToolManager;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.tool.api.Placement;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SitePage;
import org.sakaiproject.site.cover.SiteService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.FormattedText;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.NotificationService;
//import org.sakaiproject.event.cover.EventTrackingService;
import org.sakaiproject.basiclti.LocalEventTrackingService;
import org.sakaiproject.basiclti.util.SakaiBLTIUtil;
import org.sakaiproject.basiclti.util.SimpleEncryption;
import org.sakaiproject.service.gradebook.shared.Assignment;
import org.sakaiproject.service.gradebook.shared.AssignmentHasIllegalPointsException;
import org.sakaiproject.service.gradebook.shared.CategoryDefinition;
import org.sakaiproject.service.gradebook.shared.GradebookService;
import org.sakaiproject.service.gradebook.shared.GradebookExternalAssessmentService;
import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException;
import org.sakaiproject.service.gradebook.shared.ConflictingExternalIdException;
import org.sakaiproject.service.gradebook.shared.GradebookNotFoundException;
/**
* a simple IMSBLTIPortlet Portlet
*/
@SuppressWarnings("deprecation")
public class IMSBLTIPortlet extends GenericPortlet {
private static ResourceLoader rb = new ResourceLoader("basiclti");
private PortletContext pContext;
private ArrayList<String> fieldList = new ArrayList<String>();
/** Our log (commons). */
private static Log M_log = LogFactory.getLog(IMSBLTIPortlet.class);
public static final String EVENT_BASICLTI_CONFIG = "basiclti.config";
private static String LEAVE_SECRET_ALONE = "__dont_change_secret__";
/** To turn on really verbose debugging */
private static boolean verbosePrint = false;
public static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ssz";
public final static String CURRENT_HTTP_REQUEST = "org.sakaiproject.util.RequestFilter.http_request";
public void init(PortletConfig config) throws PortletException {
super.init(config);
pContext = config.getPortletContext();
// Populate the list of fields
fieldList.add("launch");
fieldList.add("secret");
fieldList.add("key");
fieldList.add("xml");
fieldList.add("frameheight");
fieldList.add("debug");
fieldList.add("pagetitle");
fieldList.add("tooltitle");
fieldList.add("custom");
fieldList.add("releasename");
fieldList.add("releaseemail");
fieldList.add("assignment");
fieldList.add("newpage");
fieldList.add("maximize");
fieldList.add("allowsettings");
fieldList.add("allowroster");
fieldList.add("allowlori");
fieldList.add("contentlink");
fieldList.add("splash");
}
// Simple Debug Print Mechanism
public void dPrint(String str)
{
if ( verbosePrint ) System.out.println(str);
M_log.trace(str);
}
// If the property is final, the property wins. If it is not final,
// the portlet preferences take precedence.
public String getTitleString(RenderRequest request)
{
return getCorrectProperty(request, "tooltitle", null);
}
// Render the portlet - this is not supposed to change the state of the portlet
// Render may be called many times so if it changes the state - that is tacky
// Render will be called when someone presses "refresh" or when another portlet
// on the same page is handed an Action.
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
dPrint("==== doView called ====");
response.setContentType("text/html; charset=UTF-8");
// Grab that underlying request to get a GET parameter
ServletRequest req = (ServletRequest) ThreadLocalManager.get(CURRENT_HTTP_REQUEST);
String popupDone = req.getParameter("sakai.popup");
PrintWriter out = response.getWriter();
String title = getTitleString(request);
if ( title != null ) response.setTitle(title);
String context = getContext();
Placement placement = ToolManager.getCurrentPlacement();
// Get the properties
Properties sakaiProperties = getSakaiProperties();
String placementSecret = getSakaiProperty(sakaiProperties,"imsti.placementsecret");
String allowOutcomes = getSakaiProperty(sakaiProperties,"imsti.allowoutcomes");
String allowSettings = getSakaiProperty(sakaiProperties,"imsti.allowsettings");
String allowRoster = getSakaiProperty(sakaiProperties,"imsti.allowroster");
String allowLORI = getSakaiProperty(sakaiProperties,"imsti.allowlori");
String assignment = getSakaiProperty(sakaiProperties,"imsti.assignent");
String launch = getSakaiProperty(sakaiProperties,"imsti.launch");
if ( placementSecret == null &&
( "on".equals(allowOutcomes) || "on".equals(allowSettings) ||
"on".equals(allowRoster) || "on".equals(allowLORI) ) ) {
String uuid = UUID.randomUUID().toString();
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);
String date_secret = sdf.format(date);
placement.getPlacementConfig().setProperty("imsti.placementsecret", uuid);
placement.getPlacementConfig().setProperty("imsti.placementsecretdate", date_secret);
placement.save();
}
// Check to see if our launch will be successful
String[] retval = SakaiBLTIUtil.postLaunchHTML(placement.getId(), rb);
if ( retval.length > 1 ) {
String iframeUrl = "/access/basiclti/site/"+context+"/"+placement.getId();
String frameHeight = getCorrectProperty(request, "frameheight", null);
dPrint("fh="+frameHeight);
String newPage = getCorrectProperty(request, "newpage", null);
String serverUrl = ServerConfigurationService.getServerUrl();
boolean forcePopup = false;
if ( request.isSecure() || ( serverUrl != null && serverUrl.startsWith("https://") ) ) {
if ( launch != null && launch.startsWith("http://") ) {
forcePopup = true;
}
}
// Change "newpage" if forcePopup so the portal will do our pop up next time
if ( forcePopup && ! "on".equals(newPage) ) {
placement.getPlacementConfig().setProperty("imsti.newpage","on");
placement.save();
}
String maximize = getCorrectProperty(request, "maximize", null);
StringBuffer text = new StringBuffer();
Session session = SessionManager.getCurrentSession();
session.setAttribute("sakai:maximized-url",iframeUrl);
dPrint("Setting sakai:maximized-url="+iframeUrl);
if ( "on".equals(newPage) || forcePopup ) {
String windowOpen = "window.open('"+iframeUrl+"','BasicLTI');";
if ( popupDone == null ) {
text.append("<p>\n");
text.append("<script type=\"text/javascript\">\n");
text.append(windowOpen+"\n");
text.append("</script>\n");
}
text.append(rb.getString("new.page.launch"));
text.append("<br><a href=\""+iframeUrl+"\" onclick=\""+windowOpen+"\" target=\"BasicLTI\">"+rb.getString("noiframe.press.here")+"</a>");
text.append("</p>\n");
} else {
if ( "on".equals(maximize) ) {
text.append("<script type=\"text/javascript\" language=\"JavaScript\">\n");
text.append("try { portalMaximizeTool(); } catch (err) { }\n");
text.append("</script>\n");
}
text.append("<iframe ");
if ( frameHeight == null ) frameHeight = "1200";
text.append("height=\""+frameHeight+"\" \n");
text.append("width=\"100%\" frameborder=\"0\" marginwidth=\"0\"\n");
text.append("marginheight=\"0\" scrolling=\"auto\"\n");
text.append("src=\""+iframeUrl+"\">\n");
text.append(rb.getString("noiframes"));
text.append("<br>");
text.append("<a href=\""+iframeUrl+"\">");
text.append(rb.getString("noiframe.press.here"));
text.append("</a>\n");
text.append("</iframe>");
}
out.println(text);
dPrint("==== doView complete ====");
return;
} else {
out.println(rb.getString("not.configured"));
}
clearErrorMessage(request);
dPrint("==== doView complete ====");
}
// Prepare the edit screen with data
public void prepareEdit(RenderRequest request)
{
// Hand up the tool properties
Placement placement = ToolManager.getCurrentPlacement();
Properties config = placement.getConfig();
dPrint("placement="+ placement.getId());
dPrint("placement.toolId="+ placement.getToolId());
dPrint("properties="+ config);
for (String element : fieldList) {
String propertyName = placement.getToolId() + "." + element;
String propValue = ServerConfigurationService.getString(propertyName,null);
if ( "splash".equals(element) && propValue == null ) {
propValue = ServerConfigurationService.getString(placement.getToolId() + ".overridesplash",null);
}
if ( propValue != null && propValue.trim().length() > 0 ) {
dPrint("Forcing Final = "+propertyName);
config.setProperty("final."+element,"true");
}
}
request.setAttribute("imsti.properties", config);
// Hand up the old values
Properties oldValues = new Properties();
Map map = getErrorMap(request);
String errorMsg = getErrorMessage(request);
request.setAttribute("error.message", errorMsg);
addProperty(oldValues, request, "launch", "");
for (String element : fieldList) {
if ( "launch".equals(element) ) continue;
String propKey = "imsti."+element;
// addProperty(oldValues, request, element, null);
String propValue = getCorrectProperty(request, element, null);
if ( map != null ) {
if ( map.containsKey(propKey) ) {
Object obj = null;
try {
String[] arr = (String []) map.get(propKey);
obj = arr[0];
} catch(Exception e) {
obj = null;
}
if ( obj instanceof String ) propValue = (String) obj;
}
}
if ( propValue != null ) {
if ( "xml".equals(element)) {
propValue = propValue.replace("&","&");
}
if ( "secret".equals(element)) {
propValue = LEAVE_SECRET_ALONE;
}
oldValues.setProperty(propKey, FormattedText.escapeHtml(propValue,false));
}
}
request.setAttribute("imsti.oldvalues", oldValues);
String allowSettings = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_SETTINGS_ENABLED, SakaiBLTIUtil.BASICLTI_SETTINGS_ENABLED_DEFAULT);
request.setAttribute("allowSettings", new Boolean("true".equals(allowSettings)));
String allowRoster = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_ROSTER_ENABLED, SakaiBLTIUtil.BASICLTI_ROSTER_ENABLED_DEFAULT);
request.setAttribute("allowRoster", new Boolean("true".equals(allowRoster)));
String allowContentLink = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_CONTENTLINK_ENABLED, SakaiBLTIUtil.BASICLTI_CONTENTLINK_ENABLED_DEFAULT);
request.setAttribute("allowContentLink", new Boolean("true".equals(allowContentLink)));
// For outcomes and LORI we check for tools in the site before offering the options
String allowOutcomes = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_OUTCOMES_ENABLED, SakaiBLTIUtil.BASICLTI_OUTCOMES_ENABLED_DEFAULT);
String allowLori = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_LORI_ENABLED, SakaiBLTIUtil.BASICLTI_LORI_ENABLED_DEFAULT);
boolean foundLessons = false;
boolean foundGradebook = false;
ToolConfiguration toolConfig = SiteService.findTool(placement.getId());
try {
Site site = SiteService.getSite(toolConfig.getSiteId());
for (SitePage page : (List<SitePage>)site.getPages()) {
for(ToolConfiguration tool : (List<ToolConfiguration>) page.getTools()) {
String tid = tool.getToolId();
if ( "sakai.lessonbuildertool".equals(tid) ) foundLessons = true;
if ( "sakai.gradebook.tool".equals(tid) || "sakai.gradebook.gwt.rpc".equals(tid) ) foundGradebook = true;
}
}
} catch (IdUnusedException ex) {
M_log.warn("Could not load site.");
}
if ( ! foundLessons ) allowLori = "false";
if ( ! foundGradebook ) allowOutcomes = "false";
request.setAttribute("allowOutcomes", new Boolean("true".equals(allowOutcomes)));
request.setAttribute("allowLori", new Boolean("true".equals(allowLori)));
if ( "true".equals(allowOutcomes) ) {
List<String> assignments = getGradeBookAssignments();
if ( assignments != null && assignments.size() > 0 ) request.setAttribute("assignments", assignments);
}
clearErrorMessage(request);
}
public void addProperty(Properties values, RenderRequest request,
String propName, String defaultValue)
{
String propValue = getCorrectProperty(request, propName, defaultValue);
if ( propValue != null ) {
values.setProperty("imsti."+propName,propValue);
}
}
// Get Property - Precedence is frozen server configuration, sakai tool properties,
// portlet preferences, sakai tool properties, and then default
public String getCorrectProperty(PortletRequest request, String propName, String defaultValue)
{
Placement placement = ToolManager.getCurrentPlacement();
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;
}
Properties config = placement.getConfig();
propValue = getSakaiProperty(config, "imsti."+propName);
if ( propValue != null && "true".equals(config.getProperty("final."+propName)) )
{
// System.out.println("Frozen "+propName+" ="+propValue);
return propValue;
}
PortletPreferences prefs = request.getPreferences();
propValue = prefs.getValue("imsti."+propName, null);
if ( propValue != null ) {
// System.out.println("Portlet "+propName+" ="+propValue);
return propValue;
}
propValue = getSakaiProperty(config, "imsti."+propName);
if ( propValue != null ) {
// System.out.println("Tool "+propName+" ="+propValue);
return propValue;
}
if ( defaultValue != null ) {
// System.out.println("Default "+propName+" ="+defaultValue);
return propValue;
}
// System.out.println("Fell through "+propName);
return null;
}
// isPropertyFinal() - if it comes from the Server configuration or
// the final.propName is set to true
public boolean isPropertyFinal(String propName)
{
Placement placement = ToolManager.getCurrentPlacement();
String propertyName = placement.getToolId() + "." + propName;
String propValue = ServerConfigurationService.getString(propertyName,null);
if ( propValue != null && propValue.trim().length() > 0 ) {
return true;
}
Properties config = placement.getConfig();
propValue = getSakaiProperty(config, "imsti."+propName);
if ( propValue != null && "true".equals(config.getProperty("final."+propName)) )
{
return true;
}
return false;
}
public void doEdit(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
dPrint("==== doEdit called ====");
PortletSession pSession = request.getPortletSession(true);
String title = getTitleString(request);
if ( title != null ) response.setTitle(title);
// Debug
String inputData = (String) pSession.getAttribute("sakai.descriptor");
if ( inputData != null ) dPrint("descriptor.length()="+inputData.length());
String url = (String) pSession.getAttribute("sakai.url");
dPrint("sakai.url="+url);
String view = (String) pSession.getAttribute("sakai.view");
dPrint("sakai.view="+view);
if ( "edit.reset".equals(view) ) {
sendToJSP(request, response, "/editreset.jsp");
} else {
prepareEdit(request);
sendToJSP(request, response, "/edit.jsp");
}
clearErrorMessage(request);
dPrint("==== doEdit called ====");
}
public void doHelp(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
dPrint("==== doHelp called ====");
String title = getTitleString(request);
if ( title != null ) response.setTitle(title);
sendToJSP(request, response, "/help.jsp");
clearErrorMessage(request);
dPrint("==== doHelp done ====");
}
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException {
dPrint("==== processAction called ====");
String action = request.getParameter("sakai.action");
dPrint("sakai.action = "+action);
PortletSession pSession = request.getPortletSession(true);
// Clear before Action
clearErrorMessage(request);
String view = (String) pSession.getAttribute("sakai.view");
dPrint("sakai.view="+view);
if ( action == null ) {
// Do nothing
} else if ( action.equals("main") ) {
response.setPortletMode(PortletMode.VIEW);
} else if ( action.equals("edit") ) {
pSession.setAttribute("sakai.view", "edit");
} else if ( action.equals("edit.reset") ) {
pSession.setAttribute("sakai.view","edit.reset");
} else if (action.equals("edit.setup")){
pSession.setAttribute("sakai.view","edit.setup");
} else if ( action.equals("edit.clear") ) {
clearSession(request);
response.setPortletMode(PortletMode.VIEW);
pSession.setAttribute("sakai.view", "main");
} else if ( action.equals("edit.do.reset") ) {
processActionReset(action,request, response);
} else if ( action.equals("edit.save") ) {
processActionSave(action,request, response);
}
dPrint("==== End of ProcessAction ====");
}
private void clearSession(PortletRequest request)
{
PortletSession pSession = request.getPortletSession(true);
pSession.removeAttribute("sakai.url");
pSession.removeAttribute("sakai.widget");
pSession.removeAttribute("sakai.descriptor");
pSession.removeAttribute("sakai.attemptdescriptor");
for (String element : fieldList) {
pSession.removeAttribute("sakai."+element);
}
}
public void processActionReset(String action,ActionRequest request, ActionResponse response)
throws PortletException, IOException {
// TODO: Check Role
dPrint("Removing preferences....");
clearSession(request);
PortletSession pSession = request.getPortletSession(true);
PortletPreferences prefs = request.getPreferences();
try {
prefs.reset("sakai.descriptor");
for (String element : fieldList) {
prefs.reset("imsti."+element);
prefs.reset("sakai:imsti."+element);
}
dPrint("Preference removed");
} catch (ReadOnlyException e) {
setErrorMessage(request, rb.getString("error.modify.prefs")) ;
return;
}
prefs.store();
// Go back to the main edit page
pSession.setAttribute("sakai.view", "edit");
}
public void processActionEdit(String action,ActionRequest request, ActionResponse response)
throws PortletException, IOException {
}
public Properties getSakaiProperties()
{
Placement placement = ToolManager.getCurrentPlacement();
return placement.getConfig();
}
// Empty or all whitespace properties are null
public String getSakaiProperty(Properties config, String key)
{
String propValue = config.getProperty(key);
if ( propValue != null && propValue.trim().length() < 1 ) propValue = null;
return propValue;
}
// Insure that if we have frozen properties - we never accept form data
public String getFormParameter(ActionRequest request, Properties sakaiProperties, String propName)
{
String propValue = getCorrectProperty(request, propName, null);
if ( propValue == null || ! isPropertyFinal(propName) )
{
propValue = request.getParameter("imsti."+propName);
}
dPrint("Form/Final imsti."+propName+"="+propValue);
if (propValue != null ) propValue = propValue.trim();
return propValue;
}
public void processActionSave(String action,ActionRequest request, ActionResponse response)
throws PortletException, IOException {
PortletSession pSession = request.getPortletSession(true);
Properties sakaiProperties = getSakaiProperties();
String imsType = getFormParameter(request,sakaiProperties,"type");
String imsTIUrl = getFormParameter(request,sakaiProperties,"launch");
if ( imsTIUrl != null && imsTIUrl.trim().length() < 1 ) imsTIUrl = null;
String imsTIXml = getFormParameter(request,sakaiProperties,"xml");
if ( imsTIXml != null && imsTIXml.trim().length() < 1 ) imsTIXml = null;
// imsType will be null if launch or xml is coming from final properties
if ( imsType != null ) {
if ( imsType.equalsIgnoreCase("XML") ) {
if ( imsTIXml != null ) imsTIUrl = null;
} else {
if ( imsTIUrl != null ) imsTIXml = null;
}
}
String launch_url = imsTIUrl;
if ( imsTIXml != null ) {
launch_url = BasicLTIUtil.validateDescriptor(imsTIXml);
if ( launch_url == null ) {
setErrorMessage(request, rb.getString("error.xml.input"));
return;
}
} else if ( imsTIUrl == null ) {
setErrorMessage(request, rb.getString("error.no.input") );
return;
} else if ( imsTIUrl.startsWith("http://") || imsTIUrl.startsWith("https://") ) {
try {
URL testUrl = new URL(imsTIUrl);
URI testUri = new URI(imsTIUrl);
}
catch(Exception e) {
setErrorMessage(request, rb.getString("error.bad.url") );
return;
}
} else {
setErrorMessage(request, rb.getString("error.bad.url") );
return;
}
// Prepare to store preferences
PortletPreferences prefs = request.getPreferences();
boolean changed = false;
// Make Sure the Assignment is a legal one
String assignment = getFormParameter(request,sakaiProperties,"assignment");
String newAssignment = getFormParameter(request,sakaiProperties,"newassignment");
String oldPlacementSecret = getSakaiProperty(sakaiProperties,"imsti.placementsecret");
String allowOutcomes = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_OUTCOMES_ENABLED, SakaiBLTIUtil.BASICLTI_OUTCOMES_ENABLED_DEFAULT);
String allowSettings = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_SETTINGS_ENABLED, SakaiBLTIUtil.BASICLTI_SETTINGS_ENABLED_DEFAULT);
String allowRoster = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_ROSTER_ENABLED, SakaiBLTIUtil.BASICLTI_ROSTER_ENABLED_DEFAULT);
String allowLori = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_LORI_ENABLED, SakaiBLTIUtil.BASICLTI_LORI_ENABLED_DEFAULT);
if ( "true".equals(allowOutcomes) && newAssignment != null && newAssignment.trim().length() > 1 ) {
if ( addGradeBookItem(request, newAssignment) ) {
// System.out.println("Success!");
assignment = newAssignment;
}
}
// System.out.println("old placementsecret="+oldPlacementSecret);
if ( oldPlacementSecret == null &&
("true".equals(allowOutcomes) || "true".equals(allowSettings) ||
"true".equals(allowRoster) || "true".equals(allowLori) ) ) {
try {
String uuid = UUID.randomUUID().toString();
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);
String date_secret = sdf.format(date);
prefs.setValue("sakai:imsti.placementsecret", uuid);
prefs.setValue("sakai:imsti.placementsecretdate", date_secret);
// System.out.println("placementsecret set to="+uuid+" data="+date_secret);
changed = true;
} catch (ReadOnlyException e) {
setErrorMessage(request, rb.getString("error.modify.prefs") );
return;
}
}
if ( "true".equals(allowOutcomes) && assignment != null && assignment.trim().length() > 1 ) {
List<String> assignments = getGradeBookAssignments();
boolean found = false;
if ( assignments != null ) for ( String assn : assignments ) {
if ( assn.equals(assignment) ) {
found = true;
break;
}
}
if ( ! found ) {
setErrorMessage(request, rb.getString("error.gradable.badassign") +
" " + FormattedText.escapeHtml(assignment,false));
return;
}
}
String imsTIHeight = getFormParameter(request,sakaiProperties,"frameheight");
if ( imsTIHeight != null && imsTIHeight.trim().length() < 1 ) imsTIHeight = null;
if ( imsTIHeight != null ) {
try {
int x = Integer.parseInt(imsTIHeight);
if ( x < 0 ) {
setErrorMessage(request, rb.getString("error.bad.height") );
return;
}
}
catch(Exception e) {
setErrorMessage(request, rb.getString("error.bad.height") );
return;
}
}
// Passed the sanity checks - time to save it all!
String context = getContext();
Placement placement = ToolManager.getCurrentPlacement();
// Update the Page Title (button text)
String imsTIPageTitle = getFormParameter(request,sakaiProperties,"pagetitle");
String prefsPageTitle = prefs.getValue("sakai:imsti.pagetitle", null);
imsTIPageTitle = imsTIPageTitle == null ? "" : imsTIPageTitle.trim();
prefsPageTitle = prefsPageTitle == null ? "" : prefsPageTitle.trim();
if ( ! imsTIPageTitle.equals(prefsPageTitle) ) {
try {
if ( imsTIPageTitle.length() > 99 ) imsTIPageTitle = imsTIPageTitle.substring(0,99);
ToolConfiguration toolConfig = SiteService.findTool(placement.getId());
Site site = SiteService.getSite(toolConfig.getSiteId());
SitePage page = site.getPage(toolConfig.getPageId());
if ( imsTIPageTitle.length() > 1 ) {
page.setTitle(imsTIPageTitle.trim());
page.setTitleCustom(true);
} else {
page.setTitle("");
page.setTitleCustom(false);
}
SiteService.save(site);
} catch (Exception e) {
setErrorMessage(request, rb.getString("error.page.title"));
return;
}
}
// Store preferences
for (String element : fieldList) {
String formParm = getFormParameter(request,sakaiProperties,element);
if ( "assignment".equals(element) ) formParm = assignment;
if ( "secret".equals(element) ) {
if ( LEAVE_SECRET_ALONE.equals(formParm) ) continue;
String key = ServerConfigurationService.getString(SakaiBLTIUtil.BASICLTI_ENCRYPTION_KEY, null);
if (key != null) {
try {
if ( formParm != null && formParm.trim().length() > 0 ) {
formParm = SimpleEncryption.encrypt(key, formParm);
// BLTI-195 convert old-style encrypted secrets
prefs.reset("sakai:imsti.encryptedsecret");
}
} catch (RuntimeException re) {
M_log.warn("Failed to encrypt secret, falling back to plaintext: "+ re.getMessage());
}
}
}
try {
prefs.setValue("sakai:imsti."+element, formParm);
changed = true;
} catch (ReadOnlyException e) {
setErrorMessage(request, rb.getString("error.modify.prefs") );
return;
}
}
// Clear out the other setting
if ( imsType != null ) {
if ( imsType.equalsIgnoreCase("XML") ) {
if ( imsTIXml != null ) {
prefs.reset("sakai:imsti.launch");
changed = true;
}
} else {
if ( imsTIUrl != null ) {
prefs.reset("sakai:imsti.xml");
changed = true;
}
}
}
// track event and store
if ( changed ) {
// 2.6 Event Tracking
Event event = LocalEventTrackingService.newEvent(EVENT_BASICLTI_CONFIG, launch_url, context, true, NotificationService.NOTI_OPTIONAL);
// 2.5 Event Tracking
// Event event = EventTrackingService.newEvent(EVENT_BASICLTI_CONFIG, launch_url, true);
LocalEventTrackingService.post(event);
prefs.store();
}
pSession.setAttribute("sakai.view", "main");
response.setPortletMode(PortletMode.VIEW);
}
/**
* Get the current site page our current tool is placed on.
*
* @return The site page id on which our tool is placed.
*/
protected String getCurrentSitePageId()
{
Placement placement = ToolManager.getCurrentPlacement();
ToolConfiguration tool = SiteService.findTool(placement.getId());
if (tool != null)
{
return tool.getPageId();
}
return null;
}
// TODO: Local cleverness ???
private void sendToJSP(RenderRequest request, RenderResponse response,
String jspPage) throws PortletException {
response.setContentType(request.getResponseContentType());
if (jspPage != null && jspPage.length() != 0) {
try {
PortletRequestDispatcher dispatcher = pContext
.getRequestDispatcher(jspPage);
dispatcher.include(request, response);
} catch (IOException e) {
throw new PortletException("Sakai Dispatch unabble to use "
+ jspPage, e);
}
}
}
// Error Message
public void clearErrorMessage(PortletRequest request)
{
PortletHelper.clearErrorMessage(request);
}
public Map getErrorMap(PortletRequest request)
{
return PortletHelper.getErrorMap(request);
}
public String getErrorOutput(PortletRequest request)
{
return PortletHelper.getErrorOutput(request);
}
public void setErrorMessage(PortletRequest request, String errorMsg)
{
PortletHelper.setErrorMessage(request,errorMsg);
}
public String getErrorMessage(PortletRequest request)
{
return PortletHelper.getErrorMessage(request);
}
public void setErrorMessage(PortletRequest request, String errorMsg, Throwable t)
{
PortletHelper.setErrorMessage(request,errorMsg,t);
}
private String getContext()
{
String retval = ToolManager.getCurrentPlacement().getContext();
return retval;
}
// Create an item in the Gradebook
protected boolean addGradeBookItem(ActionRequest request, String assignmentName)
{
try
{
GradebookService g = (GradebookService) ComponentManager.get("org.sakaiproject.service.gradebook.GradebookService");
String gradebookUid = getContext();
if ( ! (g.isGradebookDefined(gradebookUid) && (g.currentUserHasEditPerm(gradebookUid) || g.currentUserHasGradingPerm(gradebookUid)) && g.currentUserHasGradeAllPerm(gradebookUid) ) ) return false;
// add assignment to gradebook
Assignment asn = new Assignment();
asn.setPoints(Double.valueOf(100));
asn.setExternallyMaintained(false);
asn.setName(assignmentName);
asn.setReleased(true);
asn.setUngraded(false);
g.addAssignment(gradebookUid, asn);
return true;
}
catch (ConflictingAssignmentNameException e)
{
return true;
}
catch (Exception e)
{
dPrint("GradebookNotFoundException (may be because GradeBook has not yet been added to the Site) " + e.getMessage());
setErrorMessage(request, rb.getString("error.gradable.badcreate") + ":" + e.getMessage() );
M_log.warn(this + ":addGradeItem " + e.getMessage());
}
return false;
}
// get all assignments from the Gradebook
protected List<String> getGradeBookAssignments()
{
List<String> retval = new ArrayList<String>();
try
{
GradebookService g = (GradebookService) ComponentManager
.get("org.sakaiproject.service.gradebook.GradebookService");
String gradebookUid = getContext();
if ( ! (g.isGradebookDefined(gradebookUid) && (g.currentUserHasEditPerm(gradebookUid) || g.currentUserHasGradingPerm(gradebookUid)) && g.currentUserHasGradeAllPerm(gradebookUid) ) ) return null;
List gradebookAssignments = g.getAssignments(gradebookUid);
// filtering out anything externally provided
for (Iterator i=gradebookAssignments.iterator(); i.hasNext();)
{
org.sakaiproject.service.gradebook.shared.Assignment gAssignment = (org.sakaiproject.service.gradebook.shared.Assignment) i.next();
if ( gAssignment.isExternallyMaintained() ) continue;
retval.add(gAssignment.getName());
}
return retval;
}
catch (GradebookNotFoundException e)
{
dPrint("GradebookNotFoundException (may be because GradeBook has not yet been added to the Site) " + e.getMessage());
return null;
}
}
}