Index: lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java =================================================================== diff -u -r380ede712d98f28edcaea21f3525f12cc52b3237 -rcd0d3ff90f2fcd957ed96fe1bcd556524b197d39 --- lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java (.../LoginRequestLtiServlet.java) (revision 380ede712d98f28edcaea21f3525f12cc52b3237) +++ lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java (.../LoginRequestLtiServlet.java) (revision cd0d3ff90f2fcd957ed96fe1bcd556524b197d39) @@ -125,6 +125,7 @@ ExtServerLessonMap lesson = integrationService.getLtiConsumerLesson(consumerKey, resourceLinkId); //Determine method based on role parameter. Monitor roles can be either LTI standard ones or tool consumer's custom ones set + //In case of ContentItemSelectionRequest user must still be a stuff member in order to create a lesson. String method; boolean isCustomMonitorRole = LtiUtils.isToolConsumerCustomRole(roles, extServer.getLtiToolConsumerMonitorRoles()); @@ -153,6 +154,7 @@ // constructing redirectUrl by getting request.getQueryString() for POST requests URIBuilder redirectUrl = new URIBuilder("lti.do"); + redirectUrl.addParameter("_" + LoginRequestDispatcher.PARAM_METHOD, method); for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { String paramName = e.nextElement(); @@ -161,7 +163,6 @@ || !paramName.startsWith(BasicLTIConstants.OAUTH_PREFIX)) { redirectUrl.addParameter(paramName, request.getParameter(paramName)); } - redirectUrl.addParameter("_" + LoginRequestDispatcher.PARAM_METHOD, method); } URIBuilder url = new URIBuilder("LoginRequest"); Index: lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java =================================================================== diff -u -rf8946bae724b8a3f414aa1f6a27cd714fe8aae58 -rcd0d3ff90f2fcd957ed96fe1bcd556524b197d39 --- lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (.../LtiAction.java) (revision f8946bae724b8a3f414aa1f6a27cd714fe8aae58) +++ lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (.../LtiAction.java) (revision cd0d3ff90f2fcd957ed96fe1bcd556524b197d39) @@ -1,10 +1,17 @@ package org.lamsfoundation.lams.web.action; +import static org.imsglobal.lti.BasicLTIConstants.LTI_MESSAGE_TYPE; +import static org.imsglobal.lti.BasicLTIConstants.LTI_VERSION; + import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.LinkedList; import java.util.List; +import java.util.Properties; import java.util.Vector; +import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -16,11 +23,13 @@ import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionRedirect; import org.apache.tomcat.util.json.JSONException; +import org.apache.tomcat.util.json.JSONObject; import org.imsglobal.lti.BasicLTIConstants; +import org.imsglobal.lti.BasicLTIUtil; import org.lamsfoundation.lams.contentrepository.exception.RepositoryCheckedException; import org.lamsfoundation.lams.integration.ExtCourseClassMap; -import org.lamsfoundation.lams.integration.ExtServerLessonMap; import org.lamsfoundation.lams.integration.ExtServer; +import org.lamsfoundation.lams.integration.ExtServerLessonMap; import org.lamsfoundation.lams.integration.ExtUserUseridMap; import org.lamsfoundation.lams.integration.UserInfoFetchException; import org.lamsfoundation.lams.integration.UserInfoValidationException; @@ -49,6 +58,8 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import net.oauth.OAuth; + /** * Shows either addLesson.jsp or learnerMonitor.jsp pages. * @@ -79,6 +90,14 @@ String extUserId = request.getParameter(BasicLTIConstants.USER_ID); ExtServerLessonMap lesson = integrationService.getLtiConsumerLesson(consumerKey, resourceLinkId); + //support for ContentItemSelectionRequest. If lesson was created during such request, update its ExtServerLesson's resourceLinkId for the first time + boolean isContentItemSelection = WebUtil.readBooleanParam(request, "custom_isContentItemSelection", false); + if (lesson == null && isContentItemSelection) { + Long lessonId = WebUtil.readLongParam(request, "custom_lessonId"); + lesson = integrationService.getExtServerLessonMap(lessonId); + lesson.setResourceLinkId(resourceLinkId); + userManagementService.save(lesson); + } //update lessonFinishCallbackUrl. We store it one time during the very first call to LAMS and it stays the same all the time afterwards String lessonFinishCallbackUrl = request.getParameter(BasicLTIConstants.LIS_OUTCOME_SERVICE_URL); @@ -119,7 +138,7 @@ * When teacher accesses link for the very first time, we show him addLesson page where he can choose learning * design and start a lesson. */ - public ActionForward addLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, + private ActionForward addLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { initServices(); @@ -148,12 +167,29 @@ request.setAttribute(BasicLTIConstants.CONTEXT_ID, contextId); request.setAttribute(CentralConstants.PARAM_TITLE, resourceLinkTitle); request.setAttribute(CentralConstants.PARAM_DESC, resourceLinkDescription); + + //support for ContentItemSelectionRequest + String ltiMessageType = request.getParameter(BasicLTIConstants.LTI_MESSAGE_TYPE); + if (LtiUtils.LTI_MESSAGE_TYPE_CONTENTITEMSELECTIONREQUEST.equals(ltiMessageType)) { + String contentItemReturnUrl = request.getParameter(LtiUtils.CONTENT_ITEM_RETURN_URL); + if (StringUtils.isEmpty(contentItemReturnUrl)) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + "ContentItemSelectionRequest is missing content_item_return_url parameter"); + return null; + } + + request.setAttribute(BasicLTIConstants.LTI_MESSAGE_TYPE, ltiMessageType); + request.setAttribute(LtiUtils.CONTENT_ITEM_RETURN_URL, contentItemReturnUrl); + request.setAttribute("title", request.getParameter("title")); + request.setAttribute("desc", request.getParameter("text").replaceAll("\\<[^>]*>","")); + request.setAttribute("data", request.getParameter("data")); + } return mapping.findForward("addLesson"); } /** - * Starts a lesson. Then prompts to learnerMonitor page. + * Starts a lesson. Then prompts to learnerMonitor page or autosubmitForm (in case of ContentItemSelectionRequest). */ public ActionForward startLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, @@ -198,19 +234,129 @@ monitoringService.startLesson(lesson.getLessonId(), user.getUserId()); // store information which extServer has started the lesson integrationService.createExtServerLessonMap(lesson.getLessonId(), resourceLinkId, extServer); + + //support for ContentItemSelectionRequest + String ltiMessageType = request.getParameter(BasicLTIConstants.LTI_MESSAGE_TYPE); + String contentItemReturnUrl = request.getParameter(LtiUtils.CONTENT_ITEM_RETURN_URL); + if (LtiUtils.LTI_MESSAGE_TYPE_CONTENTITEMSELECTIONREQUEST.equals(ltiMessageType)) { + String opaqueTCData = request.getParameter("data"); + + // Get the post data for the placement + String returnValues = postLaunchHTML(extServer, lesson, contentItemReturnUrl, opaqueTCData); - //set roles to contain monitor so that the user can see monitor link - ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("learnerMonitorRedirect")); - redirect.addParameter(LtiUtils.OAUTH_CONSUMER_KEY, consumerKey); - redirect.addParameter(BasicLTIConstants.RESOURCE_LINK_ID, resourceLinkId); - redirect.addParameter(BasicLTIConstants.CONTEXT_ID, contextId); - return redirect; + response.setContentType("text/html; charset=UTF-8"); + response.setCharacterEncoding("utf-8"); + response.addDateHeader("Expires", System.currentTimeMillis() - (1000L * 60L * 60L * 24L * 365L)); + response.addDateHeader("Last-Modified", System.currentTimeMillis()); + response.addHeader("Cache-Control", + "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0"); + response.addHeader("Pragma", "no-cache"); + ServletOutputStream out = response.getOutputStream(); + + out.println(""); + out.println(""); + out.println("\n"); + out.println(""); + out.println("\n"); + out.println(returnValues); + out.println("\n"); + + return null; + + //regular BasicLTI request + } else { + //set roles to contain monitor so that the user can see monitor link + ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("learnerMonitorRedirect")); + redirect.addParameter(LtiUtils.OAUTH_CONSUMER_KEY, consumerKey); + redirect.addParameter(BasicLTIConstants.RESOURCE_LINK_ID, resourceLinkId); + redirect.addParameter(BasicLTIConstants.CONTEXT_ID, contextId); + return redirect; + } } + + /** + * Return HTML form to be posted to TC + */ + private String postLaunchHTML(ExtServer extServer, Lesson lesson, String contentItemReturnUrl, String opaqueTCData) throws JSONException, UnsupportedEncodingException { + String key = extServer.getServerid(); + String secret = extServer.getServerkey(); + + //required parameters +// +// +// +// +// +// +// +// +// +// +// + Properties properties = new Properties(); + properties.put(LTI_MESSAGE_TYPE, "ContentItemSelection"); + properties.put(LTI_VERSION, "LTI-1p0"); + if (StringUtils.isNotBlank(opaqueTCData)) { + properties.put("data", opaqueTCData); + } + + properties.put("lti_msg", "kkkkk lti_msg"); + properties.put(OAuth.OAUTH_VERSION, OAuth.VERSION_1_0); + properties.put("oauth_callback", "about:blank"); + properties.put(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.HMAC_SHA1); + + //contentItem Json +// { +// "@context" : "http://purl.imsglobal.org/ctx/lti/v1/ContentItem", +// "@graph" : [ +// { +// "@type" : "LtiLinkItem", +// "mediaType" : "application/vnd.ims.lti.v1.ltilink", +// "icon" : { +// "@id" : "https://www.server.com/path/animage.png", +// "width" : 50, +// "height" : 50 +// }, +// "title" : "Week 1 reading", +// "text" : "Read this section prior to your tutorial.", +// "custom" : { +// "chapter" : "12", +// "section" : "3" +// } +// } +// ] +// } + JSONObject contentItemJSON = new JSONObject(); + contentItemJSON.put("@type", "LtiLinkItem"); + contentItemJSON.put("mediaType", "application/vnd.ims.lti.v1.ltilink"); + contentItemJSON.put("title", lesson.getLessonName()); + contentItemJSON.put("text", lesson.getLessonDescription()); + JSONObject customJSON = new JSONObject(); + customJSON.put("lessonId", lesson.getLessonId().toString()); + customJSON.put("isContentItemSelection", "true"); + contentItemJSON.put("custom", customJSON); + + JSONObject responseJSON = new JSONObject(); + responseJSON.append("@graph", contentItemJSON); + responseJSON.put("@context", "http://purl.imsglobal.org/ctx/lti/v1/ContentItem"); + + String content_items = URLEncoder.encode(responseJSON.toString(), "UTF-8"); +// content_items = content_items.replace("\"", "%22"); +// content_items = content_items.replace("'", "%27"); + properties.put("content_items", content_items); + + properties = BasicLTIUtil.signProperties(properties, contentItemReturnUrl, "POST", key, secret, null, null, + null); + boolean dodebug = false; + String postData = BasicLTIUtil.postLaunchHTML(properties, contentItemReturnUrl, dodebug); + return postData; + } + /** * Once lesson was created, start showing learnerMonitor page to everybody regardless of his role. */ - public ActionForward learnerMonitor(ActionMapping mapping, ActionForm form, HttpServletRequest request, + public ActionForward learnerMonitor(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { initServices(); Index: lams_central/web/lti/addLesson.jsp =================================================================== diff -u -rbdf65e9be3cdc4959bc3c047174acf3b269c96c8 -rcd0d3ff90f2fcd957ed96fe1bcd556524b197d39 --- lams_central/web/lti/addLesson.jsp (.../addLesson.jsp) (revision bdf65e9be3cdc4959bc3c047174acf3b269c96c8) +++ lams_central/web/lti/addLesson.jsp (.../addLesson.jsp) (revision cd0d3ff90f2fcd957ed96fe1bcd556524b197d39) @@ -205,6 +205,11 @@ + <%-- ContentItemSelectionRequest items --%> + + + +