Ticket
to login and
+ * access the Content Repository.
+ *
+ * A valid ticket is needed in order to access the content from the repository. This method would be called evertime
+ * the tool needs to upload/download files from the content repository.
+ *
+ * @return ITicket The ticket for repostory access
+ * @throws SubmitFilesException
+ */
+ private ITicket getRepositoryLoginTicket() throws VideoRecorderException {
+ repositoryService = RepositoryProxy.getRepositoryService();
+ ICredentials credentials = new SimpleCredentials(VideoRecorderToolContentHandler.repositoryUser,
+ VideoRecorderToolContentHandler.repositoryId);
+ try {
+ ITicket ticket = repositoryService.login(credentials, VideoRecorderToolContentHandler.repositoryWorkspaceName);
+ return ticket;
+ } catch (AccessDeniedException ae) {
+ throw new VideoRecorderException("Access Denied to repository." + ae.getMessage());
+ } catch (WorkspaceNotFoundException we) {
+ throw new VideoRecorderException("Workspace not found." + we.getMessage());
+ } catch (LoginException e) {
+ throw new VideoRecorderException("Login failed." + e.getMessage());
+ }
+ }
+
+ /* ===============Methods implemented from ToolContentImport102Manager =============== */
+
+ /**
+ * Import the data for a 1.0.2 VideoRecorder
+ */
+ public void import102ToolContent(Long toolContentId, UserDTO user, Hashtable importValues) {
+ Date now = new Date();
+ VideoRecorder videoRecorder = new VideoRecorder();
+ videoRecorder.setContentInUse(Boolean.FALSE);
+ videoRecorder.setCreateBy(new Long(user.getUserID().longValue()));
+ videoRecorder.setCreateDate(now);
+ videoRecorder.setDefineLater(Boolean.FALSE);
+ videoRecorder.setInstructions(WebUtil.convertNewlines((String) importValues
+ .get(ToolContentImport102Manager.CONTENT_BODY)));
+ videoRecorder.setLockOnFinished(Boolean.TRUE);
+ videoRecorder.setOfflineInstructions(null);
+ videoRecorder.setOnlineInstructions(null);
+ videoRecorder.setRunOffline(Boolean.FALSE);
+ videoRecorder.setTitle((String) importValues.get(ToolContentImport102Manager.CONTENT_TITLE));
+ videoRecorder.setToolContentId(toolContentId);
+ videoRecorder.setUpdateDate(now);
+ // leave as empty, no need to set them to anything.
+ // setVideoRecorderAttachments(Set videoRecorderAttachments);
+ // setVideoRecorderSessions(Set videoRecorderSessions);
+ videoRecorderDAO.saveOrUpdate(videoRecorder);
+ }
+
+ /** Set the description, throws away the title value as this is not supported in 2.0 */
+ public void setReflectiveData(Long toolContentId, String title, String description) throws ToolException,
+ DataMissingException {
+
+ VideoRecorderService.logger
+ .warn("Setting the reflective field on a videoRecorder. This doesn't make sense as the videoRecorder is for reflection and we don't reflect on reflection!");
+ VideoRecorder videoRecorder = getVideoRecorderByContentId(toolContentId);
+ if (videoRecorder == null) {
+ throw new DataMissingException("Unable to set reflective data titled " + title
+ + " on activity toolContentId " + toolContentId + " as the tool content does not exist.");
+ }
+
+ videoRecorder.setInstructions(description);
+ }
+
+ // =========================================================================================
+ /* ********** Used by Spring to "inject" the linked objects ************* */
+
+ public IVideoRecorderAttachmentDAO getVideoRecorderAttachmentDAO() {
+ return videoRecorderAttachmentDAO;
+ }
+
+ public void setVideoRecorderAttachmentDAO(IVideoRecorderAttachmentDAO attachmentDAO) {
+ videoRecorderAttachmentDAO = attachmentDAO;
+ }
+
+ public IVideoRecorderDAO getVideoRecorderDAO() {
+ return videoRecorderDAO;
+ }
+
+ public void setVideoRecorderDAO(IVideoRecorderDAO videoRecorderDAO) {
+ this.videoRecorderDAO = videoRecorderDAO;
+ }
+
+ public IToolContentHandler getVideoRecorderToolContentHandler() {
+ return videoRecorderToolContentHandler;
+ }
+
+ public void setVideoRecorderToolContentHandler(IToolContentHandler videoRecorderToolContentHandler) {
+ this.videoRecorderToolContentHandler = videoRecorderToolContentHandler;
+ }
+
+ public IVideoRecorderSessionDAO getVideoRecorderSessionDAO() {
+ return videoRecorderSessionDAO;
+ }
+
+ public void setVideoRecorderSessionDAO(IVideoRecorderSessionDAO sessionDAO) {
+ videoRecorderSessionDAO = sessionDAO;
+ }
+
+ public IVideoRecorderRecordingDAO getVideoRecorderRecordingDAO() {
+ return videoRecorderRecordingDAO;
+ }
+
+ public void setVideoRecorderRecordingDAO(IVideoRecorderRecordingDAO videoRecorderRecordingDAO) {
+ this.videoRecorderRecordingDAO = videoRecorderRecordingDAO;
+ }
+
+ public ILamsToolService getToolService() {
+ return toolService;
+ }
+
+ public void setToolService(ILamsToolService toolService) {
+ this.toolService = toolService;
+ }
+
+ public IVideoRecorderUserDAO getVideoRecorderUserDAO() {
+ return videoRecorderUserDAO;
+ }
+
+ public void setVideoRecorderUserDAO(IVideoRecorderUserDAO userDAO) {
+ videoRecorderUserDAO = userDAO;
+ }
+
+ public ILearnerService getLearnerService() {
+ return learnerService;
+ }
+
+ public void setLearnerService(ILearnerService learnerService) {
+ this.learnerService = learnerService;
+ }
+
+ public IExportToolContentService getExportContentService() {
+ return exportContentService;
+ }
+
+ public void setExportContentService(IExportToolContentService exportContentService) {
+ this.exportContentService = exportContentService;
+ }
+
+ public ICoreNotebookService getCoreNotebookService() {
+ return coreNotebookService;
+ }
+
+ public void setCoreNotebookService(ICoreNotebookService coreNotebookService) {
+ this.coreNotebookService = coreNotebookService;
+ }
+
+ public VideoRecorderOutputFactory getVideoRecorderOutputFactory() {
+ return videoRecorderOutputFactory;
+ }
+
+ public void setVideoRecorderOutputFactory(VideoRecorderOutputFactory videoRecorderOutputFactory) {
+ this.videoRecorderOutputFactory = videoRecorderOutputFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String createConditionName(CollectionThis class act as the proxy between web layer and service layer. It is + * designed to decouple the presentation logic and business logic completely. + * In this way, the presentation tier will no longer be aware of the changes in + * service layer. Therefore we can feel free to switch the business logic + * implementation.
+ */ + +public class VideoRecorderServiceProxy { + + public static final IVideoRecorderService getVideoRecorderService(ServletContext servletContext) + { + return (IVideoRecorderService)getVideoRecorderDomainService(servletContext); + } + + private static Object getVideoRecorderDomainService(ServletContext servletContext) + { + WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + return wac.getBean("videoRecorderService"); + } + + /* + * Return the videoRecorder tool version of tool session manager implementation. + * It will delegate to the Spring helper method to retrieve the proper + * bean from Spring bean factory. + * @param servletContext the servletContext for current application + * @return noticeboard service object.*/ + public static final ToolSessionManager getVideoRecorderSessionManager(ServletContext servletContext) + { + return (ToolSessionManager)getVideoRecorderDomainService(servletContext); + } + + + /* + * Return the videoRecorder tool version of tool content manager implementation. + * It will delegate to the Spring helper method to retrieve the proper + * bean from Spring bean factory. + * @param servletContext the servletContext for current application + * @return noticeboard service object. */ + public static final ToolContentManager getVideoRecorderContentManager(ServletContext servletContext) + { + return (ToolContentManager)getVideoRecorderDomainService(servletContext); + } + +} Index: lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderConstants.java =================================================================== diff -u --- lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderConstants.java (revision 0) +++ lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderConstants.java (revision 3d081de4a45da632ee6029251318fac795d41813) @@ -0,0 +1,63 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * 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. + * + * 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 + * **************************************************************** + */ +/* $$Id$$ */ + +package org.lamsfoundation.lams.tool.videoRecorder.util; + +public interface VideoRecorderConstants { + public static final String TOOL_SIGNATURE = "lavidr10"; + + // VideoRecorder session status + public static final Integer SESSION_NOT_STARTED = new Integer(0); + public static final Integer SESSION_IN_PROGRESS = new Integer(1); + public static final Integer SESSION_COMPLETED = new Integer(2); + + public static final String AUTHORING_DEFAULT_TAB = "1"; + public static final String ATTACHMENT_LIST = "attachmentList"; + public static final String DELETED_ATTACHMENT_LIST = "deletedAttachmentList"; + public static final String AUTH_SESSION_ID_COUNTER = "authoringSessionIdCounter"; + public static final String AUTH_SESSION_ID = "authoringSessionId"; + + public static final int MONITORING_SUMMARY_MAX_MESSAGES = 5; + + // Attribute names + public static final String ATTR_MESSAGE = "message"; + public static final String ATTR_SESSION_MAP = "sessionMap"; + + // Parameter names + public static final String PARAM_PARENT_PAGE = "parentPage"; + + static final String FILTER_REPLACE_TEXT = "***"; + + public static final String ATTR_SESSION_MAP_ID = "sessionMapID"; + public static final String ATTR_CONDITION_SET = "conditionList"; + + public static final String PARAM_ORDER_ID = "orderId"; + public static final String ATTR_DELETED_CONDITION_LIST = "deletedConditionList"; + public static final String TEXT_SEARCH_DEFINITION_NAME = "text.search.output.definition.videoRecorder"; + public static final String TEXT_SEARCH_DEFAULT_CONDITION_DISPLAY_NAME_KEY = "text.search.output.definition.videoRecorder.default.condition"; + public static final String SUCCESS = "success"; + public static final String ERROR_MSG_CONDITION = "error.condition"; + public static final String ERROR_MSG_NAME_BLANK = "error.condition.name.blank"; + public static final String ERROR_MSG_NAME_DUPLICATED = "error.condition.duplicated.name"; +} Index: lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderException.java =================================================================== diff -u --- lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderException.java (revision 0) +++ lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderException.java (revision 3d081de4a45da632ee6029251318fac795d41813) @@ -0,0 +1,57 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * 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. + * + * 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 + * **************************************************************** + */ +/* $$Id$$ */ + +package org.lamsfoundation.lams.tool.videoRecorder.util; + +/** + * + * @author Anthony Sukkar + * + */ +public class VideoRecorderException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -5518806968051758859L; + + public VideoRecorderException(String message) { + super(message); + } + + public VideoRecorderException(String message, Throwable cause) { + super(message, cause); + } + + public VideoRecorderException() { + super(); + + } + + public VideoRecorderException(Throwable cause) { + super(cause); + + } + +} Index: lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderRecordingComparator.java =================================================================== diff -u --- lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderRecordingComparator.java (revision 0) +++ lams_tool_videorecorder/src/java/org/lamsfoundation/lams/tool/videoRecorder/util/VideoRecorderRecordingComparator.java (revision 3d081de4a45da632ee6029251318fac795d41813) @@ -0,0 +1,30 @@ +package org.lamsfoundation.lams.tool.videoRecorder.util; + +import java.util.Comparator; + +import org.lamsfoundation.lams.tool.videoRecorder.dto.VideoRecorderRecordingDTO; + +/** + * + * @author Paul Georges + * + */ +public class VideoRecorderRecordingComparator implements ComparatortoolContentID
will be passed in. This will be used to retrieve content for this tool.
+ *
+ */
+ @Override
+ protected ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+
+ // Extract toolContentID from parameters.
+ Long toolContentID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID));
+
+ String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID);
+
+ ToolAccessMode mode = WebUtil.readToolAccessModeParam(request, "mode", true);
+
+ // set up videoRecorderService
+ if (videoRecorderService == null) {
+ videoRecorderService = VideoRecorderServiceProxy.getVideoRecorderService(this.getServlet().getServletContext());
+ }
+
+ // retrieving VideoRecorder with given toolContentID
+ VideoRecorder videoRecorder = videoRecorderService.getVideoRecorderByContentId(toolContentID);
+ if (videoRecorder == null) {
+ videoRecorder = videoRecorderService.copyDefaultContent(toolContentID);
+ videoRecorder.setCreateDate(new Date());
+ videoRecorderService.saveOrUpdateVideoRecorder(videoRecorder);
+ // TODO NOTE: this causes DB orphans when LD not saved.
+ }
+
+ if (mode != null && mode.isTeacher()) {
+ // Set the defineLater flag so that learners cannot use content
+ // while we
+ // are editing. This flag is released when updateContent is called.
+ videoRecorder.setDefineLater(true);
+ videoRecorderService.saveOrUpdateVideoRecorder(videoRecorder);
+ }
+
+ // Set up the authForm.
+ AuthoringForm authForm = (AuthoringForm) form;
+ updateAuthForm(authForm, videoRecorder);
+
+ // Set up sessionMap
+ SessionMapAuthoringAction
action.
+ *
+ * @author Marcin Cieslak
+ * @see org.lamsfoundation.lams.tool.videoRecorder.web.action.AuthoringAction
+ *
+ */
+public class AuthoringVideoRecorderConditionAction extends Action {
+ public IVideoRecorderService videoRecorderService;
+
+ @Override
+ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) throws Exception {
+
+ String param = mapping.getParameter();
+
+ if (param.equals("newConditionInit")) {
+ return newConditionInit(mapping, form, request, response);
+ }
+ if (param.equals("editCondition")) {
+ return editCondition(mapping, form, request, response);
+ }
+ if (param.equals("saveOrUpdateCondition")) {
+ return saveOrUpdateCondition(mapping, form, request, response);
+ }
+ if (param.equals("removeCondition")) {
+ return removeCondition(mapping, form, request, response);
+ }
+ if (param.equals("upCondition")) {
+ return upCondition(mapping, form, request, response);
+ }
+ if (param.equals("downCondition")) {
+ return downCondition(mapping, form, request, response);
+ }
+
+ return null;
+ }
+
+ /**
+ * Display empty page for new taskList item.
+ *
+ * @param mapping
+ * @param form
+ * @param request
+ * @param response
+ * @return
+ */
+ private ActionForward newConditionInit(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+ String sessionMapID = WebUtil.readStrParam(request, VideoRecorderConstants.ATTR_SESSION_MAP_ID);
+ ((VideoRecorderConditionForm) form).setSessionMapID(sessionMapID);
+ ((VideoRecorderConditionForm) form).setOrderId(-1);
+ return mapping.findForward("addcondition");
+ }
+
+ /**
+ * Display edit page for existed taskList item.
+ *
+ * @param mapping
+ * @param form
+ * @param request
+ * @param response
+ * @return
+ */
+ private ActionForward editCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+
+ VideoRecorderConditionForm videoRecorderConditionForm = (VideoRecorderConditionForm) form;
+ String sessionMapID = videoRecorderConditionForm.getSessionMapID();
+ SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID);
+
+ int orderId = NumberUtils.stringToInt(request.getParameter(VideoRecorderConstants.PARAM_ORDER_ID), -1);
+ VideoRecorderCondition condition = null;
+ if (orderId != -1) {
+ SortedSetHttpSession
VideoRecorderItemList. Notice, this save is not persist them into database, just save
+ * HttpSession
temporarily. Only they will be persist when the entire authoring page is being
+ * persisted.
+ *
+ * @param mapping
+ * @param form
+ * @param request
+ * @param response
+ * @return
+ * @throws ServletException
+ */
+ private ActionForward saveOrUpdateCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+
+ VideoRecorderConditionForm conditionForm = (VideoRecorderConditionForm) form;
+ ActionErrors errors = validateVideoRecorderCondition(conditionForm, request);
+
+ if (!errors.isEmpty()) {
+ this.addErrors(request, errors);
+ return mapping.findForward("addcondition");
+ }
+
+ try {
+ extractFormToVideoRecorderCondition(request, conditionForm);
+ } catch (Exception e) {
+ // any upload exception will display as normal error message rather then throw exception directly
+ errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(VideoRecorderConstants.ERROR_MSG_CONDITION, e
+ .getMessage()));
+ if (!errors.isEmpty()) {
+ this.addErrors(request, errors);
+ return mapping.findForward("addcondition");
+ }
+ }
+ // set session map ID so that itemlist.jsp can get sessionMAP
+ request.setAttribute(VideoRecorderConstants.ATTR_SESSION_MAP_ID, conditionForm.getSessionMapID());
+ // return null to close this window
+ return mapping.findForward(VideoRecorderConstants.SUCCESS);
+ }
+
+ /**
+ * Remove taskList item from HttpSession list and update page display. As authoring rule, all persist only happen
+ * when user submit whole page. So this remove is just impact HttpSession values.
+ *
+ * @param mapping
+ * @param form
+ * @param request
+ * @param response
+ * @return
+ */
+ private ActionForward removeCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+
+ // get back sessionMAP
+ String sessionMapID = WebUtil.readStrParam(request, VideoRecorderConstants.ATTR_SESSION_MAP_ID);
+ SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID);
+
+ int orderId = NumberUtils.stringToInt(request.getParameter(VideoRecorderConstants.PARAM_ORDER_ID), -1);
+ if (orderId != -1) {
+ SortedSetjava.util.List
from HttpSession by given name.
+ *
+ * @param request
+ * @param name
+ * @return
+ */
+ private List getListFromSession(SessionMap sessionMap, String name) {
+ List list = (List) sessionMap.get(name);
+ if (list == null) {
+ list = new ArrayList();
+ sessionMap.put(name, list);
+ }
+ return list;
+ }
+
+ /**
+ * This method will populate taskList item information to its form for edit use.
+ *
+ * @param orderId
+ * @param condition
+ * @param form
+ * @param request
+ */
+ private void populateConditionToForm(int orderId, VideoRecorderCondition condition, VideoRecorderConditionForm form,
+ HttpServletRequest request) {
+ form.populateForm(condition);
+ if (orderId >= 0) {
+ form.setOrderId(orderId + 1);
+ }
+ }
+
+ /**
+ * Extract form content to taskListContent.
+ *
+ * @param request
+ * @param form
+ * @throws VideoRecorderException
+ */
+ private void extractFormToVideoRecorderCondition(HttpServletRequest request, VideoRecorderConditionForm form)
+ throws Exception {
+ /*
+ * BE CAREFUL: This method will copy necessary info from request form to a old or new VideoRecorderItem instance. It
+ * gets all info EXCEPT VideoRecorderItem.createDate and VideoRecorderItem.createBy, which need be set when persisting
+ * this taskList item.
+ */
+
+ SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(form.getSessionMapID());
+ // check whether it is "edit(old item)" or "add(new item)"
+ SortedSet
+
+
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org
Index: lams_tool_videorecorder/web/common/header.jsp =================================================================== diff -u --- lams_tool_videorecorder/web/common/header.jsp (revision 0) +++ lams_tool_videorecorder/web/common/header.jsp (revision 3d081de4a45da632ee6029251318fac795d41813) @@ -0,0 +1,17 @@ +<%@ include file="/common/taglibs.jsp"%> + ++ ${requestScope.message}; +
Index: lams_tool_videorecorder/web/common/messages.jsp =================================================================== diff -u --- lams_tool_videorecorder/web/common/messages.jsp (revision 0) +++ lams_tool_videorecorder/web/common/messages.jsp (revision 3d081de4a45da632ee6029251318fac795d41813) @@ -0,0 +1,20 @@ +<%-- Error Messages --%> +
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+ |
+
+ |
+ |||
---|---|---|---|---|
+ |
+ ||||
+ ${status.index + 1} + | + ++ ${condition.displayName} + | + +
+ ![]() ![]() ![]() ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+
+ ');" class="button-add-item">
+
+ +
Index: lams_tool_videorecorder/web/pages/authoring/headItems.jsp =================================================================== diff -u --- lams_tool_videorecorder/web/pages/authoring/headItems.jsp (revision 0) +++ lams_tool_videorecorder/web/pages/authoring/headItems.jsp (revision 3d081de4a45da632ee6029251318fac795d41813) @@ -0,0 +1,10 @@ +<%@ include file="/common/taglibs.jsp"%> +
+
+
+ |
+
+ + | +
+
+
+
+ |
+
+ + |
+
+
+
+ |
+
+ + | +
+
+
+
+ |
+
+
+ +
++ ${user.firstName} ${user.lastName } + | +|
---|---|
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
+
+ ${videoRecorderDTO.instructions} +
+ +
+
+ |
+
+ |
+
+ |
+
+ |
+
+
+
+
+
+
+ |
+ ||
+ |
+ ||
+ |
+
+
+ |
+
+
+ |
+
+ + |
+ ||
+
+
+
+
+ |
+ ||
+ |
+ ||
+ |
+
+
+ |
+
+
+ |
+
+ + ${session.sessionName} ++ |
+
+ |
+ + ${session.numberOfLearners} + | +
+ |
+ + ${session.numberOfFinishedLearners} + | +
+ + ${session.sessionName} ++ |
+
+ |
+ + ${session.numberOfLearners} + | +
+ |
+
+ |
+
---|---|
+ ${user.firstName} ${user.lastName} + | +
+ |
+
+ + ${userDTO.firstName} ${userDTO.lastName } ++ |
+ |
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+
+ |
+