Index: lams_central/.classpath =================================================================== diff -u -r5a70ca6f5834da3b63f32b40d0a38ebeb555597d -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_central/.classpath (.../.classpath) (revision 5a70ca6f5834da3b63f32b40d0a38ebeb555597d) +++ lams_central/.classpath (.../.classpath) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -33,6 +33,8 @@ + + Index: lams_central/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_central/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) +++ lams_central/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -674,4 +674,19 @@ label.your.new.shared.secret =Your new shared secret: {0} label.2FA.shared.secret =Two-factor authorization shared secret +label.create.lesson =Create Lesson +label.organisations =Select course with the lessons that needs to be export +label.lesson.id =Lesson ID +label.display.design.image =Display sequence image? +label.select.sequence =You must select a sequence before proceeding +label.choose.sequence =Choose Lams sequence +label.author.sequence =Author new LAMS lessons +label.open.monitor =Open Monitor +label.your.progress =Your Lesson Progress +label.you.completed.this.lesson =You have completed this lesson. +label.total.activities.depend.on.path =Total activities depend on your learning path. +label.lesson.not.completed =Lesson is not yet completed. +label.you.completed.activities =You have completed {0} activities + + #======= End labels: Exported 439 labels for en AU ===== \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java =================================================================== diff -u -r0ddeb3a1dcf29cbbba6ed0fccbd139f9c31c347f -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision 0ddeb3a1dcf29cbbba6ed0fccbd139f9c31c347f) +++ lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -177,10 +177,6 @@ return mapping.findForward("lessonIntro"); } - if (lesson.getForceLearnerRestart()) { - // start the lesson from the beginning each time - getLessonService().removeLearnerProgress(lessonId, user.getUserID()); - } if (mode != null) { req.setAttribute(AttributeNames.PARAM_MODE, mode); Index: lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java =================================================================== diff -u --- lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java (revision 0) +++ lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -0,0 +1,234 @@ +/** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + */ +package org.lamsfoundation.lams.web; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.util.Enumeration; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpStatus; +import org.apache.http.client.utils.URIBuilder; +import org.apache.log4j.Logger; +import org.imsglobal.lti.BasicLTIConstants; +import org.imsglobal.lti.launch.LtiLaunch; +import org.imsglobal.lti.launch.LtiOauthVerifier; +import org.imsglobal.lti.launch.LtiVerificationException; +import org.imsglobal.lti.launch.LtiVerificationResult; +import org.imsglobal.lti.launch.LtiVerifier; +import org.lamsfoundation.lams.integration.ExtServerLessonMap; +import org.lamsfoundation.lams.integration.ExtServerOrgMap; +import org.lamsfoundation.lams.integration.service.IntegrationService; +import org.lamsfoundation.lams.integration.util.LoginRequestDispatcher; +import org.lamsfoundation.lams.integration.util.LtiUtils; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.CentralConstants; +import org.lamsfoundation.lams.util.HashUtil; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * The LoginRequestLtiServlet handles login request by LTI tool consumers. This servlet checks for the correctly signed by OAuth parameters, + * and if it's valid it redirects it to LoginRequestServlet for actual authentication. + * + * @author Andrey Balan + */ +@SuppressWarnings("serial") +public class LoginRequestLtiServlet extends HttpServlet { + + private static Logger log = Logger.getLogger(LoginRequestLtiServlet.class); + + private static IntegrationService integrationService = null; + + private static IUserManagementService userManagementService = null; + + private final String DEFAULT_FIRST_NAME = "John"; + + private final String DEFAULT_LAST_NAME = "Doe"; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + initServices(); + + String extUsername = request.getParameter(BasicLTIConstants.USER_ID); + String roles = request.getParameter(BasicLTIConstants.ROLES); + // implicit login params + String firstName = request.getParameter(BasicLTIConstants.LIS_PERSON_NAME_GIVEN); + String lastName = request.getParameter(BasicLTIConstants.LIS_PERSON_NAME_FAMILY); + String email = request.getParameter(BasicLTIConstants.LIS_PERSON_CONTACT_EMAIL_PRIMARY); + + String locale = request.getParameter(BasicLTIConstants.LAUNCH_PRESENTATION_LOCALE); + String country = LoginRequestLtiServlet.getCountry(locale); + String lang = LoginRequestLtiServlet.getLanguage(locale); + + String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); + String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); + String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); + String contextLabel = request.getParameter(BasicLTIConstants.CONTEXT_LABEL); + + if ((extUsername == null) || (consumerKey == null)) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Login Failed - login parameters missing"); + return; + } + + //verify whether request was correctly signed by OAuth + ExtServerOrgMap extServer = integrationService.getExtServerOrgMap(consumerKey); + String secret = extServer.getServerkey();// retrieve corresponding secret for key from db + LtiVerificationResult ltiResult = null; + try { + LtiVerifier ltiVerifier = new LtiOauthVerifier(); + ltiResult = ltiVerifier.verify(request, secret); + } catch (LtiVerificationException e) { + log.error("Authentication error: ", e); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, + "Login Failed - authentication error. " + e.getMessage()); + return; + } + LtiLaunch ltiLaunch = ltiResult.getLtiLaunchResult(); + if (!ltiResult.getSuccess()) { + log.warn("Authentication error: " + ltiResult.getMessage()); + response.sendError(HttpStatus.SC_UNAUTHORIZED, + "Login Failed - authentication error. " + ltiResult.getMessage()); + return; + } + + //provide default values for user names, as we can't fetch them from LTI Tool consumer + if (StringUtils.isBlank(firstName)) { + firstName = DEFAULT_FIRST_NAME; + } + if (StringUtils.isBlank(firstName)) { + lastName = DEFAULT_LAST_NAME; + } + ExtServerLessonMap lesson = integrationService.getLtiConsumerLesson(consumerKey, resourceLinkId); + + //determine method based on role parameter + String method; + if (LtiUtils.isLearner(roles) && !LtiUtils.isStaff(roles) && !LtiUtils.isAdmin(roles)) { + method = LoginRequestDispatcher.METHOD_LEARNER_STRICT_AUTHENTICATION; + } else if (lesson == null) { + method = LoginRequestDispatcher.METHOD_AUTHOR; + } else { + method = LoginRequestDispatcher.METHOD_MONITOR; + } + + //provide empty lessonId in case of learner accesses LTI link before teacher authored it + String lessonId = lesson == null ? "" : lesson.getLessonId().toString(); + + String timestamp = String.valueOf(System.currentTimeMillis()); + + // in case of learnerStrictAuth we should also include lsid value when creating hash: [ts + uid + method + lsid + serverID + serverKey] + // regular case: [ts + uid + method + serverID + serverKey] + String plaintext = timestamp.toLowerCase().trim() + extUsername.toLowerCase().trim() + + method.toLowerCase().trim() + + (LoginRequestDispatcher.METHOD_LEARNER_STRICT_AUTHENTICATION.equals(method) ? lessonId + : "") + + consumerKey.toLowerCase().trim() + secret.toLowerCase().trim(); + String hash = HashUtil.sha1(plaintext); + + try { + + // constructing redirectUrl by getting request.getQueryString() for POST requests + URIBuilder redirectUrl = new URIBuilder("lti.do"); + for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { + String paramName = e.nextElement(); + + //skip parameters starting with oath_ + if (LtiUtils.OAUTH_CONSUMER_KEY.equals(paramName) + || !paramName.startsWith(BasicLTIConstants.OAUTH_PREFIX)) { + redirectUrl.addParameter(paramName, request.getParameter(paramName)); + } + redirectUrl.addParameter("_" + LoginRequestDispatcher.PARAM_METHOD, method); + } + + URIBuilder url = new URIBuilder("LoginRequest"); + url.addParameter(LoginRequestDispatcher.PARAM_USER_ID, URLEncoder.encode(extUsername, "UTF8")); + url.addParameter(LoginRequestDispatcher.PARAM_METHOD, method); + url.addParameter(LoginRequestDispatcher.PARAM_TIMESTAMP, timestamp); + url.addParameter(LoginRequestDispatcher.PARAM_SERVER_ID, consumerKey); + url.addParameter(LoginRequestDispatcher.PARAM_HASH, hash); + url.addParameter(LoginRequestDispatcher.PARAM_COURSE_ID, contextId); + url.addParameter(CentralConstants.PARAM_COURSE_NAME, contextLabel); + url.addParameter(LoginRequestDispatcher.PARAM_COUNTRY, country); + url.addParameter(LoginRequestDispatcher.PARAM_LANGUAGE, lang); + url.addParameter(LoginRequestDispatcher.PARAM_FIRST_NAME, firstName);//TODO ?? URLEncoder.encode(queryString, "UTF-8"); + url.addParameter(LoginRequestDispatcher.PARAM_LAST_NAME, lastName);//TODO ?? URLEncoder.encode(queryString, "UTF-8"); + url.addParameter(LoginRequestDispatcher.PARAM_LESSON_ID, lessonId); + url.addParameter(LoginRequestDispatcher.PARAM_EMAIL, email); + url.addParameter("redirectURL", redirectUrl.build().toString()); + response.sendRedirect(response.encodeRedirectURL(url.build().toString())); + + } catch (URISyntaxException e) { + throw new ServletException("Error creating URL for LoginRequest", e); + } + + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + doGet(request, response); + } + + /** + * + * @param localeStr + * the full balckboard locale string + * @return the language + */ + private static String getLanguage(String localeStr) { + if (localeStr == null) + return "xx"; + String[] split = localeStr.split("_"); + return split[0]; + } + + /** + * + * @param localeStr + * the full balckboard locale string + * @return the country + */ + private static String getCountry(String localeStr) { + if (localeStr == null) + return "XX"; + String[] split = localeStr.split("_"); + + //default country set to AU + String country = split.length > 1 ? split[1] : "AU"; + return country; + } + + private void initServices() { + if (integrationService == null) { + integrationService = (IntegrationService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServletContext()).getBean("integrationService"); + } + + if (userManagementService == null) { + userManagementService = (IUserManagementService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServletContext()).getBean("userManagementService"); + } + } +} Index: lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java =================================================================== diff -u --- lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (revision 0) +++ lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -0,0 +1,308 @@ +package org.lamsfoundation.lams.web.action; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionRedirect; +import org.apache.tomcat.util.json.JSONException; +import org.imsglobal.lti.BasicLTIConstants; +import org.lamsfoundation.lams.contentrepository.RepositoryCheckedException; +import org.lamsfoundation.lams.integration.ExtCourseClassMap; +import org.lamsfoundation.lams.integration.ExtServerLessonMap; +import org.lamsfoundation.lams.integration.ExtServerOrgMap; +import org.lamsfoundation.lams.integration.ExtUserUseridMap; +import org.lamsfoundation.lams.integration.UserInfoFetchException; +import org.lamsfoundation.lams.integration.UserInfoValidationException; +import org.lamsfoundation.lams.integration.service.IIntegrationService; +import org.lamsfoundation.lams.integration.service.IntegrationService; +import org.lamsfoundation.lams.integration.util.LoginRequestDispatcher; +import org.lamsfoundation.lams.integration.util.LtiUtils; +import org.lamsfoundation.lams.learningdesign.service.ILearningDesignService; +import org.lamsfoundation.lams.lesson.LearnerProgress; +import org.lamsfoundation.lams.lesson.Lesson; +import org.lamsfoundation.lams.lesson.dto.LearnerProgressDTO; +import org.lamsfoundation.lams.lesson.service.ILessonService; +import org.lamsfoundation.lams.monitoring.service.IMonitoringService; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.usermanagement.Organisation; +import org.lamsfoundation.lams.usermanagement.Role; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.exception.UserAccessDeniedException; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.CentralConstants; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.workspace.service.IWorkspaceManagementService; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * Shows either addLesson.jsp or learnerMonitor.jsp pages. + * + * @author Andrey Balan + */ +public class LtiAction extends LamsDispatchAction { + + private static Logger log = Logger.getLogger(LtiAction.class); + private static IIntegrationService integrationService = null; + private static IMonitoringService monitoringService = null; + private static IUserManagementService userManagementService = null; + private static ILearningDesignService learningDesignService; + private static ILessonService lessonService = null; + private static IWorkspaceManagementService workspaceManagementService; + private static ISecurityService securityService; + + /** + * Single entry point to LAMS LTI processing mechanism. It determines here whether to show author or learnerMonitor + * pages + */ + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { + initServices(); + String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); + String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); + String tcGradebookId = request.getParameter(BasicLTIConstants.LIS_RESULT_SOURCEDID); + String extUserId = request.getParameter(BasicLTIConstants.USER_ID); + + ExtServerLessonMap lesson = integrationService.getLtiConsumerLesson(consumerKey, resourceLinkId); + + //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); + ExtServerOrgMap extServer = integrationService.getExtServerOrgMap(consumerKey); + if (StringUtils.isNotBlank(lessonFinishCallbackUrl) && StringUtils.isBlank(extServer.getLessonFinishUrl())) { + extServer.setLessonFinishUrl(lessonFinishCallbackUrl); + userManagementService.save(extServer); + } + + //check if learner tries to access the link that hasn't been authored by teacher yet + String method = request.getParameter("_" + LoginRequestDispatcher.PARAM_METHOD); + if (LoginRequestDispatcher.METHOD_LEARNER_STRICT_AUTHENTICATION.equals(method) && lesson == null) { + String errorMsg = "Learner tries to access the link that hasn't been authored by teacher yet. resource_link_id: " + + tcGradebookId; + log.debug(errorMsg); + request.setAttribute("error", errorMsg); + request.setAttribute("javax.servlet.error.exception", new UserAccessDeniedException(errorMsg)); + return mapping.findForward("error"); + } + + //determine whether to show author or learnerMonitor pages + if (lesson == null) { + return addLesson(mapping, form, request, response); + + } else { + + //as per LTI spec we need to update tool consumer's gradebook id on every LTI call + ExtUserUseridMap extUserMap = integrationService.getExistingExtUserUseridMap(extServer, extUserId); + extUserMap.setTcGradebookId(tcGradebookId); + userManagementService.save(extUserMap); + + return learnerMonitor(mapping, form, request, response); + } + + } + + /** + * 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, + HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { + initServices(); + Integer userId = getUser().getUserID(); + String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); + String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); + String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); + String resourceLinkTitle = request.getParameter(BasicLTIConstants.RESOURCE_LINK_TITLE); + String resourceLinkDescription = request.getParameter(BasicLTIConstants.RESOURCE_LINK_DESCRIPTION); + + ExtServerOrgMap extServer = integrationService.getExtServerOrgMap(consumerKey); + ExtCourseClassMap orgMap = integrationService.getExtCourseClassMap(extServer.getSid(), contextId); + Integer organisationId = orgMap.getOrganisation().getOrganisationId(); + //only monitors are allowed to create lesson + if (!securityService.isGroupMonitor(organisationId, userId, "add lesson", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); + return null; + } + + // get all user accessible folders and LD descriptions as JSON + String folderContentsJSON = workspaceManagementService.getFolderContentsJSON(null, userId, false); + request.setAttribute("folderContents", folderContentsJSON); + request.setAttribute(LtiUtils.OAUTH_CONSUMER_KEY, consumerKey); + request.setAttribute(BasicLTIConstants.RESOURCE_LINK_ID, resourceLinkId); + request.setAttribute(CentralConstants.ATTR_COURSE_ID, organisationId); + request.setAttribute(BasicLTIConstants.CONTEXT_ID, contextId); + request.setAttribute(CentralConstants.PARAM_TITLE, resourceLinkTitle); + request.setAttribute(CentralConstants.PARAM_DESC, resourceLinkDescription); + + return mapping.findForward("addLesson"); + } + + /** + * Starts a lesson. Then prompts to learnerMonitor page. + */ + public ActionForward startLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { + initServices(); + Integer userId = getUser().getUserID(); + User user = getRealUser(getUser()); + + String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); + String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); + String title = request.getParameter(CentralConstants.PARAM_TITLE); + String desc = request.getParameter(CentralConstants.PARAM_DESC); + String ldIdStr = request.getParameter(CentralConstants.PARAM_LEARNING_DESIGN_ID); + String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); + Integer organisationId = new Integer(WebUtil.readIntParam(request, CentralConstants.ATTR_COURSE_ID)); + boolean enableLessonIntro = WebUtil.readBooleanParam(request, "enableLessonIntro", false); + + //only monitors are allowed to create lesson + if (!securityService.isGroupMonitor(organisationId, userId, "add lesson", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); + return null; + } + + ExtServerOrgMap extServer = integrationService.getExtServerOrgMap(consumerKey); + Organisation organisation = monitoringService.getOrganisation(organisationId); + + // 1. init lesson + Lesson lesson = monitoringService.initializeLesson(title, desc, new Long(ldIdStr), + organisation.getOrganisationId(), user.getUserId(), null, false, enableLessonIntro, false, false, + true, true, false, false, null, null); + // 2. create lessonClass for lesson + List staffList = new LinkedList(); + staffList.add(user); + List learnerList = new LinkedList(); + Vector learnerVector = userManagementService + .getUsersFromOrganisationByRole(organisation.getOrganisationId(), Role.LEARNER, true); + learnerList.addAll(learnerVector); + monitoringService.createLessonClassForLesson(lesson.getLessonId(), organisation, + organisation.getName() + "Learners", learnerList, organisation.getName() + "Staff", staffList, + user.getUserId()); + // 3. start lesson + monitoringService.startLesson(lesson.getLessonId(), user.getUserId()); + // store information which extServer has started the lesson + integrationService.createExtServerLessonMap(lesson.getLessonId(), resourceLinkId, extServer); + + //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; + } + + /** + * Once lesson was created, start showing learnerMonitor page to everybody regardless of his role. + */ + public ActionForward learnerMonitor(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { + initServices(); + Integer userId = getUser().getUserID(); + String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); + String resourceLinkId = request.getParameter(BasicLTIConstants.RESOURCE_LINK_ID); + + //get orgId +// String contextId = request.getParameter(BasicLTIConstants.CONTEXT_ID); +// ExtServer extServer = integrationService.getExtServer(consumerKey); +// ExtCourseClassMap orgMap = integrationService.getExtCourseClassMap(extServer.getSid(), contextId); +// Integer organisationId = orgMap.getOrganisation().getOrganisationId(); + + //get lesson + ExtServerLessonMap extLesson = integrationService.getLtiConsumerLesson(consumerKey, resourceLinkId); + Long lessonId = extLesson.getLessonId(); + Lesson lesson = (Lesson) userManagementService.findById(Lesson.class, lessonId); + + //set all required attributes for jsp + request.setAttribute("lessonId", lessonId); + request.setAttribute("ldId", lesson.getLearningDesign().getLearningDesignId()); + request.setAttribute("title", lesson.getLessonName()); + request.setAttribute("description", lesson.getLessonDescription()); + request.setAttribute("isDisplayDesignImage", lesson.isDisplayDesignImage()); + boolean isMonitor = securityService.isLessonMonitor(lessonId, userId, "learner monitor", false); + request.setAttribute("isMonitor", isMonitor); + + //get learnerProgressDto + LearnerProgress learnProg = lessonService.getUserProgressForLesson(userId, lessonId); + if (learnProg != null) { + LearnerProgressDTO learnerProgress = learnProg.getLearnerProgressData(); + request.setAttribute("learnerProgressDto", learnerProgress); + } + + // check if we need to create svg, png files on the server +// if (lesson.isDisplayDesignImage() && lesson.getLearnerProgresses().isEmpty()) { +// Long learningDesignId = lesson.getLearningDesign().getLearningDesignId(); +// learningDesignService.createLearningDesignSVG(learningDesignId, SVGGenerator.OUTPUT_FORMAT_SVG); +// learningDesignService.createLearningDesignSVG(learningDesignId, SVGGenerator.OUTPUT_FORMAT_PNG); +// } + + return mapping.findForward("learnerMonitor"); + } + + private UserDTO getUser() { + HttpSession ss = SessionManager.getSession(); + return (UserDTO) ss.getAttribute(AttributeNames.USER); + } + + private User getRealUser(UserDTO dto) { + return userManagementService.getUserByLogin(dto.getLogin()); + } + + private void initServices() { + if (integrationService == null) { + integrationService = (IntegrationService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()).getBean("integrationService"); + } + + if (monitoringService == null) { + monitoringService = (IMonitoringService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()).getBean("monitoringService"); + } + + if (userManagementService == null) { + userManagementService = (IUserManagementService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()) + .getBean("userManagementService"); + } + + if (learningDesignService == null) { + learningDesignService = (ILearningDesignService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()) + .getBean("learningDesignService"); + } + + if (lessonService == null) { + lessonService = (ILessonService) WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()).getBean("lessonService"); + } + + if (workspaceManagementService == null) { + WebApplicationContext webContext = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + workspaceManagementService = (IWorkspaceManagementService) webContext.getBean("workspaceManagementService"); + } + + if (securityService == null) { + WebApplicationContext webContext = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + securityService = (ISecurityService) webContext.getBean("securityService"); + } + } + +} Index: lams_central/src/java/org/lamsfoundation/lams/webservice/xml/LessonManagerServlet.java =================================================================== diff -u -r209169e5b23bcde0a00dc86cd250e83c9ac76492 -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_central/src/java/org/lamsfoundation/lams/webservice/xml/LessonManagerServlet.java (.../LessonManagerServlet.java) (revision 209169e5b23bcde0a00dc86cd250e83c9ac76492) +++ lams_central/src/java/org/lamsfoundation/lams/webservice/xml/LessonManagerServlet.java (.../LessonManagerServlet.java) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -360,28 +360,28 @@ doGet(request, response); } - private Long startLesson(String serverId, String datetime, String hashValue, String username, long ldId, + private static Long startLesson(String serverId, String datetime, String hashValue, String username, long ldId, String courseId, String title, String desc, String countryIsoCode, String langIsoCode, String customCSV, boolean presenceEnable, boolean imEnable, boolean enableNotifications) throws RemoteException { try { - ExtServerOrgMap serverMap = LessonManagerServlet.integrationService.getExtServerOrgMap(serverId); + ExtServerOrgMap serverMap = integrationService.getExtServerOrgMap(serverId); Authenticator.authenticate(serverMap, datetime, username, hashValue); - ExtUserUseridMap userMap = LessonManagerServlet.integrationService.getExtUserUseridMap(serverMap, username); - ExtCourseClassMap orgMap = LessonManagerServlet.integrationService.getExtCourseClassMap(serverMap, userMap, + ExtUserUseridMap userMap = integrationService.getExtUserUseridMap(serverMap, username); + ExtCourseClassMap orgMap = integrationService.getExtCourseClassMap(serverMap, userMap, courseId, countryIsoCode, langIsoCode, null, LoginRequestDispatcher.METHOD_MONITOR); User user = userMap.getUser(); Organisation organisation = orgMap.getOrganisation(); // 1. init lesson - Lesson lesson = LessonManagerServlet.monitoringService.initializeLesson(title, desc, ldId, + Lesson lesson = monitoringService.initializeLesson(title, desc, ldId, organisation.getOrganisationId(), user.getUserId(), customCSV, false, false, presenceEnable, imEnable, true, enableNotifications, false, false, null, null); // 2. create lessonClass for lesson createLessonClass(lesson, organisation, user); // 3. start lesson - LessonManagerServlet.monitoringService.startLesson(lesson.getLessonId(), user.getUserId()); + monitoringService.startLesson(lesson.getLessonId(), user.getUserId()); // store information which extServer has started the lesson - LessonManagerServlet.integrationService.createExtServerLessonMap(lesson.getLessonId(), serverMap); + integrationService.createExtServerLessonMap(lesson.getLessonId(), serverMap); return lesson.getLessonId(); } catch (Exception e) { @@ -780,17 +780,16 @@ } @SuppressWarnings("unchecked") - private void createLessonClass(Lesson lesson, Organisation organisation, User creator) { + private static void createLessonClass(Lesson lesson, Organisation organisation, User creator) { List staffList = new LinkedList(); staffList.add(creator); List learnerList = new LinkedList(); - Vector learnerVector = LessonManagerServlet.userManagementService + Vector learnerVector = userManagementService .getUsersFromOrganisationByRole(organisation.getOrganisationId(), Role.LEARNER, true); learnerList.addAll(learnerVector); - LessonManagerServlet.monitoringService.createLessonClassForLesson(lesson.getLessonId(), organisation, + monitoringService.createLessonClassForLesson(lesson.getLessonId(), organisation, organisation.getName() + " learners", learnerList, organisation.getName() + " staff", staffList, creator.getUserId()); - } /** @@ -903,7 +902,11 @@ if ((firstNames != null) && ((firstNameArray.length != lastNameArray.length) || (firstNameArray.length != emailArray.length) || (firstNameArray.length != (learnerIdArray.length + monitorIdArray.length)))) { - LessonManagerServlet.log.error("Invalid parameters sent: wrong array length."); + LessonManagerServlet.log.error("Invalid parameters sent: wrong array length. " + "learnerIds=" + + learnerIds + " &monitorIds=" + monitorIds + " &firstNames=" + firstNames + " &lastNames=" + + lastNames + " &emails=" + emails + " &array lengths=" + learnerIdArray.length + "!" + + monitorIdArray.length + "!" + firstNameArray.length + "!" + lastNameArray.length + "!" + + emailArray.length); return false; } Index: lams_central/web/WEB-INF/struts-config.xml =================================================================== diff -u -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_central/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) +++ lams_central/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -494,6 +494,34 @@ /> + + + + + + + + + LoginRequestLti + + org.lamsfoundation.lams.web.LoginRequestLtiServlet + + LearningDesignRepository @@ -416,6 +423,11 @@ LoginRequest /LoginRequest + + + LoginRequestLti + /LoginRequestLti + LearningDesignRepository @@ -640,6 +652,7 @@ Public content /LoginRequest + /LoginRequestLti /services/xml/LessonManager/* /services/xml/LearningDesignRepository/* /services/LearningDesignSVG/* @@ -702,6 +715,7 @@ Add lesson /addLesson.jsp + /lti/addLesson.jsp MONITOR Index: lams_central/web/includes/javascript/openUrls.js =================================================================== diff -u -r0ddeb3a1dcf29cbbba6ed0fccbd139f9c31c347f -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_central/web/includes/javascript/openUrls.js (.../openUrls.js) (revision 0ddeb3a1dcf29cbbba6ed0fccbd139f9c31c347f) +++ lams_central/web/includes/javascript/openUrls.js (.../openUrls.js) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -1,4 +1,3 @@ - Index: lams_central/web/lti/addLesson.jsp =================================================================== diff -u --- lams_central/web/lti/addLesson.jsp (revision 0) +++ lams_central/web/lti/addLesson.jsp (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -0,0 +1,281 @@ + + +<%@ page language="java" pageEncoding="UTF-8" contentType="text/html;charset=utf-8" %> +<%@ taglib uri="tags-lams" prefix="lams" %> +<%@ taglib uri="tags-fmt" prefix="fmt" %> +<%@ taglib uri="tags-core" prefix="c" %> +<%@ taglib uri="tags-html" prefix="html" %> +<%@ taglib uri="tags-function" prefix="fn"%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <%-- Form to Collect ID of Selected LAMS Sequence --%> + + + + + + + + + + + + + + + + + + + + + + + + + + + ${desc} + + + + + + + <%-- Preview and Author Buttons --%> + + "> + + + + "> + + + + "> + + + + + + + + + + + + + + + + + + + + + + + + + Index: lams_central/web/lti/learnerMonitor.jsp =================================================================== diff -u --- lams_central/web/lti/learnerMonitor.jsp (revision 0) +++ lams_central/web/lti/learnerMonitor.jsp (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -0,0 +1,105 @@ + + +<%@ page language="java" pageEncoding="UTF-8" contentType="text/html;charset=utf-8" %> +<%@ taglib uri="tags-lams" prefix="lams" %> +<%@ taglib uri="tags-fmt" prefix="fmt" %> +<%@ taglib uri="tags-core" prefix="c" %> +<%@ taglib uri="tags-html" prefix="html" %> +<%@ taglib uri="tags-function" prefix="fn"%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${fn:length(learnerProgressDto.completedActivities)} + + + [*] + + + + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: lams_common/.classpath =================================================================== diff -u -rf494ac5c2f49f92be600b6392d9c85c291df7bb7 -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_common/.classpath (.../.classpath) (revision f494ac5c2f49f92be600b6392d9c85c291df7bb7) +++ lams_common/.classpath (.../.classpath) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -43,7 +43,7 @@ - + Index: lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/integration/ExtServerLessonMap.hbm.xml =================================================================== diff -u -r65efb0abb529cafc1977e284e2c9a4ed33722334 -rde884cf8c730a25d2f2296f7a768d3fd45508c99 --- lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/integration/ExtServerLessonMap.hbm.xml (.../ExtServerLessonMap.hbm.xml) (revision 65efb0abb529cafc1977e284e2c9a4ed33722334) +++ lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/integration/ExtServerLessonMap.hbm.xml (.../ExtServerLessonMap.hbm.xml) (revision de884cf8c730a25d2f2296f7a768d3fd45508c99) @@ -34,6 +34,14 @@ column="lesson_id" not-null="true" /> + + + + + +
+ + + + +
+ +
+ + + ${fn:length(learnerProgressDto.completedActivities)} + + + [*] +