Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/OrgManageAction.java =================================================================== diff -u --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/OrgManageAction.java (revision 0) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/OrgManageAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,232 @@ +/**************************************************************** + * 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 version 2.0 + * 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 + * **************************************************************** + */ +package org.lamsfoundation.lams.admin.web.action; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.lamsfoundation.lams.admin.service.AdminServiceProxy; +import org.lamsfoundation.lams.admin.web.form.OrgManageForm; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.usermanagement.Organisation; +import org.lamsfoundation.lams.usermanagement.OrganisationState; +import org.lamsfoundation.lams.usermanagement.OrganisationType; +import org.lamsfoundation.lams.usermanagement.Role; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.usermanagement.service.UserManagementService; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class OrgManageAction extends LamsDispatchAction { + + private static IUserManagementService userManagementService; + + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + initServices(); + + // Get organisation whose child organisations we will populate the OrgManageForm with + Integer orgId = WebUtil.readIntParam(request, "org", true); + if (orgId == null) { + orgId = (Integer) request.getAttribute("org"); + } + if ((orgId == null) || (orgId == 0)) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing organisation ID"); + return null; + } + + // get logged in user's id + Integer userId = ((UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER)).getUserID(); + ISecurityService securityService = AdminServiceProxy.getSecurityService(getServlet().getServletContext()); + + Organisation org = null; + boolean isRootOrganisation = false; + Organisation rootOrganisation = userManagementService.getRootOrganisation(); + if (orgId.equals(rootOrganisation.getOrganisationId())) { + org = rootOrganisation; + isRootOrganisation = true; + } else { + org = (Organisation) userManagementService.findById(Organisation.class, orgId); + } + + // check if user is allowed to view and edit groups + if (!request.isUserInRole(Role.SYSADMIN) && !(isRootOrganisation + ? request.isUserInRole(Role.GROUP_ADMIN) || request.isUserInRole(Role.GROUP_MANAGER) + : securityService.hasOrgRole(orgId, userId, new String[] { Role.GROUP_ADMIN, Role.GROUP_MANAGER }, + "manage courses", false))) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a manager or admin in the organisation"); + return null; + } + + // get number of users figure + // TODO use hql that does a count instead of getting whole objects + int numUsers = org == rootOrganisation ? userManagementService.getCountUsers() + : userManagementService.getUsersFromOrganisation(orgId).size(); + String key = org == rootOrganisation ? "label.users.in.system" : "label.users.in.group"; + MessageService messageService = AdminServiceProxy.getMessageService(getServlet().getServletContext()); + request.setAttribute("numUsers", messageService.getMessage(key, new String[] { String.valueOf(numUsers) })); + + // Set OrgManageForm + OrgManageForm orgManageForm = (OrgManageForm) form; + if (orgManageForm == null) { + orgManageForm = new OrgManageForm(); + orgManageForm.setStateId(OrganisationState.ACTIVE); + } else if (orgManageForm.getStateId() == null) { + orgManageForm.setStateId(OrganisationState.ACTIVE); + } + orgManageForm.setParentId(orgId); + orgManageForm.setParentName(org.getName()); + orgManageForm.setType(org.getOrganisationType().getOrganisationTypeId()); + + // Get list of child organisations depending on requestor's role and the organisation's type + if (orgManageForm.getType().equals(OrganisationType.CLASS_TYPE)) { + // display class info, with parent group's 'courseAdminCan...' permissions. + // note the org is not saved, properties set only for passing to view component. + Organisation pOrg = org.getParentOrganisation(); + org.setCourseAdminCanAddNewUsers(pOrg.getCourseAdminCanAddNewUsers()); + org.setCourseAdminCanBrowseAllUsers(pOrg.getCourseAdminCanBrowseAllUsers()); + org.setCourseAdminCanChangeStatusOfCourse(pOrg.getCourseAdminCanChangeStatusOfCourse()); + request.setAttribute("org", org); + + // display parent org breadcrumb link + request.setAttribute("parentGroupName", pOrg.getName()); + request.setAttribute("parentGroupId", pOrg.getOrganisationId()); + } else { + request.setAttribute("OrgManageForm", orgManageForm); + + // display org info + request.setAttribute("org", org); + } + + // let the jsp know whether to display links + request.setAttribute("createGroup", + request.isUserInRole(Role.SYSADMIN) || userManagementService.isUserGlobalGroupAdmin()); + request.setAttribute("editGroup", true); + request.setAttribute("manageGlobalRoles", request.isUserInRole(Role.SYSADMIN)); + return mapping.findForward("orglist"); + } + + /** + * Returns list of organisations for . + */ + public ActionForward getOrgs(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse res) throws IOException, ServletException { + initServices(); + + Integer parentOrgId = WebUtil.readIntParam(request, "parentOrgId"); + Integer stateId = WebUtil.readIntParam(request, "stateId"); + Integer typeIdParam = WebUtil.readIntParam(request, "type"); + // the organisation type of the children + Integer typeId = (typeIdParam.equals(OrganisationType.ROOT_TYPE) ? OrganisationType.COURSE_TYPE + : OrganisationType.CLASS_TYPE); + String searchString = WebUtil.readStrParam(request, "fcol[1]", true); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer isSort1 = WebUtil.readIntParam(request, "column[0]", true); + Integer isSort2 = WebUtil.readIntParam(request, "column[1]", true); + Integer isSort3 = WebUtil.readIntParam(request, "column[2]", true); + Integer isSort4 = WebUtil.readIntParam(request, "column[3]", true); + + String sortBy = ""; + String sortOrder = ""; + if (isSort1 != null) { + sortBy = "id"; + sortOrder = isSort1.equals(0) ? "ASC" : "DESC"; + + } else if (isSort2 != null) { + sortBy = "name"; + sortOrder = isSort2.equals(0) ? "ASC" : "DESC"; + + } else if (isSort3 != null) { + sortBy = "code"; + sortOrder = isSort3.equals(0) ? "ASC" : "DESC"; + + } else if (isSort4 != null) { + sortBy = "description"; + sortOrder = isSort4.equals(0) ? "ASC" : "DESC"; + + } + + List organisations = userManagementService.getPagedCourses(parentOrgId, typeId, stateId, page, + size, sortBy, sortOrder, searchString); + + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.put("total_rows", userManagementService.getCountCoursesByParentCourseAndTypeAndState(parentOrgId, + typeId, stateId, searchString)); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + for (Organisation organisation : organisations) { + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put("id", organisation.getOrganisationId()); + String orgName = organisation.getName() == null ? "" : organisation.getName(); + responseRow.put("name", StringEscapeUtils.escapeHtml(orgName)); + String orgCode = organisation.getCode() == null ? "" : organisation.getCode(); + responseRow.put("code", StringEscapeUtils.escapeHtml(orgCode)); + String orgDescription = organisation.getDescription() == null ? "" : organisation.getDescription(); + responseRow.put("description", StringEscapeUtils.escapeHtml(orgDescription)); + + rows.add(responseRow); + } + + responseJSON.set("rows", rows); + res.setContentType("application/json;charset=utf-8"); + res.getWriter().print(responseJSON.toString()); + return null; + } + + private void initServices() { + if (userManagementService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getWebApplicationContext(getServlet().getServletContext()); + userManagementService = (UserManagementService) ctx.getBean("userManagementService"); + } + } +} \ No newline at end of file Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/ToolContentListAction.java =================================================================== diff -u --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/ToolContentListAction.java (revision 0) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/ToolContentListAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,328 @@ +/**************************************************************** + * 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 version 2.0 + * 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 + * **************************************************************** + */ + + +package org.lamsfoundation.lams.admin.web.action; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.sql.DataSource; + +import org.apache.commons.lang.StringUtils; +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.lamsfoundation.lams.admin.service.AdminServiceProxy; +import org.lamsfoundation.lams.learningdesign.LearningLibrary; +import org.lamsfoundation.lams.learningdesign.LearningLibraryGroup; +import org.lamsfoundation.lams.learningdesign.dto.LearningLibraryDTO; +import org.lamsfoundation.lams.learningdesign.dto.LibraryActivityDTO; +import org.lamsfoundation.lams.learningdesign.service.ILearningDesignService; +import org.lamsfoundation.lams.tool.Tool; +import org.lamsfoundation.lams.usermanagement.Role; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.JsonUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author jliew + * + * + * + * + * + * + */ +public class ToolContentListAction extends Action { + + private static final String PARAM_ACTION = "action"; + private static final String PARAM_LIBRARY_ID = "libraryID"; + + private static final String ATTRIBUTE_ERROR_NAME = "errorName"; + private static final String ATTRIBUTE_ERROR_MESSAGE = "errorMessage"; + private static final String ATTRIBUTE_LIBRARY = "toolLibrary"; + private static final String ATTRIBUTE_VALIDITY = "learningLibraryValidity"; + private static final String ATTRIBUTE_TOOL_VERSIONS = "toolVersions"; + private static final String ATTRIBUTE_DATABASE_VERSIONS = "dbVersions"; + + private static final String FORWARD_SUCCESS = "toolcontentlist"; + private static final String FORWARD_GROUPS = "groups"; + private static final String FORWARD_ERROR = "error"; + + private static final String ACTION_ENABLE = "enable"; + private static final String ACTION_DISABLE = "disable"; + private static final String ACTION_OPEN_GROUPS = "openLearningLibraryGroups"; + private static final String ACTION_SAVE_GROUPS = "saveLearningLibraryGroups"; + + private static final String QUERY_DATABASE_VERSIONS = "select system_name, patch_level from patches"; + + private static ILearningDesignService learningDesignService; + private static IUserManagementService userManagementService; + private static DataSource dataSource; + + @SuppressWarnings("unchecked") + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + // check permission + if (!(request.isUserInRole(Role.SYSADMIN))) { + request.setAttribute(ToolContentListAction.ATTRIBUTE_ERROR_NAME, "ToolContentListAction"); + request.setAttribute(ToolContentListAction.ATTRIBUTE_ERROR_MESSAGE, AdminServiceProxy + .getMessageService(getServlet().getServletContext()).getMessage("error.authorisation")); + return mapping.findForward(ToolContentListAction.FORWARD_ERROR); + } + + // not just display, but enable/disable a learning library + String param = request.getParameter(ToolContentListAction.PARAM_ACTION); + if (StringUtils.equals(param, ToolContentListAction.ACTION_ENABLE)) { + if (checkPriviledge(request)) { + enableLibrary(mapping, form, request, response); + } else { + return mapping.findForward(ToolContentListAction.FORWARD_ERROR); + } + } else if (StringUtils.equals(param, ToolContentListAction.ACTION_DISABLE)) { + if (checkPriviledge(request)) { + disableLibrary(mapping, form, request, response); + } else { + return mapping.findForward(ToolContentListAction.FORWARD_ERROR); + } + } else if (StringUtils.equals(param, ToolContentListAction.ACTION_OPEN_GROUPS)) { + return openLearningLibraryGroups(mapping, form, request, response); + } else if (StringUtils.equals(param, ToolContentListAction.ACTION_SAVE_GROUPS)) { + saveLearningLibraryGroups(mapping, form, request, response); + return null; + } + + // get learning library dtos and their validity + List learningLibraryDTOs = getLearningDesignService().getAllLearningLibraryDetails(false, + getUserLanguage()); + // this is filled when executing following method, for efficiency purposes + HashMap learningLibraryValidity = new HashMap(learningLibraryDTOs.size()); + ArrayList toolLibrary = filterMultipleToolEntries(learningLibraryDTOs, + learningLibraryValidity); + request.setAttribute(ToolContentListAction.ATTRIBUTE_LIBRARY, toolLibrary); + request.setAttribute(ToolContentListAction.ATTRIBUTE_VALIDITY, learningLibraryValidity); + + // get tool versions + HashMap toolVersions = new HashMap(); + List tools = getUserManagementService().findAll(Tool.class); + for (Tool tool : tools) { + toolVersions.put(tool.getToolId(), tool.getToolVersion()); + } + request.setAttribute(ToolContentListAction.ATTRIBUTE_TOOL_VERSIONS, toolVersions); + + // get tool database versions + HashMap dbVersions = new HashMap(); + Connection conn = getDataSource().getConnection(); + PreparedStatement query = conn.prepareStatement(ToolContentListAction.QUERY_DATABASE_VERSIONS); + ResultSet results = query.executeQuery(); + while (results.next()) { + dbVersions.put(results.getString("system_name"), results.getInt("patch_level")); + } + request.setAttribute(ToolContentListAction.ATTRIBUTE_DATABASE_VERSIONS, dbVersions); + + return mapping.findForward(ToolContentListAction.FORWARD_SUCCESS); + } + + // returns full list of learning libraries, valid or not + @SuppressWarnings("unchecked") + private ArrayList filterMultipleToolEntries(List learningLibraryDTOs, + HashMap learningLibraryValidity) { + ArrayList activeTools = new ArrayList(); + ArrayList activeCombinedTools = new ArrayList(); + for (LearningLibraryDTO learningLibraryDTO : learningLibraryDTOs) { + // populate information about learning libary validity + learningLibraryValidity.put(learningLibraryDTO.getLearningLibraryID(), learningLibraryDTO.getValidFlag()); + for (LibraryActivityDTO template : (List) learningLibraryDTO.getTemplateActivities()) { + // no learning library ID = a part of combined learning library, we already have it in the list + if (template.getLearningLibraryID() != null) { + // combined libraries do not have tool content ID set + if (template.getToolContentID() == null) { + if (!toolExists(template, activeCombinedTools)) { + activeCombinedTools.add(template); + } + } else { + if (!toolExists(template, activeTools)) { + activeTools.add(template); + } + } + } + } + } + // put combined libraries at the end, purely for easy of use + activeTools.addAll(activeCombinedTools); + return activeTools; + } + + private boolean toolExists(LibraryActivityDTO newItem, ArrayList list) { + for (LibraryActivityDTO libraryActivityDTO : list) { + if (newItem.getLearningLibraryID().equals(libraryActivityDTO.getLearningLibraryID())) { + return true; + } + } + return false; + } + + private String getUserLanguage() { + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + return user == null ? "" : user.getLocaleLanguage(); + } + + private boolean checkPriviledge(HttpServletRequest request) { + if (!getUserManagementService().isUserSysAdmin()) { + request.setAttribute(ToolContentListAction.ATTRIBUTE_ERROR_NAME, "ToolContentListAction"); + request.setAttribute(ToolContentListAction.ATTRIBUTE_ERROR_MESSAGE, AdminServiceProxy + .getMessageService(getServlet().getServletContext()).getMessage("error.no.sysadmin.priviledge")); + return false; + } + return true; + } + + private void disableLibrary(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + Long learningLibraryId = WebUtil.readLongParam(request, ToolContentListAction.PARAM_LIBRARY_ID, false); + ILearningDesignService ldService = getLearningDesignService(); + ldService.setValid(learningLibraryId, false); + } + + private void enableLibrary(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + Long learningLibraryId = WebUtil.readLongParam(request, ToolContentListAction.PARAM_LIBRARY_ID, false); + ILearningDesignService ldService = getLearningDesignService(); + ldService.setValid(learningLibraryId, true); + + } + + /** + * Loads groups and libraries and displays the management dialog. + */ + private ActionForward openLearningLibraryGroups(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + // build full list of available learning libraries + List learningLibraries = getLearningDesignService() + .getAllLearningLibraryDetails(getUserLanguage()); + ArrayNode learningLibrariesJSON = JsonNodeFactory.instance.arrayNode(); + for (LearningLibraryDTO learningLibrary : learningLibraries) { + ObjectNode learningLibraryJSON = JsonNodeFactory.instance.objectNode(); + learningLibraryJSON.put("learningLibraryId", learningLibrary.getLearningLibraryID()); + learningLibraryJSON.put("title", learningLibrary.getTitle()); + learningLibrariesJSON.add(learningLibraryJSON); + } + request.setAttribute("learningLibraries", learningLibrariesJSON.toString()); + + // build list of existing groups + List groups = getLearningDesignService().getLearningLibraryGroups(); + ArrayNode groupsJSON = JsonNodeFactory.instance.arrayNode(); + for (LearningLibraryGroup group : groups) { + ObjectNode groupJSON = JsonNodeFactory.instance.objectNode(); + groupJSON.put("groupId", group.getGroupId()); + groupJSON.put("name", group.getName()); + for (LearningLibrary learningLibrary : group.getLearningLibraries()) { + ObjectNode learningLibraryJSON = JsonNodeFactory.instance.objectNode(); + learningLibraryJSON.put("learningLibraryId", learningLibrary.getLearningLibraryId()); + learningLibraryJSON.put("title", learningLibrary.getTitle()); + groupJSON.withArray("learningLibraries").add(learningLibraryJSON); + } + groupsJSON.add(groupJSON); + } + request.setAttribute("groups", groupsJSON.toString()); + + return mapping.findForward(ToolContentListAction.FORWARD_GROUPS); + } + + private void saveLearningLibraryGroups(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + // extract groups from JSON and persist them + + ArrayNode groupsJSON = JsonUtil.readArray(request.getParameter("groups")); + List groups = new ArrayList<>(groupsJSON.size()); + for (JsonNode groupJSON : groupsJSON) { + LearningLibraryGroup group = new LearningLibraryGroup(); + groups.add(group); + + long groupId = groupJSON.get("groupId").asLong(); + if (groupId > 0) { + group.setGroupId(groupId); + } + group.setName(groupJSON.get("name").asText(null)); + + group.setLearningLibraries(new HashSet()); + ArrayNode learningLibrariesJSON = (ArrayNode) groupJSON.get("learningLibraries"); + for (JsonNode learningLibraryJSON : learningLibrariesJSON) { + long learningLibraryId = learningLibraryJSON.asLong(); + LearningLibrary learningLibrary = getLearningDesignService().getLearningLibrary(learningLibraryId); + group.getLearningLibraries().add(learningLibrary); + } + } + + getLearningDesignService().saveLearningLibraryGroups(groups); + } + + private ILearningDesignService getLearningDesignService() { + if (ToolContentListAction.learningDesignService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + ToolContentListAction.learningDesignService = (ILearningDesignService) ctx.getBean("learningDesignService"); + } + return ToolContentListAction.learningDesignService; + } + + private IUserManagementService getUserManagementService() { + if (ToolContentListAction.userManagementService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + ToolContentListAction.userManagementService = (IUserManagementService) ctx.getBean("userManagementService"); + } + return ToolContentListAction.userManagementService; + } + + private DataSource getDataSource() { + if (ToolContentListAction.dataSource == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + ToolContentListAction.dataSource = (DataSource) ctx.getBean("dataSource"); + } + return ToolContentListAction.dataSource; + } +} \ No newline at end of file Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/UserSearchAction.java =================================================================== diff -u --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/UserSearchAction.java (revision 0) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/UserSearchAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,157 @@ +/**************************************************************** + * 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 version 2.0 + * 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 + * **************************************************************** + */ + +package org.lamsfoundation.lams.admin.web.action; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +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.lamsfoundation.lams.admin.service.AdminServiceProxy; +import org.lamsfoundation.lams.usermanagement.Role; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author jliew + * + * + * + * + */ +public class UserSearchAction extends LamsDispatchAction { + + private static Logger log = Logger.getLogger(UserSearchAction.class); + private static IUserManagementService service; + private static MessageService messageService; + + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + initServices(); + + if (!(request.isUserInRole(Role.SYSADMIN) || service.isUserGlobalGroupAdmin())) { + log.debug("user not sysadmin or global group admin"); + + request.setAttribute("errorName", "UserSearchAction authorisation"); + request.setAttribute("errorMessage", messageService.getMessage("error.authorisation")); + return mapping.findForward("error"); + } + + return mapping.findForward("usersearchlist"); + } + + /** + * Returns list of paged users. + */ + public ActionForward getPagedUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse res) throws IOException, ServletException { + initServices(); + + // the organisation type of the children + String searchString = WebUtil.readStrParam(request, "fcol[1]", true); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer isSort1 = WebUtil.readIntParam(request, "column[0]", true); + Integer isSort2 = WebUtil.readIntParam(request, "column[1]", true); + Integer isSort3 = WebUtil.readIntParam(request, "column[2]", true); + Integer isSort4 = WebUtil.readIntParam(request, "column[3]", true); + Integer isSort5 = WebUtil.readIntParam(request, "column[4]", true); + + String sortBy = "userId"; + String sortOrder = "DESC"; + if (isSort1 != null) { + sortBy = "userId"; + sortOrder = isSort1.equals(0) ? "ASC" : "DESC"; + + } else if (isSort2 != null) { + sortBy = "login"; + sortOrder = isSort2.equals(0) ? "ASC" : "DESC"; + + } else if (isSort3 != null) { + sortBy = "firstName"; + sortOrder = isSort3.equals(0) ? "ASC" : "DESC"; + + } else if (isSort4 != null) { + sortBy = "lastName"; + sortOrder = isSort4.equals(0) ? "ASC" : "DESC"; + + } else if (isSort5 != null) { + sortBy = "email"; + sortOrder = isSort5.equals(0) ? "ASC" : "DESC"; + } + + List userDtos = service.getAllUsersPaged(page, size, sortBy, sortOrder, searchString); + + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + responcedata.put("total_rows", service.getCountUsers(searchString)); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + for (UserDTO userDto : userDtos) { + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put("userId", userDto.getUserID()); + responseRow.put("login", StringEscapeUtils.escapeHtml(userDto.getLogin())); + String firstName = userDto.getFirstName() == null ? "" : userDto.getFirstName(); + responseRow.put("firstName", StringEscapeUtils.escapeHtml(firstName)); + String lastName = userDto.getLastName() == null ? "" : userDto.getLastName(); + responseRow.put("lastName", StringEscapeUtils.escapeHtml(lastName)); + String email = userDto.getEmail() == null ? "" : userDto.getEmail(); + responseRow.put("email", StringEscapeUtils.escapeHtml(email)); + + rows.add(responseRow); + } + responcedata.set("rows", rows); + res.setContentType("application/json;charset=utf-8"); + res.getWriter().print(new String(responcedata.toString())); + return null; + } + + private void initServices() { + if (service == null) { + service = AdminServiceProxy.getService(getServlet().getServletContext()); + } + if (messageService == null) { + messageService = AdminServiceProxy.getMessageService(getServlet().getServletContext()); + } + } + +} \ No newline at end of file Index: lams_build/build_base.xml =================================================================== diff -u -r0b67ee804237056395e60ed4cca2948a595ddb72 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_build/build_base.xml (.../build_base.xml) (revision 0b67ee804237056395e60ed4cca2948a595ddb72) +++ lams_build/build_base.xml (.../build_base.xml) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -41,7 +41,6 @@ - @@ -55,6 +54,8 @@ + + Index: lams_build/common.properties =================================================================== diff -u -r6d0fd60838e941efefda00d1dd9778accf37a4b7 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_build/common.properties (.../common.properties) (revision 6d0fd60838e941efefda00d1dd9778accf37a4b7) +++ lams_build/common.properties (.../common.properties) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -18,7 +18,7 @@ # http://www.gnu.org/licenses/gpl.txt # put into EAR MANIFEST.MF file -project.version=3.0 +project.version=3.1 # is HTTPS in use? if so, set it to true, so JSESSIONID cookie is secured secure.cookie=false Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r953f62a7fc515e2dc5c4ad983df233070cf7a82c -r2c03060b238558d183472f0066ba003c76d00fd0 Binary files differ Index: lams_build/liblist.txt =================================================================== diff -u -r6d0fd60838e941efefda00d1dd9778accf37a4b7 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_build/liblist.txt (.../liblist.txt) (revision 6d0fd60838e941efefda00d1dd9778accf37a4b7) +++ lams_build/liblist.txt (.../liblist.txt) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -2,10 +2,10 @@ Folder Library Version License Vendor Description -apache-poi poi-3.10-FINAL-20140208.jar 3.10 Apache License 2.0 Apache the Java API for Microsoft Documents - poi-ooxml-3.10-FINAL-20140208.jar - poi-ooxml-schemas-3.10-FINAL-20140208.jar - xmlbeans-2.4.0.jar 2.3.0 +apache-poi poi-3.16.jar 3.16 Apache License 2.0 Apache the Java API for Microsoft Documents + poi-ooxml-3.16.jar + poi-ooxml-schemas-3.16.jar + xmlbeans-2.6.0.jar 2.6.0 autopatch autopatch-1.4.2-lams.jar 1.4.2-lams Apache License Tacit Knowledge automated Java patching system discovery-1.0.5-lams.jar 1.0.5-lams @@ -23,46 +23,36 @@ googleauth googleauth-1.1.1.jar 1.1.1 Public Domain Enrico M. Crisostomo Java server library that implements the Time-based One-time Password (TOTP) algorithm jakarta-commons commons-digester-2.1.jar 2.1 Apache Software License 2.0 Apache Software Foundation XML -> Java object mapping tool - commons-fileupload.jar 1.0 Apache Software License 1.1 Apache Software Foundation File upload component for Java servlets - commons-validator.jar 1.1.4 Apache License 2.0 The Apache Software Foundation Commons Validator + commons-fileupload-1.3.3.jar 1.3.3 Apache Software License 1.1 Apache Software Foundation File upload component for Java servlets + commons-validator-1.6.jar 1.6 Apache License 2.0 The Apache Software Foundation Commons Validator + commons-discovery-0.5.jar 0.5 Apache License 2.0 The Apache Software Foundation -jboss jbossweb.jar 2.1.3 LGPL 2.1 Apache Software Foundation SSO valve and JSON - -jlatexmath jlatexmath-1.0.3.jar 1.0.3 +jlatexmath jlatexmath-1.0.6.jar 1.0.6 json-simple json-simple-1.1.1.jar 1.1.1 Apache License 2.0 fangyidong A simple Java toolkit for JSON -lucene lucene-core-2.4.0.jar 2.4.0 Apache License 2.0 Apache text search engine library - lucene-snowball-2.4.0.jar 2.4.0 +mysql mysql-connector-java-5.1.43-bin.jar 5.1.43 GPL Oracle Java connector for MySQL -mysql mysql-connector-java-5.1.38-bin.jar 5.1.31 GPL Oracle Java connector for MySQL - odmg odmg-3.0.jar 3.0 -quartz quartz-2.2.1.jar 2.2.1 Apache License 2.0 Terracotta For running scheduled jobs +quartz quartz-2.2.3.jar 2.2.3 Apache License 2.0 Terracotta For running scheduled jobs -spring spring-core-4.0.6.RELEASE.jar 4.0.6 Apache License 2.0 GoPivotal programming and configuration model for modern Java-based enterprise applications - spring-beans-4.0.6.RELEASE.jar - spring-context-4.0.6.RELEASE.jar - spring-context-support-4.0.6.RELEASE.jar - spring-expression-4.0.6.RELEASE.jar - spring-jdbc-4.0.6.RELEASE.jar - spring-orm-4.0.6.RELEASE.jar - spring-tx-4.0.6.RELEASE.jar - spring-web-4.0.6.RELEASE.jar - aopalliance.jar 1.0 Public Domain AOP Alliance +spring spring-core-4.3.10.RELEASE.jar 4.3.10 Apache License 2.0 Pivotal programming and configuration model for modern Java-based enterprise applications + spring-beans-4.3.10.RELEASE.jar + spring-context-4.3.10.RELEASE.jar + spring-context-support-4.3.10.RELEASE.jar + spring-expression-4.3.10.RELEASE.jar + spring-jdbc-4.3.10.RELEASE.jar + spring-orm-4.3.10.RELEASE.jar + spring-tx-4.3.10.RELEASE.jar + spring-web-4.3.10.RELEASE.jar struts jakarta-oro.jar 2.0.7 Apache License 2.0 Apache regular expressions struts.jar 1.2.7 Apache License 2.0 Apache Struts Framework struts-el.jar 1.2.9 Apache License 2.0 Apache Struts extensions urlrewritefilter urlrewritefilter-4.0.3.jar 4.0.3 BSD License tuckey.org Java Web Filter which allows rewriting URLs -xml-commons xml-apis.jar 1.3 - xml-apis-ext.jar 1.3 Apache License 2.0 Apache Common code and guidelines for xml projects +xstream xstream-1.5.0-SNAPSHOT.jar 1.5.0 XML serializer -xstream xmlpull-1.1.3.1.jar 1.1.3.1 - xpp3_min-1.1.4c.jar 1.1.4c - xstream-1.5.0-SNAPSHOT.jar 1.5.0 XML serializer - yuicompressor yuicompressor-2.4.9 2.4.9 BSD License YUI CSS and JS minifier Index: lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -27,9 +27,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URLEncoder; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Date; import java.util.Set; import java.util.TreeSet; @@ -46,8 +43,6 @@ import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.DispatchAction; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.contentrepository.exception.RepositoryCheckedException; import org.lamsfoundation.lams.learningdesign.GroupUser; import org.lamsfoundation.lams.learningdesign.dao.IGroupUserDAO; @@ -75,6 +70,9 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * This is an action where all lams client environments launch. initial configuration of the individual environment * setting is done here. @@ -176,7 +174,6 @@ return mapping.findForward("lessonIntro"); } - if (mode != null) { req.setAttribute(AttributeNames.PARAM_MODE, mode); } @@ -187,7 +184,7 @@ : "/" + serverURLContextPath; serverURLContextPath += serverURLContextPath.endsWith("/") ? "" : "/"; getServlet().getServletContext().getContext(serverURLContextPath + "learning") - .getRequestDispatcher("/content.do?lessonID="+lessonId).forward(req, res); + .getRequestDispatcher("/content.do?lessonID=" + lessonId).forward(req, res); return null; } catch (Exception e) { @@ -241,8 +238,7 @@ @SuppressWarnings("unchecked") public ActionForward addLesson(ActionMapping mapping, ActionForm form, HttpServletRequest req, - HttpServletResponse res) - throws IOException, UserAccessDeniedException, JSONException, RepositoryCheckedException { + HttpServletResponse res) throws IOException, UserAccessDeniedException, RepositoryCheckedException { UserDTO userDTO = getUser(); Integer organisationID = new Integer(WebUtil.readIntParam(req, "organisationID")); @@ -255,35 +251,35 @@ String folderContentsJSON = getWorkspaceManagementService().getFolderContentsJSON(null, userDTO.getUserID(), false); req.setAttribute("folderContents", folderContentsJSON); - JSONObject users = new JSONObject(); + ObjectNode users = JsonNodeFactory.instance.objectNode(); // get learners available for newly created lesson Vector learners = getUserManagementService().getUsersFromOrganisationByRole(organisationID, "LEARNER", true); for (User user : learners) { - JSONObject userJSON = new JSONObject(); + ObjectNode userJSON = JsonNodeFactory.instance.objectNode(); userJSON.put("userID", user.getUserId()); userJSON.put("firstName", user.getFirstName()); userJSON.put("lastName", user.getLastName()); userJSON.put("login", user.getLogin()); - users.append("selectedLearners", userJSON); + users.withArray("selectedLearners").add(userJSON); } Vector monitors = getUserManagementService().getUsersFromOrganisationByRole(organisationID, "MONITOR", true); for (User user : monitors) { - JSONObject userJSON = new JSONObject(); + ObjectNode userJSON = JsonNodeFactory.instance.objectNode(); userJSON.put("userID", user.getUserId()); userJSON.put("firstName", user.getFirstName()); userJSON.put("lastName", user.getLastName()); userJSON.put("login", user.getLogin()); if (userDTO.getUserID().equals(user.getUserId())) { // creator is always selected - users.append("selectedMonitors", userJSON); + users.withArray("selectedMonitors").add(userJSON); } else { - users.append("unselectedMonitors", userJSON); + users.withArray("unselectedMonitors").add(userJSON); } } @@ -292,7 +288,7 @@ // find lessons which can be set as preceding ones for newly created lesson Organisation organisation = (Organisation) getUserManagementService().findById(Organisation.class, organisationID); - Set availableLessons = new TreeSet(new LessonDTOComparator()); + Set availableLessons = new TreeSet<>(new LessonDTOComparator()); for (Lesson availableLesson : (Set) organisation.getLessons()) { Integer availableLessonState = availableLesson.getLessonStateId(); if (!Lesson.REMOVED_STATE.equals(availableLessonState) @@ -309,8 +305,7 @@ * Gets subfolder contents in Add Lesson screen. */ public ActionForward getFolderContents(ActionMapping mapping, ActionForm form, HttpServletRequest req, - HttpServletResponse res) - throws UserAccessDeniedException, JSONException, IOException, RepositoryCheckedException { + HttpServletResponse res) throws UserAccessDeniedException, IOException, RepositoryCheckedException { Integer folderID = WebUtil.readIntParam(req, "folderID", true); boolean allowInvalidDesigns = WebUtil.readBooleanParam(req, "allowInvalidDesigns", false); String folderContentsJSON = getWorkspaceManagementService().getFolderContentsJSON(folderID, Index: lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java =================================================================== diff -u -r9b24f3330d42579e9c7b3e807568360a617d9a8c -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 9b24f3330d42579e9c7b3e807568360a617d9a8c) +++ lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -38,9 +38,6 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.index.IndexLinkBean; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.Role; @@ -57,6 +54,10 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Fei Yang @@ -74,7 +75,7 @@ public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - setHeaderLinks(request); + IndexAction.setHeaderLinks(request); setAdminLinks(request); // check if this is user's first login; some action (like displaying a dialog for disabling tutorials) can be @@ -111,25 +112,26 @@ return mapping.findForward("editprofile"); } else if (StringUtils.equals(method, "password")) { return mapping.findForward("password"); - } else if (StringUtils.equals(method, "portrait")) { + } else if (StringUtils.equals(method, "portrait")) { return mapping.findForward("portrait"); } else if (StringUtils.equals(method, "lessons")) { return mapping.findForward("lessons"); } - + // only show the growl warning the first time after a user has logged in & if turned on in configuration Boolean tzWarning = Configuration.getAsBoolean(ConfigurationKeys.SHOW_TIMEZONE_WARNING); request.setAttribute("showTimezoneWarning", tzWarning); request.setAttribute("showTimezoneWarningPopup", false); - if ( tzWarning ) { + if (tzWarning) { Boolean ssWarningShown = (Boolean) ss.getAttribute("timezoneWarningShown"); - if ( ! Boolean.TRUE.equals(ssWarningShown) ) { + if (!Boolean.TRUE.equals(ssWarningShown)) { ss.setAttribute("timezoneWarningShown", Boolean.TRUE); request.setAttribute("showTimezoneWarningPopup", true); } } - - List favoriteOrganisations = userManagementService.getFavoriteOrganisationsByUser(userDTO.getUserID()); + + List favoriteOrganisations = userManagementService + .getFavoriteOrganisationsByUser(userDTO.getUserID()); request.setAttribute("favoriteOrganisations", favoriteOrganisations); request.setAttribute("activeOrgId", user.getLastVisitedOrganisationId()); @@ -141,9 +143,9 @@ } private static void setHeaderLinks(HttpServletRequest request) { - List headerLinks = new ArrayList(); + List headerLinks = new ArrayList<>(); if (request.isUserInRole(Role.AUTHOR)) { - if (isPedagogicalPlannerAvailable()) { + if (IndexAction.isPedagogicalPlannerAvailable()) { headerLinks.add(new IndexLinkBean("index.planner", "javascript:openPedagogicalPlanner()")); } headerLinks.add(new IndexLinkBean("index.author", "javascript:showAuthoringDialog()")); @@ -159,7 +161,7 @@ } private void setAdminLinks(HttpServletRequest request) { - List adminLinks = new ArrayList(); + List adminLinks = new ArrayList<>(); if (request.isUserInRole(Role.SYSADMIN) || request.isUserInRole(Role.GROUP_ADMIN) || request.isUserInRole(Role.GROUP_MANAGER)) { adminLinks.add(new IndexLinkBean("index.courseman", "javascript:openOrgManagement(" @@ -175,10 +177,10 @@ * Returns list of organisations for user. Used by offcanvas tablesorter on main.jsp. */ public ActionForward getOrgs(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { getUserManagementService(); User loggedInUser = getUserManagementService().getUserByLogin(request.getRemoteUser()); - + Integer userId = loggedInUser.getUserId(); boolean isSysadmin = request.isUserInRole(Role.SYSADMIN); String searchString = WebUtil.readStrParam(request, "fcol[1]", true); @@ -199,27 +201,28 @@ // // } - List orgDtos = userManagementService.getActiveCoursesByUser(userId, isSysadmin, page, size, searchString); + List orgDtos = userManagementService.getActiveCoursesByUser(userId, isSysadmin, page, size, + searchString); - JSONObject responcedata = new JSONObject(); - responcedata.put("total_rows", userManagementService.getCountActiveCoursesByUser(userId, isSysadmin, searchString)); + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + responcedata.put("total_rows", + userManagementService.getCountActiveCoursesByUser(userId, isSysadmin, searchString)); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); for (OrganisationDTO orgDto : orgDtos) { - - JSONObject responseRow = new JSONObject(); + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); responseRow.put("id", orgDto.getOrganisationID()); String orgName = orgDto.getName() == null ? "" : orgDto.getName(); responseRow.put("name", StringEscapeUtils.escapeHtml(orgName)); - rows.put(responseRow); + rows.add(responseRow); } - responcedata.put("rows", rows); + responcedata.set("rows", rows); res.setContentType("application/json;charset=utf-8"); res.getWriter().print(new String(responcedata.toString())); return null; } - + /** * Toggles whether organisation is marked as favorite. */ @@ -235,18 +238,18 @@ List favoriteOrganisations = userManagementService.getFavoriteOrganisationsByUser(userId); request.setAttribute("favoriteOrganisations", favoriteOrganisations); - + String activeOrgId = request.getParameter("activeOrgId"); request.setAttribute("activeOrgId", activeOrgId); return mapping.findForward("favoriteOrganisations"); } - + /** * Saves to DB last visited organisation. It's required for displaying some org on main.jsp next time user logs in. */ - public ActionForward storeLastVisitedOrganisation(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException { + public ActionForward storeLastVisitedOrganisation(ActionMapping mapping, ActionForm form, + HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException { getUserManagementService(); Integer lastVisitedOrganisationId = WebUtil.readIntParam(request, "orgId", false); @@ -259,7 +262,7 @@ return null; } - + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO learner = (UserDTO) ss.getAttribute(AttributeNames.USER); Index: lams_central/src/java/org/lamsfoundation/lams/web/OrganisationGroupAction.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/web/OrganisationGroupAction.java (.../OrganisationGroupAction.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_central/src/java/org/lamsfoundation/lams/web/OrganisationGroupAction.java (.../OrganisationGroupAction.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -44,9 +44,6 @@ import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.DispatchAction; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.contentrepository.exception.InvalidParameterException; import org.lamsfoundation.lams.integration.dto.ExtGroupDTO; import org.lamsfoundation.lams.integration.service.IIntegrationService; @@ -71,12 +68,19 @@ import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.AlphanumComparator; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + public class OrganisationGroupAction extends DispatchAction { private static Logger log = Logger.getLogger(OrganisationGroupAction.class); @@ -215,7 +219,7 @@ Long activityId = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID, true); request.setAttribute("canEdit", isGroupSuperuser || (activityId != null)); - JSONObject orgGroupingJSON = new JSONObject(); + ObjectNode orgGroupingJSON = JsonNodeFactory.instance.objectNode(); orgGroupingJSON.put("organisationId", organisationId); Long orgGroupingId = WebUtil.readLongParam(request, "groupingId", true); @@ -259,7 +263,7 @@ boolean isUsedForBranching = (lessonGrouping != null) && lessonGrouping.isUsedForBranching(); request.setAttribute(GroupingAJAXAction.PARAM_USED_FOR_BRANCHING, isUsedForBranching); - JSONArray orgGroupsJSON = new JSONArray(); + ArrayNode orgGroupsJSON = JsonNodeFactory.instance.arrayNode(); Collection learners = null; // if teacher selected groups from integrated server - show them @@ -299,19 +303,19 @@ // sort groups by their name Collections.sort(extGroups); for (ExtGroupDTO extGroup : extGroups) { - JSONObject groupJSON = new JSONObject(); + ObjectNode groupJSON = JsonNodeFactory.instance.objectNode(); groupJSON.put("name", extGroup.getGroupName()); groupJSON.put("groupId", extGroup.getGroupId()); if (extGroup.getUsers() != null) { for (User groupUser : (List) extGroup.getUsers()) { - JSONObject groupUserJSON = WebUtil.userToJSON(groupUser); - groupJSON.append("users", groupUserJSON); + ObjectNode groupUserJSON = WebUtil.userToJSON(groupUser); + groupJSON.withArray("users").add(groupUserJSON); // remove the user who is already assigned to a group learners.remove(groupUser); } } - orgGroupsJSON.put(groupJSON); + orgGroupsJSON.add(groupJSON); } } @@ -332,14 +336,14 @@ orgGroupsJSON = getLessonGroupsDetails(lessonGroups, learners); request.setAttribute("skipInitialAssigning", true); } - orgGroupingJSON.put("groups", orgGroupsJSON); + orgGroupingJSON.set("groups", orgGroupsJSON); request.setAttribute("grouping", orgGroupingJSON); // all the remaining users are unassigned to any group - JSONArray unassignedUsersJSON = new JSONArray(); + ArrayNode unassignedUsersJSON = JsonNodeFactory.instance.arrayNode(); for (User unassignedUser : learners) { - JSONObject unassignedUserJSON = WebUtil.userToJSON(unassignedUser); - unassignedUsersJSON.put(unassignedUserJSON); + ObjectNode unassignedUserJSON = WebUtil.userToJSON(unassignedUser); + unassignedUsersJSON.add(unassignedUserJSON); } request.setAttribute("unassignedUsers", unassignedUsersJSON); @@ -350,7 +354,7 @@ * Saves a course grouping. */ public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, InvalidParameterException, IOException { + HttpServletResponse response) throws InvalidParameterException, IOException { // check if user is allowed to edit groups Integer userId = getUserDTO().getUserID(); int organisationId = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID); @@ -367,38 +371,37 @@ } // deserialize grouping - JSONObject orgGroupingJSON = new JSONObject(request.getParameter("grouping")); + ObjectNode orgGroupingJSON = new ObjectMapper().readValue(request.getParameter("grouping"), ObjectNode.class); // check if already exists - Long orgGroupingId = orgGroupingJSON.optLong("groupingId"); + Long orgGroupingId = orgGroupingJSON.get("groupingId").asLong(); if (orgGroupingId == 0L) { orgGroupingId = null; } // iterate over groups List orgGroups = new LinkedList<>(); - JSONArray orgGroupsJSON = orgGroupingJSON.optJSONArray("groups"); + ArrayNode orgGroupsJSON = JsonUtil.optArray(orgGroupingJSON, "groups"); if (orgGroupsJSON != null) { - for (int i = 0; i < orgGroupsJSON.length(); i++) { + for (JsonNode orgGroupNode : orgGroupsJSON) { // just overwrite existing groups; they will be updated if already exist Set users = new HashSet<>(); - JSONObject orgGroupJSON = orgGroupsJSON.getJSONObject(i); - JSONArray usersJSON = orgGroupJSON.optJSONArray("users"); + ObjectNode orgGroupJSON = (ObjectNode) orgGroupNode; + ArrayNode usersJSON = JsonUtil.optArray(orgGroupJSON, "users"); if (usersJSON != null) { // find user objects based on delivered IDs - for (int j = 0; j < usersJSON.length(); j++) { - Integer learnerId = usersJSON.getInt(j); - User user = (User) getUserManagementService().findById(User.class, learnerId); + for (JsonNode learnerId : usersJSON) { + User user = (User) getUserManagementService().findById(User.class, learnerId.asInt()); users.add(user); } } OrganisationGroup orgGroup = new OrganisationGroup(); - Long orgGroupId = orgGroupJSON.optLong("groupId"); + Long orgGroupId = JsonUtil.optLong(orgGroupJSON, "groupId"); if (orgGroupId > 0) { orgGroup.setGroupId(orgGroupId); orgGroup.setGroupingId(orgGroupingId); } - orgGroup.setName(orgGroupJSON.optString("name", null)); + orgGroup.setName(JsonUtil.optString(orgGroupJSON, "name")); orgGroup.setUsers(users); orgGroups.add(orgGroup); @@ -415,7 +418,7 @@ orgGrouping.setOrganisationId(organisationId); } // update grouping name - String orgGroupingName = orgGroupingJSON.getString("name"); + String orgGroupingName = JsonUtil.optString(orgGroupingJSON, "name"); orgGrouping.setName(orgGroupingName); getUserManagementService().saveOrganisationGrouping(orgGrouping, orgGroups); @@ -452,36 +455,36 @@ * Fetches course and branching so they can get matched by user. */ public ActionForward getGroupsForMapping(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { Long orgGroupingId = WebUtil.readLongParam(request, "groupingId"); Long activityID = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); OrganisationGrouping orgGrouping = (OrganisationGrouping) getUserManagementService() .findById(OrganisationGrouping.class, orgGroupingId); - JSONArray groupsJSON = new JSONArray(); + ArrayNode groupsJSON = JsonNodeFactory.instance.arrayNode(); SortedSet orgGroups = new TreeSet<>(orgGrouping.getGroups()); for (OrganisationGroup group : orgGroups) { - JSONObject groupJSON = new JSONObject(); + ObjectNode groupJSON = JsonNodeFactory.instance.objectNode(); groupJSON.put("id", group.getGroupId()); groupJSON.put("name", group.getName()); - groupsJSON.put(groupJSON); + groupsJSON.add(groupJSON); } Activity activity = (Activity) getUserManagementService().findById(Activity.class, activityID); Grouping grouping = activity.isGroupingActivity() ? ((GroupingActivity) activity).getCreateGrouping() : ((BranchingActivity) activity).getGrouping(); - JSONArray branchesJSON = new JSONArray(); + ArrayNode branchesJSON = JsonNodeFactory.instance.arrayNode(); SortedSet groups = new TreeSet<>(grouping.getGroups()); for (Group group : groups) { - JSONObject groupJSON = new JSONObject(); + ObjectNode groupJSON = JsonNodeFactory.instance.objectNode(); groupJSON.put("id", group.getGroupId()); groupJSON.put("name", group.getGroupName()); - branchesJSON.put(groupJSON); + branchesJSON.add(groupJSON); } - JSONObject responseJSON = new JSONObject(); - responseJSON.put("branches", branchesJSON); - responseJSON.put("groups", groupsJSON); + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.set("branches", branchesJSON); + responseJSON.set("groups", groupsJSON); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); @@ -492,12 +495,12 @@ * Stores course groups to branching groups mapping. */ public ActionForward saveGroupMappings(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { - JSONArray groupMapping = new JSONArray(request.getParameter("mapping")); - for (int index = 0; index < groupMapping.length(); index++) { - JSONObject entry = groupMapping.getJSONObject(index); - Long orgGroupID = entry.getLong("groupID"); - Long branchingGroupID = entry.getLong("branchID"); + HttpServletResponse response) throws IOException { + ArrayNode groupMapping = JsonUtil.readArray(request.getParameter("mapping")); + for (JsonNode entryNode : groupMapping) { + ObjectNode entry = (ObjectNode) entryNode; + Long orgGroupID = JsonUtil.optLong(entry, "groupID"); + Long branchingGroupID = JsonUtil.optLong(entry, "branchID"); OrganisationGroup orgGroup = (OrganisationGroup) getUserManagementService() .findById(OrganisationGroup.class, orgGroupID); Group branchingGroup = (Group) getUserManagementService().findById(Group.class, branchingGroupID); @@ -514,28 +517,28 @@ /** * Build JSON objects based on existing lesson-level groups. */ - private JSONArray getLessonGroupsDetails(Set groups, Collection learners) throws JSONException { + private ArrayNode getLessonGroupsDetails(Set groups, Collection learners) { // serialize database group objects into JSON - JSONArray groupsJSON = new JSONArray(); + ArrayNode groupsJSON = JsonNodeFactory.instance.arrayNode(); if (groups != null) { // sort groups by their name List groupList = new LinkedList<>(groups); Collections.sort(groupList, new GroupComparator()); for (Group group : groupList) { - JSONObject groupJSON = new JSONObject(); + ObjectNode groupJSON = JsonNodeFactory.instance.objectNode(); groupJSON.put("name", group.getGroupName()); groupJSON.put("groupId", group.getGroupId()); groupJSON.put("locked", !group.mayBeDeleted()); if (group.getUsers() != null) { for (User groupUser : group.getUsers()) { - JSONObject groupUserJSON = WebUtil.userToJSON(groupUser); - groupJSON.append("users", groupUserJSON); + ObjectNode groupUserJSON = WebUtil.userToJSON(groupUser); + groupJSON.withArray("users").add(groupUserJSON); // remove the user who is already assigned to a group learners.remove(groupUser); } } - groupsJSON.put(groupJSON); + groupsJSON.add(groupJSON); } } @@ -545,8 +548,7 @@ /** * Build JSON objects based on existing course-level groups. */ - private JSONArray getOrgGroupsDetails(Set groups, Collection learners) - throws JSONException { + private ArrayNode getOrgGroupsDetails(Set groups, Collection learners) { final Comparator ORG_GROUP_COMPARATOR = new Comparator() { @Override @@ -560,25 +562,25 @@ }; // serialize database group objects into JSON - JSONArray groupsJSON = new JSONArray(); + ArrayNode groupsJSON = JsonNodeFactory.instance.arrayNode(); if (groups != null) { // sort groups by their name List groupList = new LinkedList<>(groups); Collections.sort(groupList, ORG_GROUP_COMPARATOR); for (OrganisationGroup group : groupList) { - JSONObject groupJSON = new JSONObject(); + ObjectNode groupJSON = JsonNodeFactory.instance.objectNode(); groupJSON.put("name", group.getName()); groupJSON.put("groupId", group.getGroupId()); for (User groupUser : group.getUsers()) { - JSONObject groupUserJSON = WebUtil.userToJSON(groupUser); - groupJSON.append("users", groupUserJSON); + ObjectNode groupUserJSON = WebUtil.userToJSON(groupUser); + groupJSON.withArray("users").add(groupUserJSON); // remove the user who is already assigned to a group learners.remove(groupUser); } - groupsJSON.put(groupJSON); + groupsJSON.add(groupJSON); } } Index: lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (.../LtiAction.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_central/src/java/org/lamsfoundation/lams/web/action/LtiAction.java (.../LtiAction.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -15,7 +15,7 @@ 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.exception.RepositoryCheckedException; import org.lamsfoundation.lams.integration.ExtCourseClassMap; @@ -70,7 +70,7 @@ * pages */ public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { initServices(); String consumerKey = request.getParameter(LtiUtils.OAUTH_CONSUMER_KEY); @@ -120,7 +120,7 @@ * design and start a lesson. */ public ActionForward addLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, UserInfoFetchException, UserInfoValidationException { initServices(); Integer userId = getUser().getUserID(); @@ -156,7 +156,7 @@ * Starts a lesson. Then prompts to learnerMonitor page. */ public ActionForward startLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, UserAccessDeniedException, JSONException, + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { initServices(); Integer userId = getUser().getUserID(); @@ -211,7 +211,7 @@ * 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, + HttpServletResponse response) throws IOException, UserAccessDeniedException, RepositoryCheckedException, UserInfoValidationException, UserInfoFetchException { initServices(); Integer userId = getUser().getUserID(); Index: lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java (.../PedagogicalPlannerAction.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java (.../PedagogicalPlannerAction.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -33,9 +33,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -51,24 +49,6 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.document.Document; -import org.apache.lucene.document.Field; -import org.apache.lucene.document.StringField; -import org.apache.lucene.document.TextField; -import org.apache.lucene.index.CorruptIndexException; -import org.apache.lucene.index.DirectoryReader; -import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.index.IndexWriterConfig; -import org.apache.lucene.index.IndexWriterConfig.OpenMode; -import org.apache.lucene.queryparser.classic.MultiFieldQueryParser; -import org.apache.lucene.queryparser.classic.ParseException; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.ScoreDoc; -import org.apache.lucene.search.TopDocs; -import org.apache.lucene.store.RAMDirectory; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; @@ -124,24 +104,13 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider; +import com.thoughtworks.xstream.io.xml.StaxDriver; import com.thoughtworks.xstream.security.AnyTypePermission; /** * Action managing Pedagogical Planner base page and non-tool activities. * * @author Marcin Cieslak - * - * - * - * - * - * - * - * - * - * - * */ public class PedagogicalPlannerAction extends LamsDispatchAction { private static Logger log = Logger.getLogger(PedagogicalPlannerAction.class); @@ -155,9 +124,6 @@ private static PedagogicalPlannerDAO pedagogicalPlannerDAO; private static ActivityDAO activityDAO; - private static final RAMDirectory luceneDir = new RAMDirectory(); - private static final Analyzer luceneAnalyzer = new StandardAnalyzer(); - private static final String FILE_EXTENSION_ZIP = ".zip"; private static final String FILE_EXTENSION_LAS = ".las"; @@ -354,7 +320,7 @@ throws ServletException { ActionMessages errors = new ActionMessages(); - List activities = new ArrayList(); + List activities = new ArrayList<>(); // Create DTOs that hold all the necessary information of the activities Activity activity = learningDesign.getFirstActivity(); @@ -752,48 +718,13 @@ Boolean edit = WebUtil.readBooleanParam(request, CentralConstants.PARAM_EDIT, false); edit &= canEdit; - // Fill the DTO - PedagogicalPlannerSequenceNodeDTO dto = null; - if (filterText != null) { - try { - // Filtering = display node and all the subnodes that were found in the search (not the immediate - // children of the node) - Set filteredNodeUids = filterSubnodes(node, filterText); - if (filteredNodeUids != null) { - request.setAttribute(CentralConstants.PARAM_FILTER_TEXT, filterText); - - Set filteredNodes = new LinkedHashSet( - filteredNodeUids.size()); - for (Long filteredUid : filteredNodeUids) { - PedagogicalPlannerSequenceNode subnode = getPedagogicalPlannerDAO().getByUid(filteredUid); - filteredNodes.add(subnode); - } - - dto = new PedagogicalPlannerSequenceNodeDTO(node, filteredNodes, isSysAdmin, - getPedagogicalPlannerDAO()); - for (PedagogicalPlannerSequenceNodeDTO subnodeDTO : dto.getSubnodes()) { - List titlePath = getPedagogicalPlannerDAO().getTitlePath(subnodeDTO.getUid()); - subnodeDTO.setTitlePath(titlePath); - } - } - } catch (Exception e) { - PedagogicalPlannerAction.log.error(e, e); - ActionMessages errors = new ActionMessages(); - errors.add(ActionMessages.GLOBAL_MESSAGE, - new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILTER_PARSE)); - saveErrors(request, errors); - } + // No filtering or something went wrong in filtering + PedagogicalPlannerSequenceNodeDTO dto = new PedagogicalPlannerSequenceNodeDTO(node, node.getSubnodes(), + isSysAdmin, getPedagogicalPlannerDAO()); + if (nodeUid == null) { + dto.setRecentlyModifiedNodes(getRecentlyModifiedLearnindDesignsAsNodes()); } - if (dto == null) { - // No filtering or something went wrong in filtering - dto = new PedagogicalPlannerSequenceNodeDTO(node, node.getSubnodes(), isSysAdmin, - getPedagogicalPlannerDAO()); - if (nodeUid == null) { - dto.setRecentlyModifiedNodes(getRecentlyModifiedLearnindDesignsAsNodes()); - } - } - // Additional DTO parameters List titlePath = getPedagogicalPlannerDAO().getTitlePath(nodeUid); Boolean createSubnode = WebUtil.readBooleanParam(request, CentralConstants.PARAM_CREATE_SUBNODE, false); @@ -1181,7 +1112,7 @@ PedagogicalPlannerSequenceNode node = getPedagogicalPlannerDAO().getByUid(nodeUid); // exporting XML - XStream designXml = new XStream(new SunUnsafeReflectionProvider()); + XStream designXml = new XStream(new StaxDriver()); designXml.addPermission(AnyTypePermission.ANY); // do not serialize node's owner designXml.omitField(PedagogicalPlannerSequenceNode.class, "user"); @@ -1306,10 +1237,10 @@ @SuppressWarnings("unchecked") private LearningDesign importLearningDesign(File sourceFile, ActionMessages errors) throws ServletException { User user = getUser(); - List toolsErrorMsgs = new ArrayList(); + List toolsErrorMsgs = new ArrayList<>(); Long learningDesignID = null; LearningDesign learningDesign = null; - List learningDesignErrorMsgs = new ArrayList(); + List learningDesignErrorMsgs = new ArrayList<>(); Integer workspaceFolderId = null; @@ -1366,7 +1297,7 @@ WorkspaceFolder parentFolder = getUserManagementService().getRootOrganisation().getNormalFolder(); Integer workspaceFolderType = WorkspaceFolder.PUBLIC_SEQUENCES; - Map properties = new HashMap(); + Map properties = new HashMap<>(); properties.put("name", name); properties.put("parentWorkspaceFolder.workspaceFolderId", parentFolder.getWorkspaceFolderId()); properties.put("workspaceFolderType", workspaceFolderType); @@ -1419,7 +1350,7 @@ } } else { - List toolsErrorMsgs = new ArrayList(); + List toolsErrorMsgs = new ArrayList<>(); String exportedLdFilePath = getExportService().exportLearningDesign(node.getLearningDesignId(), toolsErrorMsgs); if (!toolsErrorMsgs.isEmpty()) { @@ -1477,100 +1408,6 @@ } } - /** - * Finds all node's descendants matching the query. Results can be not only the subnodes of the node, but also - * deeper descendants. This method uses Lucene project for query parsing and searchig. - * - * @param node - * @param filterText - * @return set of nodes' uids - * @throws ParseException - * @throws CorruptIndexException - * @throws IOException - */ - private Set filterSubnodes(PedagogicalPlannerSequenceNode node, String filterText) - throws ParseException, CorruptIndexException, IOException { - Set matchingSubnodeUids = new LinkedHashSet(); - if (!StringUtils.isEmpty(filterText)) { - - Set docs = extractSubnodeDocuments(node); - if (!docs.isEmpty()) { - // Searching is performed in title, brief description and full description of the node. - MultiFieldQueryParser queryParser = new MultiFieldQueryParser( - new String[] { PedagogicalPlannerAction.FIELD_NAME_TITLE, - PedagogicalPlannerAction.FIELD_NAME_FULL_DESCRIPTION, - PedagogicalPlannerAction.FIELD_NAME_BRIEF_DESCRIPTION }, - PedagogicalPlannerAction.luceneAnalyzer); - - Query query = queryParser.parse(filterText); - - // build index based on nodes - IndexWriterConfig config = new IndexWriterConfig(PedagogicalPlannerAction.luceneAnalyzer.getVersion(), - PedagogicalPlannerAction.luceneAnalyzer); - config.setOpenMode(OpenMode.CREATE); - IndexWriter indexWriter = new IndexWriter(PedagogicalPlannerAction.luceneDir, config); - for (Document doc : docs) { - indexWriter.addDocument(doc); - } - indexWriter.close(); - - // execute search - IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(PedagogicalPlannerAction.luceneDir)); - TopDocs topDocs = searcher.search(query, null, docs.size()); - - for (ScoreDoc scoreDoc : topDocs.scoreDocs) { - Document doc = searcher.doc(scoreDoc.doc); - String ancestorUid = doc.get(PedagogicalPlannerAction.FIELD_NAME_ANCESTOR_UID); - Long uid = new Long(ancestorUid); - matchingSubnodeUids.add(uid); - } - } - } - return matchingSubnodeUids; - } - - /** - * Adds documents made of subnodes' title, descriptions and uid, then descents deeper into descendants. - * - * @param node - * its subnodes will be parsed - * @return documents made of all of node's descendants - */ - private Set extractSubnodeDocuments(PedagogicalPlannerSequenceNode node) { - Set docs = new HashSet(); - if ((node != null) && (node.getSubnodes() != null)) { - for (PedagogicalPlannerSequenceNode subnode : node.getSubnodes()) { - Document doc = new Document(); - Field titleField = new TextField(PedagogicalPlannerAction.FIELD_NAME_TITLE, subnode.getTitle(), - Field.Store.NO); - titleField.setBoost(10); - doc.add(titleField); - - String briefDesc = WebUtil.removeHTMLtags(subnode.getBriefDescription()); - if (briefDesc != null) { - Field briefDescField = new TextField(PedagogicalPlannerAction.FIELD_NAME_BRIEF_DESCRIPTION, - briefDesc, Field.Store.NO); - doc.add(briefDescField); - } - String fullDesc = WebUtil.removeHTMLtags(subnode.getFullDescription()); - if (fullDesc != null) { - Field fullDescField = new TextField(PedagogicalPlannerAction.FIELD_NAME_FULL_DESCRIPTION, fullDesc, - Field.Store.NO); - doc.add(fullDescField); - } - - Field uidField = new StringField(PedagogicalPlannerAction.FIELD_NAME_ANCESTOR_UID, - subnode.getUid().toString(), Field.Store.YES); - doc.add(uidField); - docs.add(doc); - - Set subnodeDocs = extractSubnodeDocuments(subnode); - docs.addAll(subnodeDocs); - } - } - return docs; - } - /*----------------------- GROUPING METHODS -------------------------*/ /** @@ -1638,7 +1475,7 @@ User user = getUser(); // the list is sorted most-recently-edited-on-top (so by the timestamp descending) Set recentLDs = user.getRecentlyModifiedLearningDesigns(); - List recentNodes = new LinkedList(); + List recentNodes = new LinkedList<>(); // create "dummy", almost empty nodes for (Long learningDesignId : recentLDs) { LearningDesign learningDesign = getAuthoringService().getLearningDesign(learningDesignId); @@ -1718,7 +1555,7 @@ if (!StringUtils.isEmpty(activityMetadataString)) { String[] activityMetadataEntries = activityMetadataString.split("&"); // creata a map of metadata objects, because we are filling them multiple times during this iteration - Map activitiesMetadata = new TreeMap(); + Map activitiesMetadata = new TreeMap<>(); for (String activityMetadataEntry : activityMetadataEntries) { String[] keyAndValue = activityMetadataEntry.split("="); String[] keyParts = keyAndValue[0].split("\\."); @@ -1790,7 +1627,7 @@ HttpServletResponse response) throws IOException, ServletException { Long learningDesignId = WebUtil.readLongParam(request, CentralConstants.PARAM_LEARNING_DESIGN_ID); - List toolsErrorMsgs = new ArrayList(); + List toolsErrorMsgs = new ArrayList<>(); ActionMessages errors = new ActionMessages(); String zipFilePath = null; boolean valid = false; @@ -1854,7 +1691,7 @@ // list existing users (inherited role from parent nodes) Set allInheritedUsers = getPedagogicalPlannerDAO().getInheritedNodeUsers(nodeUid, Role.ROLE_SYSADMIN); - ArrayList filteredInheritedUsers = new ArrayList(); + ArrayList filteredInheritedUsers = new ArrayList<>(); for (Object o : allInheritedUsers) { User u = (User) o; // filter existing users of the actual node @@ -1865,7 +1702,7 @@ } // filter existing users from list of potential users - ArrayList potentialUsers = new ArrayList(); + ArrayList potentialUsers = new ArrayList<>(); for (Object o : potentialUsersVector) { User u = (User) o; if (existingUsers.contains(u) || allInheritedUsers.contains(u)) { Index: lams_central/src/java/org/lamsfoundation/lams/workspace/service/IWorkspaceManagementService.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/workspace/service/IWorkspaceManagementService.java (.../IWorkspaceManagementService.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_central/src/java/org/lamsfoundation/lams/workspace/service/IWorkspaceManagementService.java (.../IWorkspaceManagementService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -26,7 +26,7 @@ import java.io.IOException; import java.util.Vector; -import org.apache.tomcat.util.json.JSONException; + import org.lamsfoundation.lams.contentrepository.exception.RepositoryCheckedException; import org.lamsfoundation.lams.learningdesign.exception.LearningDesignException; import org.lamsfoundation.lams.usermanagement.User; @@ -128,7 +128,7 @@ * learning designs and subfolders of the given folder. Sample output: */ String getFolderContentsJSON(Integer folderID, Integer userID, boolean allowInvalidDesigns) - throws JSONException, IOException, UserAccessDeniedException, RepositoryCheckedException; + throws IOException, UserAccessDeniedException, RepositoryCheckedException; /** * Returns Folder Contents in JSON format, restricted by designType (used for Integrations) If folderID == null, @@ -137,7 +137,7 @@ * output: */ String getFolderContentsJSON(Integer folderID, Integer userID, boolean allowInvalidDesigns, String designType) - throws JSONException, IOException, UserAccessDeniedException, RepositoryCheckedException; + throws IOException, UserAccessDeniedException, RepositoryCheckedException; /** * Returns a section of the learning designs in the root of the user's personal folder. Returns the data in in JSON @@ -148,7 +148,7 @@ * "name":"TBL_BBBBB","date":"2015-07-13 10:07:41.0"}]} */ public String getPagedLearningDesignsJSON(Integer userID, boolean allowInvalidDesigns, String searchString, - int page, int size, String sortName, String sortDate) throws JSONException, IOException; + int page, int size, String sortName, String sortDate) throws IOException; /** * This method creates a new folder under the given parentFolder inside the user's default workspace. Index: lams_central/src/java/org/lamsfoundation/lams/workspace/service/WorkspaceManagementService.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_central/src/java/org/lamsfoundation/lams/workspace/service/WorkspaceManagementService.java (.../WorkspaceManagementService.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_central/src/java/org/lamsfoundation/lams/workspace/service/WorkspaceManagementService.java (.../WorkspaceManagementService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -34,9 +34,6 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.authoring.service.IAuthoringService; import org.lamsfoundation.lams.contentrepository.exception.RepositoryCheckedException; import org.lamsfoundation.lams.contentrepository.service.IRepositoryService; @@ -55,11 +52,16 @@ import org.lamsfoundation.lams.usermanagement.exception.UserException; import org.lamsfoundation.lams.usermanagement.exception.WorkspaceFolderException; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.workspace.WorkspaceFolderContent; import org.lamsfoundation.lams.workspace.dto.FolderContentDTO; import org.lamsfoundation.lams.workspace.web.WorkspaceAction; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Manpreet Minhas */ @@ -279,7 +281,7 @@ private Vector getFolderContentsInternal(User user, WorkspaceFolder workspaceFolder, Integer mode, String methodName, WorkspaceFolder skipFolder) throws UserAccessDeniedException, RepositoryCheckedException { - Vector contentDTO = new Vector(); + Vector contentDTO = new Vector<>(); if (user != null) { Integer permissions = getPermissions(workspaceFolder, user); if (permissions != WorkspaceFolder.NO_ACCESS) { @@ -334,22 +336,21 @@ @Override public String getFolderContentsJSON(Integer folderID, Integer userID, boolean allowInvalidDesigns) - throws JSONException, IOException, UserAccessDeniedException, RepositoryCheckedException { + throws IOException, UserAccessDeniedException, RepositoryCheckedException { return getFolderContentsJSON(folderID, userID, allowInvalidDesigns, false, null); } @Override public String getFolderContentsJSON(Integer folderID, Integer userID, boolean allowInvalidDesigns, - String designType) - throws JSONException, IOException, UserAccessDeniedException, RepositoryCheckedException { + String designType) throws IOException, UserAccessDeniedException, RepositoryCheckedException { return getFolderContentsJSON(folderID, userID, allowInvalidDesigns, false, designType); } public String getFolderContentsJSON(Integer folderID, Integer userID, boolean allowInvalidDesigns, boolean designsOnly, String designType) - throws JSONException, IOException, UserAccessDeniedException, RepositoryCheckedException { - JSONObject result = new JSONObject(); + throws IOException, UserAccessDeniedException, RepositoryCheckedException { + ObjectNode result = JsonNodeFactory.instance.objectNode(); Vector folderContents = null; // folderID == null: get all user accessible folders @@ -359,7 +360,7 @@ FolderContentDTO userFolder = getUserWorkspaceFolder(userID); if (folderID == null) { - folderContents = new Vector(3); + folderContents = new Vector<>(3); if (userFolder != null) { folderContents.add(userFolder); @@ -407,15 +408,15 @@ for (FolderContentDTO folderContent : folderContents) { String contentType = folderContent.getResourceType(); if (FolderContentDTO.FOLDER.equals(contentType) && !designsOnly) { - JSONObject subfolderJSON = new JSONObject(); + ObjectNode subfolderJSON = JsonNodeFactory.instance.objectNode(); subfolderJSON.put("name", folderContent.getName() == null ? "" : folderContent.getName()); subfolderJSON.put("isRunSequencesFolder", WorkspaceFolder.RUN_SEQUENCES.equals(folderContent.getResourceTypeID() == null ? null : folderContent.getResourceTypeID().intValue())); subfolderJSON.put("folderID", folderContent.getResourceID().intValue()); subfolderJSON.put("canModify", WorkspaceFolder.OWNER_ACCESS.equals(folderContent.getPermissionCode()) || ((user != null) && isSysAuthorAdmin(user))); - result.append("folders", subfolderJSON); + result.withArray("folders").add(subfolderJSON); } else if (FolderContentDTO.DESIGN.equals(contentType)) { if (folderContent.getDesignType() == null) { folderContent.setDesignType(WorkspaceManagementService.DEFAULT_DESIGN_TYPE); @@ -427,15 +428,15 @@ ? folderContent.getDesignType().equals(WorkspaceManagementService.DEFAULT_DESIGN_TYPE) : (designType.equals(WorkspaceManagementService.ALL_DESIGN_TYPES) || designType.equals(folderContent.getDesignType()))) { - JSONObject learningDesignJSON = new JSONObject(); + ObjectNode learningDesignJSON = JsonNodeFactory.instance.objectNode(); learningDesignJSON.put("name", folderContent.getName() == null ? "" : folderContent.getName()); learningDesignJSON.put("learningDesignId", folderContent.getResourceID()); - learningDesignJSON.putOpt("type", folderContent.getDesignType()); - learningDesignJSON.put("date", folderContent.getLastModifiedDateTime()); + JsonUtil.putOpt(learningDesignJSON, "type", folderContent.getDesignType()); + learningDesignJSON.put("date", folderContent.getLastModifiedDateTime().toString()); learningDesignJSON.put("canModify", WorkspaceFolder.OWNER_ACCESS.equals(folderContent.getPermissionCode()) || ((user != null) && isSysAuthorAdmin(user))); - result.append("learningDesigns", learningDesignJSON); + result.withArray("learningDesigns").add(learningDesignJSON); } } else { if (log.isDebugEnabled()) { @@ -449,11 +450,11 @@ @Override public String getPagedLearningDesignsJSON(Integer userID, boolean allowInvalidDesigns, String searchString, - int page, int size, String sortName, String sortDate) throws JSONException, IOException { - - JSONArray result = new JSONArray(); + int page, int size, String sortName, String sortDate) throws IOException { + ArrayNode resultJSON = JsonNodeFactory.instance.arrayNode(); Pattern searchPattern = searchString != null - ? Pattern.compile(Pattern.quote(searchString), Pattern.CASE_INSENSITIVE) : null; + ? Pattern.compile(Pattern.quote(searchString), Pattern.CASE_INSENSITIVE) + : null; FolderContentDTO userFolder = getUserWorkspaceFolder(userID); long numDesigns = 0; @@ -481,27 +482,27 @@ while (iterator.hasNext()) { LearningDesign design = (LearningDesign) iterator.next(); if ((searchPattern == null) || (searchPattern.matcher(design.getTitle()).find())) { - JSONObject learningDesignJSON = new JSONObject(); + ObjectNode learningDesignJSON = JsonNodeFactory.instance.objectNode(); learningDesignJSON.put("name", StringEscapeUtils.escapeHtml(design.getTitle())); learningDesignJSON.put("learningDesignId", design.getLearningDesignId()); - learningDesignJSON.putOpt("type", design.getDesignType() != null ? design.getDesignType() + learningDesignJSON.put("type", design.getDesignType() != null ? design.getDesignType() : WorkspaceManagementService.DEFAULT_DESIGN_TYPE); - learningDesignJSON.put("date", design.getLastModifiedDateTime()); - result.put(learningDesignJSON); + learningDesignJSON.put("date", design.getLastModifiedDateTime().toString()); + resultJSON.add(learningDesignJSON); } } // what is the total number (so the pager knows whether to allow paging) // if we did a search, then no paging just return the whole lot. // otherwise need the whole count from the db. - numDesigns = searchPattern != null ? result.length() + numDesigns = searchPattern != null ? resultJSON.size() : learningDesignDAO.countAllLearningDesigns(folderId, !allowInvalidDesigns); } - JSONObject completeResult = new JSONObject(); + ObjectNode completeResult = JsonNodeFactory.instance.objectNode(); completeResult.put("total_rows", numDesigns); - if (result.length() > 0) { - completeResult.put("rows", result); + if (resultJSON.size() > 0) { + completeResult.set("rows", resultJSON); } return completeResult.toString(); } @@ -837,7 +838,7 @@ */ @Override public Vector getAccessibleOrganisationWorkspaceFolders(User user) throws IOException { - Vector folders = new Vector(); + Vector folders = new Vector<>(); if (user != null) { // Get a list of organisations of which the given user is a member Index: lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java =================================================================== diff -u -r5bf2d3b201efb46864182d72901e497d0acb253f -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 5bf2d3b201efb46864182d72901e497d0acb253f) +++ lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -43,8 +43,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONObject; import org.imsglobal.pox.IMSPOXRequest; import org.lamsfoundation.lams.gradebook.GradebookUserLesson; import org.lamsfoundation.lams.gradebook.service.IGradebookService; @@ -73,10 +71,14 @@ import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CSVUtil; import org.lamsfoundation.lams.util.HashUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.LanguageUtil; import org.lamsfoundation.lams.util.ValidationUtil; import org.lamsfoundation.lams.util.WebUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; + import oauth.signpost.exception.OAuthException; /** @@ -772,25 +774,22 @@ BufferedReader isReader = new BufferedReader(new InputStreamReader(is)); String str = isReader.readLine(); - JSONArray jsonGroups = new JSONArray(str); + ArrayNode jsonGroups = JsonUtil.readArray(str); List extGroups = new ArrayList<>(); - for (int i = 0; i < jsonGroups.length(); i++) { - JSONObject jsonGroup = jsonGroups.getJSONObject(i); + for (JsonNode jsonGroup : jsonGroups) { ExtGroupDTO group = new ExtGroupDTO(); - group.setGroupName(jsonGroup.getString("groupName")); - group.setGroupId(jsonGroup.getString("groupId")); + group.setGroupName(JsonUtil.optString(jsonGroup, "groupName")); + group.setGroupId(JsonUtil.optString(jsonGroup, "groupId")); extGroups.add(group); // in case group info is also requested - provide selected groups' ids if (extGroupIds != null && extGroupIds.length > 0) { ArrayList users = new ArrayList<>(); - JSONArray jsonUsers = jsonGroup.getJSONArray("users"); - for (int j = 0; j < jsonUsers.length(); j++) { - JSONObject jsonUser = jsonUsers.getJSONObject(j); + ArrayNode jsonUsers = JsonUtil.optArray(jsonGroup, "users"); + for (JsonNode jsonUser : jsonUsers) { + String extUsername = JsonUtil.optString(jsonUser, "userName"); - String extUsername = jsonUser.getString("userName"); - ExtUserUseridMap extUserUseridMap = getExistingExtUserUseridMap(extServer, extUsername); //create extUserUseridMap if it's not available @@ -800,7 +799,7 @@ // language>, String[] userData = new String[14]; for (int k = 1; k <= 14; k++) { - String userProperty = jsonUser.getString("" + k); + String userProperty = JsonUtil.optString(jsonUser, "" + k); userData[k - 1] = userProperty; } String salt = HashUtil.salt(); @@ -824,7 +823,7 @@ group.setUsers(users); } else { - group.setNumberUsers(jsonGroup.getInt("groupSize")); + group.setNumberUsers(JsonUtil.optInt(jsonGroup, "groupSize")); } } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r2623eb7399f1ea9633c776630f379fa48a21b7e9 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 2623eb7399f1ea9633c776630f379fa48a21b7e9) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -141,9 +141,10 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; -import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider; + import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.StaxDriver; import com.thoughtworks.xstream.security.AnyTypePermission; /** @@ -477,7 +478,7 @@ } // exporting XML - XStream designXml = new XStream(new SunUnsafeReflectionProvider()); + XStream designXml = new XStream(new StaxDriver()); designXml.addPermission(AnyTypePermission.ANY); designXml.toXML(ldDto, ldFile); ldFile.close(); @@ -548,7 +549,7 @@ Writer toolFile = new OutputStreamWriter(new FileOutputStream(toolFileName), "UTF-8"); // serialize tool xml into local file. - XStream toolXml = new XStream(new SunUnsafeReflectionProvider()); + XStream toolXml = new XStream(new StaxDriver()); toolXml.addPermission(AnyTypePermission.ANY); FileConverter fileConverter = null; if (!fileHandleClassList.isEmpty()) { @@ -896,7 +897,7 @@ String toVersion) throws ImportToolContentException { Object toolPOJO = null; // change xml to Tool POJO - XStream toolXml = new XStream(new SunUnsafeReflectionProvider()); + XStream toolXml = new XStream(new StaxDriver()); toolXml.addPermission(AnyTypePermission.ANY); FileConverter fileConverter = null; if (!fileHandleClassList.isEmpty()) { Index: lams_learning/web/WEB-INF/web.xml =================================================================== diff -u -r34815c1edfbbd510266420e5cfaf4baf290e9a1e -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_learning/web/WEB-INF/web.xml (.../web.xml) (revision 34815c1edfbbd510266420e5cfaf4baf290e9a1e) +++ lams_learning/web/WEB-INF/web.xml (.../web.xml) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -34,7 +34,7 @@ HibernateFilter - org.springframework.orm.hibernate4.support.OpenSessionInViewFilter + org.springframework.orm.hibernate5.support.OpenSessionInViewFilter sessionFactoryBeanName coreSessionFactory Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -re34e0b7a8ed604692164d998b9a7d6944adfc487 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision e34e0b7a8ed604692164d998b9a7d6944adfc487) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -23,6 +23,7 @@ package org.lamsfoundation.lams.tool.assessment.service; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.sql.Timestamp; import java.util.ArrayList; @@ -48,9 +49,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.events.IEventNotificationService; import org.lamsfoundation.lams.gradebook.service.IGradebookService; import org.lamsfoundation.lams.learning.service.ILearnerService; @@ -112,6 +110,10 @@ import org.lamsfoundation.lams.util.NumberUtil; import org.lamsfoundation.lams.util.audit.IAuditService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Andrey Balan */ @@ -428,7 +430,7 @@ @Override public void setAttemptStarted(Assessment assessment, AssessmentUser assessmentUser, Long toolSessionId) { Set questions = assessment.getQuestions(); - + AssessmentResult lastResult = getLastAssessmentResult(assessment.getUid(), assessmentUser.getUserId()); if (lastResult != null) { @@ -457,7 +459,7 @@ assessmentResultDao.saveObject(lastResult); return; - // mark previous attempt as being not the latest any longer + // mark previous attempt as being not the latest any longer } else { lastResult.setLatest(false); assessmentResultDao.saveObject(lastResult); @@ -528,7 +530,8 @@ for (QuestionDTO questionDto : questionsForOnePage) { // in case single MarkHedging question needs to be stored -- search for that question - if ((singleMarkHedgingQuestionUid != null) && !questionDto.getUid().equals(singleMarkHedgingQuestionUid)) { + if ((singleMarkHedgingQuestionUid != null) + && !questionDto.getUid().equals(singleMarkHedgingQuestionUid)) { continue; } @@ -585,24 +588,24 @@ * @param isAutosave * in case of autosave there is no need to calculate marks * @return grade that user scored by answering that question - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + * @throws IllegalAccessException */ - private float storeUserAnswer(AssessmentResult assessmentResult, QuestionDTO questionDto, boolean isAutosave) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + private float storeUserAnswer(AssessmentResult assessmentResult, QuestionDTO questionDto, boolean isAutosave) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Assessment assessment = assessmentResult.getAssessment(); - + AssessmentQuestionResult questionResult = null; // get questionResult from DB instance of AssessmentResult for (AssessmentQuestionResult questionResultIter : assessmentResult.getQuestionResults()) { if (questionDto.getUid().equals(questionResultIter.getAssessmentQuestion().getUid())) { questionResult = questionResultIter; } } - - //if teacher edited content in monitor (modified question) it led to removal if autosaved questionResult - if (assessment.isContentModifiedInMonitor(assessmentResult.getStartDate()) - && questionResult == null) { + + //if teacher edited content in monitor (modified question) it led to removal if autosaved questionResult + if (assessment.isContentModifiedInMonitor(assessmentResult.getStartDate()) && questionResult == null) { //update questionDto AssessmentQuestion modifiedQuestion = assessmentQuestionDao.getByUid(questionDto.getUid()); QuestionDTO updatedQuestionDto = modifiedQuestion.getQuestionDTO(); @@ -694,7 +697,8 @@ java.util.regex.Pattern.CASE_INSENSITIVE | java.util.regex.Pattern.UNICODE_CASE); } boolean isAnswerMatchedCurrentOption = (questionDto.getAnswerString() != null) - ? pattern.matcher(questionDto.getAnswerString().trim()).matches() : false; + ? pattern.matcher(questionDto.getAnswerString().trim()).matches() + : false; if (isAnswerMatchedCurrentOption) { mark = optionDto.getGrade() * maxMark; @@ -710,7 +714,8 @@ boolean isAnswerMatchedCurrentOption = false; try { float answerFloat = Float.valueOf(questionDto.getAnswerString()); - isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getOptionFloat() - optionDto.getAcceptedError())) + isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getOptionFloat() + - optionDto.getAcceptedError())) && (answerFloat <= (optionDto.getOptionFloat() + optionDto.getAcceptedError()))); } catch (Exception e) { } @@ -728,7 +733,8 @@ answerFloat = answerFloat / unit.getMultiplier(); isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getOptionFloat() - optionDto.getAcceptedError())) - && (answerFloat <= (optionDto.getOptionFloat() + optionDto.getAcceptedError()))); + && (answerFloat <= (optionDto.getOptionFloat() + + optionDto.getAcceptedError()))); if (isAnswerMatchedCurrentOption) { break; } @@ -746,15 +752,16 @@ } } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE) { - if ((questionDto.getAnswerBoolean() == questionDto.getCorrectAnswer()) && (questionDto.getAnswerString() != null)) { + if ((questionDto.getAnswerBoolean() == questionDto.getCorrectAnswer()) + && (questionDto.getAnswerString() != null)) { mark = maxMark; } } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING) { float maxMarkForCorrectAnswer = maxMark / questionDto.getOptionDtos().size(); - TreeSet correctOptionSet = new TreeSet(new SequencableComparator()); + TreeSet correctOptionSet = new TreeSet<>(new SequencableComparator()); correctOptionSet.addAll(questionDto.getOptionDtos()); - ArrayList correctOptionList = new ArrayList(correctOptionSet); + ArrayList correctOptionList = new ArrayList<>(correctOptionSet); int i = 0; for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.getUid() == correctOptionList.get(i++).getUid()) { @@ -923,7 +930,7 @@ @Override public List getReflectList(Long contentId) { - List reflectList = new LinkedList(); + List reflectList = new LinkedList<>(); List sessionList = assessmentSessionDao.getByContentId(contentId); for (AssessmentSession session : sessionList) { @@ -974,22 +981,28 @@ @Override public List getSessionDtos(Long contentId, boolean includeStatistics) { - List sessionDtos = new ArrayList(); + List sessionDtos = new ArrayList<>(); List sessionList = assessmentSessionDao.getByContentId(contentId); for (AssessmentSession session : sessionList) { Long sessionId = session.getSessionId(); SessionDTO sessionDto = new SessionDTO(sessionId, session.getSessionName()); //for statistics tab - if ( includeStatistics ) { + if (includeStatistics) { int countUsers = assessmentUserDao.getCountUsersBySession(sessionId, ""); sessionDto.setNumberLearners(countUsers); Object[] markStats = assessmentUserDao.getStatsMarksBySession(sessionId); - if ( markStats != null ) { - sessionDto.setMinMark(markStats[0] != null ? NumberUtil.formatLocalisedNumber((Float)markStats[0], (Locale)null, 2) : "0.00"); - sessionDto.setAvgMark(markStats[1] != null ? NumberUtil.formatLocalisedNumber((Float)markStats[1], (Locale)null, 2) : "0.00"); - sessionDto.setMaxMark(markStats[2] != null ? NumberUtil.formatLocalisedNumber((Float)markStats[2], (Locale)null, 2) : "0.00"); + if (markStats != null) { + sessionDto.setMinMark(markStats[0] != null + ? NumberUtil.formatLocalisedNumber((Float) markStats[0], (Locale) null, 2) + : "0.00"); + sessionDto.setAvgMark(markStats[1] != null + ? NumberUtil.formatLocalisedNumber((Float) markStats[1], (Locale) null, 2) + : "0.00"); + sessionDto.setMaxMark(markStats[2] != null + ? NumberUtil.formatLocalisedNumber((Float) markStats[2], (Locale) null, 2) + : "0.00"); } } @@ -1003,20 +1016,26 @@ public LeaderResultsDTO getLeaderResultsDTOForLeaders(Long contentId) { LeaderResultsDTO newDto = new LeaderResultsDTO(contentId); Object[] markStats = assessmentUserDao.getStatsMarksForLeaders(contentId); - if ( markStats != null ) { - newDto.setMinMark(markStats[0] != null ? NumberUtil.formatLocalisedNumber((Float)markStats[0], (Locale)null, 2) : "0.00"); - newDto.setAvgMark(markStats[1] != null ? NumberUtil.formatLocalisedNumber((Float)markStats[1], (Locale)null, 2) : "0.00"); - newDto.setMaxMark(markStats[2] != null ? NumberUtil.formatLocalisedNumber((Float)markStats[2], (Locale)null, 2) : "0.00"); - newDto.setNumberGroupsLeaderFinished((Integer)markStats[3]); + if (markStats != null) { + newDto.setMinMark( + markStats[0] != null ? NumberUtil.formatLocalisedNumber((Float) markStats[0], (Locale) null, 2) + : "0.00"); + newDto.setAvgMark( + markStats[1] != null ? NumberUtil.formatLocalisedNumber((Float) markStats[1], (Locale) null, 2) + : "0.00"); + newDto.setMaxMark( + markStats[2] != null ? NumberUtil.formatLocalisedNumber((Float) markStats[2], (Locale) null, 2) + : "0.00"); + newDto.setNumberGroupsLeaderFinished((Integer) markStats[3]); } return newDto; } - + @Override public AssessmentResultDTO getUserMasterDetail(Long sessionId, Long userId) { AssessmentResultDTO resultDto = new AssessmentResultDTO(); resultDto.setSessionId(sessionId); - + AssessmentResult lastFinishedResult = assessmentResultDao.getLastFinishedAssessmentResultByUser(sessionId, userId); if (lastFinishedResult != null) { @@ -1025,13 +1044,13 @@ Set questionResults = lastFinishedResult.getQuestionResults(); //prepare list of the questions to display in user master detail table, filtering out questions that aren't supposed to be answered - SortedSet questionResultsToDisplay = new TreeSet( + SortedSet questionResultsToDisplay = new TreeSet<>( new AssessmentQuestionResultComparator()); //in case there is at least one random question - we need to show all questions if (assessment.hasRandomQuestion()) { questionResultsToDisplay.addAll(questionResults); - //otherwise show only questions from the question list + //otherwise show only questions from the question list } else { for (QuestionReference reference : questionReferences) { for (AssessmentQuestionResult questionResult : questionResults) { @@ -1053,7 +1072,7 @@ @Override public UserSummary getUserSummary(Long contentId, Long userId, Long sessionId) { Assessment assessment = assessmentDao.getByContentId(contentId); - + UserSummary userSummary = new UserSummary(); AssessmentUser user = assessmentUserDao.getUserByUserIDAndSessionID(userId, sessionId); userSummary.setUser(user); @@ -1068,11 +1087,11 @@ if (lastFinishedResult != null) { userSummary.setLastAttemptGrade(lastFinishedResult.getGrade()); } - + if (!results.isEmpty()) { //prepare list of the questions to display, filtering out questions that aren't supposed to be answered - Set questions = new TreeSet(); + Set questions = new TreeSet<>(); //in case there is at least one random question - we need to show all questions in a drop down select if (assessment.hasRandomQuestion()) { questions.addAll(assessment.getQuestions()); @@ -1085,12 +1104,12 @@ } //prepare list of UserSummaryItems - ArrayList userSummaryItems = new ArrayList(); + ArrayList userSummaryItems = new ArrayList<>(); for (AssessmentQuestion question : questions) { UserSummaryItem userSummaryItem = new UserSummaryItem(question); //find all questionResults that correspond to the current question - List questionResults = new ArrayList(); + List questionResults = new ArrayList<>(); for (AssessmentResult result : results) { for (AssessmentQuestionResult questionResult : result.getQuestionResults()) { if (question.getUid().equals(questionResult.getAssessmentQuestion().getUid())) { @@ -1125,27 +1144,27 @@ @Override public Map getQuestionSummaryForExport(Assessment assessment) { - Map questionSummaries = new LinkedHashMap(); + Map questionSummaries = new LinkedHashMap<>(); if (assessment.getQuestions() == null) { return questionSummaries; } - SortedSet sessions = new TreeSet(new AssessmentSessionComparator()); + SortedSet sessions = new TreeSet<>(new AssessmentSessionComparator()); sessions.addAll(assessmentSessionDao.getByContentId(assessment.getContentId())); List assessmentResults = assessmentResultDao .getLastFinishedAssessmentResults(assessment.getContentId()); - Map userUidToResultMap = new HashMap(); + Map userUidToResultMap = new HashMap<>(); for (AssessmentResult assessmentResult : assessmentResults) { userUidToResultMap.put(assessmentResult.getUser().getUid(), assessmentResult); } - Map> sessionIdToUsersMap = new HashMap>(); + Map> sessionIdToUsersMap = new HashMap<>(); for (AssessmentSession session : sessions) { Long sessionId = session.getSessionId(); - List users = new ArrayList(); + List users = new ArrayList<>(); // in case of leader aware tool show only leaders' responses if (assessment.isUseSelectLeaderToolOuput()) { @@ -1165,14 +1184,14 @@ QuestionSummary questionSummary = new QuestionSummary(); questionSummary.setQuestion(question); - List> questionResults = new ArrayList>(); + List> questionResults = new ArrayList<>(); for (AssessmentSession session : sessions) { Long sessionId = session.getSessionId(); List users = sessionIdToUsersMap.get(sessionId); - ArrayList sessionQuestionResults = new ArrayList(); + ArrayList sessionQuestionResults = new ArrayList<>(); for (AssessmentUser user : users) { AssessmentResult assessmentResult = userUidToResultMap.get(user.getUid()); AssessmentQuestionResult questionResult = null; @@ -1221,12 +1240,12 @@ @Override public LinkedHashMap exportSummary(Assessment assessment, List sessionDtos, boolean showUserNames) { - LinkedHashMap dataToExport = new LinkedHashMap(); + LinkedHashMap dataToExport = new LinkedHashMap<>(); final ExcelCell[] EMPTY_ROW = new ExcelCell[0]; // -------------- First tab: Summary ---------------------------------------------------- if (showUserNames) { - ArrayList summaryTab = new ArrayList(); + ArrayList summaryTab = new ArrayList<>(); if (sessionDtos != null) { for (SessionDTO sessionDTO : sessionDtos) { @@ -1237,8 +1256,8 @@ ExcelCell[] sessionTitle = new ExcelCell[1]; sessionTitle[0] = new ExcelCell(sessionDTO.getSessionName(), true); summaryTab.add(sessionTitle); - - List userDtos = new ArrayList(); + + List userDtos = new ArrayList<>(); // in case of UseSelectLeaderToolOuput - display only one user if (assessment.isUseSelectLeaderToolOuput()) { @@ -1264,12 +1283,15 @@ userDtos = getPagedUsersBySession(sessionId, 0, countSessionUsers, "userName", "ASC", ""); } - ArrayList summaryTabLearnerList = new ArrayList(); - + ArrayList summaryTabLearnerList = new ArrayList<>(); + ExcelCell[] summaryRowTitle = new ExcelCell[3]; - summaryRowTitle[0] = new ExcelCell(getMessage("label.export.user.id"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - summaryRowTitle[1] = new ExcelCell(getMessage("label.monitoring.summary.user.name"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - summaryRowTitle[2] = new ExcelCell(getMessage("label.monitoring.summary.total"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[0] = new ExcelCell(getMessage("label.export.user.id"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[1] = new ExcelCell(getMessage("label.monitoring.summary.user.name"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[2] = new ExcelCell(getMessage("label.monitoring.summary.total"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); summaryTabLearnerList.add(summaryRowTitle); float minGrade = -9999999; @@ -1284,18 +1306,22 @@ userResultRow[2] = new ExcelCell(grade, false); summaryTabLearnerList.add(userResultRow); - if ( grade < minGrade || minGrade == -9999999 ) + if (grade < minGrade || minGrade == -9999999) { minGrade = grade; - if ( grade > maxGrade ) + } + if (grade > maxGrade) { maxGrade = grade; + } } - if ( minGrade == -9999999) + if (minGrade == -9999999) { minGrade = 0; + } - LinkedHashMap markSummary = getMarksSummaryForSession(userDtos, minGrade, maxGrade, 10); + LinkedHashMap markSummary = getMarksSummaryForSession(userDtos, minGrade, maxGrade, + 10); // work out total marks so we can do percentages. need as float for the correct divisions int totalNumEntries = 0; - for ( Map.Entry entry : markSummary.entrySet() ) { + for (Map.Entry entry : markSummary.entrySet()) { totalNumEntries += entry.getValue(); } @@ -1307,25 +1333,29 @@ summaryTab.add(minMaxRow); minMaxRow = new ExcelCell[2]; minMaxRow[0] = new ExcelCell(getMessage("label.lowest.mark"), true); - minMaxRow[1] = new ExcelCell((double)minGrade, false); + minMaxRow[1] = new ExcelCell((double) minGrade, false); summaryTab.add(minMaxRow); minMaxRow = new ExcelCell[2]; minMaxRow[0] = new ExcelCell(getMessage("label.highest.mark"), true); - minMaxRow[1] = new ExcelCell((double)maxGrade, false); + minMaxRow[1] = new ExcelCell((double) maxGrade, false); summaryTab.add(minMaxRow); - + summaryTab.add(EMPTY_ROW); ExcelCell[] binSummaryRow = new ExcelCell[3]; - binSummaryRow[0] = new ExcelCell(getMessage("label.authoring.basic.list.header.mark"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - binSummaryRow[1] = new ExcelCell(getMessage("label.number.learners"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - binSummaryRow[2] = new ExcelCell(getMessage("label.percentage"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + binSummaryRow[0] = new ExcelCell(getMessage("label.authoring.basic.list.header.mark"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + binSummaryRow[1] = new ExcelCell(getMessage("label.number.learners"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + binSummaryRow[2] = new ExcelCell(getMessage("label.percentage"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); summaryTab.add(binSummaryRow); - float totalNumEntriesAsFloat = (float) totalNumEntries; - for ( Map.Entry entry : markSummary.entrySet() ) { + float totalNumEntriesAsFloat = totalNumEntries; + for (Map.Entry entry : markSummary.entrySet()) { binSummaryRow = new ExcelCell[3]; - binSummaryRow[0] = new ExcelCell(entry.getKey(),false); - binSummaryRow[1] = new ExcelCell(entry.getValue(),false); - binSummaryRow[2] = new ExcelCell(Math.round(entry.getValue() / totalNumEntriesAsFloat * 100),false); + binSummaryRow[0] = new ExcelCell(entry.getKey(), false); + binSummaryRow[1] = new ExcelCell(entry.getValue(), false); + binSummaryRow[2] = new ExcelCell(Math.round(entry.getValue() / totalNumEntriesAsFloat * 100), + false); summaryTab.add(binSummaryRow); } summaryTab.add(EMPTY_ROW); @@ -1342,7 +1372,7 @@ // ------------------------------------------------------------------ // -------------- Second tab: Question Summary ---------------------- - ArrayList questionSummaryTab = new ArrayList(); + ArrayList questionSummaryTab = new ArrayList<>(); // Create the question summary ExcelCell[] summaryTitle = new ExcelCell[1]; @@ -1382,13 +1412,13 @@ ExcelCell.BORDER_STYLE_BOTTOM_THIN); int questionNumber = 1; - + for (AssessmentQuestion question : questions) { int colsNum = showUserNames ? 10 : 9; ExcelCell[] questionTitle = new ExcelCell[1]; - questionTitle[0] = new ExcelCell(getMessage("label.monitoring.question.summary.question") + " " - + questionNumber++, true); + questionTitle[0] = new ExcelCell( + getMessage("label.monitoring.question.summary.question") + " " + questionNumber++, true); questionSummaryTab.add(questionTitle); // set up the summary table data for the top of the question area. @@ -1398,16 +1428,16 @@ || question.getType() == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE; // For MC, Numeric & Short Answer Key is optionUid, Value is number of answers // For True/False Key 0 is false and Key 1 is true - Map summaryOfAnswers = new HashMap(); + Map summaryOfAnswers = new HashMap<>(); Integer summaryNACount = 0; Long trueKey = 1L; Long falseKey = 0L; if (doSummaryTable) { questionSummaryTab.add(startSummaryTable(question, summaryOfAnswers, trueKey, falseKey)); } - - ArrayList questionSummaryTabTemp = new ArrayList(); + ArrayList questionSummaryTabTemp = new ArrayList<>(); + //add question title row if (question.getType() == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { count = 0; @@ -1488,9 +1518,10 @@ } else { userResultRow[count++] = new ExcelCell( AssessmentEscapeUtils.printResponsesForExcelExport(questionResult), false); - - if ( doSummaryTable ) { - summaryNACount = updateSummaryCounts(question, questionResult, summaryOfAnswers, summaryNACount); + + if (doSummaryTable) { + summaryNACount = updateSummaryCounts(question, questionResult, summaryOfAnswers, + summaryNACount); } } @@ -1518,10 +1549,11 @@ } if (doSummaryTable) { - questionSummaryTab.add(outputSummaryTable(question, summaryOfAnswers, summaryNACount, trueKey, falseKey)); + questionSummaryTab + .add(outputSummaryTable(question, summaryOfAnswers, summaryNACount, trueKey, falseKey)); questionSummaryTab.add(EMPTY_ROW); } - + // Calculating the averages ExcelCell[] averageRow; @@ -1557,7 +1589,7 @@ questionSummaryTab.addAll(questionSummaryTabTemp); questionSummaryTab.add(averageRow); questionSummaryTab.add(EMPTY_ROW); - + } } @@ -1567,24 +1599,29 @@ // ------------------------------------------------------------------ // -------------- Third tab: User Summary --------------------------- - ArrayList userSummaryTab = new ArrayList(); + ArrayList userSummaryTab = new ArrayList<>(); // Create the question summary ExcelCell[] userSummaryTitle = new ExcelCell[1]; userSummaryTitle[0] = new ExcelCell(getMessage("label.export.user.summary"), true); userSummaryTab.add(userSummaryTitle); ExcelCell[] summaryRowTitle = new ExcelCell[5]; - summaryRowTitle[0] = new ExcelCell(getMessage("label.monitoring.question.summary.question"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - summaryRowTitle[1] = new ExcelCell(getMessage("label.authoring.basic.list.header.type"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - summaryRowTitle[2] = new ExcelCell(getMessage("label.authoring.basic.penalty.factor"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - summaryRowTitle[3] = new ExcelCell(getMessage("label.monitoring.question.summary.default.mark"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); - summaryRowTitle[4] = new ExcelCell(getMessage("label.monitoring.question.summary.average.mark"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[0] = new ExcelCell(getMessage("label.monitoring.question.summary.question"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[1] = new ExcelCell(getMessage("label.authoring.basic.list.header.type"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[2] = new ExcelCell(getMessage("label.authoring.basic.penalty.factor"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[3] = new ExcelCell(getMessage("label.monitoring.question.summary.default.mark"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[4] = new ExcelCell(getMessage("label.monitoring.question.summary.average.mark"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); userSummaryTab.add(summaryRowTitle); Float totalGradesPossible = new Float(0); Float totalAverage = new Float(0); if (assessment.getQuestionReferences() != null) { - Set questionReferences = new TreeSet(new SequencableComparator()); + Set questionReferences = new TreeSet<>(new SequencableComparator()); questionReferences.addAll(assessment.getQuestionReferences()); int randomQuestionsCount = 1; @@ -1640,7 +1677,7 @@ if (sessionDtos != null) { List assessmentResults = assessmentResultDao .getLastFinishedAssessmentResults(assessment.getContentId()); - Map userUidToResultMap = new HashMap(); + Map userUidToResultMap = new HashMap<>(); for (AssessmentResult assessmentResult : assessmentResults) { userUidToResultMap.put(assessmentResult.getUser().getUid(), assessmentResult); } @@ -1752,30 +1789,26 @@ summaryTable = new ExcelCell[question.getOptions().size() + 1]; for (AssessmentQuestionOption option : question.getOptions()) { summaryOfAnswers.put(option.getUid(), 0); - StringBuilder bldr = new StringBuilder(getMessage("label.authoring.basic.option.answer")) - .append(" ") - .append(i + 1) - .append(" - "); - if ( question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL ) { - bldr.append(option.getOptionFloat()) - .append(" +- ") - .append(option.getAcceptedError()); + StringBuilder bldr = new StringBuilder(getMessage("label.authoring.basic.option.answer")).append(" ") + .append(i + 1).append(" - "); + if (question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + bldr.append(option.getOptionFloat()).append(" +- ").append(option.getAcceptedError()); } else { bldr.append(option.getOptionString().replaceAll("\\<.*?\\>", "")); } summaryTable[i] = new ExcelCell(bldr.toString(), false); i++; } - if ( question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE ) { - summaryTable[i++] = new ExcelCell(getMessage("label.not.answered"), false); + if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + summaryTable[i++] = new ExcelCell(getMessage("label.not.answered"), false); } else { - summaryTable[i++] = new ExcelCell(getMessage("label.other"), false); + summaryTable[i++] = new ExcelCell(getMessage("label.other"), false); } } else { summaryTable = new ExcelCell[3]; summaryTable[0] = new ExcelCell(getMessage("label.authoring.true.false.true"), false); summaryTable[1] = new ExcelCell(getMessage("label.authoring.true.false.false"), false); - summaryTable[2] = new ExcelCell(getMessage("label.not.answered"), false); + summaryTable[2] = new ExcelCell(getMessage("label.not.answered"), false); summaryOfAnswers.put(trueKey, 0); summaryOfAnswers.put(falseKey, 0); } @@ -1792,11 +1825,10 @@ if (optionAnswer.getAnswerBoolean()) { Integer currentCount = summaryOfAnswers.get(optionAnswer.getOptionUid()); if (currentCount == null) { - log.error("Assessment Export: Unable to count answer in summary, refers to an unexpected option. QuestionResult " - + questionResult.getUid() - + " OptionUid " - + optionAnswer.getOptionUid() - + " question " + question.getUid()); + log.error( + "Assessment Export: Unable to count answer in summary, refers to an unexpected option. QuestionResult " + + questionResult.getUid() + " OptionUid " + optionAnswer.getOptionUid() + + " question " + question.getUid()); } else { summaryOfAnswers.put(optionAnswer.getOptionUid(), currentCount + 1); foundOption = true; @@ -1813,12 +1845,10 @@ if (submittedUid != null) { Integer currentCount = summaryOfAnswers.get(submittedUid); if (currentCount == null) { - log.error("Assessment Export: Unable to count answer in summary, refers to an unexpected option. QuestionResult " - + questionResult.getUid() - + " submittedOptionUid " - + submittedUid - + " question " - + question.getUid()); + log.error( + "Assessment Export: Unable to count answer in summary, refers to an unexpected option. QuestionResult " + + questionResult.getUid() + " submittedOptionUid " + submittedUid + " question " + + question.getUid()); } else { summaryOfAnswers.put(submittedUid, currentCount + 1); } @@ -1839,39 +1869,38 @@ private String valueAsPercentage(Integer value, int total) { Double percentage = (double) value / total * 100; - return NumberUtil.formatLocalisedNumber(percentage, (Locale)null, 2) + "%"; - } - + return NumberUtil.formatLocalisedNumber(percentage, (Locale) null, 2) + "%"; + } + private ExcelCell[] outputSummaryTable(AssessmentQuestion question, Map summaryOfAnswers, Integer summaryNACount, Long trueKey, Long falseKey) { - ExcelCell[] summaryTable = new ExcelCell[summaryOfAnswers.size()+1]; + ExcelCell[] summaryTable = new ExcelCell[summaryOfAnswers.size() + 1]; int total = summaryNACount; - for ( int value : summaryOfAnswers.values() ) { - total += value; + for (int value : summaryOfAnswers.values()) { + total += value; } int i = 0; if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE || question.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER - || question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL ) { - for (AssessmentQuestionOption option : question.getOptions()) { - summaryTable[i] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(option.getUid()), total), false); - if ( option.getGrade() > 0 ) { - summaryTable[i].setColor(IndexedColors.GREEN); + || question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + for (AssessmentQuestionOption option : question.getOptions()) { + summaryTable[i] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(option.getUid()), total), false); + if (option.getGrade() > 0) { + summaryTable[i].setColor(IndexedColors.GREEN); + } + i++; } - i++; - } - summaryTable[i++] = new ExcelCell(valueAsPercentage(summaryNACount, total), false); + summaryTable[i++] = new ExcelCell(valueAsPercentage(summaryNACount, total), false); } else { - summaryTable = new ExcelCell[3]; - summaryTable[0] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(trueKey), total), false); - summaryTable[1] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(falseKey), total), false); - summaryTable[2] = new ExcelCell(valueAsPercentage(summaryNACount,total), false); - summaryTable[question.getCorrectAnswer() ? 0 : 1].setColor(IndexedColors.GREEN); + summaryTable = new ExcelCell[3]; + summaryTable[0] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(trueKey), total), false); + summaryTable[1] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(falseKey), total), false); + summaryTable[2] = new ExcelCell(valueAsPercentage(summaryNACount, total), false); + summaryTable[question.getCorrectAnswer() ? 0 : 1].setColor(IndexedColors.GREEN); } return summaryTable; } - /** * Used only for excell export (for getUserSummaryData() method). */ @@ -1912,11 +1941,11 @@ // When changing a mark for user and isUseSelectLeaderToolOuput is true, the mark should be propagated to all // students within the group - List users = new ArrayList(); + List users = new ArrayList<>(); if (assessment.isUseSelectLeaderToolOuput()) { users = getUsersBySession(toolSessionId); } else { - users = new ArrayList(); + users = new ArrayList<>(); AssessmentUser user = assessmentResult.getUser(); users.add(user); } @@ -1960,7 +1989,7 @@ List deletedReferences) { // create list of modified questions - List modifiedQuestions = new ArrayList(); + List modifiedQuestions = new ArrayList<>(); for (AssessmentQuestion oldQuestion : oldQuestions) { for (AssessmentQuestion newQuestion : newQuestions) { if (oldQuestion.getUid().equals(newQuestion.getUid())) { @@ -2006,7 +2035,7 @@ // create list of modified references // modifiedReferences holds pairs newReference -> oldReference.getDefaultGrade() - Map modifiedReferences = new HashMap(); + Map modifiedReferences = new HashMap<>(); for (QuestionReference oldReference : oldReferences) { for (QuestionReference newReference : newReferences) { if (oldReference.getUid().equals(newReference.getUid()) @@ -2017,7 +2046,7 @@ } // create list of added references - List addedReferences = new ArrayList(); + List addedReferences = new ArrayList<>(); for (QuestionReference newReference : newReferences) { boolean isNewReferenceMetInOldReferences = false; @@ -2045,7 +2074,7 @@ user.getUserId()); AssessmentResult lastFinishedAssessmentResult = (assessmentResults.isEmpty()) ? null : assessmentResults.get(assessmentResults.size() - 1); - + //add autosave assessmentResult as well AssessmentResult lastAssessmentResult = getLastAssessmentResult(assessment.getUid(), user.getUserId()); if (lastAssessmentResult != null && lastAssessmentResult.getFinishDate() == null) { @@ -2126,7 +2155,7 @@ } // find all question answers from random question reference - ArrayList nonRandomQuestionAnswers = new ArrayList(); + ArrayList nonRandomQuestionAnswers = new ArrayList<>(); for (AssessmentQuestionResult questionAnswer : questionAnswers) { for (QuestionReference reference : newReferences) { if (!reference.isRandomQuestion() && questionAnswer.getAssessmentQuestion().getUid() @@ -2234,7 +2263,7 @@ public boolean isGroupedActivity(long toolContentID) { return toolService.isGroupedActivity(toolContentID); } - + @Override public void auditLogStartEditingActivityInMonitor(long toolContentID) { toolService.auditLogStartEditingActivityInMonitor(toolContentID); @@ -2261,7 +2290,6 @@ eventNotificationService.notifyLessonMonitors(sessionId, message, false); } - @Override public List getMarksArray(Long sessionId) { return assessmentUserDao.getRawUserMarksBySession(sessionId); @@ -2272,66 +2300,70 @@ return assessmentUserDao.getRawLeaderMarksByToolContentId(toolContentId); } - private LinkedHashMap getMarksSummaryForSession(List userDtos, float minGrade, float maxGrade, Integer numBuckets) { + private LinkedHashMap getMarksSummaryForSession(List userDtos, float minGrade, + float maxGrade, Integer numBuckets) { - LinkedHashMap summary = new LinkedHashMap(); - TreeMap inProgress = new TreeMap(); - - if ( numBuckets == null ) + LinkedHashMap summary = new LinkedHashMap<>(); + TreeMap inProgress = new TreeMap<>(); + + if (numBuckets == null) { numBuckets = 10; - + } + int bucketSize = 1; - int intMinGrade = (int)Math.floor(minGrade); + int intMinGrade = (int) Math.floor(minGrade); float gradeDifference = maxGrade - minGrade; - if ( gradeDifference <= 10 ) { - for ( int i= intMinGrade; i <= (int)Math.ceil(maxGrade); i++ ) { + if (gradeDifference <= 10) { + for (int i = intMinGrade; i <= (int) Math.ceil(maxGrade); i++) { inProgress.put(i, 0); } } else { int intGradeDifference = (int) Math.ceil(gradeDifference); - bucketSize = (int) Math.ceil(intGradeDifference / numBuckets); - for ( int i=intMinGrade; i <= maxGrade; i = i+bucketSize ) { + bucketSize = (int) Math.ceil(intGradeDifference / numBuckets); + for (int i = intMinGrade; i <= maxGrade; i = i + bucketSize) { inProgress.put(i, 0); } } - + for (AssessmentUserDTO userDto : userDtos) { float grade = userDto.getGrade(); int bucketStart = intMinGrade; - int bucketStop = bucketStart+bucketSize; + int bucketStop = bucketStart + bucketSize; boolean looking = true; - while ( bucketStart <= maxGrade && looking ) { - if ( grade >= bucketStart && grade < bucketStop ) { + while (bucketStart <= maxGrade && looking) { + if (grade >= bucketStart && grade < bucketStop) { inProgress.put(bucketStart, inProgress.get(bucketStart) + 1); looking = false; } else { bucketStart = bucketStop; - bucketStop = bucketStart+bucketSize; + bucketStop = bucketStart + bucketSize; } } } - - for ( Map.Entry entry : inProgress.entrySet() ) { + + for (Map.Entry entry : inProgress.entrySet()) { String key; - if ( bucketSize == 1 ) + if (bucketSize == 1) { key = entry.getKey().toString(); - else { - if ( maxGrade >= entry.getKey() && maxGrade <= entry.getKey()+bucketSize-1) { - if ( (int)maxGrade == entry.getKey() ) - key = NumberUtil.formatLocalisedNumber(maxGrade, (Locale)null, 2); - else + } else { + if (maxGrade >= entry.getKey() && maxGrade <= entry.getKey() + bucketSize - 1) { + if ((int) maxGrade == entry.getKey()) { + key = NumberUtil.formatLocalisedNumber(maxGrade, (Locale) null, 2); + } else { key = new StringBuilder().append(entry.getKey()).append(" - ") - .append(NumberUtil.formatLocalisedNumber(maxGrade, (Locale)null, 2)).toString(); + .append(NumberUtil.formatLocalisedNumber(maxGrade, (Locale) null, 2)).toString(); + } } else { - key = new StringBuilder().append(entry.getKey()).append(" - ").append(entry.getKey()+bucketSize-.01).toString(); + key = new StringBuilder().append(entry.getKey()).append(" - ") + .append(entry.getKey() + bucketSize - .01).toString(); } } summary.put(key, entry.getValue()); } - + return summary; } - + // ***************************************************************************** // private methods // ***************************************************************************** @@ -2768,116 +2800,126 @@ Date startDate = null; Date finishDate = null; for (AssessmentResult result : results) { - if (startDate == null || (result.getStartDate() != null && result.getStartDate().before(startDate))) + if (startDate == null || (result.getStartDate() != null && result.getStartDate().before(startDate))) { startDate = result.getStartDate(); - if (finishDate == null || (result.getFinishDate() != null && result.getFinishDate().after(finishDate))) + } + if (finishDate == null || (result.getFinishDate() != null && result.getFinishDate().after(finishDate))) { finishDate = result.getFinishDate(); + } } - if (learner.isSessionFinished()) + if (learner.isSessionFinished()) { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, startDate, finishDate); - else + } else { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, startDate, null); + } } // ****************** REST methods ************************* /** * Rest call to create a new Assessment content. Required fields in toolContentJSON: "title", "instructions", * "questions", "firstName", "lastName", "lastName", "questions" and "references". * - * The questions entry should be a JSONArray containing JSON objects, which in turn must contain "questionTitle", + * The questions entry should be a ArrayNode containing JSON objects, which in turn must contain "questionTitle", * "questionText", "displayOrder" (Integer), "type" (Integer). If the type is Multiple Choice, Numerical or Matching - * Pairs then a JSONArray "answers" is required. + * Pairs then a ArrayNode "answers" is required. * - * The answers entry should be JSONArray containing JSON objects, which in turn must contain "answerText" or + * The answers entry should be ArrayNode containing JSON objects, which in turn must contain "answerText" or * "answerFloat", "displayOrder" (Integer), "grade" (Integer). * - * The references entry should be a JSONArray containing JSON objects, which in turn must contain "displayOrder" + * The references entry should be a ArrayNode containing JSON objects, which in turn must contain "displayOrder" * (Integer), "questionDisplayOrder" (Integer - to match to the question). It may also have "defaultGrade" (Integer) * and "randomQuestion" (Boolean) + * + * @throws IOException */ @SuppressWarnings("unchecked") @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) + throws IOException { Assessment assessment = new Assessment(); assessment.setContentId(toolContentID); - assessment.setTitle(toolContentJSON.getString(RestTags.TITLE)); - assessment.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + assessment.setTitle(toolContentJSON.get(RestTags.TITLE).asText()); + assessment.setInstructions(toolContentJSON.get(RestTags.INSTRUCTIONS).asText()); assessment.setCreated(new Date()); - assessment.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); - assessment.setReflectInstructions(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, (String) null)); - assessment.setAllowGradesAfterAttempt(JsonUtil.opt(toolContentJSON, "allowGradesAfterAttempt", Boolean.FALSE)); - assessment.setAllowHistoryResponses(JsonUtil.opt(toolContentJSON, "allowHistoryResponses", Boolean.FALSE)); + assessment.setReflectOnActivity( + JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + assessment.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + assessment.setAllowGradesAfterAttempt( + JsonUtil.optBoolean(toolContentJSON, "allowGradesAfterAttempt", Boolean.FALSE)); + assessment + .setAllowHistoryResponses(JsonUtil.optBoolean(toolContentJSON, "allowHistoryResponses", Boolean.FALSE)); assessment.setAllowOverallFeedbackAfterQuestion( - JsonUtil.opt(toolContentJSON, "allowOverallFeedbackAfterQuestion", Boolean.FALSE)); - assessment.setAllowQuestionFeedback(JsonUtil.opt(toolContentJSON, "allowQuestionFeedback", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "allowOverallFeedbackAfterQuestion", Boolean.FALSE)); + assessment + .setAllowQuestionFeedback(JsonUtil.optBoolean(toolContentJSON, "allowQuestionFeedback", Boolean.FALSE)); assessment.setAllowRightAnswersAfterQuestion( - JsonUtil.opt(toolContentJSON, "allowRightAnswersAfterQuestion", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "allowRightAnswersAfterQuestion", Boolean.FALSE)); assessment.setAllowWrongAnswersAfterQuestion( - JsonUtil.opt(toolContentJSON, "allowWrongAnswersAfterQuestion", Boolean.FALSE)); - assessment.setAttemptsAllowed(JsonUtil.opt(toolContentJSON, "attemptsAllows", 1)); + JsonUtil.optBoolean(toolContentJSON, "allowWrongAnswersAfterQuestion", Boolean.FALSE)); + assessment.setAttemptsAllowed(JsonUtil.optInt(toolContentJSON, "attemptsAllows", 1)); assessment.setDefineLater(false); - assessment.setDisplaySummary(JsonUtil.opt(toolContentJSON, "displaySummary", Boolean.FALSE)); + assessment.setDisplaySummary(JsonUtil.optBoolean(toolContentJSON, "displaySummary", Boolean.FALSE)); assessment.setNotifyTeachersOnAttemptCompletion( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnAttemptCompletion", Boolean.FALSE)); - assessment.setNumbered(JsonUtil.opt(toolContentJSON, "numbered", Boolean.TRUE)); - assessment.setPassingMark(JsonUtil.opt(toolContentJSON, "passingMark", 0)); - assessment.setQuestionsPerPage(JsonUtil.opt(toolContentJSON, "questionsPerPage", 0)); - assessment.setReflectInstructions(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, "")); - assessment.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); - assessment.setShuffled(JsonUtil.opt(toolContentJSON, "shuffled", Boolean.FALSE)); - assessment.setTimeLimit(JsonUtil.opt(toolContentJSON, "timeLimit", 0)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnAttemptCompletion", Boolean.FALSE)); + assessment.setNumbered(JsonUtil.optBoolean(toolContentJSON, "numbered", Boolean.TRUE)); + assessment.setPassingMark(JsonUtil.optInt(toolContentJSON, "passingMark", 0)); + assessment.setQuestionsPerPage(JsonUtil.optInt(toolContentJSON, "questionsPerPage", 0)); + assessment.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, "")); + assessment.setReflectOnActivity( + JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + assessment.setShuffled(JsonUtil.optBoolean(toolContentJSON, "shuffled", Boolean.FALSE)); + assessment.setTimeLimit(JsonUtil.optInt(toolContentJSON, "timeLimit", 0)); assessment.setUseSelectLeaderToolOuput( - JsonUtil.opt(toolContentJSON, RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, Boolean.FALSE)); // submission deadline set in monitoring if (toolContentJSON.has("overallFeedback")) { - throw new JSONException( + throw new IOException( "Assessment Tool does not support Overall Feedback for REST Authoring. " + toolContentJSON); } AssessmentUser assessmentUser = getUserByIDAndContent(userID.longValue(), toolContentID); if (assessmentUser == null) { assessmentUser = new AssessmentUser(); - assessmentUser.setFirstName(toolContentJSON.getString("firstName")); - assessmentUser.setLastName(toolContentJSON.getString("lastName")); - assessmentUser.setLoginName(toolContentJSON.getString("loginName")); + assessmentUser.setFirstName(toolContentJSON.get("firstName").asText()); + assessmentUser.setLastName(toolContentJSON.get("lastName").asText()); + assessmentUser.setLoginName(toolContentJSON.get("loginName").asText()); assessmentUser.setAssessment(assessment); } assessment.setCreatedBy(assessmentUser); // **************************** Set the question bank ********************* - JSONArray questions = toolContentJSON.getJSONArray("questions"); + ArrayNode questions = JsonUtil.optArray(toolContentJSON, "questions"); Set newQuestionSet = assessment.getQuestions(); // the Assessment constructor will set up the collection - for (int i = 0; i < questions.length(); i++) { - JSONObject questionJSONData = (JSONObject) questions.get(i); + for (JsonNode questionJSONData : questions) { AssessmentQuestion question = new AssessmentQuestion(); - short type = (short) questionJSONData.getInt("type"); + short type = JsonUtil.optInt(questionJSONData, "type").shortValue(); question.setType(type); - question.setTitle(questionJSONData.getString(RestTags.QUESTION_TITLE)); - question.setQuestion(questionJSONData.getString(RestTags.QUESTION_TEXT)); - question.setSequenceId(questionJSONData.getInt(RestTags.DISPLAY_ORDER)); + question.setTitle(questionJSONData.get(RestTags.QUESTION_TITLE).asText()); + question.setQuestion(questionJSONData.get(RestTags.QUESTION_TEXT).asText()); + question.setSequenceId(JsonUtil.optInt(questionJSONData, RestTags.DISPLAY_ORDER)); - question.setAllowRichEditor(JsonUtil.opt(questionJSONData, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); - question.setAnswerRequired(JsonUtil.opt(questionJSONData, "answerRequired", Boolean.FALSE)); - question.setCaseSensitive(JsonUtil.opt(questionJSONData, "caseSensitive", Boolean.FALSE)); - question.setCorrectAnswer(JsonUtil.opt(questionJSONData, "correctAnswer", Boolean.FALSE)); - question.setDefaultGrade(JsonUtil.opt(questionJSONData, "defaultGrade", 1)); - question.setFeedback(JsonUtil.opt(questionJSONData, "feedback", (String) null)); - question.setFeedbackOnCorrect(JsonUtil.opt(questionJSONData, "feedbackOnCorrect", (String) null)); - question.setFeedbackOnIncorrect(JsonUtil.opt(questionJSONData, "feedbackOnIncorrect", (String) null)); - question.setFeedbackOnPartiallyCorrect( - JsonUtil.opt(questionJSONData, "feedbackOnPartiallyCorrect", (String) null)); - question.setGeneralFeedback(JsonUtil.opt(questionJSONData, "generalFeedback", "")); - question.setMaxWordsLimit(JsonUtil.opt(questionJSONData, "maxWordsLimit", 0)); - question.setMinWordsLimit(JsonUtil.opt(questionJSONData, "minWordsLimit", 0)); - question.setMultipleAnswersAllowed(JsonUtil.opt(questionJSONData, "multipleAnswersAllowed", Boolean.FALSE)); + question.setAllowRichEditor( + JsonUtil.optBoolean(questionJSONData, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); + question.setAnswerRequired(JsonUtil.optBoolean(questionJSONData, "answerRequired", Boolean.FALSE)); + question.setCaseSensitive(JsonUtil.optBoolean(questionJSONData, "caseSensitive", Boolean.FALSE)); + question.setCorrectAnswer(JsonUtil.optBoolean(questionJSONData, "correctAnswer", Boolean.FALSE)); + question.setDefaultGrade(JsonUtil.optInt(questionJSONData, "defaultGrade", 1)); + question.setFeedback(JsonUtil.optString(questionJSONData, "feedback")); + question.setFeedbackOnCorrect(JsonUtil.optString(questionJSONData, "feedbackOnCorrect")); + question.setFeedbackOnIncorrect(JsonUtil.optString(questionJSONData, "feedbackOnIncorrect")); + question.setFeedbackOnPartiallyCorrect(JsonUtil.optString(questionJSONData, "feedbackOnPartiallyCorrect")); + question.setGeneralFeedback(JsonUtil.optString(questionJSONData, "generalFeedback", "")); + question.setMaxWordsLimit(JsonUtil.optInt(questionJSONData, "maxWordsLimit", 0)); + question.setMinWordsLimit(JsonUtil.optInt(questionJSONData, "minWordsLimit", 0)); + question.setMultipleAnswersAllowed( + JsonUtil.optBoolean(questionJSONData, "multipleAnswersAllowed", Boolean.FALSE)); question.setIncorrectAnswerNullifiesMark( - JsonUtil.opt(questionJSONData, "incorrectAnswerNullifiesMark", Boolean.FALSE)); - question.setPenaltyFactor(Float.parseFloat(JsonUtil.opt(questionJSONData, "penaltyFactor", "0.0"))); + JsonUtil.optBoolean(questionJSONData, "incorrectAnswerNullifiesMark", Boolean.FALSE)); + question.setPenaltyFactor(JsonUtil.optDouble(questionJSONData, "penaltyFactor", 0.0).floatValue()); // question.setUnits(units); Needed for numerical type question if ((type == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) @@ -2886,22 +2928,21 @@ || (type == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING)) { if (!questionJSONData.has(RestTags.ANSWERS)) { - throw new JSONException("REST Authoring is missing answers for a question of type " + type - + ". Data:" + toolContentJSON); + throw new IOException("REST Authoring is missing answers for a question of type " + type + ". Data:" + + toolContentJSON); } - Set optionList = new LinkedHashSet(); - JSONArray optionsData = questionJSONData.getJSONArray(RestTags.ANSWERS); - for (int j = 0; j < optionsData.length(); j++) { - JSONObject answerData = (JSONObject) optionsData.get(j); + Set optionList = new LinkedHashSet<>(); + ArrayNode optionsData = JsonUtil.optArray(questionJSONData, RestTags.ANSWERS); + for (JsonNode answerData : optionsData) { AssessmentQuestionOption option = new AssessmentQuestionOption(); - option.setSequenceId(answerData.getInt(RestTags.DISPLAY_ORDER)); - option.setGrade(Float.parseFloat(answerData.getString("grade"))); - option.setCorrect(Boolean.parseBoolean(JsonUtil.opt(answerData, "correct", "false"))); - option.setAcceptedError(Float.parseFloat(JsonUtil.opt(answerData, "acceptedError", "0.0"))); - option.setFeedback(JsonUtil.opt(answerData, "feedback", (String) null)); - option.setOptionString(JsonUtil.opt(answerData, RestTags.ANSWER_TEXT, (String) null)); - option.setOptionFloat(Float.parseFloat(JsonUtil.opt(answerData, "answerFloat", "0.0"))); + option.setSequenceId(JsonUtil.optInt(answerData, RestTags.DISPLAY_ORDER)); + option.setGrade(answerData.get("grade").floatValue()); + option.setCorrect(JsonUtil.optBoolean(answerData, "correct", false)); + option.setAcceptedError(JsonUtil.optDouble(answerData, "acceptedError", 0.0).floatValue()); + option.setFeedback(JsonUtil.optString(answerData, "feedback")); + option.setOptionString(JsonUtil.optString(answerData, RestTags.ANSWER_TEXT)); + option.setOptionFloat(JsonUtil.optDouble(answerData, "answerFloat", 0.0).floatValue()); // option.setQuestion(question); can't find the use for this field yet! optionList.add(option); } @@ -2913,23 +2954,23 @@ } // **************************** Now set up the references to the questions in the bank ********************* - JSONArray references = toolContentJSON.getJSONArray("references"); + ArrayNode references = JsonUtil.optArray(toolContentJSON, "references"); Set newReferenceSet = assessment.getQuestionReferences(); // the Assessment constructor will set up the - // collection - for (int i = 0; i < references.length(); i++) { - JSONObject referenceJSONData = (JSONObject) references.get(i); + + ;// collection + for (JsonNode referenceJSONData : references) { QuestionReference reference = new QuestionReference(); reference.setType((short) 0); - reference.setDefaultGrade(JsonUtil.opt(referenceJSONData, "defaultGrade", 1)); - reference.setSequenceId(referenceJSONData.getInt(RestTags.DISPLAY_ORDER)); + reference.setDefaultGrade(JsonUtil.optInt(referenceJSONData, "defaultGrade", 1)); + reference.setSequenceId(JsonUtil.optInt(referenceJSONData, RestTags.DISPLAY_ORDER)); AssessmentQuestion matchingQuestion = matchQuestion(newQuestionSet, - referenceJSONData.getInt("questionDisplayOrder")); + JsonUtil.optInt(referenceJSONData, "questionDisplayOrder")); if (matchingQuestion == null) { - throw new JSONException("Unable to find matching question for displayOrder " + throw new IOException("Unable to find matching question for displayOrder " + referenceJSONData.get("questionDisplayOrder") + ". Data:" + toolContentJSON); } reference.setQuestion(matchingQuestion); - reference.setRandomQuestion(JsonUtil.opt(referenceJSONData, "randomQuestion", Boolean.FALSE)); + reference.setRandomQuestion(JsonUtil.optBoolean(referenceJSONData, "randomQuestion", Boolean.FALSE)); reference.setTitle(null); newReferenceSet.add(reference); } @@ -2951,10 +2992,10 @@ } // TODO Implement REST support for all types and then remove checkType method - void checkType(short type) throws JSONException { + void checkType(short type) throws IOException { if ((type != AssessmentConstants.QUESTION_TYPE_ESSAY) && (type != AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE)) { - throw new JSONException( + throw new IOException( "Assessment Tool does not support REST Authoring for anything but Essay Type and Multiple Choice. Found type " + type); } Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java (.../ForumService.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java (.../ForumService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -42,9 +42,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.upload.FormFile; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; import org.lamsfoundation.lams.contentrepository.NodeKey; @@ -114,6 +111,9 @@ import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.audit.IAuditService; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Steve.Ni @@ -1514,50 +1514,49 @@ /** * Used by the Rest calls to create content. Mandatory fields in toolContentJSON: title, instructions, topics. - * Topics must contain a JSONArray of JSONObject objects, which have the following mandatory fields: subject, body + * Topics must contain a ArrayNode of ObjectNode objects, which have the following mandatory fields: subject, body * There will usually be at least one topic object in the Topics array but the array may be of zero length. */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { Forum forum = new Forum(); Date updateDate = new Date(); forum.setCreated(updateDate); forum.setUpdated(updateDate); forum.setContentId(toolContentID); - forum.setTitle(toolContentJSON.getString(RestTags.TITLE)); - forum.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + forum.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + forum.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); - forum.setAllowAnonym(JsonUtil.opt(toolContentJSON, "allowAnonym", Boolean.FALSE)); - forum.setAllowEdit(JsonUtil.opt(toolContentJSON, "allowEdit", Boolean.TRUE)); // defaults to true in the default - // entry in the db - forum.setAllowNewTopic(JsonUtil.opt(toolContentJSON, "allowNewTopic", Boolean.TRUE)); // defaults to true in the - // default entry in the db - forum.setAllowRateMessages(JsonUtil.opt(toolContentJSON, "allowRateMessages", Boolean.FALSE)); - forum.setAllowRichEditor(JsonUtil.opt(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); - forum.setAllowUpload(JsonUtil.opt(toolContentJSON, "allowUpload", Boolean.FALSE)); + forum.setAllowAnonym(JsonUtil.optBoolean(toolContentJSON, "allowAnonym", Boolean.FALSE)); + forum.setAllowEdit(JsonUtil.optBoolean(toolContentJSON, "allowEdit", Boolean.TRUE)); // defaults to true in the default + // entry in the db + forum.setAllowNewTopic(JsonUtil.optBoolean(toolContentJSON, "allowNewTopic", Boolean.TRUE)); // defaults to true in the + // default entry in the db + forum.setAllowRateMessages(JsonUtil.optBoolean(toolContentJSON, "allowRateMessages", Boolean.FALSE)); + forum.setAllowRichEditor(JsonUtil.optBoolean(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); + forum.setAllowUpload(JsonUtil.optBoolean(toolContentJSON, "allowUpload", Boolean.FALSE)); forum.setContentInUse(false); forum.setDefineLater(false); - forum.setLimitedMaxCharacters(JsonUtil.opt(toolContentJSON, "limitedMaxCharacters", Boolean.TRUE)); - forum.setLimitedMinCharacters(JsonUtil.opt(toolContentJSON, "limitedMinCharacters", Boolean.FALSE)); - forum.setLockWhenFinished(JsonUtil.opt(toolContentJSON, "lockWhenFinished", Boolean.FALSE)); - forum.setMaxCharacters(JsonUtil.opt(toolContentJSON, "maxCharacters", 5000)); // defaults to 5000 chars in the - // default entry in the db. - forum.setMaximumRate(JsonUtil.opt(toolContentJSON, "maximumRate", 0)); - forum.setMaximumReply(JsonUtil.opt(toolContentJSON, "maximumReply", 0)); - forum.setMinCharacters(JsonUtil.opt(toolContentJSON, "minCharacters", 0)); - forum.setMinimumRate(JsonUtil.opt(toolContentJSON, "minimumRate", 0)); - forum.setMinimumReply(JsonUtil.opt(toolContentJSON, "minimumReply", 0)); + forum.setLimitedMaxCharacters(JsonUtil.optBoolean(toolContentJSON, "limitedMaxCharacters", Boolean.TRUE)); + forum.setLimitedMinCharacters(JsonUtil.optBoolean(toolContentJSON, "limitedMinCharacters", Boolean.FALSE)); + forum.setLockWhenFinished(JsonUtil.optBoolean(toolContentJSON, "lockWhenFinished", Boolean.FALSE)); + forum.setMaxCharacters(JsonUtil.optInt(toolContentJSON, "maxCharacters", 5000)); // defaults to 5000 chars in the + // default entry in the db. + forum.setMaximumRate(JsonUtil.optInt(toolContentJSON, "maximumRate", 0)); + forum.setMaximumReply(JsonUtil.optInt(toolContentJSON, "maximumReply", 0)); + forum.setMinCharacters(JsonUtil.optInt(toolContentJSON, "minCharacters", 0)); + forum.setMinimumRate(JsonUtil.optInt(toolContentJSON, "minimumRate", 0)); + forum.setMinimumReply(JsonUtil.optInt(toolContentJSON, "minimumReply", 0)); forum.setNotifyLearnersOnForumPosting( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnForumPosting", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnForumPosting", Boolean.FALSE)); forum.setNotifyLearnersOnMarkRelease( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); forum.setNotifyTeachersOnForumPosting( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnForumPosting", Boolean.FALSE)); - forum.setReflectInstructions((String) JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, null)); - forum.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnForumPosting", Boolean.FALSE)); + forum.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + forum.setReflectOnActivity(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); // submissionDeadline is set in monitoring // *******************************Handle user******************* @@ -1571,27 +1570,27 @@ // UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); ForumUser forumUser = getUserByID(userID.longValue()); if (forumUser == null) { - forumUser = new ForumUser(userID.longValue(), toolContentJSON.getString("firstName"), - toolContentJSON.getString("lastName"), toolContentJSON.getString("loginName")); + forumUser = new ForumUser(userID.longValue(), JsonUtil.optString(toolContentJSON, "firstName"), + JsonUtil.optString(toolContentJSON, "lastName"), JsonUtil.optString(toolContentJSON, "loginName")); getForumUserDao().save(forumUser); } forum.setCreatedBy(forumUser); updateForum(forum); // **************************** Handle topic ********************* - JSONArray topics = toolContentJSON.getJSONArray("topics"); - for (int i = 0; i < topics.length(); i++) { - JSONObject msgData = (JSONObject) topics.get(i); + ArrayNode topics = JsonUtil.optArray(toolContentJSON, "topics"); + for (int i = 0; i < topics.size(); i++) { + ObjectNode msgData = (ObjectNode) topics.get(i); Message newMsg = new Message(); // newMsg.setAttachments(attachments); TODO newMsg.setCreatedBy(forumUser); newMsg.setCreated(updateDate); newMsg.setModifiedBy(null); newMsg.setUpdated(updateDate); - newMsg.setSubject(msgData.getString("subject")); - newMsg.setBody(msgData.getString("body")); + newMsg.setSubject(JsonUtil.optString(msgData, "subject")); + newMsg.setBody(JsonUtil.optString(msgData, "body")); newMsg.setForum(forum); newMsg.setHideFlag(false); // newMsg.setIsAnonymous(false); Does not appear on authoring interface Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McService.java =================================================================== diff -u --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McService.java (revision 0) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McService.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,1976 @@ +/*************************************************************************** + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.mc.service; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.TreeSet; + +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; +import org.lamsfoundation.lams.gradebook.service.IGradebookService; +import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService; +import org.lamsfoundation.lams.learningdesign.service.ImportToolContentException; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; +import org.lamsfoundation.lams.rest.RestTags; +import org.lamsfoundation.lams.rest.ToolRestManager; +import org.lamsfoundation.lams.tool.IToolVO; +import org.lamsfoundation.lams.tool.ToolCompletionStatus; +import org.lamsfoundation.lams.tool.ToolContentManager; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.ToolSessionExportOutputData; +import org.lamsfoundation.lams.tool.ToolSessionManager; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.mc.McAppConstants; +import org.lamsfoundation.lams.tool.mc.dao.IMcContentDAO; +import org.lamsfoundation.lams.tool.mc.dao.IMcOptionsContentDAO; +import org.lamsfoundation.lams.tool.mc.dao.IMcQueContentDAO; +import org.lamsfoundation.lams.tool.mc.dao.IMcSessionDAO; +import org.lamsfoundation.lams.tool.mc.dao.IMcUserDAO; +import org.lamsfoundation.lams.tool.mc.dao.IMcUsrAttemptDAO; +import org.lamsfoundation.lams.tool.mc.dto.AnswerDTO; +import org.lamsfoundation.lams.tool.mc.dto.LeaderResultsDTO; +import org.lamsfoundation.lams.tool.mc.dto.McOptionDTO; +import org.lamsfoundation.lams.tool.mc.dto.McQuestionDTO; +import org.lamsfoundation.lams.tool.mc.dto.McSessionMarkDTO; +import org.lamsfoundation.lams.tool.mc.dto.McUserMarkDTO; +import org.lamsfoundation.lams.tool.mc.dto.ReflectionDTO; +import org.lamsfoundation.lams.tool.mc.dto.SessionDTO; +import org.lamsfoundation.lams.tool.mc.dto.ToolOutputDTO; +import org.lamsfoundation.lams.tool.mc.pojos.McContent; +import org.lamsfoundation.lams.tool.mc.pojos.McOptsContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueUsr; +import org.lamsfoundation.lams.tool.mc.pojos.McSession; +import org.lamsfoundation.lams.tool.mc.pojos.McUsrAttempt; +import org.lamsfoundation.lams.tool.mc.util.McSessionComparator; +import org.lamsfoundation.lams.tool.mc.util.McStringComparator; +import org.lamsfoundation.lams.tool.service.ILamsToolService; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.ExcelUtil; +import org.lamsfoundation.lams.util.JsonUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.NumberUtil; +import org.lamsfoundation.lams.util.audit.IAuditService; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.dao.DataAccessException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * + * The POJO implementation of Mc service. All business logics of MCQ tool are implemented in this class. It translate + * the request from presentation layer and perform appropriate database operation. + * + * @author Ozgur Demirtas + */ +public class McService implements IMcService, ToolContentManager, ToolSessionManager, ToolRestManager, McAppConstants { + private static Logger logger = Logger.getLogger(McService.class.getName()); + + private IMcContentDAO mcContentDAO; + private IMcQueContentDAO mcQueContentDAO; + private IMcOptionsContentDAO mcOptionsContentDAO; + private IMcSessionDAO mcSessionDAO; + private IMcUserDAO mcUserDAO; + private IMcUsrAttemptDAO mcUsrAttemptDAO; + private MCOutputFactory mcOutputFactory; + + private IAuditService auditService; + private IUserManagementService userManagementService; + private ILearnerService learnerService; + private ILamsToolService toolService; + private IToolContentHandler mcToolContentHandler = null; + private IExportToolContentService exportContentService; + private IGradebookService gradebookService; + + private ICoreNotebookService coreNotebookService; + + private MessageService messageService; + + public McService() { + } + + @Override + public McQueUsr checkLeaderSelectToolForSessionLeader(McQueUsr user, Long toolSessionId) { + if ((user == null) || (toolSessionId == null)) { + return null; + } + + McSession mcSession = mcSessionDAO.getMcSessionById(toolSessionId); + McQueUsr leader = mcSession.getGroupLeader(); + // check leader select tool for a leader only in case QA tool doesn't know it. As otherwise it will screw + // up previous scratches done + if (leader == null) { + + Long leaderUserId = toolService.getLeaderUserId(toolSessionId, user.getQueUsrId().intValue()); + if (leaderUserId != null) { + + leader = getMcUserBySession(leaderUserId, mcSession.getUid()); + + // create new user in a DB + if (leader == null) { + logger.debug("creating new user with userId: " + leaderUserId); + User leaderDto = (User) userManagementService.findById(User.class, leaderUserId.intValue()); + String userName = leaderDto.getLogin(); + String fullName = leaderDto.getFirstName() + " " + leaderDto.getLastName(); + leader = new McQueUsr(leaderUserId, userName, fullName, mcSession, new TreeSet()); + mcUserDAO.saveMcUser(user); + } + + // set group leader + mcSession.setGroupLeader(leader); + mcSessionDAO.updateMcSession(mcSession); + } + } + + return leader; + } + + @Override + public void copyAnswersFromLeader(McQueUsr user, McQueUsr leader) { + + if ((user == null) || (leader == null) || user.getUid().equals(leader.getUid())) { + return; + } + + List leaderAttempts = this.getFinalizedUserAttempts(leader); + for (McUsrAttempt leaderAttempt : leaderAttempts) { + + McQueContent question = leaderAttempt.getMcQueContent(); + McUsrAttempt userAttempt = mcUsrAttemptDAO.getUserAttemptByQuestion(user.getUid(), question.getUid()); + + // if response doesn't exist - created mcUsrAttempt in the db + if (userAttempt == null) { + userAttempt = new McUsrAttempt(leaderAttempt.getAttemptTime(), question, user, + leaderAttempt.getMcOptionsContent(), leaderAttempt.getMark(), leaderAttempt.isPassed(), + leaderAttempt.isAttemptCorrect()); + mcUsrAttemptDAO.saveMcUsrAttempt(userAttempt); + + // if it's been changed by the leader + } else if (leaderAttempt.getAttemptTime().compareTo(userAttempt.getAttemptTime()) != 0) { + userAttempt.setMcOptionsContent(leaderAttempt.getMcOptionsContent()); + userAttempt.setAttemptTime(leaderAttempt.getAttemptTime()); + this.updateMcUsrAttempt(userAttempt); + } + + user.setNumberOfAttempts(leader.getNumberOfAttempts()); + user.setLastAttemptTotalMark(leader.getLastAttemptTotalMark()); + this.updateMcQueUsr(user); + } + } + + @Override + public void createMc(McContent mcContent) throws McApplicationException { + try { + mcContentDAO.saveMcContent(mcContent); + } catch (DataAccessException e) { + throw new McApplicationException("Exception occured when lams is creating mc content: " + e.getMessage(), + e); + } + } + + @Override + public McContent getMcContent(Long toolContentId) throws McApplicationException { + try { + return mcContentDAO.findMcContentById(toolContentId); + } catch (DataAccessException e) { + throw new McApplicationException("Exception occured when lams is loading mc content: " + e.getMessage(), e); + } + } + + @Override + public void setDefineLater(String strToolContentID, boolean value) { + + McContent mcContent = getMcContent(new Long(strToolContentID)); + if (mcContent != null) { + mcContent.setDefineLater(value); + updateMc(mcContent); + } + } + + @Override + public void updateQuestion(McQueContent mcQueContent) throws McApplicationException { + try { + mcQueContentDAO.updateMcQueContent(mcQueContent); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is updating mc que content: " + e.getMessage(), e); + } + + } + + @Override + public McQueContent getQuestionByDisplayOrder(final Long displayOrder, final Long mcContentUid) + throws McApplicationException { + try { + return mcQueContentDAO.getQuestionContentByDisplayOrder(displayOrder, mcContentUid); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is getting mc que content by display order: " + e.getMessage(), e); + } + } + + @Override + public List getAllQuestionsSorted(final long mcContentId) throws McApplicationException { + try { + return mcQueContentDAO.getAllQuestionEntriesSorted(mcContentId); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is getting all question entries: " + e.getMessage(), e); + } + } + + @Override + public void saveOrUpdateMcQueContent(McQueContent mcQueContent) throws McApplicationException { + try { + mcQueContentDAO.saveOrUpdateMcQueContent(mcQueContent); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is updating mc que content: " + e.getMessage(), e); + } + } + + @Override + public McContent createQuestions(List questionDTOs, McContent content) { + + int displayOrder = 0; + for (McQuestionDTO questionDTO : questionDTOs) { + String currentQuestionText = questionDTO.getQuestion(); + + // skip empty questions + if (currentQuestionText.isEmpty()) { + continue; + } + + ++displayOrder; + String currentFeedback = questionDTO.getFeedback(); + String currentMark = questionDTO.getMark(); + /* set the default mark in case it is not provided */ + if (currentMark == null) { + currentMark = "1"; + } + + McQueContent question = getQuestionByUid(questionDTO.getUid()); + + // in case question doesn't exist + if (question == null) { + question = new McQueContent(currentQuestionText, new Integer(displayOrder), new Integer(currentMark), + currentFeedback, content, null, null); + + // adding a new question to content + content.getMcQueContents().add(question); + question.setMcContent(content); + + // in case question exists already + } else { + + question.setQuestion(currentQuestionText); + question.setFeedback(currentFeedback); + question.setDisplayOrder(new Integer(displayOrder)); + question.setMark(new Integer(currentMark)); + } + + // persist candidate answers + List optionDTOs = questionDTO.getOptionDtos(); + Set oldOptions = question.getMcOptionsContents(); + Set newOptions = new HashSet(); + int displayOrderOption = 1; + for (McOptionDTO optionDTO : optionDTOs) { + + Long optionUid = optionDTO.getUid(); + String optionText = optionDTO.getCandidateAnswer(); + boolean isCorrectOption = "Correct".equals(optionDTO.getCorrect()); + + //find persisted option if it exists + McOptsContent option = new McOptsContent(); + for (McOptsContent oldOption : oldOptions) { + if (oldOption.getUid().equals(optionUid)) { + option = oldOption; + } + } + + option.setDisplayOrder(displayOrderOption); + option.setCorrectOption(isCorrectOption); + option.setMcQueOptionText(optionText); + option.setMcQueContent(question); + + newOptions.add(option); + displayOrderOption++; + } + + question.setMcOptionsContents(newOptions); + + // updating the existing question content + updateQuestion(question); + + } + return content; + } + + @Override + public void releaseQuestionsFromCache(McContent content) { + for (McQueContent question : (Set) content.getMcQueContents()) { + mcQueContentDAO.releaseQuestionFromCache(question); + } + } + + @Override + public McQueUsr createMcUser(Long toolSessionID) throws McApplicationException { + try { + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = toolUser.getUserID().longValue(); + String userName = toolUser.getLogin(); + String fullName = toolUser.getFirstName() + " " + toolUser.getLastName(); + McSession mcSession = getMcSessionById(toolSessionID.longValue()); + + McQueUsr user = new McQueUsr(userId, userName, fullName, mcSession, new TreeSet()); + mcUserDAO.saveMcUser(user); + + return user; + } catch (DataAccessException e) { + throw new McApplicationException("Exception occured when lams is creating mc QueUsr: " + e.getMessage(), e); + } + } + + @Override + public void updateMcQueUsr(McQueUsr mcQueUsr) throws McApplicationException { + try { + mcUserDAO.updateMcUser(mcQueUsr); + } catch (DataAccessException e) { + throw new McApplicationException("Exception occured when lams is updating mc QueUsr: " + e.getMessage(), e); + } + } + + @Override + public McQueUsr getMcUserBySession(final Long queUsrId, final Long mcSessionUid) throws McApplicationException { + try { + return mcUserDAO.getMcUserBySession(queUsrId, mcSessionUid); + } catch (DataAccessException e) { + throw new McApplicationException("Exception occured when lams is getting mc QueUsr: " + e.getMessage(), e); + } + } + + @Override + public McQueUsr getMcUserByUID(Long uid) throws McApplicationException { + try { + return mcUserDAO.getMcUserByUID(uid); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is getting the mc QueUsr by uid." + e.getMessage(), e); + } + } + + @Override + public List getPagedUsersBySession(Long sessionId, int page, int size, String sortBy, + String sortOrder, String searchString) { + return mcUserDAO.getPagedUsersBySession(sessionId, page, size, sortBy, sortOrder, searchString); + } + + @Override + public int getCountPagedUsersBySession(Long sessionId, String searchString) { + return mcUserDAO.getCountPagedUsersBySession(sessionId, searchString); + } + + @Override + public String getLocalizedMessage(String key) { + return messageService.getMessage(key); + } + + @Override + public void saveUserAttempt(McQueUsr user, List answerDtos) { + + Date attemptTime = new Date(System.currentTimeMillis()); + + for (AnswerDTO answerDto : answerDtos) { + + Long questionUid = answerDto.getQuestionUid(); + McQueContent question = this.getQuestionByUid(questionUid); + if (question == null) { + throw new McApplicationException( + "Can't find question with specified question uid: " + answerDto.getQuestionUid()); + } + + McOptsContent answerOption = answerDto.getAnswerOption(); + if (answerOption != null) { + + Integer mark = answerDto.getMark(); + boolean passed = user.isMarkPassed(mark); + boolean isAttemptCorrect = answerDto.isAttemptCorrect(); + + McUsrAttempt userAttempt = this.getUserAttemptByQuestion(user.getUid(), questionUid); + if (userAttempt != null) { + + McOptsContent previosAnswer = userAttempt.getMcOptionsContent(); + // check if answer hasn't been changed since the last time + if (previosAnswer.getUid().equals(answerOption.getUid())) { + // don't save anything + continue; + + } else { + // in case answer has been changed update userttempt + userAttempt.setAttemptTime(attemptTime); + userAttempt.setMcOptionsContent(answerOption); + userAttempt.setMark(mark); + userAttempt.setPassed(passed); + userAttempt.setAttemptCorrect(isAttemptCorrect); + } + + } else { + // create new userAttempt + userAttempt = new McUsrAttempt(attemptTime, question, user, answerOption, mark, passed, + isAttemptCorrect); + } + + mcUsrAttemptDAO.saveMcUsrAttempt(userAttempt); + + } + } + } + + @Override + public void updateMcUsrAttempt(McUsrAttempt mcUsrAttempt) throws McApplicationException { + try { + mcUsrAttemptDAO.updateMcUsrAttempt(mcUsrAttempt); + } catch (DataAccessException e) { + throw new McApplicationException("Exception occured when lams is updating mc UsrAttempt: " + e.getMessage(), + e); + } + } + + @Override + public List getAnswersFromDatabase(McContent mcContent, McQueUsr user) { + List answerDtos = new LinkedList(); + List questions = this.getQuestionsByContentUid(mcContent.getUid()); + + for (McQueContent question : questions) { + AnswerDTO answerDto = new AnswerDTO(); + Set optionSet = question.getMcOptionsContents(); + List optionList = new LinkedList(optionSet); + + boolean randomize = mcContent.isRandomize(); + if (randomize) { + ArrayList shuffledList = new ArrayList(optionList); + Collections.shuffle(shuffledList); + optionList = new LinkedList(shuffledList); + } + + answerDto.setQuestion(question.getQuestion()); + answerDto.setDisplayOrder(question.getDisplayOrder().toString()); + answerDto.setQuestionUid(question.getUid()); + + answerDto.setMark(question.getMark()); + answerDto.setOptions(optionList); + + answerDtos.add(answerDto); + } + + // populate answers + if (user != null) { + + for (AnswerDTO answerDto : answerDtos) { + Long questionUid = answerDto.getQuestionUid(); + + McUsrAttempt dbAttempt = this.getUserAttemptByQuestion(user.getUid(), questionUid); + if (dbAttempt != null) { + Long selectedOptionUid = dbAttempt.getMcOptionsContent().getUid(); + + // mark selected option as selected + for (McOptsContent option : answerDto.getOptions()) { + if (selectedOptionUid.equals(option.getUid())) { + option.setSelected(true); + } + } + } + } + } + + return answerDtos; + } + + @Override + public List buildGroupsMarkData(McContent mcContent, boolean isFullAttemptDetailsRequired) { + List listMonitoredMarksContainerDTO = new LinkedList(); + Set sessions = new TreeSet(new McSessionComparator()); + sessions.addAll(mcContent.getMcSessions()); + int numQuestions = mcContent.getMcQueContents().size(); + + for (McSession session : sessions) { + + McSessionMarkDTO mcSessionMarkDTO = new McSessionMarkDTO(); + mcSessionMarkDTO.setSessionId(session.getMcSessionId().toString()); + mcSessionMarkDTO.setSessionName(session.getSession_name().toString()); + + Set sessionUsers = session.getMcQueUsers(); + Iterator usersIterator = sessionUsers.iterator(); + + Map mapSessionUsersData = new TreeMap( + new McStringComparator()); + Long mapIndex = new Long(1); + + while (usersIterator.hasNext()) { + McQueUsr user = usersIterator.next(); + + McUserMarkDTO mcUserMarkDTO = new McUserMarkDTO(); + mcUserMarkDTO.setSessionId(session.getMcSessionId().toString()); + mcUserMarkDTO.setSessionName(session.getSession_name().toString()); + mcUserMarkDTO.setFullName(user.getFullname()); + mcUserMarkDTO.setUserGroupLeader(session.isUserGroupLeader(user)); + mcUserMarkDTO.setUserName(user.getUsername()); + mcUserMarkDTO.setQueUsrId(user.getUid().toString()); + + if (isFullAttemptDetailsRequired) { + + // The marks for the user must be listed in the display order of the question. + // Other parts of the code assume that the questions will be in consecutive display + // order starting 1 (e.g. 1, 2, 3, not 1, 3, 4) so we set up an array and use + // the ( display order - 1) as the index (arrays start at 0, rather than 1 hence -1) + // The user must answer all questions, so we can assume that they will have marks + // for all questions or no questions. + // At present there can only be one answer for each question but there may be more + // than one in the future and if so, we don't want to count the mark twice hence + // we need to check if we've already processed this question in the total. + Integer[] userMarks = new Integer[numQuestions]; + String[] answeredOptions = new String[numQuestions]; + Date attemptTime = null; + List finalizedUserAttempts = this.getFinalizedUserAttempts(user); + long totalMark = 0; + for (McUsrAttempt attempt : finalizedUserAttempts) { + Integer displayOrder = attempt.getMcQueContent().getDisplayOrder(); + int arrayIndex = (displayOrder != null) && (displayOrder.intValue() > 0) + ? displayOrder.intValue() - 1 + : 1; + if (userMarks[arrayIndex] == null) { + + // We get the mark for the attempt if the answer is correct and we don't allow + // retries, or if the answer is correct and the learner has met the passmark if + // we do allow retries. + boolean isRetries = session.getMcContent().isRetries(); + Integer mark = attempt.getMarkForShow(isRetries); + userMarks[arrayIndex] = mark; + totalMark += mark.intValue(); + + // find out the answered option's sequential letter - A,B,C... + String answeredOptionLetter = ""; + int optionCount = 1; + for (McOptsContent option : (Set) attempt.getMcQueContent() + .getMcOptionsContents()) { + if (attempt.getMcOptionsContent().getUid().equals(option.getUid())) { + answeredOptionLetter = String.valueOf((char) ((optionCount + 'A') - 1)); + break; + } + optionCount++; + } + answeredOptions[arrayIndex] = answeredOptionLetter; + } + // get the attempt time, (NB all questions will have the same attempt time) + // Not efficient, since we assign this value for each attempt + attemptTime = attempt.getAttemptTime(); + } + + mcUserMarkDTO.setMarks(userMarks); + mcUserMarkDTO.setAnsweredOptions(answeredOptions); + mcUserMarkDTO.setAttemptTime(attemptTime); + mcUserMarkDTO.setTotalMark(new Long(totalMark)); + + } else { + int totalMark = mcUsrAttemptDAO.getUserTotalMark(user.getUid()); + mcUserMarkDTO.setTotalMark(new Long(totalMark)); + } + + mapSessionUsersData.put(mapIndex.toString(), mcUserMarkDTO); + mapIndex = new Long(mapIndex.longValue() + 1); + } + + mcSessionMarkDTO.setUserMarks(mapSessionUsersData); + listMonitoredMarksContainerDTO.add(mcSessionMarkDTO); + } + + return listMonitoredMarksContainerDTO; + } + + @Override + public List getFinalizedUserAttempts(final McQueUsr user) throws McApplicationException { + try { + return mcUsrAttemptDAO.getFinalizedUserAttempts(user.getUid()); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is getting the learner's attempts by user id and que content id and attempt order: " + + e.getMessage(), + e); + } + } + + @Override + public McUsrAttempt getUserAttemptByQuestion(Long queUsrUid, Long mcQueContentId) throws McApplicationException { + try { + return mcUsrAttemptDAO.getUserAttemptByQuestion(queUsrUid, mcQueContentId); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is getting the learner's attempts by user id and que content id and attempt order: " + + e.getMessage(), + e); + } + } + + @Override + public List getLearnerMarksByContentId(Long toolContentId) { + return mcUsrAttemptDAO.getLearnerMarksByContentId(toolContentId); + } + + @Override + public List getQuestionsByContentUid(final Long contentUid) throws McApplicationException { + try { + return mcQueContentDAO.getQuestionsByContentUid(contentUid.longValue()); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is getting by uid mc question content: " + e.getMessage(), e); + } + } + + @Override + public List refreshQuestionContent(final Long mcContentId) throws McApplicationException { + try { + return mcQueContentDAO.refreshQuestionContent(mcContentId); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is refreshing mc question content: " + e.getMessage(), e); + } + + } + + @Override + public void removeMcQueContent(McQueContent mcQueContent) throws McApplicationException { + try { + mcQueContentDAO.removeMcQueContent(mcQueContent); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is removing mc question content: " + e.getMessage(), e); + } + } + + @Override + public List getOptionDtos(Long mcQueContentId) throws McApplicationException { + try { + return mcOptionsContentDAO.getOptionDtos(mcQueContentId); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is populating candidate answers dto" + e.getMessage(), e); + } + } + + @Override + public McSession getMcSessionById(Long mcSessionId) throws McApplicationException { + try { + return mcSessionDAO.getMcSessionById(mcSessionId); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is retrieving by id mc session : " + e.getMessage(), e); + } + } + + @Override + public void updateMc(McContent mc) throws McApplicationException { + try { + mcContentDAO.updateMcContent(mc); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is updating" + " the mc content: " + e.getMessage(), e); + } + } + + @Override + public Object[] getMarkStatistics(McSession mcSession) { + return mcUserDAO.getStatsMarksBySession(mcSession.getMcSessionId()); + } + + @Override + public List findOptionsByQuestionUid(Long mcQueContentId) throws McApplicationException { + try { + return mcOptionsContentDAO.findMcOptionsContentByQueId(mcQueContentId); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is finding by que id" + " the mc options: " + e.getMessage(), e); + } + } + + @Override + public McQueContent getQuestionByUid(Long uid) { + if (uid == null) { + return null; + } + + return mcQueContentDAO.findMcQuestionContentByUid(uid); + } + + @Override + public void updateMcOptionsContent(McOptsContent mcOptsContent) throws McApplicationException { + try { + mcOptionsContentDAO.updateMcOptionsContent(mcOptsContent); + } catch (DataAccessException e) { + throw new McApplicationException( + "Exception occured when lams is updating" + " the mc options content: " + e.getMessage(), e); + } + } + + @Override + public void changeUserAttemptMark(Long userAttemptUid, Integer newMark) { + if (newMark == null) { + return; + } + + McUsrAttempt userAttempt = mcUsrAttemptDAO.getUserAttemptByUid(userAttemptUid); + Integer userId = userAttempt.getMcQueUsr().getQueUsrId().intValue(); + Long userUid = userAttempt.getMcQueUsr().getUid(); + Long toolSessionId = userAttempt.getMcQueUsr().getMcSession().getMcSessionId(); + Integer oldMark = userAttempt.getMark(); + int oldTotalMark = mcUsrAttemptDAO.getUserTotalMark(userUid); + + int totalMark = (oldMark == null) ? oldTotalMark + newMark : (oldTotalMark - oldMark) + newMark; + + //update mark for one particular question + userAttempt.setMark(newMark); + mcUsrAttemptDAO.saveMcUsrAttempt(userAttempt); + + //update user's total mark + McQueUsr user = userAttempt.getMcQueUsr(); + user.setLastAttemptTotalMark(totalMark); + updateMcQueUsr(user); + + // propagade changes to Gradebook + gradebookService.updateActivityMark(new Double(totalMark), null, userId, toolSessionId, false); + + // record mark change with audit service + auditService.logMarkChange(McAppConstants.TOOL_SIGNATURE, userAttempt.getMcQueUsr().getQueUsrId(), + userAttempt.getMcQueUsr().getUsername(), "" + oldMark, "" + totalMark); + + } + + @Override + public void recalculateUserAnswers(McContent content, Set oldQuestions, + List questionDTOs, List deletedQuestions) { + + // create list of modified questions + List modifiedQuestions = new ArrayList(); + // create list of modified question marks + List modifiedQuestionsMarksOnly = new ArrayList(); + for (McQueContent oldQuestion : oldQuestions) { + for (McQuestionDTO questionDTO : questionDTOs) { + if (oldQuestion.getUid().equals(questionDTO.getUid())) { + + boolean isQuestionModified = false; + boolean isQuestionMarkModified = false; + + // question is different + if (!oldQuestion.getQuestion().equals(questionDTO.getQuestion())) { + isQuestionModified = true; + } + + // mark is different + if (oldQuestion.getMark().intValue() != (new Integer(questionDTO.getMark())).intValue()) { + isQuestionMarkModified = true; + } + + // options are different + Set oldOptions = oldQuestion.getMcOptionsContents(); + List optionDTOs = questionDTO.getOptionDtos(); + for (McOptsContent oldOption : oldOptions) { + for (McOptionDTO optionDTO : optionDTOs) { + if (oldOption.getUid().equals(optionDTO.getUid())) { + + if (!StringUtils.equals(oldOption.getMcQueOptionText(), optionDTO.getCandidateAnswer()) + || (oldOption.isCorrectOption() != "Correct".equals(optionDTO.getCorrect()))) { + isQuestionModified = true; + } + } + } + } + + if (isQuestionModified) { + modifiedQuestions.add(questionDTO); + + } else if (isQuestionMarkModified) { + modifiedQuestionsMarksOnly.add(questionDTO); + } + } + } + } + + Set sessionList = content.getMcSessions(); + for (McSession session : sessionList) { + Long toolSessionId = session.getMcSessionId(); + Set sessionUsers = session.getMcQueUsers(); + + for (McQueUsr user : sessionUsers) { + + final int oldTotalMark = mcUsrAttemptDAO.getUserTotalMark(user.getUid()); + int newTotalMark = oldTotalMark; + + // get all finished user results + List userAttempts = getFinalizedUserAttempts(user); + Iterator iter = userAttempts.iterator(); + while (iter.hasNext()) { + McUsrAttempt userAttempt = iter.next(); + + McQueContent question = userAttempt.getMcQueContent(); + + boolean isRemoveQuestionResult = false; + + // [+] if the question mark is modified + for (McQuestionDTO modifiedQuestion : modifiedQuestionsMarksOnly) { + if (question.getUid().equals(modifiedQuestion.getUid())) { + Integer newQuestionMark = new Integer(modifiedQuestion.getMark()); + Integer oldQuestionMark = question.getMark(); + Integer newActualMark = (userAttempt.getMark() * newQuestionMark) / oldQuestionMark; + + newTotalMark += newActualMark - userAttempt.getMark(); + + // update question answer's mark + userAttempt.setMark(newActualMark); + mcUsrAttemptDAO.saveMcUsrAttempt(userAttempt); + + break; + } + + } + + // [+] if the question is modified + for (McQuestionDTO modifiedQuestion : modifiedQuestions) { + if (question.getUid().equals(modifiedQuestion.getUid())) { + isRemoveQuestionResult = true; + break; + } + } + + // [+] if the question was removed + for (McQuestionDTO deletedQuestion : deletedQuestions) { + if (question.getUid().equals(deletedQuestion.getUid())) { + isRemoveQuestionResult = true; + break; + } + } + + if (isRemoveQuestionResult) { + + Integer oldMark = userAttempt.getMark(); + if (oldMark != null) { + newTotalMark -= oldMark; + } + + iter.remove(); + mcUsrAttemptDAO.removeAttempt(userAttempt); + } + + // [+] doing nothing if the new question was added + + } + + // propagade new total mark to Gradebook if it was changed + if (newTotalMark != oldTotalMark) { + gradebookService.updateActivityMark(new Double(newTotalMark), null, user.getQueUsrId().intValue(), + toolSessionId, false); + } + + } + } + + } + + @Override + public byte[] prepareSessionDataSpreadsheet(McContent mcContent) throws IOException { + + Set questions = mcContent.getMcQueContents(); + int maxOptionsInQuestion = 0; + for (McQueContent question : questions) { + if (question.getMcOptionsContents().size() > maxOptionsInQuestion) { + maxOptionsInQuestion = question.getMcOptionsContents().size(); + } + } + + int totalNumberOfUsers = 0; + for (McSession session : (Set) mcContent.getMcSessions()) { + totalNumberOfUsers += session.getMcQueUsers().size(); + } + + List sessionMarkDTOs = this.buildGroupsMarkData(mcContent, true); + + // create an empty excel file + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFCellStyle greenColor = wb.createCellStyle(); + greenColor.setFillForegroundColor(IndexedColors.LIME.getIndex()); + greenColor.setFillPattern(CellStyle.SOLID_FOREGROUND); + Font whiteFont = wb.createFont(); + whiteFont.setColor(IndexedColors.WHITE.getIndex()); + whiteFont.setFontName(ExcelUtil.DEFAULT_FONT_NAME); + greenColor.setFont(whiteFont); + + // ======================================================= Report by question IRA page + // ======================================= + + HSSFSheet sheet = wb.createSheet(messageService.getMessage("label.report.by.question")); + + HSSFRow row; + HSSFCell cell; + int rowCount = 0; + + row = sheet.createRow(rowCount++); + int count = 0; + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.question")); + for (int optionCount = 0; optionCount < maxOptionsInQuestion; optionCount++) { + cell = row.createCell(count++); + cell.setCellValue(String.valueOf((char) (optionCount + 'A'))); + } + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.not.available")); + + for (McQueContent question : questions) { + + row = sheet.createRow(rowCount); + count = 0; + + cell = row.createCell(count++); + cell.setCellValue(rowCount); + rowCount++; + + int totalPercentage = 0; + for (McOptsContent option : (Set) question.getMcOptionsContents()) { + int optionAttemptCount = mcUsrAttemptDAO.getAttemptsCountPerOption(option.getUid()); + cell = row.createCell(count++); + int percentage = (optionAttemptCount * 100) / totalNumberOfUsers; + cell.setCellValue(percentage + "%"); + totalPercentage += percentage; + if (option.isCorrectOption()) { + cell.setCellStyle(greenColor); + } + } + cell = row.createCell(maxOptionsInQuestion + 1); + cell.setCellValue((100 - totalPercentage) + "%"); + } + + rowCount++; + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.legend")); + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.denotes.correct.answer")); + cell.setCellStyle(greenColor); + cell = row.createCell(1); + cell.setCellStyle(greenColor); + cell = row.createCell(2); + cell.setCellStyle(greenColor); + + // ======================================================= Report by student IRA page + // ======================================= + + sheet = wb.createSheet(messageService.getMessage("label.report.by.student")); + rowCount = 0; + + row = sheet.createRow(rowCount++); + count = 2; + for (int questionCount = 1; questionCount <= questions.size(); questionCount++) { + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.question") + questionCount); + } + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.total")); + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.total") + " %"); + + row = sheet.createRow(rowCount++); + count = 1; + ArrayList correctAnswers = new ArrayList(); + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.correct.answer")); + for (McQueContent question : questions) { + + // find out the correct answer's sequential letter - A,B,C... + String correctAnswerLetter = ""; + int answerCount = 1; + for (McOptsContent option : (Set) question.getMcOptionsContents()) { + if (option.isCorrectOption()) { + correctAnswerLetter = String.valueOf((char) ((answerCount + 'A') - 1)); + break; + } + answerCount++; + } + cell = row.createCell(count++); + cell.setCellValue(correctAnswerLetter); + correctAnswers.add(correctAnswerLetter); + } + + row = sheet.createRow(rowCount++); + count = 0; + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("group.label")); + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.learner")); + + ArrayList totalPercentList = new ArrayList(); + int[] numberOfCorrectAnswersPerQuestion = new int[questions.size()]; + for (McSessionMarkDTO sessionMarkDTO : sessionMarkDTOs) { + Map usersMarksMap = sessionMarkDTO.getUserMarks(); + + for (McUserMarkDTO userMark : usersMarksMap.values()) { + row = sheet.createRow(rowCount++); + count = 0; + cell = row.createCell(count++); + cell.setCellValue(sessionMarkDTO.getSessionName()); + + cell = row.createCell(count++); + cell.setCellValue(userMark.getFullName()); + + String[] answeredOptions = userMark.getAnsweredOptions(); + int numberOfCorrectlyAnsweredByUser = 0; + for (int i = 0; i < answeredOptions.length; i++) { + String answeredOption = answeredOptions[i]; + cell = row.createCell(count++); + cell.setCellValue(answeredOption); + if (StringUtils.equals(answeredOption, correctAnswers.get(i))) { + cell.setCellStyle(greenColor); + numberOfCorrectlyAnsweredByUser++; + numberOfCorrectAnswersPerQuestion[count - 3]++; + } + } + + cell = row.createCell(count++); + cell.setCellValue(new Long(userMark.getTotalMark())); + + int totalPercents = (numberOfCorrectlyAnsweredByUser * 100) / questions.size(); + totalPercentList.add(totalPercents); + cell = row.createCell(count++); + cell.setCellValue(totalPercents + "%"); + } + + rowCount++; + } + + // ave + row = sheet.createRow(rowCount++); + count = 1; + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.ave")); + for (int numberOfCorrectAnswers : numberOfCorrectAnswersPerQuestion) { + cell = row.createCell(count++); + cell.setCellValue(((numberOfCorrectAnswers * 100) / totalPercentList.size()) + "%"); + } + + // class mean + Integer[] totalPercents = totalPercentList.toArray(new Integer[0]); + Arrays.sort(totalPercents); + int sum = 0; + for (int i = 0; i < totalPercents.length; i++) { + sum += totalPercents[i]; + } + row = sheet.createRow(rowCount++); + cell = row.createCell(1); + cell.setCellValue(messageService.getMessage("label.class.mean")); + if (totalPercents.length != 0) { + int classMean = sum / totalPercents.length; + cell = row.createCell(questions.size() + 3); + cell.setCellValue(classMean + "%"); + } + + // median + row = sheet.createRow(rowCount++); + cell = row.createCell(1); + cell.setCellValue(messageService.getMessage("label.median")); + if (totalPercents.length != 0) { + int median; + int middle = totalPercents.length / 2; + if ((totalPercents.length % 2) == 1) { + median = totalPercents[middle]; + } else { + median = (int) ((totalPercents[middle - 1] + totalPercents[middle]) / 2.0); + } + cell = row.createCell(questions.size() + 3); + cell.setCellValue(median + "%"); + } + + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.legend")); + + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.denotes.correct.answer")); + cell.setCellStyle(greenColor); + cell = row.createCell(1); + cell.setCellStyle(greenColor); + cell = row.createCell(2); + cell.setCellStyle(greenColor); + + // ======================================================= Marks page + // ======================================= + + sheet = wb.createSheet("Marks"); + + rowCount = 0; + count = 0; + + row = sheet.createRow(rowCount++); + for (McQueContent question : questions) { + cell = row.createCell(2 + count++); + cell.setCellValue(messageService.getMessage("label.monitoring.downloadMarks.question.mark", + new Object[] { count, question.getMark() })); + } + + for (McSessionMarkDTO sessionMarkDTO : sessionMarkDTOs) { + Map usersMarksMap = sessionMarkDTO.getUserMarks(); + + String currentSessionName = sessionMarkDTO.getSessionName(); + + row = sheet.createRow(rowCount++); + + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("group.label")); + + cell = row.createCell(1); + cell.setCellValue(currentSessionName); + cell.setCellStyle(greenColor); + + rowCount++; + count = 0; + + row = sheet.createRow(rowCount++); + + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.learner")); + + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.downloadMarks.username")); + + cell = row.createCell(questions.size() + 2); + cell.setCellValue(messageService.getMessage("label.total")); + + for (McUserMarkDTO userMark : usersMarksMap.values()) { + row = sheet.createRow(rowCount++); + count = 0; + + cell = row.createCell(count++); + cell.setCellValue(userMark.getFullName()); + + cell = row.createCell(count++); + cell.setCellValue(userMark.getUserName()); + + Integer[] marks = userMark.getMarks(); + for (int i = 0; i < marks.length; i++) { + cell = row.createCell(count++); + Integer mark = (marks[i] == null) ? 0 : marks[i]; + cell.setCellValue(mark); + } + + cell = row.createCell(count++); + cell.setCellValue(userMark.getTotalMark()); + } + + rowCount++; + + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + wb.write(bos); + + byte[] data = bos.toByteArray(); + + return data; + } + + @Override + public void copyToolContent(Long fromContentId, Long toContentId) { + + if (fromContentId == null) { + logger.warn("fromContentId is null."); + long defaultContentId = getToolDefaultContentIdBySignature(McAppConstants.TOOL_SIGNATURE); + fromContentId = new Long(defaultContentId); + } + + if (toContentId == null) { + logger.error("throwing ToolException: toContentId is null"); + throw new ToolException("toContentId is missing"); + } + + McContent fromContent = mcContentDAO.findMcContentById(fromContentId); + + if (fromContent == null) { + logger.warn("fromContent is null."); + long defaultContentId = getToolDefaultContentIdBySignature(McAppConstants.TOOL_SIGNATURE); + fromContent = mcContentDAO.findMcContentById(defaultContentId); + } + + McContent toContent = McContent.newInstance(fromContent, toContentId); + if (toContent == null) { + logger.error("throwing ToolException: WARNING!, retrieved toContent is null."); + throw new ToolException("WARNING! Fail to create toContent. Can't continue!"); + } else { + mcContentDAO.saveMcContent(toContent); + } + } + + @SuppressWarnings("unchecked") + @Override + public void removeToolContent(Long toolContentId) throws ToolException { + McContent mcContent = mcContentDAO.findMcContentById(toolContentId); + if (mcContent == null) { + logger.warn("Can not remove the tool content as it does not exist, ID: " + toolContentId); + return; + } + + for (McSession session : (Set) mcContent.getMcSessions()) { + List entries = coreNotebookService.getEntry(session.getMcSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, McAppConstants.TOOL_SIGNATURE); + for (NotebookEntry entry : entries) { + coreNotebookService.deleteEntry(entry); + } + } + + mcContentDAO.delete(mcContent); + } + + @Override + public void resetDefineLater(Long toolContentId) throws DataMissingException, ToolException { + McContent mcContent = getMcContent(toolContentId); + if (mcContent == null) { + throw new DataMissingException("mcContent is missing"); + } + mcContent.setDefineLater(false); + mcContentDAO.saveMcContent(mcContent); + } + + @Override + @SuppressWarnings("unchecked") + public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException { + if (logger.isDebugEnabled()) { + logger.debug( + "Removing Multiple Choice attempts for user ID " + userId + " and toolContentId " + toolContentId); + } + + McContent content = mcContentDAO.findMcContentById(toolContentId); + if (content != null) { + for (McSession session : (Set) content.getMcSessions()) { + McQueUsr user = mcUserDAO.getMcUserBySession(userId.longValue(), session.getUid()); + if (user != null) { + mcUsrAttemptDAO.removeAllUserAttempts(user.getUid()); + + NotebookEntry entry = getEntry(session.getMcSessionId(), CoreNotebookConstants.NOTEBOOK_TOOL, + McAppConstants.TOOL_SIGNATURE, userId); + if (entry != null) { + mcContentDAO.delete(entry); + } + + if ((session.getGroupLeader() != null) && session.getGroupLeader().getUid().equals(user.getUid())) { + session.setGroupLeader(null); + } + + mcUserDAO.removeMcUser(user); + + gradebookService.updateActivityMark(null, null, userId, session.getMcSessionId(), false); + } + } + } + } + + @Override + public void exportToolContent(Long toolContentId, String rootPath) throws DataMissingException, ToolException { + McContent toolContentObj = mcContentDAO.findMcContentById(toolContentId); + if (toolContentObj == null) { + long defaultContentId = getToolDefaultContentIdBySignature(McAppConstants.TOOL_SIGNATURE); + toolContentObj = mcContentDAO.findMcContentById(defaultContentId); + } + if (toolContentObj == null) { + throw new DataMissingException("Unable to find default content for the multiple choice tool"); + } + + try { + // set ToolContentHandler as null to avoid copy file node in repository again. + toolContentObj = McContent.newInstance(toolContentObj, toolContentId); + toolContentObj.setMcSessions(null); + exportContentService.exportToolContent(toolContentId, toolContentObj, mcToolContentHandler, rootPath); + } catch (ExportToolContentException e) { + throw new ToolException(e); + } + } + + @Override + public void importToolContent(Long toolContentId, Integer newUserUid, String toolContentPath, String fromVersion, + String toVersion) throws ToolException { + try { + // register version filter class + exportContentService.registerImportVersionFilterClass(McImportContentVersionFilter.class); + + Object toolPOJO = exportContentService.importToolContent(toolContentPath, mcToolContentHandler, fromVersion, + toVersion); + if (!(toolPOJO instanceof McContent)) { + throw new ImportToolContentException( + "Import MC tool content failed. Deserialized object is " + toolPOJO); + } + McContent toolContentObj = (McContent) toolPOJO; + + // reset it to new toolContentId + toolContentObj.setMcContentId(toolContentId); + toolContentObj.setCreatedBy(newUserUid); + mcContentDAO.saveMcContent(toolContentObj); + } catch (ImportToolContentException e) { + throw new ToolException(e); + } + } + + @Override + public SortedMap getToolOutputDefinitions(Long toolContentId, int definitionType) + throws ToolException { + McContent content = getMcContent(toolContentId); + if (content == null) { + long defaultToolContentId = getToolDefaultContentIdBySignature(McAppConstants.TOOL_SIGNATURE); + content = getMcContent(defaultToolContentId); + } + return mcOutputFactory.getToolOutputDefinitions(content, definitionType); + } + + @Override + public String getToolContentTitle(Long toolContentId) { + return mcContentDAO.findMcContentById(toolContentId).getTitle(); + } + + @Override + public boolean isContentEdited(Long toolContentId) { + return mcContentDAO.findMcContentById(toolContentId).isDefineLater(); + } + + @Override + public boolean isReadOnly(Long toolContentId) { + McContent content = mcContentDAO.findMcContentById(toolContentId); + for (McSession session : (Set) content.getMcSessions()) { + if (!session.getMcQueUsers().isEmpty()) { + return true; + } + } + + return false; + } + + /** + * it is possible that the tool session id already exists in the tool sessions table as the users from the same + * session are involved. existsSession(long toolSessionId) + * + * @param toolSessionId + * @return boolean + */ + @Override + public boolean existsSession(Long toolSessionId) { + McSession mcSession = getMcSessionById(toolSessionId); + return mcSession != null; + } + + @Override + public void createToolSession(Long toolSessionId, String toolSessionName, Long toolContentId) throws ToolException { + + if (toolSessionId == null) { + logger.error("toolSessionId is null"); + throw new ToolException("toolSessionId is missing"); + } + + McContent mcContent = mcContentDAO.findMcContentById(toolContentId); + + // create a new a new tool session if it does not already exist in the tool session table + if (!existsSession(toolSessionId)) { + try { + McSession mcSession = new McSession(toolSessionId, new Date(System.currentTimeMillis()), + McSession.INCOMPLETE, toolSessionName, mcContent, new TreeSet()); + + mcSessionDAO.saveMcSession(mcSession); + + } catch (Exception e) { + logger.error("Error creating new toolsession in the db"); + throw new ToolException("Error creating new toolsession in the db: " + e); + } + } + } + + @Override + public void removeToolSession(Long toolSessionId) throws DataMissingException, ToolException { + if (toolSessionId == null) { + logger.error("toolSessionId is null"); + throw new DataMissingException("toolSessionId is missing"); + } + + McSession mcSession = null; + try { + mcSession = getMcSessionById(toolSessionId); + } catch (McApplicationException e) { + throw new DataMissingException("error retrieving mcSession: " + e); + } catch (Exception e) { + throw new ToolException("error retrieving mcSession: " + e); + } + + if (mcSession == null) { + logger.error("mcSession is null"); + throw new DataMissingException("mcSession is missing"); + } + + try { + mcSessionDAO.removeMcSession(mcSession); + logger.debug("mcSession " + mcSession + " has been deleted successfully."); + } catch (McApplicationException e) { + throw new ToolException("error deleting mcSession:" + e); + } + } + + @Override + public String leaveToolSession(Long toolSessionId, Long learnerId) throws DataMissingException, ToolException { + + if (learnerService == null) { + return "dummyNextUrl"; + } + + if (learnerId == null) { + logger.error("learnerId is null"); + throw new DataMissingException("learnerId is missing"); + } + + if (toolSessionId == null) { + logger.error("toolSessionId is null"); + throw new DataMissingException("toolSessionId is missing"); + } + + McSession mcSession = null; + try { + mcSession = getMcSessionById(toolSessionId); + } catch (McApplicationException e) { + throw new DataMissingException("error retrieving mcSession: " + e); + } catch (Exception e) { + throw new ToolException("error retrieving mcSession: " + e); + } + mcSession.setSessionStatus(McAppConstants.COMPLETED); + mcSessionDAO.updateMcSession(mcSession); + + String nextUrl = learnerService.completeToolSession(toolSessionId, learnerId); + if (nextUrl == null) { + logger.error("nextUrl is null"); + throw new ToolException("nextUrl is null"); + } + return nextUrl; + } + + @Override + public ToolSessionExportOutputData exportToolSession(Long toolSessionId) + throws DataMissingException, ToolException { + throw new ToolException("not yet implemented"); + } + + @Override + public ToolSessionExportOutputData exportToolSession(List toolSessionIds) + throws DataMissingException, ToolException { + throw new ToolException("not yet implemented"); + + } + + @Override + public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { + return mcOutputFactory.getToolOutput(names, this, toolSessionId, learnerId); + } + + @Override + public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { + return mcOutputFactory.getToolOutput(name, this, toolSessionId, learnerId); + } + + @Override + public List getToolOutputs(String name, Long toolContentId) { + return mcOutputFactory.getToolOutputs(name, this, toolContentId); + } + + @Override + public void forceCompleteUser(Long toolSessionId, User user) { + Long userId = user.getUserId().longValue(); + + McSession session = getMcSessionById(toolSessionId); + if ((session == null) || (session.getMcContent() == null)) { + return; + } + McContent content = session.getMcContent(); + + // copy answers only in case leader aware feature is ON + if (content.isUseSelectLeaderToolOuput()) { + + McQueUsr mcUser = getMcUserBySession(userId, session.getUid()); + // create user if he hasn't accessed this activity yet + if (mcUser == null) { + + String userName = user.getLogin(); + String fullName = user.getFirstName() + " " + user.getLastName(); + mcUser = new McQueUsr(userId, userName, fullName, session, new TreeSet()); + mcUserDAO.saveMcUser(mcUser); + } + + McQueUsr groupLeader = session.getGroupLeader(); + + // check if leader has submitted answers + if ((groupLeader != null) && groupLeader.isResponseFinalised()) { + + // we need to make sure specified user has the same scratches as a leader + copyAnswersFromLeader(mcUser, groupLeader); + } + + } + + } + + @Override + public IToolVO getToolBySignature(String toolSignature) throws McApplicationException { + IToolVO tool = toolService.getToolBySignature(toolSignature); + return tool; + } + + @Override + public long getToolDefaultContentIdBySignature(String toolSignature) { + long contentId = 0; + contentId = toolService.getToolDefaultContentIdBySignature(toolSignature); + return contentId; + } + + @Override + public boolean isGroupedActivity(long toolContentID) { + return toolService.isGroupedActivity(toolContentID); + } + + @Override + public void auditLogStartEditingActivityInMonitor(long toolContentID) { + toolService.auditLogStartEditingActivityInMonitor(toolContentID); + } + + @Override + public String getActivityEvaluation(Long toolContentId) { + return toolService.getActivityEvaluation(toolContentId); + } + + @Override + public void setActivityEvaluation(Long toolContentId, String toolOutputDefinition) { + toolService.setActivityEvaluation(toolContentId, toolOutputDefinition); + } + + /** + * @param mcContentDAO + * The mcContentDAO to set. + */ + public void setMcContentDAO(IMcContentDAO mcContentDAO) { + this.mcContentDAO = mcContentDAO; + } + + /** + * @param mcOptionsContentDAO + * The mcOptionsContentDAO to set. + */ + public void setMcOptionsContentDAO(IMcOptionsContentDAO mcOptionsContentDAO) { + this.mcOptionsContentDAO = mcOptionsContentDAO; + } + + /** + * @param mcQueContentDAO + * The mcQueContentDAO to set. + */ + public void setMcQueContentDAO(IMcQueContentDAO mcQueContentDAO) { + this.mcQueContentDAO = mcQueContentDAO; + } + + /** + * @param mcSessionDAO + * The mcSessionDAO to set. + */ + public void setMcSessionDAO(IMcSessionDAO mcSessionDAO) { + this.mcSessionDAO = mcSessionDAO; + } + + /** + * @param mcUserDAO + * The mcUserDAO to set. + */ + public void setMcUserDAO(IMcUserDAO mcUserDAO) { + this.mcUserDAO = mcUserDAO; + } + + /** + * @param mcUsrAttemptDAO + * The mcUsrAttemptDAO to set. + */ + public void setMcUsrAttemptDAO(IMcUsrAttemptDAO mcUsrAttemptDAO) { + this.mcUsrAttemptDAO = mcUsrAttemptDAO; + } + + public void setUserManagementService(IUserManagementService userManagementService) { + this.userManagementService = userManagementService; + } + + public void setToolService(ILamsToolService toolService) { + this.toolService = toolService; + } + + /** + * @param mcToolContentHandler + * The mcToolContentHandler to set. + */ + public void setMcToolContentHandler(IToolContentHandler mcToolContentHandler) { + this.mcToolContentHandler = mcToolContentHandler; + } + + /** + * @param learnerService + * The learnerService to set. + */ + public void setLearnerService(ILearnerService learnerService) { + this.learnerService = learnerService; + } + + public void setExportContentService(IExportToolContentService exportContentService) { + this.exportContentService = exportContentService; + } + + public void setGradebookService(IGradebookService gradebookService) { + this.gradebookService = gradebookService; + } + + public void setMcOutputFactory(MCOutputFactory mcOutputFactory) { + this.mcOutputFactory = mcOutputFactory; + } + + @Override + public List getReflectionList(McContent mcContent, Long userID) { + List reflectionsContainerDTO = new LinkedList(); + if (userID == null) { + // all users mode + for (McSession mcSession : (Set) mcContent.getMcSessions()) { + + for (McQueUsr user : (Set) mcSession.getMcQueUsers()) { + + NotebookEntry notebookEntry = this.getEntry(mcSession.getMcSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, McAppConstants.TOOL_SIGNATURE, + new Integer(user.getQueUsrId().toString())); + + if (notebookEntry != null) { + ReflectionDTO reflectionDTO = new ReflectionDTO(); + reflectionDTO.setUserId(user.getQueUsrId().toString()); + reflectionDTO.setSessionId(mcSession.getMcSessionId().toString()); + reflectionDTO.setUserName(user.getFullname()); + reflectionDTO.setReflectionUid(notebookEntry.getUid().toString()); + // String notebookEntryPresentable = McUtils.replaceNewLines(notebookEntry.getEntry()); + reflectionDTO.setEntry(notebookEntry.getEntry()); + reflectionsContainerDTO.add(reflectionDTO); + } + } + } + } else { + // single user mode + for (Iterator sessionIter = mcContent.getMcSessions().iterator(); sessionIter.hasNext();) { + McSession mcSession = (McSession) sessionIter.next(); + for (Iterator userIter = mcSession.getMcQueUsers().iterator(); userIter.hasNext();) { + McQueUsr user = (McQueUsr) userIter.next(); + if (user.getQueUsrId().equals(userID)) { + NotebookEntry notebookEntry = this.getEntry(mcSession.getMcSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, McAppConstants.TOOL_SIGNATURE, + new Integer(user.getQueUsrId().toString())); + + if (notebookEntry != null) { + ReflectionDTO reflectionDTO = new ReflectionDTO(); + reflectionDTO.setUserId(user.getQueUsrId().toString()); + reflectionDTO.setSessionId(mcSession.getMcSessionId().toString()); + reflectionDTO.setUserName(user.getFullname()); + reflectionDTO.setReflectionUid(notebookEntry.getUid().toString()); + // String notebookEntryPresentable = McUtils.replaceNewLines(notebookEntry.getEntry()); + reflectionDTO.setEntry(notebookEntry.getEntry()); + reflectionsContainerDTO.add(reflectionDTO); + } + } + } + } + } + + return reflectionsContainerDTO; + } + + @Override + public Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry) { + return coreNotebookService.createNotebookEntry(id, idType, signature, userID, "", entry); + } + + @Override + public NotebookEntry getEntry(Long id, Integer idType, String signature, Integer userID) { + + List list = coreNotebookService.getEntry(id, idType, signature, userID); + if ((list == null) || list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public void updateEntry(NotebookEntry notebookEntry) { + coreNotebookService.updateEntry(notebookEntry); + } + + /** + * @return Returns the coreNotebookService. + */ + public ICoreNotebookService getCoreNotebookService() { + return coreNotebookService; + } + + /** + * @param coreNotebookService + * The coreNotebookService to set. + */ + public void setCoreNotebookService(ICoreNotebookService coreNotebookService) { + this.coreNotebookService = coreNotebookService; + } + + /** + * @return Returns the auditService. + */ + public IAuditService getAuditService() { + return auditService; + } + + /** + * @param auditService + * The auditService to set. + */ + public void setAuditService(IAuditService auditService) { + this.auditService = auditService; + } + + /** + * @return Returns the MessageService. + */ + public MessageService getMessageService() { + return messageService; + } + + /** + * @param messageService + * The MessageService to set. + */ + public void setMessageService(MessageService messageService) { + this.messageService = messageService; + } + + @Override + public Class[] getSupportedToolOutputDefinitionClasses(int definitionType) { + return mcOutputFactory.getSupportedDefinitionClasses(definitionType); + } + + @Override + public ToolCompletionStatus getCompletionStatus(Long learnerId, Long toolSessionId) { + McSession session = getMcSessionById(toolSessionId); + McQueUsr learner = mcUserDAO.getMcUserBySession(learnerId, session.getUid()); + if (learner == null) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); + } + + Date startDate = null; + Date endDate = null; + List attempts = getFinalizedUserAttempts(learner); + for (McUsrAttempt item : attempts) { + Date newDate = item.getAttemptTime(); + if (newDate != null) { + if (startDate == null || newDate.before(startDate)) { + startDate = newDate; + } + if (endDate == null || newDate.after(endDate)) { + endDate = newDate; + } + } + } + + if (learner.isResponseFinalised()) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, startDate, endDate); + } else { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, startDate, null); + } + } + + @Override + public LeaderResultsDTO getLeaderResultsDTOForLeaders(Long contentId) { + LeaderResultsDTO newDto = new LeaderResultsDTO(contentId); + Object[] markStats = mcUserDAO.getStatsMarksForLeaders(contentId); + if (markStats != null) { + newDto.setMinMark( + markStats[0] != null ? NumberUtil.formatLocalisedNumber((Float) markStats[0], (Locale) null, 2) + : "0.00"); + newDto.setAvgMark( + markStats[1] != null ? NumberUtil.formatLocalisedNumber((Float) markStats[1], (Locale) null, 2) + : "0.00"); + newDto.setMaxMark( + markStats[2] != null ? NumberUtil.formatLocalisedNumber((Float) markStats[2], (Locale) null, 2) + : "0.00"); + newDto.setNumberGroupsLeaderFinished((Integer) markStats[3]); + } + return newDto; + } + + @SuppressWarnings("unchecked") + @Override + public List getSessionDtos(Long contentId, boolean includeStatistics) { + List sessionDtos = new ArrayList(); + + McContent mcContent = getMcContent(contentId); + if (mcContent != null) { + Set sessions = new TreeSet(new McSessionComparator()); + sessions.addAll(mcContent.getMcSessions()); + for (McSession session : sessions) { + SessionDTO sessionDto = new SessionDTO(); + sessionDto.setSessionId(session.getMcSessionId()); + sessionDto.setSessionName(session.getSession_name()); + //for statistics tab + if (includeStatistics) { + int countUsers = mcUserDAO.getCountPagedUsersBySession(session.getMcSessionId(), ""); + sessionDto.setNumberLearners(countUsers); + Object[] markStats = mcUserDAO.getStatsMarksBySession(session.getMcSessionId()); + if (markStats != null) { + sessionDto.setMinMark(markStats[0] != null + ? NumberUtil.formatLocalisedNumber((Float) markStats[0], (Locale) null, 2) + : "0.00"); + sessionDto.setAvgMark(markStats[1] != null + ? NumberUtil.formatLocalisedNumber((Float) markStats[1], (Locale) null, 2) + : "0.00"); + sessionDto.setMaxMark(markStats[2] != null + ? NumberUtil.formatLocalisedNumber((Float) markStats[2], (Locale) null, 2) + : "0.00"); + } + } + + sessionDtos.add(sessionDto); + } + } + return sessionDtos; + } + + @Override + public List getMarksArray(Long sessionId) { + return mcUserDAO.getRawUserMarksBySession(sessionId); + } + + @Override + public List getMarksArrayForLeaders(Long toolContentId) { + return mcUserDAO.getRawLeaderMarksByToolContentId(toolContentId); + } + + // ****************** REST methods ************************* + + /** + * Rest call to create a new Multiple Choice content. Required fields in toolContentJSON: "title", "instructions", + * "questions". The questions entry should be ArrayNode containing JSON objects, which in turn must contain + * "questionText", "displayOrder" (Integer) and a ArrayNode "answers". The answers entry should be ArrayNode + * containing JSON objects, which in turn must contain "answerText", "displayOrder" (Integer), "correct" (Boolean). + * + * Retries are controlled by lockWhenFinished, which defaults to true (no retries). + */ + @SuppressWarnings("unchecked") + @Override + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { + + McContent mcq = new McContent(); + Date updateDate = new Date(); + + mcq.setCreationDate(updateDate); + mcq.setUpdateDate(updateDate); + mcq.setCreatedBy(userID.longValue()); + mcq.setDefineLater(false); + + mcq.setMcContentId(toolContentID); + mcq.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + mcq.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); + + mcq.setRetries(JsonUtil.optBoolean(toolContentJSON, "allowRetries", Boolean.FALSE)); + mcq.setUseSelectLeaderToolOuput( + JsonUtil.optBoolean(toolContentJSON, RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, Boolean.FALSE)); + mcq.setReflect(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + mcq.setReflectionSubject(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, "")); + mcq.setQuestionsSequenced(JsonUtil.optBoolean(toolContentJSON, "questionsSequenced", Boolean.FALSE)); + mcq.setRandomize(JsonUtil.optBoolean(toolContentJSON, "randomize", Boolean.FALSE)); + mcq.setShowReport(JsonUtil.optBoolean(toolContentJSON, "showReport", Boolean.FALSE)); + mcq.setDisplayAnswers(JsonUtil.optBoolean(toolContentJSON, "displayAnswers", Boolean.FALSE)); + mcq.setShowMarks(JsonUtil.optBoolean(toolContentJSON, "showMarks", Boolean.FALSE)); + mcq.setPrefixAnswersWithLetters(JsonUtil.optBoolean(toolContentJSON, "prefixAnswersWithLetters", Boolean.TRUE)); + mcq.setPassMark(JsonUtil.optInt(toolContentJSON, "passMark", 0)); + // submissionDeadline is set in monitoring + + createMc(mcq); + + // Questions + ArrayNode questions = JsonUtil.optArray(toolContentJSON, RestTags.QUESTIONS); + for (JsonNode questionData : questions) { + McQueContent question = new McQueContent(JsonUtil.optString(questionData, RestTags.QUESTION_TEXT), + JsonUtil.optInt(questionData, RestTags.DISPLAY_ORDER), 1, "", mcq, null, + new HashSet()); + + ArrayNode optionsData = JsonUtil.optArray(questionData, RestTags.ANSWERS); + for (JsonNode optionData : optionsData) { + question.getMcOptionsContents() + .add(new McOptsContent(JsonUtil.optInt(optionData, RestTags.DISPLAY_ORDER), + JsonUtil.optBoolean(optionData, RestTags.CORRECT), + JsonUtil.optString(optionData, RestTags.ANSWER_TEXT), question)); + } + saveOrUpdateMcQueContent(question); + } + + // TODO + // mcq.setContent(content) - can't find in database + // mcq.setConditions(conditions); + + } +} Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McLearningAction.java =================================================================== diff -u --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McLearningAction.java (revision 0) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McLearningAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,767 @@ +/*************************************************************************** + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.mc.web.action; + +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +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.lamsfoundation.lams.learning.web.util.LearningWebUtil; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.mc.McAppConstants; +import org.lamsfoundation.lams.tool.mc.dto.AnswerDTO; +import org.lamsfoundation.lams.tool.mc.dto.McGeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.mc.pojos.McContent; +import org.lamsfoundation.lams.tool.mc.pojos.McOptsContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueUsr; +import org.lamsfoundation.lams.tool.mc.pojos.McSession; +import org.lamsfoundation.lams.tool.mc.pojos.McUsrAttempt; +import org.lamsfoundation.lams.tool.mc.service.IMcService; +import org.lamsfoundation.lams.tool.mc.service.McServiceProxy; +import org.lamsfoundation.lams.tool.mc.util.LearningUtil; +import org.lamsfoundation.lams.tool.mc.util.McComparator; +import org.lamsfoundation.lams.tool.mc.web.form.McLearningForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.web.util.SessionMap; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Ozgur Demirtas + */ +public class McLearningAction extends LamsDispatchAction { + private static Logger logger = Logger.getLogger(McLearningAction.class.getName()); + + private static IMcService mcService; + + /** + * main content/question content management and workflow logic + * + * if the passed toolContentId exists in the db, we need to get the relevant data into the Map if not, create the + * default Map + */ + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + McLearningForm mcLearningForm = (McLearningForm) form; + LearningUtil.saveFormRequestData(request, mcLearningForm); + return null; + } + + /** + * responds to learner activity in learner mode. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward displayMc(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + McLearningForm mcLearningForm = (McLearningForm) form; + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + mcLearningForm.setToolSessionID(toolSessionID); + + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + + String toolContentId = mcSession.getMcContent().getMcContentId().toString(); + mcLearningForm.setToolContentID(toolContentId); + + LearningUtil.saveFormRequestData(request, mcLearningForm); + + if (mcLearningForm.getNextQuestionSelected() != null && !mcLearningForm.getNextQuestionSelected().equals("")) { + mcLearningForm.resetParameters(); + return getNextOptions(mapping, form, request, response); + } + if (mcLearningForm.getContinueOptionsCombined() != null) { + return continueOptionsCombined(mapping, form, request, response); + } else if (mcLearningForm.getNextOptions() != null) { + return getNextOptions(mapping, form, request, response); + } else if (mcLearningForm.getRedoQuestions() != null) { + return redoQuestions(request, mcLearningForm, mapping); + } else if (mcLearningForm.getViewAnswers() != null) { + return viewAnswers(mapping, mcLearningForm, request, response); + } else if (mcLearningForm.getSubmitReflection() != null) { + return submitReflection(mapping, form, request, response); + } else if (mcLearningForm.getForwardtoReflection() != null) { + return forwardtoReflection(mapping, form, request, response); + } else if (mcLearningForm.getLearnerFinished() != null) { + return endLearning(mapping, form, request, response); + } + + return mapping.findForward(McAppConstants.LOAD_LEARNER); + } + + /** + * ActionForward endLearning(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse + * response) + * + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward endLearning(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + McLearningForm mcLearningForm = (McLearningForm) form; + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + mcLearningForm.setToolSessionID(toolSessionID); + + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + + String toolContentId = mcSession.getMcContent().getMcContentId().toString(); + mcLearningForm.setToolContentID(toolContentId); + + LearningUtil.saveFormRequestData(request, mcLearningForm); + // requested learner finished, the learner should be directed to next activity + + HttpSession ss = SessionManager.getSession(); + UserDTO userDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + + String nextUrl = null; + try { + nextUrl = mcService.leaveToolSession(new Long(toolSessionID), userDto.getUserID().longValue()); + } catch (DataMissingException e) { + McLearningAction.logger.error("failure getting nextUrl: " + e); + return mapping.findForward(McAppConstants.LEARNING_STARTER); + } catch (ToolException e) { + McLearningAction.logger.error("failure getting nextUrl: " + e); + return mapping.findForward(McAppConstants.LEARNING_STARTER); + } catch (Exception e) { + McLearningAction.logger.error("unknown exception getting nextUrl: " + e); + return mapping.findForward(McAppConstants.LEARNING_STARTER); + } + + response.sendRedirect(nextUrl); + + return null; + } + + /** + * + */ + protected List buildAnswerDtos(List answers, McContent content) { + + List answerDtos = new LinkedList(); + + for (McQueContent question : (Set) content.getMcQueContents()) { + String questionUid = question.getUid().toString(); + int questionMark = question.getMark().intValue(); + + AnswerDTO answerDto = new AnswerDTO(); + answerDto.setQuestion(question.getQuestion()); + answerDto.setDisplayOrder(question.getDisplayOrder().toString()); + answerDto.setQuestionUid(question.getUid()); + answerDto.setFeedback(question.getFeedback() != null ? question.getFeedback() : ""); + + //search for according answer + McOptsContent answerOption = null; + for (String answer : answers) { + int hyphenPosition = answer.indexOf("-"); + String answeredQuestionUid = answer.substring(0, hyphenPosition); + + if (questionUid.equals(answeredQuestionUid)) { + String answeredOptionUid = answer.substring(hyphenPosition + 1); + answerOption = question.getOptionsContentByUID(new Long(answeredOptionUid)); + answerDto.setAnswerOption(answerOption); + break; + } + } + + boolean isCorrect = (answerOption != null) && answerOption.isCorrectOption(); + answerDto.setAttemptCorrect(isCorrect); + if (isCorrect) { + answerDto.setFeedbackCorrect(question.getFeedback()); + answerDto.setMark(questionMark); + } else { + answerDto.setFeedbackIncorrect(question.getFeedback()); + answerDto.setMark(0); + } + + answerDtos.add(answerDto); + + } + + return answerDtos; + } + + /** + * responses to learner when they answer all the questions on a single page + */ + public ActionForward continueOptionsCombined(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + McLearningForm mcLearningForm = (McLearningForm) form; + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + + String httpSessionID = mcLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(httpSessionID); + request.getSession().setAttribute(httpSessionID, sessionMap); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + McSession session = mcService.getMcSessionById(new Long(toolSessionID)); + String toolContentId = session.getMcContent().getMcContentId().toString(); + McContent mcContent = mcService.getMcContent(new Long(toolContentId)); + + List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, + mcContent.isQuestionsSequenced()); + if (mcContent.isQuestionsSequenced()) { + sessionMap.put(McAppConstants.QUESTION_AND_CANDIDATE_ANSWERS_KEY, answers); + } + + mcLearningForm.resetCa(mapping, request); + + McQueUsr user = getCurrentUser(toolSessionID); + + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (user.isResponseFinalised()) { + return viewAnswers(mapping, mcLearningForm, request, response); + } + + /* process the answers */ + List answerDtos = buildAnswerDtos(answers, mcContent); + mcService.saveUserAttempt(user, answerDtos); + + //calculate total learner mark + int learnerMark = 0; + for (AnswerDTO answerDto : answerDtos) { + learnerMark += answerDto.getMark(); + } + + Integer numberOfAttempts = user.getNumberOfAttempts() + 1; + user.setNumberOfAttempts(numberOfAttempts); + user.setLastAttemptTotalMark(learnerMark); + user.setResponseFinalised(true); + mcService.updateMcQueUsr(user); + + return viewAnswers(mapping, mcLearningForm, request, response); + } + + /** + * takes the learner to the next set of questions + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward getNextOptions(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + McLearningForm mcLearningForm = (McLearningForm) form; + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + String toolContentId = mcSession.getMcContent().getMcContentId().toString(); + McContent mcContent = mcService.getMcContent(new Long(toolContentId)); + + McQueUsr user = getCurrentUser(toolSessionID); + + String httpSessionID = mcLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (user.isResponseFinalised()) { + return viewAnswers(mapping, mcLearningForm, request, response); + } + + //parse learner input + List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, + mcContent.isQuestionsSequenced()); + sessionMap.put(McAppConstants.QUESTION_AND_CANDIDATE_ANSWERS_KEY, answers); + + //save user attempt + List answerDtos = buildAnswerDtos(answers, mcContent); + mcService.saveUserAttempt(user, answerDtos); + + List learnerAnswersDTOList = mcService.getAnswersFromDatabase(mcContent, user); + request.setAttribute(McAppConstants.LEARNER_ANSWERS_DTO_LIST, learnerAnswersDTOList); + + McGeneralLearnerFlowDTO mcGeneralLearnerFlowDTO = LearningUtil.buildMcGeneralLearnerFlowDTO(mcContent); + + Integer totalQuestionCount = mcGeneralLearnerFlowDTO.getTotalQuestionCount(); + Integer questionIndex = mcLearningForm.getQuestionIndex(); + if (totalQuestionCount.equals(questionIndex)) { + mcGeneralLearnerFlowDTO.setTotalCountReached(new Boolean(true).toString()); + } + + mcGeneralLearnerFlowDTO.setReflection(new Boolean(mcContent.isReflect()).toString()); + mcGeneralLearnerFlowDTO.setReflectionSubject(mcContent.getReflectionSubject()); + mcGeneralLearnerFlowDTO.setRetries(new Boolean(mcContent.isRetries()).toString()); + mcGeneralLearnerFlowDTO.setTotalMarksPossible(mcContent.getTotalMarksPossible()); + mcGeneralLearnerFlowDTO.setQuestionIndex(questionIndex); + request.setAttribute(McAppConstants.MC_GENERAL_LEARNER_FLOW_DTO, mcGeneralLearnerFlowDTO); + + LearningWebUtil.putActivityPositionInRequestByToolSessionId(new Long(toolSessionID), request, + getServlet().getServletContext()); + + request.setAttribute("sessionMapID", sessionMap.getSessionID()); + + return mapping.findForward(McAppConstants.LOAD_LEARNER); + } + + /** + * allows the learner to view their answer history + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward viewAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + McLearningForm mcLearningForm = (McLearningForm) form; + + // may have to get service from the form - if class has been created by starter action, rather than by struts + if (mcService == null) { + if (getServlet() != null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } else { + mcService = mcLearningForm.getMcService(); + } + } + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + + String toolContentId = mcSession.getMcContent().getMcContentId().toString(); + McContent mcContent = mcService.getMcContent(new Long(toolContentId)); + + String sessionMapID = mcLearningForm.getHttpSessionID(); + request.setAttribute("sessionMapID", sessionMapID); + + McGeneralLearnerFlowDTO mcGeneralLearnerFlowDTO = LearningUtil.buildMcGeneralLearnerFlowDTO(mcContent); + + Map mapQuestionsUidContent = new TreeMap(new McComparator()); + if (mcContent != null) { + List list = mcService.refreshQuestionContent(mcContent.getUid()); + + Iterator listIterator = list.iterator(); + Long mapIndex = new Long(1); + while (listIterator.hasNext()) { + McQueContent mcQueContent = (McQueContent) listIterator.next(); + mapQuestionsUidContent.put(mapIndex.toString(), mcQueContent.getUid()); + mapIndex = new Long(mapIndex.longValue() + 1); + } + } + + //builds a map to hold all the candidate answers for all the questions by accessing the db + Map mapStartupGeneralOptionsContent = new TreeMap(new McComparator()); + Iterator itMap = mapQuestionsUidContent.entrySet().iterator(); + Long mapIndex = new Long(1); + while (itMap.hasNext()) { + Map.Entry pairs = (Map.Entry) itMap.next(); + String currentQuestionUid = pairs.getValue().toString(); + List listQuestionOptions = mcService.findOptionsByQuestionUid(new Long(currentQuestionUid)); + + //builds a questions map from questions list + Map mapOptsContent = new TreeMap(new McComparator()); + Iterator iter = listQuestionOptions.iterator(); + Long mapIndex2 = new Long(1); + while (iter.hasNext()) { + McOptsContent option = iter.next(); + mapOptsContent.put(mapIndex2.toString(), option.getMcQueOptionText()); + mapIndex2 = new Long(mapIndex2.longValue() + 1); + } + + mapStartupGeneralOptionsContent.put(mapIndex.toString(), mapOptsContent); + mapIndex = new Long(mapIndex.longValue() + 1); + } + mcGeneralLearnerFlowDTO.setMapGeneralOptionsContent(mapStartupGeneralOptionsContent); + + //builds a map to hold question texts + Map mapQuestionsContent = new TreeMap(new McComparator()); + List list = mcService.refreshQuestionContent(mcContent.getUid()); + Iterator iter = list.iterator(); + Long mapIndex3 = new Long(1); + while (iter.hasNext()) { + McQueContent question = (McQueContent) iter.next(); + mapQuestionsContent.put(mapIndex3.toString(), question.getQuestion()); + mapIndex3 = new Long(mapIndex3.longValue() + 1); + } + mcGeneralLearnerFlowDTO.setMapQuestionsContent(mapQuestionsContent); + + //rebuildFeedbackMapfromDB + Map mapFeedbackContent = new TreeMap(new McComparator()); + List list2 = mcService.refreshQuestionContent(mcContent.getUid()); + Iterator iter2 = list2.iterator(); + Long mapIndex4 = new Long(1); + while (iter2.hasNext()) { + McQueContent question = (McQueContent) iter2.next(); + + String feedback = question.getFeedback(); + + mapFeedbackContent.put(mapIndex4.toString(), feedback); + mapIndex4 = new Long(mapIndex4.longValue() + 1); + } + mcGeneralLearnerFlowDTO.setMapFeedbackContent(mapFeedbackContent); + + McQueUsr user = getCurrentUser(toolSessionID); + + Long toolContentUID = mcContent.getUid(); + + //create attemptMap for displaying on jsp + Map attemptMap = new TreeMap(new McComparator()); + for (int i = 1; i <= mcContent.getMcQueContents().size(); i++) { + McQueContent question = mcService.getQuestionByDisplayOrder(new Long(i), toolContentUID); + + McUsrAttempt userAttempt = mcService.getUserAttemptByQuestion(user.getUid(), question.getUid()); + + if (userAttempt != null) { + attemptMap.put(new Integer(i).toString(), userAttempt); + } + } + mcGeneralLearnerFlowDTO.setAttemptMap(attemptMap); + mcGeneralLearnerFlowDTO.setReflection(new Boolean(mcContent.isReflect()).toString()); + mcGeneralLearnerFlowDTO.setReflectionSubject(mcContent.getReflectionSubject()); + + NotebookEntry notebookEntry = mcService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + McAppConstants.TOOL_SIGNATURE, new Integer(user.getQueUsrId().intValue())); + request.setAttribute("notebookEntry", notebookEntry); + if (notebookEntry != null) { + mcGeneralLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); + } + + mcGeneralLearnerFlowDTO.setRetries(new Boolean(mcContent.isRetries()).toString()); + mcGeneralLearnerFlowDTO.setPassMarkApplicable(new Boolean(mcContent.isPassMarkApplicable()).toString()); + mcGeneralLearnerFlowDTO.setUserOverPassMark(new Boolean(user.isLastAttemptMarkPassed()).toString()); + mcGeneralLearnerFlowDTO.setTotalMarksPossible(mcContent.getTotalMarksPossible()); + mcGeneralLearnerFlowDTO.setShowMarks(new Boolean(mcContent.isShowMarks()).toString()); + mcGeneralLearnerFlowDTO.setDisplayAnswers(new Boolean(mcContent.isDisplayAnswers()).toString()); + mcGeneralLearnerFlowDTO.setLearnerMark(user.getLastAttemptTotalMark()); + + Object[] markStatistics = null; + if (mcContent.isShowMarks()) { + markStatistics = mcService.getMarkStatistics(mcSession); + } + if (markStatistics != null) { + mcGeneralLearnerFlowDTO + .setLowestMark(markStatistics[0] != null ? ((Float) markStatistics[0]).intValue() : 0); + mcGeneralLearnerFlowDTO + .setAverageMark(markStatistics[1] != null ? ((Float) markStatistics[1]).intValue() : 0); + mcGeneralLearnerFlowDTO.setTopMark(markStatistics[2] != null ? ((Float) markStatistics[2]).intValue() : 0); + } else { + mcGeneralLearnerFlowDTO.setLowestMark(0); + mcGeneralLearnerFlowDTO.setAverageMark(0); + mcGeneralLearnerFlowDTO.setTopMark(0); + } + + request.setAttribute(McAppConstants.MC_GENERAL_LEARNER_FLOW_DTO, mcGeneralLearnerFlowDTO); + + LearningWebUtil.putActivityPositionInRequestByToolSessionId(new Long(toolSessionID), request, + getServlet().getServletContext()); + + return mapping.findForward(McAppConstants.VIEW_ANSWERS); + } + + /** + * + */ + public ActionForward redoQuestions(HttpServletRequest request, McLearningForm mcLearningForm, + ActionMapping mapping) { + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + String toolContentId = mcSession.getMcContent().getMcContentId().toString(); + McContent mcContent = mcService.getMcContent(new Long(toolContentId)); + McQueUsr mcQueUsr = getCurrentUser(toolSessionID); + + //in order to track whether redo button is pressed store this info + mcQueUsr.setResponseFinalised(false); + mcService.updateMcQueUsr(mcQueUsr); + + //clear sessionMap + String httpSessionID = mcLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(httpSessionID); + List sequentialCheckedCa = new LinkedList(); + sessionMap.put(McAppConstants.QUESTION_AND_CANDIDATE_ANSWERS_KEY, sequentialCheckedCa); + + List learnerAnswersDTOList = mcService.getAnswersFromDatabase(mcContent, mcQueUsr); + request.setAttribute(McAppConstants.LEARNER_ANSWERS_DTO_LIST, learnerAnswersDTOList); + + McGeneralLearnerFlowDTO mcGeneralLearnerFlowDTO = LearningUtil.buildMcGeneralLearnerFlowDTO(mcContent); + mcGeneralLearnerFlowDTO.setQuestionIndex(new Integer(1)); + mcGeneralLearnerFlowDTO.setReflection(new Boolean(mcContent.isReflect()).toString()); + mcGeneralLearnerFlowDTO.setReflectionSubject(mcContent.getReflectionSubject()); + mcGeneralLearnerFlowDTO.setRetries(new Boolean(mcContent.isRetries()).toString()); + + String passMarkApplicable = new Boolean(mcContent.isPassMarkApplicable()).toString(); + mcGeneralLearnerFlowDTO.setPassMarkApplicable(passMarkApplicable); + mcLearningForm.setPassMarkApplicable(passMarkApplicable); + + String userOverPassMark = Boolean.FALSE.toString(); + mcGeneralLearnerFlowDTO.setUserOverPassMark(userOverPassMark); + mcLearningForm.setUserOverPassMark(userOverPassMark); + + mcGeneralLearnerFlowDTO.setTotalMarksPossible(mcContent.getTotalMarksPossible()); + + // should we show the marks for each question - we show the marks if any of the questions + // have a mark > 1. + Boolean showMarks = LearningUtil.isShowMarksOnQuestion(learnerAnswersDTOList); + mcGeneralLearnerFlowDTO.setShowMarks(showMarks.toString()); + + request.setAttribute("sessionMapID", mcLearningForm.getHttpSessionID()); + + request.setAttribute(McAppConstants.MC_GENERAL_LEARNER_FLOW_DTO, mcGeneralLearnerFlowDTO); + return mapping.findForward(McAppConstants.LOAD_LEARNER); + } + + /** + * checks Leader Progress + */ + public ActionForward checkLeaderProgress(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + Long toolSessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + + McSession session = mcService.getMcSessionById(toolSessionId); + McQueUsr leader = session.getGroupLeader(); + + boolean isLeaderResponseFinalized = leader.isResponseFinalised(); + + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put("isLeaderResponseFinalized", isLeaderResponseFinalized); + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(ObjectNode); + return null; + } + + /** + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + public ActionForward submitReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + McLearningForm mcLearningForm = (McLearningForm) form; + + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + mcLearningForm.setToolSessionID(toolSessionID); + + Long userID = mcLearningForm.getUserID(); + + String reflectionEntry = request.getParameter(McAppConstants.ENTRY_TEXT); + NotebookEntry notebookEntry = mcService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + McAppConstants.TOOL_SIGNATURE, userID.intValue()); + + if (notebookEntry != null) { + notebookEntry.setEntry(reflectionEntry); + mcService.updateEntry(notebookEntry); + } else { + mcService.createNotebookEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + McAppConstants.TOOL_SIGNATURE, userID.intValue(), reflectionEntry); + } + + return endLearning(mapping, form, request, response); + } + + /** + * + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + public ActionForward forwardtoReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + McLearningForm mcLearningForm = (McLearningForm) form; + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + + McContent mcContent = mcSession.getMcContent(); + + McGeneralLearnerFlowDTO mcGeneralLearnerFlowDTO = new McGeneralLearnerFlowDTO(); + mcGeneralLearnerFlowDTO.setActivityTitle(mcContent.getTitle()); + mcGeneralLearnerFlowDTO.setReflectionSubject(mcContent.getReflectionSubject()); + + Long userID = mcLearningForm.getUserID(); + + // attempt getting notebookEntry + NotebookEntry notebookEntry = mcService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + McAppConstants.TOOL_SIGNATURE, userID.intValue()); + + if (notebookEntry != null) { + String notebookEntryPresentable = notebookEntry.getEntry(); + mcLearningForm.setEntryText(notebookEntryPresentable); + + } + + request.setAttribute(McAppConstants.MC_GENERAL_LEARNER_FLOW_DTO, mcGeneralLearnerFlowDTO); + + return mapping.findForward(McAppConstants.NOTEBOOK); + } + + /** + * auto saves responses + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward autoSaveAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + if (mcService == null) { + mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + } + McLearningForm mcLearningForm = (McLearningForm) form; + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionID)); + McContent mcContent = mcSession.getMcContent(); + + Long userID = mcLearningForm.getUserID(); + McQueUsr user = mcService.getMcUserBySession(userID, mcSession.getUid()); + + //prohibit users from autosaving answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (user.isResponseFinalised()) { + return null; + } + + List answers = McLearningAction.parseLearnerAnswers(mcLearningForm, request, + mcContent.isQuestionsSequenced()); + + List answerDtos = buildAnswerDtos(answers, mcContent); + mcService.saveUserAttempt(user, answerDtos); + + return null; + } + + private static List parseLearnerAnswers(McLearningForm mcLearningForm, HttpServletRequest request, + boolean isQuestionsSequenced) { + String httpSessionID = mcLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(httpSessionID); + + List answers = new LinkedList(); + if (isQuestionsSequenced) { + + List previousAnswers = (List) sessionMap + .get(McAppConstants.QUESTION_AND_CANDIDATE_ANSWERS_KEY); + answers.addAll(previousAnswers); + + /* checkedCa refers to candidate answers */ + String[] checkedCa = mcLearningForm.getCheckedCa(); + + if (checkedCa != null) { + for (int i = 0; i < checkedCa.length; i++) { + String currentCa = checkedCa[i]; + answers.add(currentCa); + } + } + + } else { + Map parameters = request.getParameterMap(); + Iterator iter = parameters.keySet().iterator(); + while (iter.hasNext()) { + String key = iter.next(); + if (key.startsWith("checkedCa")) { + String currentCheckedCa = request.getParameter(key); + if (currentCheckedCa != null) { + answers.add(currentCheckedCa); + } + } + } + } + + return answers; + } + + private McQueUsr getCurrentUser(String toolSessionId) { + McSession mcSession = mcService.getMcSessionById(new Long(toolSessionId)); + + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = new Long(toolUser.getUserID().longValue()); + + return mcService.getMcUserBySession(userId, mcSession.getUid()); + } + +} Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McMonitoringAction.java =================================================================== diff -u --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McMonitoringAction.java (revision 0) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/action/McMonitoringAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,409 @@ +/*************************************************************************** + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.mc.web.action; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +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.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.mc.McAppConstants; +import org.lamsfoundation.lams.tool.mc.dto.LeaderResultsDTO; +import org.lamsfoundation.lams.tool.mc.dto.McGeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.mc.dto.McUserMarkDTO; +import org.lamsfoundation.lams.tool.mc.dto.SessionDTO; +import org.lamsfoundation.lams.tool.mc.pojos.McContent; +import org.lamsfoundation.lams.tool.mc.pojos.McOptsContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueUsr; +import org.lamsfoundation.lams.tool.mc.pojos.McSession; +import org.lamsfoundation.lams.tool.mc.pojos.McUsrAttempt; +import org.lamsfoundation.lams.tool.mc.service.IMcService; +import org.lamsfoundation.lams.tool.mc.service.McServiceProxy; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.JsonUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * * @author Ozgur Demirtas + */ +public class McMonitoringAction extends LamsDispatchAction { + /** + * displayAnswers + */ + public ActionForward displayAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + String strToolContentID = request.getParameter(AttributeNames.PARAM_TOOL_CONTENT_ID); + String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID); + + McContent mcContent = mcService.getMcContent(new Long(strToolContentID)); + mcContent.setDisplayAnswers(new Boolean(true)); + mcService.updateMc(mcContent); + + // use redirect to prevent resubmition of the same request + ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("monitoringStarterRedirect")); + redirect.addParameter(McAppConstants.TOOL_CONTENT_ID, strToolContentID); + redirect.addParameter(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); + return redirect; + } + + /** + * allows viewing users reflection data + */ + public ActionForward openNotebook(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + String userId = request.getParameter("userId"); + String userName = request.getParameter("userName"); + String sessionId = request.getParameter("sessionId"); + NotebookEntry notebookEntry = mcService.getEntry(new Long(sessionId), CoreNotebookConstants.NOTEBOOK_TOOL, + McAppConstants.TOOL_SIGNATURE, new Integer(userId)); + + McGeneralLearnerFlowDTO mcGeneralLearnerFlowDTO = new McGeneralLearnerFlowDTO(); + if (notebookEntry != null) { + // String notebookEntryPresentable = McUtils.replaceNewLines(notebookEntry.getEntry()); + mcGeneralLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); + mcGeneralLearnerFlowDTO.setUserName(userName); + } + + request.setAttribute(McAppConstants.MC_GENERAL_LEARNER_FLOW_DTO, mcGeneralLearnerFlowDTO); + + return mapping.findForward(McAppConstants.LEARNER_NOTEBOOK); + } + + /** + * downloadMarks + */ + public ActionForward downloadMarks(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + MessageService messageService = McServiceProxy.getMessageService(getServlet().getServletContext()); + + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + Long toolContentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID, false); + + McContent mcContent = mcService.getMcContent(new Long(toolContentID)); + + byte[] spreadsheet = null; + + try { + spreadsheet = mcService.prepareSessionDataSpreadsheet(mcContent); + } catch (Exception e) { + log.error("Error preparing spreadsheet: ", e); + request.setAttribute("errorName", messageService.getMessage("error.monitoring.spreadsheet.download")); + request.setAttribute("errorMessage", e); + return mapping.findForward("error"); + } + + // set cookie that will tell JS script that export has been finished + String downloadTokenValue = WebUtil.readStrParam(request, "downloadTokenValue"); + Cookie fileDownloadTokenCookie = new Cookie("fileDownloadToken", downloadTokenValue); + fileDownloadTokenCookie.setPath("/"); + response.addCookie(fileDownloadTokenCookie); + + // construct download file response header + OutputStream out = response.getOutputStream(); + String fileName = "lams_mcq.xls"; + String mineType = "application/vnd.ms-excel"; + String header = "attachment; filename=\"" + fileName + "\";"; + response.setContentType(mineType); + response.setHeader("Content-Disposition", header); + + // write response + try { + out.write(spreadsheet); + out.flush(); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + } + } + + return null; + } + + /** + * Set Submission Deadline + * + * @throws IOException + */ + public ActionForward setSubmissionDeadline(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + IMcService service = McServiceProxy.getMcService(getServlet().getServletContext()); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + McContent mcContent = service.getMcContent(contentID); + + Long dateParameter = WebUtil.readLongParam(request, McAppConstants.ATTR_SUBMISSION_DEADLINE, true); + Date tzSubmissionDeadline = null; + String formattedDate = ""; + if (dateParameter != null) { + Date submissionDeadline = new Date(dateParameter); + HttpSession ss = SessionManager.getSession(); + org.lamsfoundation.lams.usermanagement.dto.UserDTO teacher = (org.lamsfoundation.lams.usermanagement.dto.UserDTO) ss + .getAttribute(AttributeNames.USER); + TimeZone teacherTimeZone = teacher.getTimeZone(); + tzSubmissionDeadline = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, submissionDeadline); + formattedDate = DateUtil.convertToStringForJSON(tzSubmissionDeadline, request.getLocale()); + } + mcContent.setSubmissionDeadline(tzSubmissionDeadline); + service.updateMc(mcContent); + response.setContentType("text/plain;charset=utf-8"); + response.getWriter().print(formattedDate); + return null; + } + + /** + * Set tool's activityEvaluation + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws JSONException + * @throws IOException + */ + public ActionForward setActivityEvaluation(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + IMcService service = McServiceProxy.getMcService(getServlet().getServletContext()); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + String activityEvaluation = WebUtil.readStrParam(request, McAppConstants.ATTR_ACTIVITY_EVALUATION); + service.setActivityEvaluation(contentID, activityEvaluation); + + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.put("success", "true"); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responseJSON.toString())); + return null; + } + + /** + * Populate user jqgrid table on summary page. + */ + public ActionForward userMasterDetail(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + + Long userUid = WebUtil.readLongParam(request, McAppConstants.USER_UID); + McQueUsr user = mcService.getMcUserByUID(userUid); + List userAttempts = mcService.getFinalizedUserAttempts(user); + + // Escapes all characters that may brake JS code on assigning Java value to JS String variable (particularly + // escapes all quotes in the following way \"). + if (userAttempts != null) { + for (McUsrAttempt userAttempt : userAttempts) { + McQueContent question = userAttempt.getMcQueContent(); + McOptsContent option = userAttempt.getMcOptionsContent(); + + String questionText = question.getQuestion(); + if (questionText != null) { + String escapedQuestion = StringEscapeUtils.escapeJavaScript(questionText); + question.setEscapedQuestion(escapedQuestion); + } + + String optionText = option.getMcQueOptionText(); + if (optionText != null) { + String escapedOptionText = StringEscapeUtils.escapeJavaScript(optionText); + option.setEscapedOptionText(escapedOptionText); + } + } + } + + request.setAttribute(McAppConstants.USER_ATTEMPTS, userAttempts); + request.setAttribute(McAppConstants.TOOL_SESSION_ID, user.getMcSession().getMcSessionId()); + return (userAttempts == null || userAttempts.isEmpty()) ? null + : mapping.findForward(McAppConstants.USER_MASTER_DETAIL); + } + + /** + * Return paged users for jqGrid. + */ + public ActionForward getPagedUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + + Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + McSession session = mcService.getMcSessionById(sessionId); + //find group leader, if any + McQueUsr groupLeader = session.getGroupLeader(); + + // Getting the params passed in from the jqGrid + int page = WebUtil.readIntParam(request, AttributeNames.PARAM_PAGE); + int rowLimit = WebUtil.readIntParam(request, AttributeNames.PARAM_ROWS); + String sortOrder = WebUtil.readStrParam(request, AttributeNames.PARAM_SORD); + String sortBy = WebUtil.readStrParam(request, AttributeNames.PARAM_SIDX, true); + if (StringUtils.isEmpty(sortBy)) { + sortBy = "userName"; + } + String searchString = WebUtil.readStrParam(request, "userName", true); + + List userDtos = mcService.getPagedUsersBySession(sessionId, page - 1, rowLimit, sortBy, + sortOrder, searchString); + int countVisitLogs = mcService.getCountPagedUsersBySession(sessionId, searchString); + + int totalPages = new Double( + Math.ceil(new Integer(countVisitLogs).doubleValue() / new Integer(rowLimit).doubleValue())).intValue(); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + int i = 1; + for (McUserMarkDTO userDto : userDtos) { + + ArrayNode visitLogData = JsonNodeFactory.instance.arrayNode(); + Long userUid = Long.parseLong(userDto.getQueUsrId()); + visitLogData.add(userUid); + String fullName = StringEscapeUtils.escapeHtml(userDto.getFullName()); + if (groupLeader != null && groupLeader.getUid().equals(userUid)) { + fullName += " (" + mcService.getLocalizedMessage("label.monitoring.group.leader") + ")"; + } + + visitLogData.add(fullName); + Long totalMark = (userDto.getTotalMark() == null) ? 0 : userDto.getTotalMark(); + visitLogData.add(totalMark); + + ObjectNode userRow = JsonNodeFactory.instance.objectNode(); + userRow.put("id", i++); + userRow.set("cell", visitLogData); + + rows.add(userRow); + } + + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.put("total", totalPages); + responseJSON.put("page", page); + responseJSON.put("records", countVisitLogs); + responseJSON.set("rows", rows); + + response.setContentType("application/json;charset=utf-8"); + response.getWriter().write(responseJSON.toString()); + return null; + } + + public ActionForward saveUserMark(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + if ((request.getParameter(McAppConstants.PARAM_NOT_A_NUMBER) == null) + && !StringUtils.isEmpty(request.getParameter(McAppConstants.PARAM_USER_ATTEMPT_UID))) { + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + + Long userAttemptUid = WebUtil.readLongParam(request, McAppConstants.PARAM_USER_ATTEMPT_UID); + Integer newGrade = Integer.valueOf(request.getParameter(McAppConstants.PARAM_GRADE)); + mcService.changeUserAttemptMark(userAttemptUid, newGrade); + } + + return null; + } + + /** + * Get the mark summary with data arranged in bands. Can be displayed graphically or in a table. + */ + public ActionForward getMarkChartData(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse res) throws IOException, ServletException { + + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + McContent mcContent = mcService.getMcContent(contentID); + List results = null; + + if (mcContent != null) { + if (mcContent.isUseSelectLeaderToolOuput()) { + results = mcService.getMarksArrayForLeaders(contentID); + } else { + Long sessionID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + results = mcService.getMarksArray(sessionID); + } + } + + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + if (results != null) { + responseJSON.set("data", JsonUtil.readArray(results)); + } else { + responseJSON.set("data", JsonUtil.readArray(new Float[0])); + } + + res.setContentType("application/json;charset=utf-8"); + res.getWriter().write(responseJSON.toString()); + return null; + + } + + public ActionForward statistic(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + IMcService mcService = McServiceProxy.getMcService(getServlet().getServletContext()); + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + request.setAttribute(AttributeNames.PARAM_TOOL_CONTENT_ID, contentID); + McContent mcContent = mcService.getMcContent(contentID); + if (mcContent != null) { + if (mcContent.isUseSelectLeaderToolOuput()) { + LeaderResultsDTO leaderDto = mcService.getLeaderResultsDTOForLeaders(contentID); + request.setAttribute("leaderDto", leaderDto); + } else { + List sessionDtos = mcService.getSessionDtos(contentID, true); + request.setAttribute("sessionDtos", sessionDtos); + } + request.setAttribute("useSelectLeaderToolOutput", mcContent.isUseSelectLeaderToolOuput()); + } + + // prepare toolOutputDefinitions and activityEvaluation + List toolOutputDefinitions = new ArrayList(); + toolOutputDefinitions.add(McAppConstants.OUTPUT_NAME_LEARNER_MARK); + toolOutputDefinitions.add(McAppConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT); + String activityEvaluation = mcService.getActivityEvaluation(contentID); + request.setAttribute(McAppConstants.ATTR_TOOL_OUTPUT_DEFINITIONS, toolOutputDefinitions); + request.setAttribute(McAppConstants.ATTR_ACTIVITY_EVALUATION, activityEvaluation); + + return mapping.findForward(McAppConstants.STATISTICS); + } + +} Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/service/QaService.java =================================================================== diff -u --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/service/QaService.java (revision 0) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/service/QaService.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,1289 @@ +/**************************************************************** + * 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 + * **************************************************************** + */ + +package org.lamsfoundation.lams.tool.qa.service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; +import org.lamsfoundation.lams.events.IEventNotificationService; +import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService; +import org.lamsfoundation.lams.learningdesign.service.ImportToolContentException; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; +import org.lamsfoundation.lams.rating.dto.ItemRatingDTO; +import org.lamsfoundation.lams.rating.model.LearnerItemRatingCriteria; +import org.lamsfoundation.lams.rating.model.RatingCriteria; +import org.lamsfoundation.lams.rating.service.IRatingService; +import org.lamsfoundation.lams.rest.RestTags; +import org.lamsfoundation.lams.rest.ToolRestManager; +import org.lamsfoundation.lams.tool.IToolVO; +import org.lamsfoundation.lams.tool.ToolCompletionStatus; +import org.lamsfoundation.lams.tool.ToolContentManager; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.ToolSessionExportOutputData; +import org.lamsfoundation.lams.tool.ToolSessionManager; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.qa.QaAppConstants; +import org.lamsfoundation.lams.tool.qa.QaCondition; +import org.lamsfoundation.lams.tool.qa.QaConfigItem; +import org.lamsfoundation.lams.tool.qa.QaContent; +import org.lamsfoundation.lams.tool.qa.QaQueContent; +import org.lamsfoundation.lams.tool.qa.QaQueUsr; +import org.lamsfoundation.lams.tool.qa.QaSession; +import org.lamsfoundation.lams.tool.qa.QaUsrResp; +import org.lamsfoundation.lams.tool.qa.QaWizardCategory; +import org.lamsfoundation.lams.tool.qa.dao.IQaConfigItemDAO; +import org.lamsfoundation.lams.tool.qa.dao.IQaContentDAO; +import org.lamsfoundation.lams.tool.qa.dao.IQaQueUsrDAO; +import org.lamsfoundation.lams.tool.qa.dao.IQaQuestionDAO; +import org.lamsfoundation.lams.tool.qa.dao.IQaSessionDAO; +import org.lamsfoundation.lams.tool.qa.dao.IQaUsrRespDAO; +import org.lamsfoundation.lams.tool.qa.dao.IQaWizardDAO; +import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; +import org.lamsfoundation.lams.tool.qa.util.QaApplicationException; +import org.lamsfoundation.lams.tool.service.ILamsToolService; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.JsonUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.audit.IAuditService; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.dao.DataAccessException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * The POJO implementation of Qa service. All business logics of Qa tool are implemented in this class. It translate the + * request from presentation layer and perform approporiate database operation. + * + * @author Ozgur Demirtas + */ +public class QaService implements IQaService, ToolContentManager, ToolSessionManager, ToolRestManager, QaAppConstants { + private static Logger logger = Logger.getLogger(QaService.class.getName()); + + private IQaContentDAO qaDAO; + private IQaQuestionDAO qaQuestionDAO; + + private IQaSessionDAO qaSessionDAO; + private IQaQueUsrDAO qaQueUsrDAO; + private IQaUsrRespDAO qaUsrRespDAO; + + private IToolContentHandler qaToolContentHandler = null; + private IUserManagementService userManagementService; + private ILamsToolService toolService; + private ILearnerService learnerService; + private IAuditService auditService; + private IExportToolContentService exportContentService; + private QaOutputFactory qaOutputFactory; + private IQaConfigItemDAO qaConfigItemDAO; + private IQaWizardDAO qaWizardDAO; + + private ICoreNotebookService coreNotebookService; + private IRatingService ratingService; + private IEventNotificationService eventNotificationService; + private MessageService messageService; + + private Random generator = new Random(); + + @Override + public boolean isUserGroupLeader(QaQueUsr user, Long toolSessionId) { + + QaSession session = this.getSessionById(toolSessionId); + QaQueUsr groupLeader = session.getGroupLeader(); + + boolean isUserLeader = (groupLeader != null) && user.getUid().equals(groupLeader.getUid()); + return isUserLeader; + } + + @Override + public QaQueUsr checkLeaderSelectToolForSessionLeader(QaQueUsr user, Long toolSessionId) { + if ((user == null) || (toolSessionId == null)) { + return null; + } + + QaSession qaSession = this.getSessionById(toolSessionId); + QaQueUsr leader = qaSession.getGroupLeader(); + // check leader select tool for a leader only in case QA tool doesn't know it. As otherwise it will screw + // up previous scratches done + if (leader == null) { + + Long leaderUserId = toolService.getLeaderUserId(toolSessionId, user.getQueUsrId().intValue()); + if (leaderUserId != null) { + leader = getUserByIdAndSession(leaderUserId, toolSessionId); + + // create new user in a DB + if (leader == null) { + User leaderDto = (User) getUserManagementService().findById(User.class, leaderUserId.intValue()); + String userName = leaderDto.getLogin(); + String fullName = leaderDto.getFirstName() + " " + leaderDto.getLastName(); + leader = new QaQueUsr(leaderUserId, userName, fullName, qaSession, new TreeSet()); + qaQueUsrDAO.createUsr(user); + } + + // set group leader + qaSession.setGroupLeader(leader); + this.updateSession(qaSession); + } + } + + return leader; + } + + @Override + public void copyAnswersFromLeader(QaQueUsr user, QaQueUsr leader) { + + if ((user == null) || (leader == null) || user.getUid().equals(leader.getUid())) { + return; + } + + for (QaUsrResp leaderResponse : (Set) leader.getQaUsrResps()) { + QaQueContent question = leaderResponse.getQaQuestion(); + QaUsrResp response = qaUsrRespDAO.getResponseByUserAndQuestion(user.getQueUsrId(), question.getUid()); + + // if response doesn't exist + if (response == null) { + response = new QaUsrResp(leaderResponse.getAnswer(), leaderResponse.getAnswerAutosaved(), + leaderResponse.getAttemptTime(), "", question, user, true); + createUserResponse(response); + + // if it's been changed by the leader + } else if (leaderResponse.getAttemptTime().compareTo(response.getAttemptTime()) != 0) { + response.setAnswer(leaderResponse.getAnswer()); + response.setAttemptTime(leaderResponse.getAttemptTime()); + response.setTimezone(""); + updateUserResponse(response); + } + } + } + + @Override + public void setDefineLater(String strToolContentID, boolean value) { + + QaContent qaContent = getQaContent(new Long(strToolContentID).longValue()); + + if (qaContent != null) { + qaContent.setDefineLater(value); + updateQaContent(qaContent); + } + } + + @Override + public List getUsersBySessionId(Long toolSessionID) { + QaSession session = qaSessionDAO.getQaSessionById(toolSessionID); + return qaQueUsrDAO.getUserBySessionOnly(session); + } + + @Override + public void createQaContent(QaContent qaContent) { + qaDAO.saveQa(qaContent); + } + + @Override + public QaContent getQaContent(long toolContentID) { + return qaDAO.getQaByContentId(toolContentID); + } + + @Override + public void saveOrUpdateQaContent(QaContent qa) { + qaDAO.saveOrUpdateQa(qa); + } + + @Override + public QaQueContent getQuestionByContentAndDisplayOrder(Long displayOrder, Long contentUid) { + return qaQuestionDAO.getQuestionByDisplayOrder(displayOrder, contentUid); + } + + @Override + public QaQueContent getQuestionByUid(Long questionUid) { + if (questionUid == null) { + return null; + } + + return qaQuestionDAO.getQuestionByUid(questionUid); + } + + @Override + public void saveOrUpdateQuestion(QaQueContent question) { + qaQuestionDAO.saveOrUpdateQaQueContent(question); + } + + @Override + public void createQuestion(QaQueContent question) { + qaQuestionDAO.createQueContent(question); + } + + @Override + public QaQueUsr createUser(Long toolSessionID, Integer userId) { + User user = (User) userManagementService.findById(User.class, userId); + String userName = user.getLogin(); + String fullName = user.getFirstName() + " " + user.getLastName(); + QaSession qaSession = getSessionById(toolSessionID.longValue()); + + QaQueUsr qaUser = new QaQueUsr(userId.longValue(), userName, fullName, qaSession, new TreeSet()); + // make sure the user was not created in the meantime + QaQueUsr existingUser = getUserByIdAndSession(userId.longValue(), toolSessionID); + if (existingUser == null) { + qaQueUsrDAO.createUsr(qaUser); + return qaUser; + } else { + return existingUser; + } + } + + @Override + public QaQueUsr getUserByIdAndSession(final Long queUsrId, final Long qaSessionId) { + return qaQueUsrDAO.getQaUserBySession(queUsrId, qaSessionId); + } + + @Override + public List getResponsesByUserUid(final Long userUid) { + return qaUsrRespDAO.getResponsesByUserUid(userUid); + } + + @Override + public QaUsrResp getResponseByUserAndQuestion(final Long queUsrId, final Long qaQueContentId) { + return qaUsrRespDAO.getResponseByUserAndQuestion(queUsrId, qaQueContentId); + } + + @Override + public List getResponseBySessionAndQuestion(final Long qaSessionId, final Long questionId) { + return qaUsrRespDAO.getResponseBySessionAndQuestion(qaSessionId, questionId); + } + + @Override + public List getResponsesForTablesorter(final Long toolContentId, final Long qaSessionId, + final Long questionId, final Long excludeUserId, boolean isOnlyLeadersIncluded, int page, int size, + int sorting, String searchString) { + return qaUsrRespDAO.getResponsesForTablesorter(toolContentId, qaSessionId, questionId, excludeUserId, + isOnlyLeadersIncluded, page, size, sorting, searchString); + } + + @Override + public int getCountResponsesBySessionAndQuestion(final Long qaSessionId, final Long questionId, + final Long excludeUserId, boolean isOnlyLeadersIncluded, String searchString) { + return qaUsrRespDAO.getCountResponsesBySessionAndQuestion(qaSessionId, questionId, excludeUserId, + isOnlyLeadersIncluded, searchString); + } + + @Override + public void updateUserResponse(QaUsrResp resp) { + qaUsrRespDAO.updateUserResponse(resp); + } + + @Override + public void updateResponseWithNewAnswer(String newAnswer, String toolSessionID, Long questionDisplayOrder, + boolean isAutosave) { + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = new Long(toolUser.getUserID().longValue()); + QaQueUsr user = getUserByIdAndSession(userId, new Long(toolSessionID)); + + QaSession session = getSessionById(new Long(toolSessionID)); + QaContent qaContent = session.getQaContent(); + + QaQueContent question = getQuestionByContentAndDisplayOrder(new Long(questionDisplayOrder), qaContent.getUid()); + + QaUsrResp response = getResponseByUserAndQuestion(user.getQueUsrId(), question.getUid()); + // if response doesn't exist + if (response == null) { + response = isAutosave + ? new QaUsrResp(null, newAnswer, new Date(System.currentTimeMillis()), "", question, user, true) + : new QaUsrResp(newAnswer, null, new Date(System.currentTimeMillis()), "", question, user, true); + createUserResponse(response); + + // if answer has changed + } else if (!newAnswer.equals(response.getAnswer())) { + if (isAutosave) { + response.setAnswerAutosaved(newAnswer); + } else { + response.setAnswer(newAnswer); + response.setAnswerAutosaved(null); + } + + response.setAttemptTime(new Date(System.currentTimeMillis())); + response.setTimezone(""); + updateUserResponse(response); + } + } + + @Override + public void createUserResponse(QaUsrResp qaUsrResp) { + qaUsrRespDAO.createUserResponse(qaUsrResp); + } + + @Override + public void updateUser(QaQueUsr qaQueUsr) { + qaQueUsrDAO.updateUsr(qaQueUsr); + } + + @Override + public QaUsrResp getResponseById(Long responseId) { + return qaUsrRespDAO.getResponseById(responseId); + } + + @Override + public QaSession getSessionById(long qaSessionId) { + return qaSessionDAO.getQaSessionById(qaSessionId); + } + + @Override + public void updateQaContent(QaContent qa) { + qaDAO.updateQa(qa); + } + + @Override + public void updateSession(QaSession qaSession) { + qaSessionDAO.UpdateQaSession(qaSession); + } + + @Override + public void removeUserResponse(QaUsrResp resp) { + auditService.logChange(QaAppConstants.MY_SIGNATURE, resp.getQaQueUser().getQueUsrId(), + resp.getQaQueUser().getUsername(), resp.getAnswer(), null); + qaUsrRespDAO.removeUserResponse(resp); + } + + @Override + public void updateResponseVisibility(Long responseUid, boolean isHideItem) { + + QaUsrResp response = getResponseById(responseUid); + if (response != null) { + // createBy should be null for system default value. + Long userId = 0L; + String loginName = "No user"; + if (response.getQaQueUser() != null) { + userId = response.getQaQueUser().getQueUsrId(); + loginName = response.getQaQueUser().getUsername(); + } + if (isHideItem) { + auditService.logHideEntry(QaAppConstants.MY_SIGNATURE, userId, loginName, response.getAnswer()); + } else { + auditService.logShowEntry(QaAppConstants.MY_SIGNATURE, userId, loginName, response.getAnswer()); + } + response.setVisible(!isHideItem); + updateUserResponse(response); + } + } + + @Override + public List getAllQuestionEntries(final Long uid) { + return qaQuestionDAO.getAllQuestionEntries(uid.longValue()); + } + + @Override + public List getAllQuestionEntriesSorted(final long contentUid) { + return qaQuestionDAO.getAllQuestionEntriesSorted(contentUid); + } + + @Override + public void removeQuestion(QaQueContent question) { + qaQuestionDAO.removeQaQueContent(question); + } + + @Override + public boolean isStudentActivityOccurredGlobal(QaContent qaContent) { + int countResponses = 0; + if (qaContent != null) { + countResponses = qaUsrRespDAO.getCountResponsesByQaContent(qaContent.getQaContentId()); + } + return countResponses > 0; + } + + @Override + public void recalculateUserAnswers(QaContent content, Set oldQuestions, + List questionDTOs, List deletedQuestions) { + + // create list of modified questions + List modifiedQuestions = new ArrayList(); + for (QaQueContent oldQuestion : oldQuestions) { + for (QaQuestionDTO questionDTO : questionDTOs) { + if (oldQuestion.getUid().equals(questionDTO.getUid())) { + + // question is different + if (!oldQuestion.getQuestion().equals(questionDTO.getQuestion())) { + modifiedQuestions.add(questionDTO); + } + } + } + } + + Set sessionList = content.getQaSessions(); + for (QaSession session : sessionList) { + Long toolSessionId = session.getQaSessionId(); + Set sessionUsers = session.getQaQueUsers(); + + for (QaQueUsr user : sessionUsers) { + + // get all finished user results + List userAttempts = qaUsrRespDAO.getResponsesByUserUid(user.getUid()); + Iterator iter = userAttempts.iterator(); + while (iter.hasNext()) { + QaUsrResp resp = iter.next(); + + QaQueContent question = resp.getQaQuestion(); + + boolean isRemoveQuestionResult = false; + + // [+] if the question is modified + for (QaQuestionDTO modifiedQuestion : modifiedQuestions) { + if (question.getUid().equals(modifiedQuestion.getUid())) { + isRemoveQuestionResult = true; + break; + } + } + + // [+] if the question was removed + for (QaQuestionDTO deletedQuestion : deletedQuestions) { + if (question.getUid().equals(deletedQuestion.getUid())) { + isRemoveQuestionResult = true; + break; + } + } + + if (isRemoveQuestionResult) { + iter.remove(); + qaUsrRespDAO.removeUserResponse(resp); + } + + // [+] doing nothing if the new question was added + + } + + } + } + + } + + @Override + public void resetDefineLater(Long toolContentId) throws DataMissingException, ToolException { + QaContent qaContent = qaDAO.getQaByContentId(toolContentId.longValue()); + if (qaContent == null) { + logger.error("throwing DataMissingException: WARNING!: retrieved qaContent is null."); + throw new DataMissingException("qaContent is missing"); + } + qaContent.setDefineLater(false); + updateQaContent(qaContent); + } + + @Override + public void copyToolContent(Long fromContentId, Long toContentId) { + long defaultContentId = 0; + if (fromContentId == null) { + defaultContentId = getToolDefaultContentIdBySignature(QaAppConstants.MY_SIGNATURE); + fromContentId = new Long(defaultContentId); + } + + if (toContentId == null) { + logger.error("throwing ToolException: toContentId is null"); + throw new ToolException("toContentId is missing"); + } + + QaContent fromContent = qaDAO.getQaByContentId(fromContentId.longValue()); + + if (fromContent == null) { + defaultContentId = getToolDefaultContentIdBySignature(QaAppConstants.MY_SIGNATURE); + fromContentId = new Long(defaultContentId); + + fromContent = qaDAO.getQaByContentId(fromContentId.longValue()); + } + QaContent toContent = QaContent.newInstance(fromContent, toContentId); + if (toContent == null) { + logger.error("throwing ToolException: WARNING!, retrieved toContent is null."); + throw new ToolException("WARNING! Fail to create toContent. Can't continue!"); + } else { + // save questions first, because if Hibernate decides to flush Conditions first, + // there is no cascade to questions and it may trigger an error + for (QaQueContent question : toContent.getQaQueContents()) { + qaQuestionDAO.saveOrUpdateQaQueContent(question); + } + qaDAO.saveQa(toContent); + } + + } + + @SuppressWarnings("unchecked") + @Override + public void removeToolContent(Long toolContentId) throws ToolException { + QaContent qaContent = qaDAO.getQaByContentId(toolContentId.longValue()); + if (qaContent == null) { + logger.warn("Can not remove the tool content as it does not exist, ID: " + toolContentId); + return; + } + + for (QaSession session : (Set) qaContent.getQaSessions()) { + List entries = coreNotebookService.getEntry(session.getQaSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, QaAppConstants.MY_SIGNATURE); + for (NotebookEntry entry : entries) { + coreNotebookService.deleteEntry(entry); + } + } + + qaDAO.removeQa(toolContentId); + } + + @Override + @SuppressWarnings("unchecked") + public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException { + if (logger.isDebugEnabled()) { + logger.debug("Removing Q&A answers for user ID " + userId + " and toolContentId " + toolContentId); + } + + QaContent content = qaDAO.getQaByContentId(toolContentId); + if (content != null) { + for (QaSession session : (Set) content.getQaSessions()) { + QaQueUsr user = qaQueUsrDAO.getQaUserBySession(userId.longValue(), session.getQaSessionId()); + if (user != null) { + for (QaUsrResp response : (Set) user.getQaUsrResps()) { + qaUsrRespDAO.removeUserResponse(response); + } + + if ((session.getGroupLeader() != null) && session.getGroupLeader().getUid().equals(user.getUid())) { + session.setGroupLeader(null); + } + + qaQueUsrDAO.deleteQaQueUsr(user); + + NotebookEntry entry = getEntry(session.getQaSessionId(), CoreNotebookConstants.NOTEBOOK_TOOL, + QaAppConstants.MY_SIGNATURE, userId); + if (entry != null) { + qaDAO.delete(entry); + } + } + } + } + } + + @Override + public List getUserReflectionsForTablesorter(Long toolSessionId, int page, int size, int sorting, + String searchString) { + return qaQueUsrDAO.getUserReflectionsForTablesorter(toolSessionId, page, size, sorting, searchString, + getCoreNotebookService()); + } + + @Override + public int getCountUsersBySessionWithSearch(Long toolSessionId, String searchString) { + return qaQueUsrDAO.getCountUsersBySessionWithSearch(toolSessionId, searchString); + } + + @Override + public void notifyTeachersOnResponseSubmit(Long sessionId) { + final String NEW_LINE_CHARACTER = "
"; + + HttpSession ss = SessionManager.getSession(); + UserDTO userDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = new Long(userDto.getUserID().longValue()); + QaQueUsr user = getUserByIdAndSession(userId, new Long(sessionId)); + String fullName = user.getFullname(); + + // add question-answer pairs to email message + List responses = qaUsrRespDAO.getResponsesByUserUid(user.getUid()); + Date attemptTime = new Date(); + String message = new String(); + for (QaUsrResp response : responses) { + String question = response.getQaQuestion().getQuestion(); + String answer = response.getAnswer(); + + message += NEW_LINE_CHARACTER + NEW_LINE_CHARACTER + question + " " + answer; + attemptTime = response.getAttemptTime(); + } + + message = NEW_LINE_CHARACTER + NEW_LINE_CHARACTER + + messageService.getMessage("label.user.has.answered.questions", new Object[] { fullName, attemptTime }) + + message + NEW_LINE_CHARACTER + NEW_LINE_CHARACTER; + + eventNotificationService.notifyLessonMonitors(sessionId, message, true); + } + + @Override + public void exportToolContent(Long toolContentID, String rootPath) { + QaContent toolContentObj = qaDAO.getQaByContentId(toolContentID); + if (toolContentObj == null) { + long defaultToolContentId = toolService.getToolDefaultContentIdBySignature(QaAppConstants.MY_SIGNATURE); + toolContentObj = getQaContent(defaultToolContentId); + } + if (toolContentObj == null) { + throw new DataMissingException("Unable to find default content for the question and answer tool"); + } + + try { + // set ToolContentHandler as null to avoid copy file node in + // repository again. + toolContentObj = QaContent.newInstance(toolContentObj, toolContentID); + + // don't export following fields value + toolContentObj.setQaSessions(null); + Set questions = toolContentObj.getQaQueContents(); + for (QaQueContent question : questions) { + question.setQaContent(null); + } + for (LearnerItemRatingCriteria criteria : toolContentObj.getRatingCriterias()) { + criteria.setToolContentId(null); + } + + exportContentService.exportToolContent(toolContentID, toolContentObj, qaToolContentHandler, rootPath); + } catch (ExportToolContentException e) { + throw new ToolException(e); + } + } + + @Override + public void importToolContent(Long toolContentID, Integer newUserUid, String toolContentPath, String fromVersion, + String toVersion) throws ToolException { + try { + // register version filter class + exportContentService.registerImportVersionFilterClass(QaImportContentVersionFilter.class); + + Object toolPOJO = exportContentService.importToolContent(toolContentPath, qaToolContentHandler, fromVersion, + toVersion); + if (!(toolPOJO instanceof QaContent)) { + throw new ImportToolContentException( + "Import QA tool content failed. Deserialized object is " + toolPOJO); + } + QaContent toolContentObj = (QaContent) toolPOJO; + + // reset it to new toolContentID + toolContentObj.setQaContentId(toolContentID); + toolContentObj.setCreatedBy(newUserUid); + Set criterias = toolContentObj.getRatingCriterias(); + if (criterias != null) { + for (LearnerItemRatingCriteria criteria : toolContentObj.getRatingCriterias()) { + criteria.setToolContentId(toolContentID); + if (criteria.getMaxRating() == null || criteria.getRatingStyle() == null) { + if (criteria.getOrderId() == 0) { + criteria.setMaxRating(0); + criteria.setRatingStyle(RatingCriteria.RATING_STYLE_COMMENT); + } else { + criteria.setMaxRating(RatingCriteria.RATING_STYLE_STAR_DEFAULT_MAX); + criteria.setRatingStyle(RatingCriteria.RATING_STYLE_STAR); + } + } + } + } + + // set back the tool content + Set questions = toolContentObj.getQaQueContents(); + for (QaQueContent question : questions) { + question.setQaContent(toolContentObj); + } + qaDAO.saveOrUpdateQa(toolContentObj); + } catch (ImportToolContentException e) { + throw new ToolException(e); + } + } + + @Override + public SortedMap getToolOutputDefinitions(Long toolContentId, int definitionType) + throws ToolException { + QaContent qaContent = qaDAO.getQaByContentId(toolContentId); + if (qaContent == null) { + long defaultToolContentId = toolService.getToolDefaultContentIdBySignature(QaAppConstants.MY_SIGNATURE); + qaContent = getQaContent(defaultToolContentId); + } + return getQaOutputFactory().getToolOutputDefinitions(qaContent, definitionType); + } + + @Override + public String getToolContentTitle(Long toolContentId) { + return qaDAO.getQaByContentId(toolContentId).getTitle(); + } + + @Override + public boolean isContentEdited(Long toolContentId) { + return qaDAO.getQaByContentId(toolContentId).isDefineLater(); + } + + @Override + public boolean isReadOnly(Long toolContentId) { + QaContent content = qaDAO.getQaByContentId(toolContentId); + for (QaSession session : (Set) content.getQaSessions()) { + if (!session.getQaQueUsers().isEmpty()) { + return true; + } + } + + return false; + } + + @Override + public void createToolSession(Long toolSessionId, String toolSessionName, Long toolContentID) throws ToolException { + + if (toolSessionId == null) { + logger.error("toolSessionId is null"); + throw new ToolException("toolSessionId is missing"); + } + + QaContent qaContent = qaDAO.getQaByContentId(toolContentID.longValue()); + + /* + * create a new a new tool session if it does not already exist in the tool session table + */ + QaSession qaSession = getSessionById(toolSessionId); + if (qaSession == null) { + try { + qaSession = new QaSession(toolSessionId, new Date(System.currentTimeMillis()), QaSession.INCOMPLETE, + toolSessionName, qaContent, new TreeSet()); + qaSessionDAO.createSession(qaSession); + } catch (Exception e) { + logger.error("Error creating new toolsession in the db"); + throw new ToolException("Error creating new toolsession in the db: " + e); + } + } + } + + @Override + public void removeToolSession(Long toolSessionId) throws DataMissingException, ToolException { + if (toolSessionId == null) { + logger.error("toolSessionId is null"); + throw new DataMissingException("toolSessionId is missing"); + } + + QaSession qaSession = null; + try { + qaSession = getSessionById(toolSessionId.longValue()); + } catch (QaApplicationException e) { + throw new DataMissingException("error retrieving qaSession: " + e); + } catch (Exception e) { + throw new ToolException("error retrieving qaSession: " + e); + } + + if (qaSession == null) { + logger.error("qaSession is null"); + throw new DataMissingException("qaSession is missing"); + } + + try { + qaSessionDAO.deleteQaSession(qaSession); + } catch (QaApplicationException e) { + throw new ToolException("error deleting qaSession:" + e); + } + } + + @Override + public String leaveToolSession(Long toolSessionId, Long learnerId) throws DataMissingException, ToolException { + + if (toolSessionId == null) { + logger.error("toolSessionId is null"); + throw new DataMissingException("toolSessionId is missing"); + } + + if (learnerId == null) { + logger.error("learnerId is null"); + throw new DataMissingException("learnerId is missing"); + } + + QaSession qaSession = getSessionById(toolSessionId.longValue()); + qaSession.setSession_end_date(new Date(System.currentTimeMillis())); + qaSession.setSession_status(QaAppConstants.COMPLETED); + updateSession(qaSession); + + try { + String nextUrl = learnerService.completeToolSession(toolSessionId, learnerId); + return nextUrl; + } catch (DataAccessException e) { + throw new ToolException("Exception occured when user is leaving tool session: " + e); + } + + } + + @Override + public List getRatingCriterias(Long toolContentId) { + return ratingService.getCriteriasByToolContentId(toolContentId); + } + + @Override + public void saveRatingCriterias(HttpServletRequest request, Collection oldCriterias, + Long toolContentId) { + ratingService.saveRatingCriterias(request, oldCriterias, toolContentId); + } + + @Override + public boolean isCommentsEnabled(Long toolContentId) { + return ratingService.isCommentsEnabled(toolContentId); + } + + @Override + public boolean isRatingsEnabled(QaContent qaContent) { + //check if allow rate answers is ON and also that there is at least one non-comments rating criteria available + boolean allowRateAnswers = false; + if (qaContent.isAllowRateAnswers()) { + List ratingCriterias = getRatingCriterias(qaContent.getQaContentId()); + for (RatingCriteria ratingCriteria : ratingCriterias) { + if (!ratingCriteria.isCommentsEnabled()) { + allowRateAnswers = true; + break; + } + } + } + return allowRateAnswers; + } + + @Override + public List getRatingCriteriaDtos(Long contentId, Long toolSessionId, Collection itemIds, + boolean isCommentsByOtherUsersRequired, Long userId) { + return ratingService.getRatingCriteriaDtos(contentId, toolSessionId, itemIds, isCommentsByOtherUsersRequired, + userId); + } + + @Override + public int getCountItemsRatedByUser(Long toolContentId, Integer userId) { + return ratingService.getCountItemsRatedByUser(toolContentId, userId); + } + + /** + * ToolSessionManager CONTRACT + */ + @Override + public ToolSessionExportOutputData exportToolSession(Long toolSessionId) + throws DataMissingException, ToolException { + throw new ToolException("not yet implemented"); + } + + /** + * ToolSessionManager CONTRACT + */ + @Override + public ToolSessionExportOutputData exportToolSession(List toolSessionIds) + throws DataMissingException, ToolException { + throw new ToolException("not yet implemented"); + } + + @Override + public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { + return getQaOutputFactory().getToolOutput(names, this, toolSessionId, learnerId); + } + + @Override + public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { + return getQaOutputFactory().getToolOutput(name, this, toolSessionId, learnerId); + } + + @Override + public List getToolOutputs(String name, Long toolContentId) { + return new ArrayList(); + } + + @Override + public void forceCompleteUser(Long toolSessionId, User user) { + Long userId = user.getUserId().longValue(); + + QaSession session = getSessionById(toolSessionId); + if ((session == null) || (session.getQaContent() == null)) { + return; + } + QaContent content = session.getQaContent(); + + // copy answers only in case leader aware feature is ON + if (content.isUseSelectLeaderToolOuput()) { + + QaQueUsr qaUser = getUserByIdAndSession(userId, toolSessionId); + // create user if he hasn't accessed this activity yet + if (qaUser == null) { + + String userName = user.getLogin(); + String fullName = user.getFirstName() + " " + user.getLastName(); + qaUser = new QaQueUsr(userId, userName, fullName, session, new TreeSet()); + qaQueUsrDAO.createUsr(qaUser); + } + + QaQueUsr groupLeader = session.getGroupLeader(); + + // check if leader has submitted answers + if ((groupLeader != null) && groupLeader.isResponseFinalized()) { + + // we need to make sure specified user has the same scratches as a leader + copyAnswersFromLeader(qaUser, groupLeader); + } + + } + + } + + @Override + public IToolVO getToolBySignature(String toolSignature) { + IToolVO tool = toolService.getToolBySignature(toolSignature); + return tool; + } + + @Override + public long getToolDefaultContentIdBySignature(String toolSignature) { + long contentId = 0; + contentId = toolService.getToolDefaultContentIdBySignature(toolSignature); + return contentId; + } + + @Override + public Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry) { + return coreNotebookService.createNotebookEntry(id, idType, signature, userID, "", entry); + } + + @Override + public NotebookEntry getEntry(Long id, Integer idType, String signature, Integer userID) { + + List list = coreNotebookService.getEntry(id, idType, signature, userID); + if ((list == null) || list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public boolean isGroupedActivity(long toolContentID) { + return toolService.isGroupedActivity(toolContentID); + } + + @Override + public void auditLogStartEditingActivityInMonitor(long toolContentID) { + toolService.auditLogStartEditingActivityInMonitor(toolContentID); + } + + @Override + public String getLearnerContentFolder(Long toolSessionId, Long userId) { + return toolService.getLearnerContentFolder(toolSessionId, userId); + } + + /** + * @return Returns the userManagementService. + */ + public IUserManagementService getUserManagementService() { + return userManagementService; + } + + public void setLearnerService(ILearnerService learnerService) { + this.learnerService = learnerService; + } + + public void setQaDAO(IQaContentDAO qaDAO) { + this.qaDAO = qaDAO; + } + + public void setQaQuestionDAO(IQaQuestionDAO qaQuestionDAO) { + this.qaQuestionDAO = qaQuestionDAO; + } + + public void setQaSessionDAO(IQaSessionDAO qaSessionDAO) { + this.qaSessionDAO = qaSessionDAO; + } + + public void setQaQueUsrDAO(IQaQueUsrDAO qaQueUsrDAO) { + this.qaQueUsrDAO = qaQueUsrDAO; + } + + public void setQaUsrRespDAO(IQaUsrRespDAO qaUsrRespDAO) { + this.qaUsrRespDAO = qaUsrRespDAO; + } + + /** + * @return Returns the qaDAO. + */ + public IQaContentDAO getQaDAO() { + return qaDAO; + } + + public void setUserManagementService(IUserManagementService userManagementService) { + this.userManagementService = userManagementService; + } + + public void setToolService(ILamsToolService toolService) { + this.toolService = toolService; + } + + /** + * @param qaToolContentHandler + * The qaToolContentHandler to set. + */ + public void setQaToolContentHandler(IToolContentHandler qaToolContentHandler) { + this.qaToolContentHandler = qaToolContentHandler; + } + + @Override + public IAuditService getAuditService() { + return auditService; + } + + public void setAuditService(IAuditService auditService) { + this.auditService = auditService; + } + + public IExportToolContentService getExportContentService() { + return exportContentService; + } + + public void setExportContentService(IExportToolContentService exportContentService) { + this.exportContentService = exportContentService; + } + + // ========================================================================================= + /** + * @return Returns the coreNotebookService. + */ + public ICoreNotebookService getCoreNotebookService() { + return coreNotebookService; + } + + /** + * @param coreNotebookService + * The coreNotebookService to set. + */ + public void setCoreNotebookService(ICoreNotebookService coreNotebookService) { + this.coreNotebookService = coreNotebookService; + } + + public void setRatingService(IRatingService ratingService) { + this.ratingService = ratingService; + } + + public void setEventNotificationService(IEventNotificationService eventNotificationService) { + this.eventNotificationService = eventNotificationService; + } + + public void setMessageService(MessageService messageService) { + this.messageService = messageService; + } + + @Override + public void updateEntry(NotebookEntry notebookEntry) { + coreNotebookService.updateEntry(notebookEntry); + } + + public QaOutputFactory getQaOutputFactory() { + return qaOutputFactory; + } + + public void setQaOutputFactory(QaOutputFactory qaOutputFactory) { + this.qaOutputFactory = qaOutputFactory; + } + + public IQaConfigItemDAO getQaConfigItemDAO() { + return qaConfigItemDAO; + } + + public void setQaConfigItemDAO(IQaConfigItemDAO qaConfigItemDAO) { + this.qaConfigItemDAO = qaConfigItemDAO; + } + + public IQaWizardDAO getQaWizardDAO() { + return qaWizardDAO; + } + + public void setQaWizardDAO(IQaWizardDAO qaWizardDAO) { + this.qaWizardDAO = qaWizardDAO; + } + + @Override + public QaContent getQaContentBySessionId(Long sessionId) { + QaSession session = qaSessionDAO.getQaSessionById(sessionId); + // to skip CGLib problem + Long contentId = session.getQaContent().getQaContentId(); + QaContent qaContent = qaDAO.getQaByContentId(contentId); + return qaContent; + } + + @Override + public String createConditionName(Collection existingConditions) { + String uniqueNumber = null; + do { + uniqueNumber = String.valueOf(Math.abs(generator.nextInt())); + for (QaCondition condition : existingConditions) { + String[] splitedName = getQaOutputFactory().splitConditionName(condition.getName()); + if (uniqueNumber.equals(splitedName[1])) { + uniqueNumber = null; + } + } + } while (uniqueNumber == null); + return getQaOutputFactory().buildUserAnswersConditionName(uniqueNumber); + } + + @Override + public void deleteCondition(QaCondition condition) { + if ((condition != null) && (condition.getConditionId() != null)) { + qaDAO.deleteCondition(condition); + } + } + + @Override + public QaConfigItem getConfigItem(String configKey) { + return qaConfigItemDAO.getConfigItemByKey(configKey); + } + + @Override + public void saveOrUpdateConfigItem(QaConfigItem configItem) { + qaConfigItemDAO.saveOrUpdate(configItem); + } + + @Override + public SortedSet getWizardCategories() { + return qaWizardDAO.getWizardCategories(); + } + + @Override + public void saveOrUpdateQaWizardCategories(SortedSet categories) { + qaWizardDAO.saveOrUpdateCategories(categories); + } + + @Override + public void deleteWizardCategoryByUID(Long uid) { + qaWizardDAO.deleteWizardCategoryByUID(uid); + } + + @Override + public void deleteWizardSkillByUID(Long uid) { + qaWizardDAO.deleteWizardSkillByUID(uid); + } + + @Override + public void deleteWizardQuestionByUID(Long uid) { + qaWizardDAO.deleteWizardQuestionByUID(uid); + } + + @Override + public void deleteAllWizardCategories() { + qaWizardDAO.deleteAllWizardCategories(); + } + + @Override + public void removeQuestionsFromCache(QaContent qaContent) { + qaDAO.removeQuestionsFromCache(qaContent); + } + + @Override + public void removeQaContentFromCache(QaContent qaContent) { + qaDAO.removeQaContentFromCache(qaContent); + } + + @Override + public Class[] getSupportedToolOutputDefinitionClasses(int definitionType) { + return getQaOutputFactory().getSupportedDefinitionClasses(definitionType); + } + + @Override + public ToolCompletionStatus getCompletionStatus(Long learnerId, Long toolSessionId) { + QaQueUsr learner = qaQueUsrDAO.getQaUserBySession(learnerId, toolSessionId); + if (learner == null) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); + } + + Date startDate = null; + Date endDate = null; + Set attempts = learner.getQaUsrResps(); + for (QaUsrResp item : attempts) { + Date newDate = item.getAttemptTime(); + if (newDate != null) { + if (startDate == null || newDate.before(startDate)) { + startDate = newDate; + } + if (endDate == null || newDate.after(endDate)) { + endDate = newDate; + } + } + } + + if (learner.isLearnerFinished()) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, startDate, endDate); + } else { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, startDate, null); + } + } + // ****************** REST methods ************************* + + /** + * Rest call to create a new Q&A content. Required fields in toolContentJSON: title, instructions, questions. The + * questions entry should be ArrayNode containing JSON objects, which in turn must contain "questionText", + * "displayOrder" and may also contain feedback and required (boolean) + */ + @Override + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { + + QaContent qa = new QaContent(); + Date updateDate = new Date(); + + qa.setCreationDate(updateDate); + qa.setUpdateDate(updateDate); + qa.setCreatedBy(userID.longValue()); + + qa.setQaContentId(toolContentID); + qa.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + qa.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); + + qa.setDefineLater(false); + + qa.setLockWhenFinished(JsonUtil.optBoolean(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); + qa.setNoReeditAllowed(JsonUtil.optBoolean(toolContentJSON, "noReeditAllowed", Boolean.FALSE)); + qa.setAllowRichEditor(JsonUtil.optBoolean(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); + qa.setUseSelectLeaderToolOuput( + JsonUtil.optBoolean(toolContentJSON, RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, Boolean.FALSE)); + qa.setMinimumRates(JsonUtil.optInt(toolContentJSON, RestTags.MINIMUM_RATES, 0)); + qa.setMaximumRates(JsonUtil.optInt(toolContentJSON, RestTags.MAXIMUM_RATES, 0)); + qa.setShowOtherAnswers(JsonUtil.optBoolean(toolContentJSON, "showOtherAnswers", Boolean.TRUE)); + qa.setUsernameVisible(JsonUtil.optBoolean(toolContentJSON, "usernameVisible", Boolean.FALSE)); + qa.setAllowRateAnswers(JsonUtil.optBoolean(toolContentJSON, "allowRateAnswers", Boolean.FALSE)); + qa.setNotifyTeachersOnResponseSubmit( + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnResponseSubmit", Boolean.FALSE)); + qa.setReflect(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + qa.setReflectionSubject(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + qa.setQuestionsSequenced(JsonUtil.optBoolean(toolContentJSON, "questionsSequenced", Boolean.FALSE)); + + // submissionDeadline is set in monitoring + // qa.setMonitoringReportTitle(); Can't find this field in the database - assuming unused. + // qa.setReportTitle(); Can't find this field in the database - assuming unused. + // qa.setContent(content); Can't find this field in the database - assuming unused. + + saveOrUpdateQaContent(qa); + // Questions + ArrayNode questions = JsonUtil.optArray(toolContentJSON, RestTags.QUESTIONS); + for (JsonNode questionData : questions) { + QaQueContent question = new QaQueContent(JsonUtil.optString(questionData, RestTags.QUESTION_TEXT), + JsonUtil.optInt(questionData, RestTags.DISPLAY_ORDER), JsonUtil.optString(questionData, "feedback"), + JsonUtil.optBoolean(questionData, "required", Boolean.FALSE), + JsonUtil.optInt(questionData, "minWordsLimit", 0), qa); + saveOrUpdateQuestion(question); + } + + // TODO + // qa.setConditions(conditions); + + } +} Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/action/QaLearningAction.java =================================================================== diff -u --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/action/QaLearningAction.java (revision 0) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/action/QaLearningAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,1223 @@ +/*************************************************************************** +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 version 2 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.qa.web.action; + +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.TreeMap; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.apache.struts.action.ActionRedirect; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.rating.dto.ItemRatingCriteriaDTO; +import org.lamsfoundation.lams.rating.dto.ItemRatingDTO; +import org.lamsfoundation.lams.rating.dto.RatingCommentDTO; +import org.lamsfoundation.lams.rating.model.LearnerItemRatingCriteria; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.qa.QaAppConstants; +import org.lamsfoundation.lams.tool.qa.QaContent; +import org.lamsfoundation.lams.tool.qa.QaQueContent; +import org.lamsfoundation.lams.tool.qa.QaQueUsr; +import org.lamsfoundation.lams.tool.qa.QaSession; +import org.lamsfoundation.lams.tool.qa.QaUsrResp; +import org.lamsfoundation.lams.tool.qa.dto.GeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; +import org.lamsfoundation.lams.tool.qa.service.IQaService; +import org.lamsfoundation.lams.tool.qa.service.QaServiceProxy; +import org.lamsfoundation.lams.tool.qa.util.LearningUtil; +import org.lamsfoundation.lams.tool.qa.util.QaComparator; +import org.lamsfoundation.lams.tool.qa.util.QaStringComparator; +import org.lamsfoundation.lams.tool.qa.web.form.QaLearningForm; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.ValidationUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.web.util.SessionMap; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Ozgur Demirtas + */ +public class QaLearningAction extends LamsDispatchAction implements QaAppConstants { + private static Logger logger = Logger.getLogger(QaLearningAction.class.getName()); + + private static IQaService qaService; + + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + QaLearningAction.logger.warn("dispatching unspecified..."); + return null; + } + + /** + * submits users responses + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward submitAnswersContent(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("learningStarter")); + redirect.addParameter(AttributeNames.PARAM_TOOL_SESSION_ID, toolSessionID); + redirect.addParameter(QaAppConstants.MODE, "learner"); + return redirect; + } + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + String totalQuestionCount = generalLearnerFlowDTO.getTotalQuestionCount().toString(); + int intTotalQuestionCount = new Integer(totalQuestionCount).intValue(); + + String questionListingMode = generalLearnerFlowDTO.getQuestionListingMode(); + + Map mapAnswers = new TreeMap(new QaComparator()); + Map mapAnswersPresentable = new TreeMap(new QaComparator()); + + String forwardName = QaAppConstants.INDIVIDUAL_LEARNER_RESULTS; + ActionMessages errors = new ActionMessages(); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + /* if the listing mode is QUESTION_LISTING_MODE_COMBINED populate the answers here */ + if (questionListingMode.equalsIgnoreCase(QaAppConstants.QUESTION_LISTING_MODE_COMBINED)) { + + for (int questionIndex = QaAppConstants.INITIAL_QUESTION_COUNT + .intValue(); questionIndex <= intTotalQuestionCount; questionIndex++) { + // TestHarness can not send "answerX" fields, so stick to the original, unfiltered field + boolean isTestHarness = Boolean.valueOf(request.getParameter("testHarness")); + String answerParamName = "answer" + questionIndex + (isTestHarness ? "__textarea" : ""); + String answer = request.getParameter(answerParamName); + + Integer questionIndexInteger = new Integer(questionIndex); + mapAnswers.put(questionIndexInteger.toString(), answer); + mapAnswersPresentable.put(questionIndexInteger.toString(), answer); + + //validate + ActionMessages newErrors = validateQuestionAnswer(answer, questionIndexInteger, generalLearnerFlowDTO); + errors.add(newErrors); + + // store + if (errors.isEmpty()) { + QaLearningAction.qaService.updateResponseWithNewAnswer(answer, toolSessionID, + new Long(questionIndex), false); + } + } + + } else { + Object[] results = storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, true); + mapAnswers = (Map) results[0]; + errors = (ActionMessages) results[1]; + + mapAnswersPresentable = (Map) sessionMap.get(QaAppConstants.MAP_ALL_RESULTS_KEY); + mapAnswersPresentable = QaLearningAction.removeNewLinesMap(mapAnswersPresentable); + } + + //finalize response so user won't need to edit his answers again, if coming back to the activity after leaving activity at this point + if (errors.isEmpty()) { + qaQueUsr.setResponseFinalized(true); + QaLearningAction.qaService.updateUser(qaQueUsr); + + //in case of errors - prompt learner to enter answers again + } else { + saveErrors(request, errors); + forwardName = QaAppConstants.LOAD_LEARNER; + } + + generalLearnerFlowDTO.setMapAnswers(mapAnswers); + generalLearnerFlowDTO.setMapAnswersPresentable(mapAnswersPresentable); + + /* mapAnswers will be used in the viewAllAnswers screen */ + if (sessionMap == null) { + sessionMap = new SessionMap(); + } + + sessionMap.put(QaAppConstants.MAP_ALL_RESULTS_KEY, mapAnswers); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + qaLearningForm.resetAll(); + generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); + + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + // notify teachers on response submit + if (errors.isEmpty() && qaContent.isNotifyTeachersOnResponseSubmit()) { + qaService.notifyTeachersOnResponseSubmit(new Long(toolSessionID)); + } + + return (mapping.findForward(forwardName)); + } + + public ActionForward checkLeaderProgress(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + Long toolSessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + + QaSession session = qaService.getSessionById(toolSessionId); + QaQueUsr leader = session.getGroupLeader(); + + boolean isLeaderResponseFinalized = leader.isResponseFinalized(); + + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put("isLeaderResponseFinalized", isLeaderResponseFinalized); + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(ObjectNode); + return null; + } + + /** + * auto saves responses + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward autoSaveAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from autosaving answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + return null; + } + + LearningUtil.saveFormRequestData(request, qaLearningForm); + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + int intTotalQuestionCount = qaContent.getQaQueContents().size(); + + if (!qaContent.isQuestionsSequenced()) { + + for (int questionIndex = QaAppConstants.INITIAL_QUESTION_COUNT + .intValue(); questionIndex <= intTotalQuestionCount; questionIndex++) { + String newAnswer = request.getParameter("answer" + questionIndex); + QaLearningAction.qaService.updateResponseWithNewAnswer(newAnswer, toolSessionID, + new Long(questionIndex), true); + } + + } else { + String currentQuestionIndex = qaLearningForm.getCurrentQuestionIndex(); + String newAnswer = qaLearningForm.getAnswer(); + QaQueContent currentQuestion = QaLearningAction.qaService + .getQuestionByContentAndDisplayOrder(new Long(currentQuestionIndex), qaContent.getUid()); + + boolean isRequiredQuestionMissed = currentQuestion.isRequired() && isEmpty(newAnswer); + if (!isRequiredQuestionMissed) { + QaLearningAction.qaService.updateResponseWithNewAnswer(newAnswer, toolSessionID, + new Long(currentQuestionIndex), true); + } + } + return null; + } + + /** + * enables retaking the activity + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward redoQuestions(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + qaLearningForm.setCurrentQuestionIndex(new Integer(1).toString()); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); + generalLearnerFlowDTO.setToolContentID(qaContent.getQaContentId().toString()); + + // create mapQuestions + Map mapQuestions = generalLearnerFlowDTO.getMapQuestionContentLearner(); + generalLearnerFlowDTO.setMapQuestions(mapQuestions); + generalLearnerFlowDTO.setTotalQuestionCount(new Integer(mapQuestions.size())); + generalLearnerFlowDTO.setRemainingQuestionCount(new Integer(mapQuestions.size()).toString()); + qaLearningForm.setTotalQuestionCount(new Integer(mapQuestions.size()).toString()); + + //in order to track whether redo button is pressed store this info + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + qaQueUsr.setResponseFinalized(false); + QaLearningAction.qaService.updateUser(qaQueUsr); + + // populate answers + LearningUtil.populateAnswers(sessionMap, qaContent, qaQueUsr, mapQuestions, generalLearnerFlowDTO, + QaLearningAction.qaService); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + qaLearningForm.resetAll(); + return (mapping.findForward(QaAppConstants.LOAD_LEARNER)); + } + + /** + * Stores all results and moves onto the next step. If view other users answers = true, then goes to the view all + * answers screen, otherwise goes straight to the reflection screen (if any). + * + * @return Learner Report for a session + * @throws IOException + * @throws ServletException + */ + public ActionForward storeAllResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + String userID = request.getParameter("userID"); + QaQueUsr user = qaService.getUserByIdAndSession(new Long(userID), new Long(toolSessionID)); + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + // LearningUtil.storeResponses(mapAnswers, qaService, toolContentID, new Long(toolSessionID)); + + qaLearningForm.resetUserActions(); + qaLearningForm.setSubmitAnswersContent(null); + + if (qaContent.isShowOtherAnswers()) { + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + String httpSessionID = qaLearningForm.getHttpSessionID(); + generalLearnerFlowDTO.setHttpSessionID(httpSessionID); + + /** Set up the data for the view all answers screen */ + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, QaLearningAction.qaService, + httpSessionID, user, generalLearnerFlowDTO); + + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(false).toString()); + + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + + qaLearningForm.resetAll(); + + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + + boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); + generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); + + boolean allowRichEditor = qaContent.isAllowRichEditor(); + generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); + generalLearnerFlowDTO.setUserUid(user.getQueUsrId().toString()); + + boolean usernameVisible = qaContent.isUsernameVisible(); + generalLearnerFlowDTO.setUserNameVisible(new Boolean(usernameVisible).toString()); + + NotebookEntry notebookEntry = QaLearningAction.qaService.getEntry(new Long(toolSessionID), + CoreNotebookConstants.NOTEBOOK_TOOL, QaAppConstants.MY_SIGNATURE, new Integer(userID)); + + if (notebookEntry != null) { + // String notebookEntryPresentable=QaUtils.replaceNewLines(notebookEntry.getEntry()); + String notebookEntryPresentable = notebookEntry.getEntry(); + qaLearningForm.setEntryText(notebookEntryPresentable); + } + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + return (mapping.findForward(QaAppConstants.LEARNER_REP)); + + } else if (qaContent.isReflect()) { + return forwardtoReflection(mapping, request, qaContent, toolSessionID, userID, qaLearningForm); + + } else { + return endLearning(mapping, qaLearningForm, request, response); + } + } + + /** + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward refreshAllResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + QaQueUsr user = qaService.getUserByIdAndSession(new Long(userID), new Long(toolSessionID)); + + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaContent qaContent = qaSession.getQaContent(); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + qaLearningForm.setHttpSessionID(httpSessionID); + generalLearnerFlowDTO.setHttpSessionID(httpSessionID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + /* recreate the users and responses */ + qaLearningForm.resetUserActions(); + qaLearningForm.setSubmitAnswersContent(null); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, QaLearningAction.qaService, httpSessionID, + user, generalLearnerFlowDTO); + + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(false).toString()); + + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + // generalLearnerFlowDTO.setNotebookEntriesVisible(new Boolean(false).toString()); + + qaLearningForm.resetAll(); + + boolean lockWhenFinished; + boolean noReeditAllowed; + if (sessionMap.get("noRefresh") != null && (boolean) sessionMap.get("noRefresh")) { + lockWhenFinished = true; + noReeditAllowed = true; + } else { + lockWhenFinished = qaContent.isLockWhenFinished(); + noReeditAllowed = qaContent.isNoReeditAllowed(); + } + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(noReeditAllowed); + + boolean allowRichEditor = qaContent.isAllowRichEditor(); + generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); + + boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); + generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + generalLearnerFlowDTO.setUserUid(qaQueUsr.getQueUsrId().toString()); + + boolean usernameVisible = qaContent.isUsernameVisible(); + generalLearnerFlowDTO.setUserNameVisible(new Boolean(usernameVisible).toString()); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return (mapping.findForward(QaAppConstants.LEARNER_REP)); + } + + /** + * moves to the next question and modifies the map ActionForward + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + public ActionForward getNextQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + String httpSessionID = qaLearningForm.getHttpSessionID(); + qaLearningForm.setHttpSessionID(httpSessionID); + + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("learningStarter")); + redirect.addParameter(AttributeNames.PARAM_TOOL_SESSION_ID, toolSessionID); + redirect.addParameter(QaAppConstants.MODE, "learner"); + return redirect; + } + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, true); + + qaLearningForm.resetAll(); + return (mapping.findForward(QaAppConstants.LOAD_LEARNER)); + } + + /** + * Get the answer from the form and copy into DTO. Set up the next question. If the current question is required and + * the answer is blank, then just persist the error and don't change questions. + * + * @param form + * @param request + * @param generalLearnerFlowDTO + * @param getNextQuestion + * @return + */ + private Object[] storeSequentialAnswer(ActionForm form, HttpServletRequest request, + GeneralLearnerFlowDTO generalLearnerFlowDTO, boolean getNextQuestion) { + QaLearningForm qaLearningForm = (QaLearningForm) form; + String httpSessionID = qaLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + String currentQuestionIndex = qaLearningForm.getCurrentQuestionIndex(); + + Map mapAnswers = (Map) sessionMap.get(QaAppConstants.MAP_ALL_RESULTS_KEY); + if (mapAnswers == null) { + mapAnswers = new TreeMap(new QaComparator()); + } + + String newAnswer = qaLearningForm.getAnswer(); + Map mapSequentialAnswers = (Map) sessionMap + .get(QaAppConstants.MAP_SEQUENTIAL_ANSWERS_KEY); + if (mapSequentialAnswers.size() >= new Integer(currentQuestionIndex).intValue()) { + mapSequentialAnswers.remove(new Long(currentQuestionIndex).toString()); + } + mapSequentialAnswers.put(new Long(currentQuestionIndex).toString(), newAnswer); + mapAnswers.put(currentQuestionIndex, newAnswer); + + int nextQuestionOffset = getNextQuestion ? 1 : -1; + + // validation only if trying to go to the next question + ActionMessages errors = new ActionMessages(); + if (getNextQuestion) { + errors = validateQuestionAnswer(newAnswer, new Integer(currentQuestionIndex), generalLearnerFlowDTO); + } + + // store + if (errors.isEmpty()) { + QaLearningAction.qaService.updateResponseWithNewAnswer(newAnswer, qaLearningForm.getToolSessionID(), + new Long(currentQuestionIndex), false); + } else { + saveErrors(request, errors); + nextQuestionOffset = 0; + } + + int intCurrentQuestionIndex = new Integer(currentQuestionIndex).intValue() + nextQuestionOffset; + String currentAnswer = ""; + if (mapAnswers.size() >= intCurrentQuestionIndex) { + currentAnswer = mapAnswers.get(new Long(intCurrentQuestionIndex).toString()); + } + generalLearnerFlowDTO.setCurrentAnswer(currentAnswer); + + // currentQuestionIndex will be: + generalLearnerFlowDTO.setCurrentQuestionIndex(new Integer(intCurrentQuestionIndex)); + + String totalQuestionCount = qaLearningForm.getTotalQuestionCount(); + + int remainingQuestionCount = new Long(totalQuestionCount).intValue() + - new Integer(currentQuestionIndex).intValue() + 1; + String userFeedback = ""; + if (remainingQuestionCount != 0) { + userFeedback = "Remaining question count: " + remainingQuestionCount; + } else { + userFeedback = "End of the questions."; + } + generalLearnerFlowDTO.setUserFeedback(userFeedback); + generalLearnerFlowDTO.setRemainingQuestionCount("" + remainingQuestionCount); + + qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + + sessionMap.put(QaAppConstants.MAP_ALL_RESULTS_KEY, mapAnswers); + sessionMap.put(QaAppConstants.MAP_SEQUENTIAL_ANSWERS_KEY, mapSequentialAnswers); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return new Object[] { mapSequentialAnswers, errors }; + } + + private ActionMessages validateQuestionAnswer(String newAnswer, Integer questionIndex, + GeneralLearnerFlowDTO generalLearnerFlowDTO) { + ActionMessages errors = new ActionMessages(); + + Map questionMap = generalLearnerFlowDTO.getMapQuestionContentLearner(); + QaQuestionDTO dto = questionMap.get(questionIndex); + + // if so, check if the answer is blank and generate an error if it is blank. + boolean isRequiredQuestionMissed = dto.isRequired() && isEmpty(newAnswer); + if (isRequiredQuestionMissed) { + errors.add(Globals.ERROR_KEY, new ActionMessage("error.required", questionIndex)); + } + + boolean isMinWordsLimitReached = ValidationUtil.isMinWordsLimitReached(newAnswer, dto.getMinWordsLimit(), + Boolean.parseBoolean(generalLearnerFlowDTO.getAllowRichEditor())); + if (!isMinWordsLimitReached) { + errors.add(Globals.ERROR_KEY, + new ActionMessage("label.minimum.number.words", ": " + dto.getMinWordsLimit())); + } + + return errors; + } + + /** + * Is this string empty? Need to strip out all HTML tags first otherwise an empty DIV might look like a valid answer + * Smileys and math functions only put in an img tag so explicitly look for that. + */ + private boolean isEmpty(String answer) { + if ((answer != null) && ((answer.indexOf(" -1) || (answer.indexOf(" -1))) { + return false; + } else { + return StringUtils.isBlank(WebUtil.removeHTMLtags(answer)); + } + } + + /** + * moves to the previous question and modifies the map ActionForward + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + public ActionForward getPreviousQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + qaLearningForm.setHttpSessionID(httpSessionID); + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("learningStarter")); + redirect.addParameter(AttributeNames.PARAM_TOOL_SESSION_ID, toolSessionID); + redirect.addParameter(QaAppConstants.MODE, "learner"); + return redirect; + } + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, false); + + qaLearningForm.resetAll(); + return (mapping.findForward(QaAppConstants.LOAD_LEARNER)); + } + + /** + * finishes the user's tool activity + * + * @param request + * @param qaService + * @param response + * @throws IOException + * @throws ToolException + */ + public ActionForward endLearning(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + qaLearningForm.setUserID(userID); + + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaQueUsr qaQueUsr = QaLearningAction.qaService.getUserByIdAndSession(new Long(userID), + qaSession.getQaSessionId()); + qaQueUsr.setLearnerFinished(true); + QaLearningAction.qaService.updateUser(qaQueUsr); + + /* + * The learner is done with the tool session. The tool needs to clean-up. + */ + HttpSession ss = SessionManager.getSession(); + /* get back login user DTO */ + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + + qaSession.setSession_end_date(new Date(System.currentTimeMillis())); + qaSession.setSession_status(QaAppConstants.COMPLETED); + QaLearningAction.qaService.updateSession(qaSession); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + // request.getSession().removeAttribute(httpSessionID); + qaLearningForm.setHttpSessionID(httpSessionID); + + qaLearningForm.resetAll(); + + String nextActivityUrl = QaLearningAction.qaService.leaveToolSession(new Long(toolSessionID), + new Long(user.getUserID().longValue())); + response.sendRedirect(nextActivityUrl); + + return null; + } + + public ActionForward updateReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + qaLearningForm.setHttpSessionID(httpSessionID); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + qaLearningForm.setUserID(userID); + + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = QaLearningAction.qaService.getUserByIdAndSession(new Long(userID), + qaSession.getQaSessionId()); + + String entryText = request.getParameter("entryText"); + qaLearningForm.setEntryText(entryText); + + NotebookEntry notebookEntryLocal = new NotebookEntry(); + notebookEntryLocal.setEntry(entryText); + // notebookEntry.setUser(qaQueUsr); + User user = new User(); + user.setUserId(new Integer(userID)); + notebookEntryLocal.setUser(user); + + QaLearningAction.qaService.updateEntry(notebookEntryLocal); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + generalLearnerFlowDTO.setNotebookEntry(entryText); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, QaLearningAction.qaService, httpSessionID, + qaQueUsr, generalLearnerFlowDTO); + + boolean isLearnerFinished = qaQueUsr.isLearnerFinished(); + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(isLearnerFinished).toString()); + + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + + boolean allowRichEditor = qaContent.isAllowRichEditor(); + generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); + + boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); + generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); + + NotebookEntry notebookEntry = QaLearningAction.qaService.getEntry(new Long(toolSessionID), + CoreNotebookConstants.NOTEBOOK_TOOL, QaAppConstants.MY_SIGNATURE, new Integer(userID)); + + if (notebookEntry != null) { + // String notebookEntryPresentable = QaUtils.replaceNewLines(notebookEntry.getEntry()); + qaLearningForm.setEntryText(notebookEntry.getEntry()); + } + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return (mapping.findForward(QaAppConstants.REVISITED_LEARNER_REP)); + } + + /** + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + public ActionForward submitReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + qaLearningForm.setHttpSessionID(httpSessionID); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + qaLearningForm.setUserID(userID); + + String reflectionEntry = request.getParameter(QaAppConstants.ENTRY_TEXT); + + QaLearningAction.qaService.createNotebookEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + QaAppConstants.MY_SIGNATURE, new Integer(userID), reflectionEntry); + + qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + return endLearning(mapping, form, request, response); + } + + /** + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + public ActionForward forwardtoReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + initializeQAService(); + QaLearningForm qaLearningForm = (QaLearningForm) form; + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + qaLearningForm.setHttpSessionID(httpSessionID); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + QaSession qaSession = QaLearningAction.qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaContent qaContent = qaSession.getQaContent(); + + String userID = request.getParameter("userID"); + qaLearningForm.setUserID(userID); + + return forwardtoReflection(mapping, request, qaContent, toolSessionID, userID, qaLearningForm); + } + + private ActionForward forwardtoReflection(ActionMapping mapping, HttpServletRequest request, QaContent qaContent, + String toolSessionID, String userID, QaLearningForm qaLearningForm) { + + GeneralLearnerFlowDTO generalLearnerFlowDTO = new GeneralLearnerFlowDTO(); + generalLearnerFlowDTO.setActivityTitle(qaContent.getTitle()); + String reflectionSubject = qaContent.getReflectionSubject(); + // reflectionSubject = QaUtils.replaceNewLines(reflectionSubject); + generalLearnerFlowDTO.setReflectionSubject(reflectionSubject); + + // attempt getting notebookEntry + NotebookEntry notebookEntry = QaLearningAction.qaService.getEntry(new Long(toolSessionID), + CoreNotebookConstants.NOTEBOOK_TOOL, QaAppConstants.MY_SIGNATURE, new Integer(userID)); + + if (notebookEntry != null) { + // String notebookEntryPresentable=QaUtils.replaceNewLines(notebookEntry.getEntry()); + String notebookEntryPresentable = notebookEntry.getEntry(); + generalLearnerFlowDTO.setNotebookEntry(notebookEntryPresentable); + qaLearningForm.setEntryText(notebookEntryPresentable); + } + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + + qaLearningForm.resetAll(); + return (mapping.findForward(QaAppConstants.NOTEBOOK)); + } + + /** + * populates data for summary screen, view all results screen. + * + * User id is needed if isUserNamesVisible is false && learnerRequest is true, as it is required to work out if the + * data being analysed is the current user. + */ + public static void refreshSummaryData(HttpServletRequest request, QaContent qaContent, QaSession qaSession, + IQaService qaService, String httpSessionID, QaQueUsr user, GeneralLearnerFlowDTO generalLearnerFlowDTO) { + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + Long userId = user.getQueUsrId(); + Set questions = qaContent.getQaQueContents(); + generalLearnerFlowDTO.setQuestions(questions); + generalLearnerFlowDTO.setUserNameVisible(new Boolean(qaContent.isUsernameVisible()).toString()); + + // potentially empty list if the user starts the lesson after the time restriction has expired. + List userResponses = qaService.getResponsesByUserUid(user.getUid()); + + //handle rating criterias + int commentsMinWordsLimit = 0; + boolean isCommentsEnabled = false; + int countRatedQuestions = 0; + if (qaContent.isAllowRateAnswers()) { + + if (userResponses.isEmpty()) { + Set criterias = qaContent.getRatingCriterias(); + for (LearnerItemRatingCriteria criteria : criterias) { + if (criteria.isCommentRating()) { + isCommentsEnabled = true; + break; + } + } + + } else { + // create itemIds list + List itemIds = new LinkedList(); + for (QaUsrResp responseIter : userResponses) { + itemIds.add(responseIter.getResponseId()); + } + + List itemRatingDtos = qaService.getRatingCriteriaDtos(qaContent.getQaContentId(), + qaSession.getQaSessionId(), itemIds, true, userId); + sessionMap.put(AttributeNames.ATTR_ITEM_RATING_DTOS, itemRatingDtos); + + if (itemRatingDtos.size() > 0) { + commentsMinWordsLimit = itemRatingDtos.get(0).getCommentsMinWordsLimit(); + isCommentsEnabled = itemRatingDtos.get(0).isCommentsEnabled(); + } + + //map itemRatingDto to corresponding response + for (QaUsrResp response : userResponses) { + + //find corresponding itemRatingDto + ItemRatingDTO itemRatingDto = null; + for (ItemRatingDTO itemRatingDtoIter : itemRatingDtos) { + if (itemRatingDtoIter.getItemId().equals(response.getResponseId())) { + itemRatingDto = itemRatingDtoIter; + break; + } + } + + response.setItemRatingDto(itemRatingDto); + } + + // store how many items are rated + countRatedQuestions = qaService.getCountItemsRatedByUser(qaContent.getQaContentId(), userId.intValue()); + } + } + + request.setAttribute(TOOL_SESSION_ID, qaSession.getQaSessionId()); + + sessionMap.put("commentsMinWordsLimit", commentsMinWordsLimit); + sessionMap.put("isCommentsEnabled", isCommentsEnabled); + sessionMap.put(AttributeNames.ATTR_COUNT_RATED_ITEMS, countRatedQuestions); + + generalLearnerFlowDTO.setUserResponses(userResponses); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); + } + + /** + * Refreshes user list. + */ + public ActionForward getResponses(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse res) throws IOException, ServletException { + initializeQAService(); + + // teacher timezone + HttpSession ss = SessionManager.getSession(); + UserDTO userDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone userTimeZone = userDto.getTimeZone(); + + boolean isAllowRateAnswers = WebUtil.readBooleanParam(request, "isAllowRateAnswers"); + boolean isAllowRichEditor = WebUtil.readBooleanParam(request, "isAllowRichEditor"); + boolean isOnlyLeadersIncluded = WebUtil.readBooleanParam(request, "isOnlyLeadersIncluded", false); + Long qaContentId = WebUtil.readLongParam(request, "qaContentId"); + + Long questionUid = WebUtil.readLongParam(request, "questionUid"); + Long qaSessionId = WebUtil.readLongParam(request, "qaSessionId"); + + //in case of monitoring we show all results. in case of learning - don't show results from the current user + boolean isMonitoring = WebUtil.readBooleanParam(request, "isMonitoring", false); + Long userId = isMonitoring ? -1 : WebUtil.readLongParam(request, "userId"); + + //paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByCol1 = WebUtil.readIntParam(request, "column[0]", true); + Integer sortByCol2 = WebUtil.readIntParam(request, "column[1]", true); + String searchString = request.getParameter("fcol[0]"); + + int sorting = QaAppConstants.SORT_BY_NO; + if (sortByCol1 != null) { + if (isMonitoring) { + sorting = sortByCol1.equals(0) ? QaAppConstants.SORT_BY_USERNAME_ASC + : QaAppConstants.SORT_BY_USERNAME_DESC; + } else { + sorting = sortByCol1.equals(0) ? QaAppConstants.SORT_BY_ANSWER_ASC : QaAppConstants.SORT_BY_ANSWER_DESC; + } + + } else if (sortByCol2 != null) { + sorting = sortByCol2.equals(0) ? QaAppConstants.SORT_BY_RATING_ASC : QaAppConstants.SORT_BY_RATING_DESC; + + } else if (!isMonitoring) { + // Is it learner and comment only? If so sort by number of comments. + QaSession qaSession = QaLearningAction.qaService.getSessionById(qaSessionId); + Set criterias = qaSession.getQaContent().getRatingCriterias(); + boolean hasComment = false; + boolean hasRating = false; + for (LearnerItemRatingCriteria criteria : criterias) { + if (criteria.isCommentRating()) { + hasComment = true; + } else { + hasRating = true; + } + } + if (hasComment && !hasRating) { + sorting = QaAppConstants.SORT_BY_COMMENT_COUNT; + } + } + + List responses = QaLearningAction.qaService.getResponsesForTablesorter(qaContentId, qaSessionId, + questionUid, userId, isOnlyLeadersIncluded, page, size, sorting, searchString); + + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + + responcedata.put("total_rows", QaLearningAction.qaService.getCountResponsesBySessionAndQuestion(qaSessionId, + questionUid, userId, isOnlyLeadersIncluded, searchString)); + + // handle rating criterias - even though we may have searched on ratings earlier we can't use the average ratings + // calculated as they may have been averages over more than one criteria. + List itemRatingDtos = null; + if (isAllowRateAnswers && !responses.isEmpty()) { + //create itemIds list + List itemIds = new LinkedList(); + for (QaUsrResp response : responses) { + itemIds.add(response.getResponseId()); + } + + //all comments required only for monitoring + boolean isCommentsByOtherUsersRequired = isMonitoring; + itemRatingDtos = QaLearningAction.qaService.getRatingCriteriaDtos(qaContentId, qaSessionId, itemIds, + isCommentsByOtherUsersRequired, userId); + + // store how many items are rated + int countRatedQuestions = QaLearningAction.qaService.getCountItemsRatedByUser(qaContentId, + userId.intValue()); + responcedata.put(AttributeNames.ATTR_COUNT_RATED_ITEMS, countRatedQuestions); + } + + for (QaUsrResp response : responses) { + QaQueUsr user = response.getQaQueUser(); + + /* + * LDEV-3891: This code has been commented out, as the escapeCsv puts double quotes in the string, which + * goes through to the + * client and wrecks img src entries. It appears the browser cannot process the string with all the double + * quotes. + * This is the second time it is being fixed - the escapeCsv was removed in LDEV-3448 and then added back in + * when Peer Review was added (LDEV-3480). If escapeCsv needs to be added in again, make sure it does not + * break + * learner added images being seen in monitoring. + * //remove leading and trailing quotes + * String answer = StringEscapeUtils.escapeCsv(response.getAnswer()); + * if (isAllowRichEditor && answer.startsWith("\"") && answer.length() >= 3) { + * answer = answer.substring(1, answer.length() - 1); + * } + */ + + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put("responseUid", response.getResponseId().toString()); + responseRow.put("answer", response.getAnswer()); + responseRow.put("userName", StringEscapeUtils.escapeCsv(user.getFullname())); + responseRow.put("visible", new Boolean(response.isVisible()).toString()); + + // format attemptTime - got straight from server time to other timezones in formatter + // as trying to convert dates runs into tz issues - any Date object created is still + // in the server time zone. + Date attemptTime = response.getAttemptTime(); + responseRow.put("attemptTime", DateUtil.convertToStringForJSON(attemptTime, request.getLocale())); + responseRow.put("timeAgo", DateUtil.convertToStringForTimeagoJSON(attemptTime)); + + if (isAllowRateAnswers) { + + //find corresponding itemRatingDto + ItemRatingDTO itemRatingDto = null; + for (ItemRatingDTO itemRatingDtoIter : itemRatingDtos) { + if (response.getResponseId().equals(itemRatingDtoIter.getItemId())) { + itemRatingDto = itemRatingDtoIter; + break; + } + } + + boolean isItemAuthoredByUser = response.getQaQueUser().getQueUsrId().equals(userId); + responseRow.put("isItemAuthoredByUser", isItemAuthoredByUser); + + ArrayNode criteriasRows = JsonNodeFactory.instance.arrayNode(); + for (ItemRatingCriteriaDTO criteriaDto : itemRatingDto.getCriteriaDtos()) { + ObjectNode criteriasRow = JsonNodeFactory.instance.objectNode(); + criteriasRow.put("ratingCriteriaId", criteriaDto.getRatingCriteria().getRatingCriteriaId()); + criteriasRow.put("title", criteriaDto.getRatingCriteria().getTitle()); + criteriasRow.put("averageRating", criteriaDto.getAverageRating()); + criteriasRow.put("numberOfVotes", criteriaDto.getNumberOfVotes()); + criteriasRow.put("userRating", criteriaDto.getUserRating()); + + criteriasRows.add(criteriasRow); + } + responseRow.set("criteriaDtos", criteriasRows); + + //handle comments + responseRow.put("commentsCriteriaId", itemRatingDto.getCommentsCriteriaId()); + String commentPostedByUser = itemRatingDto.getCommentPostedByUser() == null ? "" + : itemRatingDto.getCommentPostedByUser().getComment(); + responseRow.put("commentPostedByUser", commentPostedByUser); + if (itemRatingDto.getCommentDtos() != null) { + + ArrayNode comments = JsonNodeFactory.instance.arrayNode(); + for (RatingCommentDTO commentDto : itemRatingDto.getCommentDtos()) { + ObjectNode comment = JsonNodeFactory.instance.objectNode(); + comment.put("comment", StringEscapeUtils.escapeCsv(commentDto.getComment())); + + if (isMonitoring) { + // format attemptTime + Date postedDate = commentDto.getPostedDate(); + postedDate = DateUtil.convertToTimeZoneFromDefault(userTimeZone, postedDate); + comment.put("postedDate", DateUtil.convertToStringForJSON(postedDate, request.getLocale())); + + comment.put("userFullName", StringEscapeUtils.escapeCsv(commentDto.getUserFullName())); + } + + comments.add(comment); + } + responseRow.set("comments", comments); + } + } + + rows.add(responseRow); + } + responcedata.set("rows", rows); + + res.setContentType("application/json;charset=utf-8"); + res.getWriter().print(new String(responcedata.toString())); + return null; + } + + private static Map removeNewLinesMap(Map map) { + Map newMap = new TreeMap(new QaStringComparator()); + + Iterator itMap = map.entrySet().iterator(); + while (itMap.hasNext()) { + Map.Entry pairs = (Map.Entry) itMap.next(); + String newText = ""; + if (pairs.getValue().toString() != null) { + newText = pairs.getValue().toString().replaceAll("\n", "
"); + } + newMap.put(pairs.getKey(), newText); + } + return newMap; + } + + private void initializeQAService() { + if (QaLearningAction.qaService == null) { + QaLearningAction.qaService = QaServiceProxy.getQaService(getServlet().getServletContext()); + } + } + + private QaQueUsr getCurrentUser(String toolSessionID) { + + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = new Long(toolUser.getUserID().longValue()); + + return QaLearningAction.qaService.getUserByIdAndSession(userId, new Long(toolSessionID)); + } + +} Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/action/QaMonitoringAction.java =================================================================== diff -u --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/action/QaMonitoringAction.java (revision 0) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/action/QaMonitoringAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,214 @@ +/*************************************************************************** +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 version 2 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.qa.web.action; + +import java.io.IOException; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.qa.QaAppConstants; +import org.lamsfoundation.lams.tool.qa.QaContent; +import org.lamsfoundation.lams.tool.qa.QaUsrResp; +import org.lamsfoundation.lams.tool.qa.service.IQaService; +import org.lamsfoundation.lams.tool.qa.service.QaServiceProxy; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Ozgur Demirtas + */ +public class QaMonitoringAction extends LamsDispatchAction implements QaAppConstants { + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + return null; + } + + public ActionForward updateResponse(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + + IQaService qaService = QaServiceProxy.getQaService(getServlet().getServletContext()); + + Long responseUid = WebUtil.readLongParam(request, QaAppConstants.RESPONSE_UID); + String updatedResponse = request.getParameter("updatedResponse"); + QaUsrResp qaUsrResp = qaService.getResponseById(responseUid); + + /* + * write out the audit log entry. If you move this after the update of the response, then make sure you update + * the audit call to use a copy of the original answer + */ + qaService.getAuditService().logChange(QaAppConstants.MY_SIGNATURE, qaUsrResp.getQaQueUser().getQueUsrId(), + qaUsrResp.getQaQueUser().getUsername(), qaUsrResp.getAnswer(), updatedResponse); + + qaUsrResp.setAnswer(updatedResponse); + qaService.updateUserResponse(qaUsrResp); + + return null; + } + + public ActionForward updateResponseVisibility(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + IQaService qaService = QaServiceProxy.getQaService(getServlet().getServletContext()); + + Long responseUid = WebUtil.readLongParam(request, QaAppConstants.RESPONSE_UID); + boolean isHideItem = WebUtil.readBooleanParam(request, QaAppConstants.IS_HIDE_ITEM); + qaService.updateResponseVisibility(responseUid, isHideItem); + + return null; + } + + /** + * Set Submission Deadline + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + */ + public ActionForward setSubmissionDeadline(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + IQaService qaService = getQAService(); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + QaContent content = qaService.getQaContent(contentID); + + Long dateParameter = WebUtil.readLongParam(request, QaAppConstants.ATTR_SUBMISSION_DEADLINE, true); + Date tzSubmissionDeadline = null; + String formattedDate = ""; + if (dateParameter != null) { + Date submissionDeadline = new Date(dateParameter); + HttpSession ss = SessionManager.getSession(); + UserDTO teacher = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone teacherTimeZone = teacher.getTimeZone(); + tzSubmissionDeadline = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, submissionDeadline); + formattedDate = DateUtil.convertToStringForJSON(tzSubmissionDeadline, request.getLocale()); + } else { + //set showOtherAnswersAfterDeadline to false + content.setShowOtherAnswersAfterDeadline(false); + } + content.setSubmissionDeadline(tzSubmissionDeadline); + qaService.saveOrUpdateQaContent(content); + + response.setContentType("text/plain;charset=utf-8"); + response.getWriter().print(formattedDate); + return null; + } + + /** + * Set Submission Deadline + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward setShowOtherAnswersAfterDeadline(ActionMapping mapping, ActionForm form, + HttpServletRequest request, HttpServletResponse response) { + IQaService qaService = getQAService(); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + QaContent content = qaService.getQaContent(contentID); + + boolean showOtherAnswersAfterDeadline = WebUtil.readBooleanParam(request, + QaAppConstants.PARAM_SHOW_OTHER_ANSWERS_AFTER_DEADLINE); + content.setShowOtherAnswersAfterDeadline(showOtherAnswersAfterDeadline); + qaService.saveOrUpdateQaContent(content); + + return null; + } + + private IQaService getQAService() { + return QaServiceProxy.getQaService(getServlet().getServletContext()); + } + + /** + * Get Paged Reflections + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward getReflectionsJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + Long toolSessionId = WebUtil.readLongParam(request, QaAppConstants.TOOL_SESSION_ID); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByName = WebUtil.readIntParam(request, "column[0]", true); + String searchString = request.getParameter("fcol[0]"); + + int sorting = QaAppConstants.SORT_BY_NO; + if (sortByName != null) { + sorting = sortByName.equals(0) ? QaAppConstants.SORT_BY_USERNAME_ASC : QaAppConstants.SORT_BY_USERNAME_DESC; + } + + //return user list according to the given sessionID + IQaService qaService = getQAService(); + List users = qaService.getUserReflectionsForTablesorter(toolSessionId, page, size, sorting, + searchString); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("total_rows", qaService.getCountUsersBySessionWithSearch(toolSessionId, searchString)); + + for (Object[] userAndReflection : users) { + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put("username", StringEscapeUtils.escapeHtml((String) userAndReflection[1])); + if (userAndReflection.length > 2 && userAndReflection[2] != null) { + String reflection = StringEscapeUtils.escapeHtml((String) userAndReflection[2]); + responseRow.put(QaAppConstants.NOTEBOOK, reflection.replaceAll("\n", "
")); + } + rows.add(responseRow); + } + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + +} \ No newline at end of file Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/ResourceServiceImpl.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/ResourceServiceImpl.java (.../ResourceServiceImpl.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/ResourceServiceImpl.java (.../ResourceServiceImpl.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; @@ -46,9 +45,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.upload.FormFile; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; import org.lamsfoundation.lams.contentrepository.IVersionedNode; @@ -116,6 +112,10 @@ import org.lamsfoundation.lams.util.zipfile.ZipFileUtilException; import org.lamsfoundation.lams.web.util.AttributeNames; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Dapeng.Ni */ @@ -310,7 +310,7 @@ } // add resource items from Authoring Resource resource = session.getResource(); - List items = new ArrayList(); + List items = new ArrayList<>(); items.addAll(resource.getResourceItems()); // add resource items from ResourceSession @@ -428,7 +428,7 @@ @Override public List getSummary(Long contentId) { - List groupList = new ArrayList(); + List groupList = new ArrayList<>(); Resource resource = resourceDao.getByContentId(contentId); @@ -442,14 +442,14 @@ group.setSessionId(session.getSessionId()); group.setSessionName(session.getSessionName()); - Set items = new TreeSet(new ResourceItemComparator()); + Set items = new TreeSet<>(new ResourceItemComparator()); // firstly, put all initial resource item into this group. items.addAll(resource.getResourceItems()); // add this session's resource items items.addAll(session.getResourceItems()); // item ids of items that could be rated. - List itemsToRate = new ArrayList(); + List itemsToRate = new ArrayList<>(); // get all item which is accessed by users in this session Map visitCountMap = resourceItemVisitDao.getSummary(contentId, session.getSessionId()); @@ -460,24 +460,25 @@ resourceItemDTO.setViewNumber(visitCountMap.get(item.getUid()).intValue()); } group.getItems().add(resourceItemDTO); - if ( item.isAllowRating() ) { + if (item.isAllowRating()) { itemsToRate.add(item.getUid()); } } - + List itemRatingDtos = null; - if ( itemsToRate.size() > 0 ) { - itemRatingDtos = ratingService.getRatingCriteriaDtos(contentId, session.getSessionId(), itemsToRate, false, -1L); + if (itemsToRate.size() > 0) { + itemRatingDtos = ratingService.getRatingCriteriaDtos(contentId, session.getSessionId(), itemsToRate, + false, -1L); group.setAllowRating(true); } else { group.setAllowRating(false); } - for (ResourceItemDTO item: group.getItems()) { + for (ResourceItemDTO item : group.getItems()) { if (item.isAllowRating()) { // find corresponding itemRatingDto - for ( ItemRatingDTO ratingDTO : itemRatingDtos ) { - if ( item.getItemUid().equals(ratingDTO.getItemId()) ) { + for (ItemRatingDTO ratingDTO : itemRatingDtos) { + if (item.getItemUid().equals(ratingDTO.getItemId())) { item.setRatingDTO(ratingDTO); break; } @@ -493,7 +494,7 @@ @Override public List getReflectList(Long contentId) { - List reflections = new LinkedList(); + List reflections = new LinkedList<>(); List sessionList = resourceSessionDao.getByContentId(contentId); for (ResourceSession session : sessionList) { @@ -529,7 +530,8 @@ user.setAccessDate(visit.getAccessDate()); user.setCompleteDate(visit.getCompleteDate()); Date timeTaken = ((visit.getCompleteDate() != null) && (visit.getAccessDate() != null)) - ? new Date(visit.getCompleteDate().getTime() - visit.getAccessDate().getTime()) : null; + ? new Date(visit.getCompleteDate().getTime() - visit.getAccessDate().getTime()) + : null; user.setTimeTaken(timeTaken); userList.add(user); } @@ -791,10 +793,10 @@ public boolean isGroupedActivity(long toolContentID) { return toolService.isGroupedActivity(toolContentID); } - + @Override public void auditLogStartEditingActivityInMonitor(long toolContentID) { - toolService.auditLogStartEditingActivityInMonitor(toolContentID); + toolService.auditLogStartEditingActivityInMonitor(toolContentID); } // ******************************************************************************* @@ -867,13 +869,13 @@ item.setCreateBy(user); useRatings = useRatings || item.isAllowRating(); } - + Set criterias = toolContentObj.getRatingCriterias(); if (criterias != null) { for (LearnerItemRatingCriteria criteria : criterias) { criteria.setToolContentId(toolContentId); } - } + } resourceDao.saveObject(toolContentObj); } catch (ImportToolContentException e) { @@ -1091,7 +1093,7 @@ @Override public List getToolOutputs(String name, Long toolContentId) { - return new ArrayList(); + return new ArrayList<>(); } @Override @@ -1107,8 +1109,9 @@ @Override public LearnerItemRatingCriteria createRatingCriteria(Long toolContentId) throws RatingException { List ratingCriterias = ratingService.getCriteriasByToolContentId(toolContentId); - if ( ratingCriterias == null || ratingCriterias.size() == 0 ) { - return ratingService.saveLearnerItemRatingCriteria(toolContentId, null, 1, RatingCriteria.RATING_STYLE_STAR, false, 0); + if (ratingCriterias == null || ratingCriterias.size() == 0) { + return ratingService.saveLearnerItemRatingCriteria(toolContentId, null, 1, RatingCriteria.RATING_STYLE_STAR, + false, 0); } else { return (LearnerItemRatingCriteria) ratingCriterias.get(0); } @@ -1118,9 +1121,10 @@ public int deleteRatingCriteria(Long toolContentId) { return ratingService.deleteAllRatingCriterias(toolContentId); } - + @Override - public List getRatingCriteriaDtos(Long toolContentId, Long toolSessionId, Collection itemIds, Long userId) { + public List getRatingCriteriaDtos(Long toolContentId, Long toolSessionId, Collection itemIds, + Long userId) { return ratingService.getRatingCriteriaDtos(toolContentId, toolSessionId, itemIds, false, userId); } @@ -1229,91 +1233,94 @@ if (learner == null) { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); } - + Object[] dates = resourceItemVisitDao.getDateRangeOfAccesses(learner.getUid(), toolSessionId); - if (learner.isSessionFinished()) - return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, (Date)dates[0], (Date)dates[1]); - else - return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED,(Date) dates[0], null); + if (learner.isSessionFinished()) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, (Date) dates[0], (Date) dates[1]); + } else { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, (Date) dates[0], null); + } } - + // ****************** REST methods ************************* /** * Used by the Rest calls to create content. Mandatory fields in toolContentJSON: title, instructions, resources, - * user fields firstName, lastName and loginName Resources must contain a JSONArray of JSONObject objects, which + * user fields firstName, lastName and loginName Resources must contain a ArrayNode of ObjectNode objects, which * have the following mandatory fields: title, description, type. If there are instructions for a resource, the - * instructions are a JSONArray of Strings. There should be at least one resource object in the resources array. + * instructions are a ArrayNode of Strings. There should be at least one resource object in the resources array. + * + * @throws IOException */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) + throws IOException { Date updateDate = new Date(); Resource resource = new Resource(); resource.setContentId(toolContentID); - resource.setTitle(toolContentJSON.getString(RestTags.TITLE)); - resource.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + resource.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + resource.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); resource.setCreated(updateDate); - resource.setAllowAddFiles(JsonUtil.opt(toolContentJSON, "allowAddFiles", Boolean.FALSE)); - resource.setAllowAddUrls(JsonUtil.opt(toolContentJSON, "allowAddUrls", Boolean.FALSE)); - resource.setLockWhenFinished(JsonUtil.opt(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); - resource.setMiniViewResourceNumber(JsonUtil.opt(toolContentJSON, "minViewResourceNumber", 0)); + resource.setAllowAddFiles(JsonUtil.optBoolean(toolContentJSON, "allowAddFiles", Boolean.FALSE)); + resource.setAllowAddUrls(JsonUtil.optBoolean(toolContentJSON, "allowAddUrls", Boolean.FALSE)); + resource.setLockWhenFinished(JsonUtil.optBoolean(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); + resource.setMiniViewResourceNumber(JsonUtil.optInt(toolContentJSON, "minViewResourceNumber", 0)); resource.setNotifyTeachersOnAssigmentSumbit( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnAssigmentSubmit", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnAssigmentSubmit", Boolean.FALSE)); resource.setNotifyTeachersOnAssigmentSumbit( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnFileUpload", Boolean.FALSE)); - resource.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); - resource.setReflectInstructions(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, (String) null)); - resource.setRunAuto(JsonUtil.opt(toolContentJSON, "runAuto", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnFileUpload", Boolean.FALSE)); + resource.setReflectOnActivity( + JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + resource.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + resource.setRunAuto(JsonUtil.optBoolean(toolContentJSON, "runAuto", Boolean.FALSE)); resource.setContentInUse(false); resource.setDefineLater(false); ResourceUser resourceUser = getUserByIDAndContent(userID.longValue(), toolContentID); if (resourceUser == null) { resourceUser = new ResourceUser(); - resourceUser.setFirstName(toolContentJSON.getString("firstName")); - resourceUser.setLastName(toolContentJSON.getString("lastName")); - resourceUser.setLoginName(toolContentJSON.getString("loginName")); + resourceUser.setFirstName(JsonUtil.optString(toolContentJSON, "firstName")); + resourceUser.setLastName(JsonUtil.optString(toolContentJSON, "lastName")); + resourceUser.setLoginName(JsonUtil.optString(toolContentJSON, "loginName")); // resourceUser.setResource(content); } resource.setCreatedBy(resourceUser); // **************************** Handle topic ********************* - JSONArray resources = toolContentJSON.getJSONArray("resources"); + ArrayNode resources = JsonUtil.optArray(toolContentJSON, "resources"); Set itemList = new LinkedHashSet(); - for (int i = 0; i < resources.length(); i++) { - JSONObject itemData = (JSONObject) resources.get(i); + for (JsonNode itemData : resources) { ResourceItem item = new ResourceItem(); - item.setTitle(itemData.getString("title")); - item.setType((short) itemData.getInt("type")); + item.setTitle(JsonUtil.optString(itemData, "title")); + item.setType(JsonUtil.optInt(itemData, "type").shortValue()); item.setCreateBy(resourceUser); item.setCreateDate(updateDate); item.setComplete(false); item.setCreateByAuthor(true); item.setHide(false); - item.setOrderId(itemData.getInt(RestTags.DISPLAY_ORDER)); + item.setOrderId(JsonUtil.optInt(itemData, RestTags.DISPLAY_ORDER)); - item.setDescription(JsonUtil.opt(itemData, "description", (String) null)); - item.setFileName(JsonUtil.opt(itemData, "name", (String) null)); - item.setFileType(JsonUtil.opt(itemData, "fileType", (String) null)); + item.setDescription(JsonUtil.optString(itemData, "description")); + item.setFileName(JsonUtil.optString(itemData, "name")); + item.setFileType(JsonUtil.optString(itemData, "fileType")); item.setFileUuid(JsonUtil.optLong(itemData, "crUuid")); item.setFileVersionId(JsonUtil.optLong(itemData, "crVersionId")); - item.setImsSchema(JsonUtil.opt(itemData, "imsSchema", (String) null)); - item.setOrganizationXml(JsonUtil.opt(itemData, "organizationXml", (String) null)); - item.setOpenUrlNewWindow(JsonUtil.opt(itemData, "openUrlNewWindow", Boolean.FALSE)); - item.setUrl(JsonUtil.opt(itemData, "url", (String) null)); + item.setImsSchema(JsonUtil.optString(itemData, "imsSchema")); + item.setOrganizationXml(JsonUtil.optString(itemData, "organizationXml")); + item.setOpenUrlNewWindow(JsonUtil.optBoolean(itemData, "openUrlNewWindow", Boolean.FALSE)); + item.setUrl(JsonUtil.optString(itemData, "url")); - JSONArray instructionStrings = itemData.getJSONArray("instructions"); - if ((instructionStrings != null) && (instructionStrings.length() > 0)) { + ArrayNode instructionStrings = JsonUtil.optArray(itemData, "instructions"); + if ((instructionStrings != null) && (instructionStrings.size() > 0)) { Set instructions = new LinkedHashSet(); - for (int j = 0; j < instructionStrings.length(); j++) { + for (int j = 0; j < instructionStrings.size(); j++) { ResourceItemInstruction rii = new ResourceItemInstruction(); - rii.setDescription(instructionStrings.getString(j)); + rii.setDescription(instructionStrings.get(j).asText(null)); rii.setSequenceId(j); instructions.add(rii); } @@ -1322,7 +1329,7 @@ // TODO files - need to save it somehow, validate the file size, etc. Needed for websites, files & LO if ((item.getFileName() != null) || (item.getFileUuid() != null)) { - throw new JSONException( + throw new IOException( "Only URLS supported via REST interface currently - files and learning objects are not supported."); } @@ -1335,6 +1342,7 @@ } + @Override public void evict(Object object) { resourceDao.releaseFromCache(object); } Index: lams_tool_leader/src/java/org/lamsfoundation/lams/tool/leaderselection/service/LeaderselectionService.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_tool_leader/src/java/org/lamsfoundation/lams/tool/leaderselection/service/LeaderselectionService.java (.../LeaderselectionService.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_tool_leader/src/java/org/lamsfoundation/lams/tool/leaderselection/service/LeaderselectionService.java (.../LeaderselectionService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -31,8 +31,6 @@ import java.util.SortedMap; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; @@ -70,7 +68,10 @@ import org.lamsfoundation.lams.tool.service.ILamsToolService; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.JsonUtil; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * An implementation of the ILeaderselectionService interface. * @@ -332,7 +333,7 @@ /* ********** ILeaderselectionService Methods ********************************* */ @Override - public void setGroupLeader(Long userUid, Long toolSessionId) throws JSONException, IOException { + public void setGroupLeader(Long userUid, Long toolSessionId) throws IOException { if ((userUid == null) || (toolSessionId == null)) { return; } @@ -615,14 +616,13 @@ * Rest call to create a new Learner Selection content. Required fields in toolContentJSON: "title", "instructions". */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { Date updateDate = new Date(); Leaderselection leaderselection = new Leaderselection(); leaderselection.setToolContentId(toolContentID); - leaderselection.setTitle(toolContentJSON.getString(RestTags.TITLE)); - leaderselection.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + leaderselection.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + leaderselection.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); leaderselection.setCreateBy(userID.longValue()); leaderselection.setCreateDate(updateDate); leaderselection.setUpdateDate(updateDate); Index: lams_tool_nb/src/java/org/lamsfoundation/lams/tool/noticeboard/service/NoticeboardService.java =================================================================== diff -u --- lams_tool_nb/src/java/org/lamsfoundation/lams/tool/noticeboard/service/NoticeboardService.java (revision 0) +++ lams_tool_nb/src/java/org/lamsfoundation/lams/tool/noticeboard/service/NoticeboardService.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,657 @@ +/**************************************************************** + * 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 version 2.0 + * 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 + * **************************************************************** + */ + +package org.lamsfoundation.lams.tool.noticeboard.service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; +import org.lamsfoundation.lams.contentrepository.exception.ItemNotFoundException; +import org.lamsfoundation.lams.contentrepository.exception.RepositoryCheckedException; +import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService; +import org.lamsfoundation.lams.learningdesign.service.ImportToolContentException; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; +import org.lamsfoundation.lams.rest.RestTags; +import org.lamsfoundation.lams.rest.ToolRestManager; +import org.lamsfoundation.lams.tool.ToolCompletionStatus; +import org.lamsfoundation.lams.tool.ToolContentManager; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.ToolSessionExportOutputData; +import org.lamsfoundation.lams.tool.ToolSessionManager; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.noticeboard.NoticeboardConstants; +import org.lamsfoundation.lams.tool.noticeboard.NoticeboardContent; +import org.lamsfoundation.lams.tool.noticeboard.NoticeboardSession; +import org.lamsfoundation.lams.tool.noticeboard.NoticeboardUser; +import org.lamsfoundation.lams.tool.noticeboard.dao.INoticeboardContentDAO; +import org.lamsfoundation.lams.tool.noticeboard.dao.INoticeboardSessionDAO; +import org.lamsfoundation.lams.tool.noticeboard.dao.INoticeboardUserDAO; +import org.lamsfoundation.lams.tool.noticeboard.util.NbApplicationException; +import org.lamsfoundation.lams.tool.service.ILamsToolService; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.util.JsonUtil; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * An implementation of the NoticeboardService interface. + * + * As a requirement, all LAMS tool's service bean must implement ToolContentManager and ToolSessionManager. + * + * @author mtruong + */ +public class NoticeboardService + implements INoticeboardService, ToolContentManager, ToolSessionManager, ToolRestManager { + private static Logger log = Logger.getLogger(NoticeboardService.class); + + private ILearnerService learnerService; + private ILamsToolService toolService; + private IExportToolContentService exportContentService; + private IToolContentHandler nbToolContentHandler; + private ICoreNotebookService coreNotebookService; + + private INoticeboardContentDAO nbContentDAO; + private INoticeboardSessionDAO nbSessionDAO; + private INoticeboardUserDAO nbUserDAO; + + @Override + public NoticeboardContent retrieveNoticeboard(Long nbContentId) throws NbApplicationException { + if (nbContentId == null) { + throw new NbApplicationException("Tool content ID is missing"); + } + + return nbContentDAO.findNbContentById(nbContentId); + } + + @Override + public NoticeboardContent retrieveNoticeboardBySessionID(Long nbSessionId) { + if (nbSessionId == null) { + throw new NbApplicationException("Tool session ID is missing"); + } + + return nbContentDAO.getNbContentBySession(nbSessionId); + } + + @Override + public void saveNoticeboard(NoticeboardContent nbContent) { + if (nbContent.getUid() == null) { + nbContentDAO.saveNbContent(nbContent); + } else { + nbContentDAO.updateNbContent(nbContent); + } + } + + @Override + public void removeNoticeboardSessionsFromContent(NoticeboardContent nbContent) { + nbContent.getNbSessions().clear(); + nbContentDAO.removeNbSessions(nbContent); + } + + @Override + public void removeNoticeboard(Long nbContentId) { + if (nbContentId == null) { + throw new NbApplicationException("Tool content ID is missing"); + } + nbContentDAO.removeNoticeboard(nbContentId); + } + + @Override + public void removeNoticeboard(NoticeboardContent nbContent) { + nbContentDAO.removeNoticeboard(nbContent); + } + + @Override + public NoticeboardSession retrieveNoticeboardSession(Long nbSessionId) { + if (nbSessionId == null) { + throw new NbApplicationException("Tool session ID is missing"); + } + + return nbSessionDAO.findNbSessionById(nbSessionId); + } + + @Override + public void saveNoticeboardSession(NoticeboardSession nbSession) { + NoticeboardContent content = nbSession.getNbContent(); + nbSessionDAO.saveNbSession(nbSession); + } + + @Override + public void updateNoticeboardSession(NoticeboardSession nbSession) { + nbSessionDAO.updateNbSession(nbSession); + } + + @Override + public void removeSession(Long nbSessionId) { + if (nbSessionId == null) { + throw new NbApplicationException("Tool session id is missing"); + } + + NoticeboardSession sessionToDelete = retrieveNoticeboardSession(nbSessionId); + NoticeboardContent contentReferredBySession = sessionToDelete.getNbContent(); + // un-associate the session from content + contentReferredBySession.getNbSessions().remove(sessionToDelete); + nbSessionDAO.removeNbSession(nbSessionId); + } + + @Override + public void removeSession(NoticeboardSession nbSession) { + NoticeboardContent contentReferredBySession = nbSession.getNbContent(); + // un-associate the session from content + contentReferredBySession.getNbSessions().remove(nbSession); + nbSessionDAO.removeNbSession(nbSession); + } + + @Override + public void removeNoticeboardUsersFromSession(NoticeboardSession nbSession) { + nbSession.getNbUsers().clear(); + nbSessionDAO.removeNbUsers(nbSession); + } + + @Override + public NoticeboardSession retrieveNbSessionByUserID(Long userId) { + if (userId == null) { + throw new NbApplicationException("Tool session ID is missing"); + } + return nbSessionDAO.getNbSessionByUser(userId); + } + + @Override + public NoticeboardUser retrieveNoticeboardUser(Long nbUserId, Long nbSessionId) { + if (nbUserId == null) { + throw new NbApplicationException("User ID is missing"); + } + + return nbUserDAO.getNbUser(nbUserId, nbSessionId); + } + + @Override + public void saveNoticeboardUser(NoticeboardUser nbUser) { + NoticeboardSession session = nbUser.getNbSession(); + session.getNbUsers().add(nbUser); + nbUserDAO.saveNbUser(nbUser); + } + + @Override + public NoticeboardUser retrieveNbUserBySession(Long userId, Long sessionId) { + return nbUserDAO.getNbUserBySession(userId, sessionId); + } + + @Override + public void updateNoticeboardUser(NoticeboardUser nbUser) { + nbUserDAO.updateNbUser(nbUser); + } + + @Override + public void removeUser(NoticeboardUser nbUser) { + nbUserDAO.delete(nbUser); + } + + @Override + public void removeUser(Long nbUserId, Long toolSessionId) { + NoticeboardUser user = retrieveNoticeboardUser(nbUserId, toolSessionId); + nbUserDAO.delete(user); + } + + @Override + public void addSession(Long nbContentId, NoticeboardSession session) { + if ((nbContentId == null) || (session == null)) { + throw new NbApplicationException("Tool content ID or session is missing"); + } + + nbContentDAO.addNbSession(nbContentId, session); + } + + @Override + public void addUser(Long nbSessionId, NoticeboardUser user) { + if (nbSessionId == null) { + throw new NbApplicationException("Tool session ID is missing"); + } + nbSessionDAO.addNbUsers(nbSessionId, user); + } + + @Override + public int getNumberOfUsersInSession(NoticeboardSession session) { + return nbUserDAO.getNumberOfUsers(session); + } + + @Override + public int calculateTotalNumberOfUsers(Long toolContentId) { + if (toolContentId == null) { + throw new NbApplicationException("Tool content id is missing"); + } + + int totalNumberOfUsers = 0; + NoticeboardContent nbContent = retrieveNoticeboard(toolContentId); + for (NoticeboardSession session : nbContent.getNbSessions()) { + totalNumberOfUsers += getNumberOfUsersInSession(session); + } + + return totalNumberOfUsers; + } + + @SuppressWarnings("unchecked") + @Override + public List getUsersBySession(Long sessionId) { + if (sessionId == null) { + throw new NbApplicationException("Session ID is missing"); + } + return nbUserDAO.getNbUsersBySession(sessionId); + } + + @Override + public boolean isGroupedActivity(long toolContentID) { + return toolService.isGroupedActivity(toolContentID); + } + + @Override + public void auditLogStartEditingActivityInMonitor(long toolContentID) { + toolService.auditLogStartEditingActivityInMonitor(toolContentID); + } + + @Override + public void copyToolContent(Long fromContentId, Long toContentId) throws ToolException { + if (toContentId == null) { + throw new ToolException("Failed to copy Noticeboard tool content. Missing parameter: toContentId"); + } + if (fromContentId == null) { + // use the default content Id + fromContentId = getToolDefaultContentIdBySignature(NoticeboardConstants.TOOL_SIGNATURE); + } + + // fromContentId might not have any content, in this case use default content + // default content id might not have any contnet, throw exception + NoticeboardContent originalNb = null; + + try { + if ((originalNb = retrieveNoticeboard(fromContentId)) == null) // the id given does not have content, use + // default content + { + // use default content id to grab contents + NoticeboardContent defaultContent = retrieveNoticeboard( + getToolDefaultContentIdBySignature(NoticeboardConstants.TOOL_SIGNATURE)); + + if (defaultContent != null) { + NoticeboardContent newContent = NoticeboardContent.newInstance(defaultContent, toContentId); + saveNoticeboard(newContent); + } else { + throw new ToolException("Default content is missing. Unable to copy tool content"); + } + } else { + NoticeboardContent newNbContent = NoticeboardContent.newInstance(originalNb, toContentId); + saveNoticeboard(newNbContent); + } + } catch (RepositoryCheckedException e) { + log.error("Unable to copy the tool content due to a content repository error. fromContentId " + + fromContentId + " toContentId " + toContentId); + throw new ToolException(e); + } + + } + + @Override + public void resetDefineLater(Long toolContentId) throws DataMissingException, ToolException { + NoticeboardContent nbContent = getAndCheckIDandObject(toolContentId); + nbContent.setDefineLater(false); + saveNoticeboard(nbContent); + } + + @Override + public void removeToolContent(Long toolContentId) throws ToolException { + NoticeboardContent nbContent = retrieveNoticeboard(toolContentId); + if (nbContent == null) { + log.warn("Can not remove the tool content as it does not exist, ID: " + toolContentId); + return; + } + + for (NoticeboardSession session : nbContent.getNbSessions()) { + List entries = coreNotebookService.getEntry(session.getNbSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, NoticeboardConstants.TOOL_SIGNATURE); + for (NotebookEntry entry : entries) { + coreNotebookService.deleteEntry(entry); + } + } + + removeNoticeboard(toolContentId); + } + + @Override + public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException { + if (log.isDebugEnabled()) { + log.debug("Removing Noticeboard user for user ID " + userId + " and toolContentId " + toolContentId); + } + + NoticeboardContent nbContent = nbContentDAO.findNbContentById(toolContentId); + if (nbContent == null) { + log.warn("Did not find activity with toolContentId: " + toolContentId + " to remove learner content"); + return; + } + + for (NoticeboardSession session : nbContent.getNbSessions()) { + NoticeboardUser user = nbUserDAO.getNbUser(userId.longValue(), session.getNbSessionId()); + if (user != null) { + NotebookEntry entry = getEntry(session.getNbSessionId(), CoreNotebookConstants.NOTEBOOK_TOOL, + NoticeboardConstants.TOOL_SIGNATURE, userId); + if (entry != null) { + nbContentDAO.delete(entry); + } + + nbUserDAO.delete(user); + } + } + } + + private NoticeboardContent getAndCheckIDandObject(Long toolContentId) throws ToolException, DataMissingException { + if (toolContentId == null) { + throw new ToolException("Tool content ID is missing. Unable to continue"); + } + + NoticeboardContent nbContent = retrieveNoticeboard(toolContentId); + if (nbContent == null) { + throw new DataMissingException("No tool content matches this tool content id"); + } + + return nbContent; + } + + private NoticeboardSession getAndCheckSessionIDandObject(Long toolSessionId) + throws ToolException, DataMissingException { + if (toolSessionId == null) { + throw new ToolException("Tool session ID is missing."); + } + + NoticeboardSession nbSession = retrieveNoticeboardSession(toolSessionId); + if (nbSession == null) { + throw new DataMissingException("No tool session matches this tool session id"); + } + + return nbSession; + } + + @Override + public void exportToolContent(Long toolContentId, String rootPath) throws DataMissingException, ToolException { + NoticeboardContent toolContentObj = nbContentDAO.findNbContentById(toolContentId); + if (toolContentObj == null) { + Long defaultContentId = getToolDefaultContentIdBySignature(NoticeboardConstants.TOOL_SIGNATURE); + toolContentObj = retrieveNoticeboard(defaultContentId); + } + if (toolContentObj == null) { + throw new DataMissingException("Unable to find default content for the noticeboard tool"); + } + + try { + // set ResourceToolContentHandler as null to avoid copy file node in repository again. + toolContentObj = NoticeboardContent.newInstance(toolContentObj, toolContentId); + toolContentObj.setNbSessions(null); + exportContentService.exportToolContent(toolContentId, toolContentObj, nbToolContentHandler, rootPath); + } catch (ExportToolContentException e) { + throw new ToolException(e); + } catch (ItemNotFoundException e) { + throw new ToolException(e); + } catch (RepositoryCheckedException e) { + throw new ToolException(e); + } + } + + @Override + public void importToolContent(Long toolContentId, Integer newUserUid, String toolContentPath, String fromVersion, + String toVersion) throws ToolException { + try { + // register version filter class + exportContentService.registerImportVersionFilterClass(NoticeboardImportContentVersionFilter.class); + + Object toolPOJO = exportContentService.importToolContent(toolContentPath, nbToolContentHandler, fromVersion, + toVersion); + if (!(toolPOJO instanceof NoticeboardContent)) { + throw new ImportToolContentException( + "Import Noteice board tool content failed. Deserialized object is " + toolPOJO); + } + NoticeboardContent toolContentObj = (NoticeboardContent) toolPOJO; + + // reset it to new toolContentId + toolContentObj.setNbContentId(toolContentId); + nbContentDAO.saveNbContent(toolContentObj); + } catch (ImportToolContentException e) { + throw new ToolException(e); + } + } + + @Override + public SortedMap getToolOutputDefinitions(Long toolContentId, int definitionType) + throws ToolException { + return new TreeMap(); + } + + @Override + public String getToolContentTitle(Long toolContentId) { + return retrieveNoticeboard(toolContentId).getTitle(); + } + + @Override + public boolean isContentEdited(Long toolContentId) { + return retrieveNoticeboard(toolContentId).isDefineLater(); + } + + @Override + public boolean isReadOnly(Long toolContentId) { + NoticeboardContent nbContent = nbContentDAO.findNbContentById(toolContentId); + for (NoticeboardSession session : nbContent.getNbSessions()) { + if (!session.getNbUsers().isEmpty()) { + return true; + } + } + + return false; + } + + @Override + public void createToolSession(Long toolSessionId, String toolSessionName, Long toolContentId) throws ToolException { + if ((toolSessionId == null) || (toolContentId == null)) { + String error = "Failed to create tool session. The tool session id or tool content id is invalid"; + throw new ToolException(error); + } + + NoticeboardContent nbContent = retrieveNoticeboard(toolContentId); + NoticeboardSession nbSession = new NoticeboardSession(toolSessionId, toolSessionName, nbContent, + new Date(System.currentTimeMillis()), NoticeboardSession.NOT_ATTEMPTED); + + nbContent.getNbSessions().add(nbSession); + saveNoticeboard(nbContent); + } + + @Override + public String leaveToolSession(Long toolSessionId, Long learnerId) throws DataMissingException, ToolException { + getAndCheckSessionIDandObject(toolSessionId); + + return learnerService.completeToolSession(toolSessionId, learnerId); + } + + @Override + public ToolSessionExportOutputData exportToolSession(Long toolSessionId) + throws ToolException, DataMissingException { + getAndCheckSessionIDandObject(toolSessionId); + throw new UnsupportedOperationException("not yet implemented"); + } + + @SuppressWarnings("unchecked") + @Override + public ToolSessionExportOutputData exportToolSession(List toolSessionIds) + throws ToolException, DataMissingException { + Iterator i = toolSessionIds.iterator(); + if (i.hasNext()) { + Long id = i.next(); + getAndCheckSessionIDandObject(id); + } + + throw new UnsupportedOperationException("not yet implemented"); + } + + @Override + public void removeToolSession(Long toolSessionId) throws DataMissingException, ToolException { + NoticeboardSession session = getAndCheckSessionIDandObject(toolSessionId); + removeSession(session); + } + + @Override + public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { + return new TreeMap(); + } + + @Override + public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { + return null; + } + + @Override + public List getToolOutputs(String name, Long toolContentId) { + return new ArrayList(); + } + + @Override + public void forceCompleteUser(Long toolSessionId, User user) { + //no actions required + } + + @Override + public Long getToolDefaultContentIdBySignature(String toolSignature) { + return toolService.getToolDefaultContentIdBySignature(toolSignature); + } + + public void setNbContentDAO(INoticeboardContentDAO nbContentDAO) { + this.nbContentDAO = nbContentDAO; + } + + public void setNbSessionDAO(INoticeboardSessionDAO nbSessionDAO) { + this.nbSessionDAO = nbSessionDAO; + } + + public void setNbUserDAO(INoticeboardUserDAO nbUserDAO) { + this.nbUserDAO = nbUserDAO; + } + + public void setLearnerService(ILearnerService learnerService) { + this.learnerService = learnerService; + } + + public void setToolService(ILamsToolService toolService) { + this.toolService = toolService; + } + + public IToolContentHandler getNbToolContentHandler() { + return nbToolContentHandler; + } + + public void setNbToolContentHandler(IToolContentHandler nbToolContentHandler) { + this.nbToolContentHandler = nbToolContentHandler; + } + + 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; + } + + /* =============== Wrappers Methods for Notebook Service (Reflective Option) =============== */ + + @Override + public Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry) { + return coreNotebookService.createNotebookEntry(id, idType, signature, userID, "", entry); + } + + @Override + public NotebookEntry getEntry(Long id, Integer idType, String signature, Integer userID) { + List list = coreNotebookService.getEntry(id, idType, signature, userID); + if ((list == null) || list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public void updateEntry(NotebookEntry notebookEntry) { + coreNotebookService.updateEntry(notebookEntry); + } + + @Override + public Class[] getSupportedToolOutputDefinitionClasses(int definitionType) { + return null; + } + + @Override + public ToolCompletionStatus getCompletionStatus(Long learnerId, Long toolSessionId) { + // db doesn't have a start/finish date for learner, and session start/finish is null + NoticeboardUser learner = retrieveNoticeboardUser(learnerId, toolSessionId); + if (learner == null) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); + } + + return new ToolCompletionStatus( + NoticeboardUser.COMPLETED.equals(learner.getUserStatus()) ? ToolCompletionStatus.ACTIVITY_COMPLETED + : ToolCompletionStatus.ACTIVITY_ATTEMPTED, + null, null); + } + + // ****************** REST methods ************************* + + @Override + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { + Date updateDate = new Date(); + + NoticeboardContent noticeboard = new NoticeboardContent(); + noticeboard.setNbContentId(toolContentID); + noticeboard.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + noticeboard.setContent(JsonUtil.optString(toolContentJSON, "content")); + noticeboard.setReflectOnActivity( + JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + noticeboard.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + + noticeboard.setCreatorUserId(userID.longValue()); + noticeboard.setDateCreated(updateDate); + noticeboard.setDateUpdated(updateDate); + noticeboard.setContentInUse(false); + + saveNoticeboard(noticeboard); + } +} \ No newline at end of file Index: lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/service/SubmitFilesService.java =================================================================== diff -u -rb67c428939ed96f08f56192d54b8ee55d8ab89d2 -r2c03060b238558d183472f0066ba003c76d00fd0 --- lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/service/SubmitFilesService.java (.../SubmitFilesService.java) (revision b67c428939ed96f08f56192d54b8ee55d8ab89d2) +++ lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/service/SubmitFilesService.java (.../SubmitFilesService.java) (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -21,8 +21,6 @@ * **************************************************************** */ - - package org.lamsfoundation.lams.tool.sbmt.service; import java.io.FileNotFoundException; @@ -44,8 +42,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.upload.FormFile; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; import org.lamsfoundation.lams.contentrepository.IVersionedNode; @@ -105,6 +101,8 @@ import org.lamsfoundation.lams.util.audit.IAuditService; import org.springframework.dao.DataAccessException; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Manpreet Minhas */ @@ -534,10 +532,10 @@ public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { return getSubmitFilesOutputFactory().getToolOutput(name, this, toolSessionId, learnerId); } - + @Override public List getToolOutputs(String name, Long toolContentId) { - return new ArrayList(); + return new ArrayList<>(); } @Override @@ -620,7 +618,8 @@ * java.lang.Long) */ @Override - public List getFilesUploadedByUser(Integer userID, Long sessionID, Locale currentLocale, boolean includeRemovedFiles) { + public List getFilesUploadedByUser(Integer userID, Long sessionID, Locale currentLocale, + boolean includeRemovedFiles) { List list = submissionDetailsDAO.getBySessionAndLearner(sessionID, userID); SortedSet details = new TreeSet(this.new FileDtoComparator()); if (list == null) { @@ -629,7 +628,7 @@ NumberFormat numberFormat = currentLocale != null ? NumberFormat.getInstance(currentLocale) : null; for (SubmissionDetails submissionDetails : list) { - if ( includeRemovedFiles || ! submissionDetails.isRemoved() ) { + if (includeRemovedFiles || !submissionDetails.isRemoved()) { FileDetailsDTO detailDto = new FileDetailsDTO(submissionDetails, numberFormat); details.add(detailDto); } @@ -743,16 +742,15 @@ } } - @Override public void removeLearnerFile(Long detailID, UserDTO monitor) { SubmissionDetails detail = submissionDetailsDAO.getSubmissionDetailsByID(detailID); if (detail != null) { - if(monitor != null){ + if (monitor != null) { - auditRemoveRestore(monitor, detail, "audit.file.delete"); + auditRemoveRestore(monitor, detail, "audit.file.delete"); } detail.setRemoved(true); @@ -762,13 +760,13 @@ @Override public void restoreLearnerFile(Long detailID, UserDTO monitor) { - + SubmissionDetails detail = submissionDetailsDAO.getSubmissionDetailsByID(detailID); if (detail != null) { - - auditRemoveRestore(monitor, detail,"audit.file.restore"); - + + auditRemoveRestore(monitor, detail, "audit.file.restore"); + detail.setRemoved(false); submissionDetailsDAO.update(detail); } @@ -777,17 +775,16 @@ private void auditRemoveRestore(UserDTO monitor, SubmissionDetails detail, String i18nKey) { SubmitUser learner = detail.getLearner(); - StringBuilder instructorTxt = new StringBuilder(monitor.getLogin()).append(" (").append(monitor.getUserID()).append(") ") - .append(monitor.getFirstName()).append(" ").append(monitor.getLastName()); - StringBuilder learnerTxt = new StringBuilder(learner.getLogin()).append(" (").append(learner.getUserID()).append(") ") - .append(learner.getFirstName()).append(" ").append(learner.getLastName()); + StringBuilder instructorTxt = new StringBuilder(monitor.getLogin()).append(" (").append(monitor.getUserID()) + .append(") ").append(monitor.getFirstName()).append(" ").append(monitor.getLastName()); + StringBuilder learnerTxt = new StringBuilder(learner.getLogin()).append(" (").append(learner.getUserID()) + .append(") ").append(learner.getFirstName()).append(" ").append(learner.getLastName()); - String auditMsg = getLocalisedMessage(i18nKey, new Object[] { instructorTxt.toString(), detail.getFilePath(), - learnerTxt.toString() }); + String auditMsg = getLocalisedMessage(i18nKey, + new Object[] { instructorTxt.toString(), detail.getFilePath(), learnerTxt.toString() }); auditService.log(SbmtConstants.AUDIT_LOG_MODULE_NAME, auditMsg); } - @Override public IVersionedNode downloadFile(Long uuid, Long versionID) throws SubmitFilesException { ITicket ticket = getRepositoryLoginTicket(); @@ -824,14 +821,14 @@ Map notificationMessages = null; Object[] notificationMessageParameters = null; if (notifyLearnersOnMarkRelease) { - notificationMessages = new TreeMap(); + notificationMessages = new TreeMap<>(); notificationMessageParameters = new Object[3]; } while (iter.hasNext()) { details = (SubmissionDetails) iter.next(); report = details.getReport(); report.setDateMarksReleased(new Date()); - if (notifyLearnersOnMarkRelease && ! details.isRemoved()) { + if (notifyLearnersOnMarkRelease && !details.isRemoved()) { SubmitUser user = details.getLearner(); StringBuilder notificationMessage = notificationMessages.get(user.getUserID()); if (notificationMessage == null) { @@ -891,7 +888,7 @@ if (detailsList != null) { Float totalMark = null; for (SubmissionDetails details : detailsList) { - if ( ! details.isRemoved() ) { + if (!details.isRemoved()) { SubmitFilesReport report = details.getReport(); if (report != null) { if (totalMark == null) { @@ -973,10 +970,10 @@ public boolean isGroupedActivity(long toolContentID) { return toolService.isGroupedActivity(toolContentID); } - + @Override public void auditLogStartEditingActivityInMonitor(long toolContentID) { - toolService.auditLogStartEditingActivityInMonitor(toolContentID); + toolService.auditLogStartEditingActivityInMonitor(toolContentID); } @Override @@ -1198,11 +1195,11 @@ } public IAuditService getAuditService() { - return auditService; + return auditService; } public void setAuditService(IAuditService auditService) { - this.auditService = auditService; + this.auditService = auditService; } public void setGradebookService(IGradebookService gradebookService) { @@ -1222,7 +1219,7 @@ public void setSubmitFilesOutputFactory(SubmitFilesOutputFactory submitFilesOutputFactory) { this.submitFilesOutputFactory = submitFilesOutputFactory; } - + @Override public ToolCompletionStatus getCompletionStatus(Long learnerId, Long toolSessionId) { SubmitUser learner = getSessionUser(toolSessionId, learnerId.intValue()); @@ -1233,20 +1230,23 @@ Date startDate = null; Date endDate = null; List list = submissionDetailsDAO.getBySessionAndLearner(toolSessionId, learnerId.intValue()); - for ( SubmissionDetails detail : list ) { + for (SubmissionDetails detail : list) { Date newDate = detail.getDateOfSubmission(); - if ( newDate != null ) { - if ( startDate == null || newDate.before(startDate) ) + if (newDate != null) { + if (startDate == null || newDate.before(startDate)) { startDate = newDate; - if ( endDate == null || newDate.after(endDate) ) + } + if (endDate == null || newDate.after(endDate)) { endDate = newDate; + } } } - - if (learner.isFinished()) + + if (learner.isFinished()) { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, startDate, endDate); - else + } else { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, startDate, null); + } } // ****************** REST methods ************************* @@ -1255,35 +1255,35 @@ * Used by the Rest calls to create content. Mandatory fields in toolContentJSON: title, instructions */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { SubmitFilesContent content = new SubmitFilesContent(); Date updateDate = new Date(); content.setCreated(updateDate); content.setUpdated(updateDate); content.setContentID(toolContentID); - content.setTitle(toolContentJSON.getString(RestTags.TITLE)); - content.setInstruction(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + content.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + content.setInstruction(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); content.setContentInUse(false); content.setDefineLater(false); content.setNotifyTeachersOnFileSubmit( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnFileSubmit", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnFileSubmit", Boolean.FALSE)); content.setNotifyLearnersOnMarkRelease( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); - content.setReflectInstructions((String) JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, null)); - content.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); - content.setLockOnFinished(JsonUtil.opt(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); - content.setLimitUpload(JsonUtil.opt(toolContentJSON, "limitUpload", Boolean.FALSE)); - content.setLimitUploadNumber(JsonUtil.opt(toolContentJSON, "limitUploadNumber", 0)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); + content.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + content.setReflectOnActivity(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + content.setLockOnFinished(JsonUtil.optBoolean(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); + content.setLimitUpload(JsonUtil.optBoolean(toolContentJSON, "limitUpload", Boolean.FALSE)); + content.setLimitUploadNumber(JsonUtil.optInt(toolContentJSON, "limitUploadNumber", 0)); // submissionDeadline is set in monitoring SubmitUser user = getContentUser(toolContentID, userID); if (user == null) { - user = createContentUser(userID, toolContentJSON.getString("firstName"), - toolContentJSON.getString("lastName"), toolContentJSON.getString("loginName"), toolContentID); + user = createContentUser(userID, JsonUtil.optString(toolContentJSON, "firstName"), + JsonUtil.optString(toolContentJSON, "lastName"), JsonUtil.optString(toolContentJSON, "loginName"), + toolContentID); } content.setCreatedBy(user); saveOrUpdateContent(content); Index: lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/web/action/MonitoringAction.java =================================================================== diff -u --- lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/web/action/MonitoringAction.java (revision 0) +++ lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/web/action/MonitoringAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,640 @@ +/**************************************************************** + * 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 version 2.0 + * 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 + * **************************************************************** + */ +package org.lamsfoundation.lams.tool.sbmt.web.action; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Comparator; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TimeZone; +import java.util.TreeSet; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.DynaActionForm; +import org.lamsfoundation.lams.tool.sbmt.SbmtConstants; +import org.lamsfoundation.lams.tool.sbmt.SubmissionDetails; +import org.lamsfoundation.lams.tool.sbmt.SubmitFilesContent; +import org.lamsfoundation.lams.tool.sbmt.SubmitFilesSession; +import org.lamsfoundation.lams.tool.sbmt.SubmitUser; +import org.lamsfoundation.lams.tool.sbmt.dto.AuthoringDTO; +import org.lamsfoundation.lams.tool.sbmt.dto.FileDetailsDTO; +import org.lamsfoundation.lams.tool.sbmt.dto.SessionDTO; +import org.lamsfoundation.lams.tool.sbmt.dto.StatisticDTO; +import org.lamsfoundation.lams.tool.sbmt.service.ISubmitFilesService; +import org.lamsfoundation.lams.tool.sbmt.service.SubmitFilesServiceProxy; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Manpreet Minhas + */ +public class MonitoringAction extends LamsDispatchAction { + + public ISubmitFilesService submitFilesService; + + private class SessionComparator implements Comparator { + @Override + public int compare(SessionDTO o1, SessionDTO o2) { + if (o1 != null && o2 != null) { + return o1.getSessionName().compareTo(o2.getSessionName()); + } else if (o1 != null) { + return 1; + } else { + return -1; + } + } + } + + private class StatisticComparator implements Comparator { + @Override + public int compare(StatisticDTO o1, StatisticDTO o2) { + if (o1 != null && o2 != null) { + return o1.getSessionName().compareTo(o2.getSessionName()); + } else if (o1 != null) { + return 1; + } else { + return -1; + } + } + } + + /** + * Default ActionForward for Monitor + */ + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID); + Long contentID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID)); + submitFilesService = getSubmitFilesService(); + + request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); + request.setAttribute(AttributeNames.PARAM_TOOL_CONTENT_ID, contentID); + + List submitFilesSessionList = submitFilesService.getSubmitFilesSessionByContentID(contentID); + summary(request, submitFilesSessionList); + statistic(request, contentID); + + // instruction + SubmitFilesContent persistContent = submitFilesService.getSubmitFilesContent(contentID); + // if this content does not exist, then reset the contentID to current value to keep it on HTML page. + persistContent.setContentID(contentID); + + AuthoringDTO authorDto = new AuthoringDTO(persistContent); + request.setAttribute(SbmtConstants.AUTHORING_DTO, authorDto); + request.setAttribute(SbmtConstants.PAGE_EDITABLE, !persistContent.isContentInUse()); + request.setAttribute(SbmtConstants.ATTR_IS_GROUPED_ACTIVITY, submitFilesService.isGroupedActivity(contentID)); + request.setAttribute(SbmtConstants.ATTR_REFLECTION_ON, persistContent.isReflectOnActivity()); + + // set SubmissionDeadline, if any + if (persistContent.getSubmissionDeadline() != null) { + Date submissionDeadline = persistContent.getSubmissionDeadline(); + HttpSession ss = SessionManager.getSession(); + UserDTO teacher = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone teacherTimeZone = teacher.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(teacherTimeZone, submissionDeadline); + request.setAttribute(SbmtConstants.ATTR_SUBMISSION_DEADLINE, tzSubmissionDeadline.getTime()); + request.setAttribute(SbmtConstants.ATTR_SUBMISSION_DEADLINE_DATESTRING, + DateUtil.convertToStringForJSON(submissionDeadline, request.getLocale())); + } + + DynaActionForm smbtMonitoringForm = (DynaActionForm) form; + // smbtMonitoringForm.set("currentTab", WebUtil.readStrParam(request, AttributeNames.PARAM_CURRENT_TAB,true)); + + return mapping.findForward("success"); + } + + /** Ajax call to populate the tablesorter */ + public ActionForward getUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + Long sessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); + Long contentId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByName = WebUtil.readIntParam(request, "column[0]", true); + Integer sortByNumFiles = WebUtil.readIntParam(request, "column[1]", true); + Integer sortByMarked = WebUtil.readIntParam(request, "column[2]", true); + String searchString = request.getParameter("fcol[0]"); + + int sorting = SbmtConstants.SORT_BY_NO; + if (sortByName != null) { + sorting = sortByName.equals(0) ? SbmtConstants.SORT_BY_USERNAME_ASC : SbmtConstants.SORT_BY_USERNAME_DESC; + } else if (sortByNumFiles != null) { + sorting = sortByNumFiles.equals(0) ? SbmtConstants.SORT_BY_NUM_FILES_ASC + : SbmtConstants.SORT_BY_NUM_FILES_DESC; + } else if (sortByMarked != null) { + sorting = sortByMarked.equals(0) ? SbmtConstants.SORT_BY_MARKED_ASC : SbmtConstants.SORT_BY_MARKED_DESC; + } + + // return user list according to the given sessionID + ISubmitFilesService service = getSubmitFilesService(); + SubmitFilesContent spreadsheet = service.getSubmitFilesContent(contentId); + List users = service.getUsersForTablesorter(sessionID, page, size, sorting, searchString, + spreadsheet.isReflectOnActivity()); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("total_rows", service.getCountUsersBySession(sessionID, searchString)); + + for (Object[] userAndReflection : users) { + + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + + SubmitUser user = (SubmitUser) userAndReflection[0]; + responseRow.put(SbmtConstants.ATTR_USER_UID, user.getUid()); + responseRow.put(SbmtConstants.USER_ID, user.getUserID()); + responseRow.put(SbmtConstants.ATTR_USER_FULLNAME, StringEscapeUtils.escapeHtml(user.getFullName())); + + if (userAndReflection.length > 2) { + responseRow.put(SbmtConstants.ATTR_USER_NUM_FILE, + (Integer) userAndReflection[1] - (Integer) userAndReflection[2]); + } + + if (userAndReflection.length > 3) { + responseRow.put(SbmtConstants.ATTR_USER_FILE_MARKED, (Integer) userAndReflection[3] > 0); + } + + if (userAndReflection.length > 4) { + responseRow.put(SbmtConstants.ATTR_USER_REFLECTION, (String) userAndReflection[4]); + } + + rows.add(responseRow); + } + + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + + } + + /** + * AJAX call to refresh statistic page. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward doStatistic(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + Long contentID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID)); + submitFilesService = getSubmitFilesService(); + statistic(request, contentID); + request.setAttribute(SbmtConstants.ATTR_IS_GROUPED_ACTIVITY, submitFilesService.isGroupedActivity(contentID)); + return mapping.findForward("statistic"); + } + + private void statistic(HttpServletRequest request, Long contentID) { + SortedSet statistics = new TreeSet(new StatisticComparator()); + statistics.addAll(submitFilesService.getStatisticsBySession(contentID)); + request.setAttribute("statisticList", statistics); + } + + /** + * Release mark + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward releaseMarks(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + // get service then update report table + submitFilesService = getSubmitFilesService(); + Long sessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); + submitFilesService.releaseMarksForSession(sessionID); + + try { + response.setContentType("text/html;charset=utf-8"); + PrintWriter out = response.getWriter(); + SubmitFilesSession session = submitFilesService.getSessionById(sessionID); + String sessionName = ""; + if (session != null) { + sessionName = session.getSessionName(); + } + out.write(getMessageService().getMessage("msg.mark.released", new String[] { sessionName })); + out.flush(); + } catch (IOException e) { + } + return null; + } + + /** + * Download submit file marks by MS Excel file format. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward downloadMarks(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + Long sessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); + submitFilesService = getSubmitFilesService(); + // return FileDetailsDTO list according to the given sessionID + Map userFilesMap = submitFilesService.getFilesUploadedBySession(sessionID, request.getLocale()); + // construct Excel file format and download + String errors = null; + try { + // create an empty excel file + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Marks"); + sheet.setColumnWidth(0, 5000); + HSSFRow row; + HSSFCell cell; + + Iterator iter = userFilesMap.values().iterator(); + Iterator dtoIter; + + int idx = 0; + + row = sheet.createRow(idx++); + cell = row.createCell(2); + cell.setCellValue(getMessageService().getMessage("label.learner.fileName")); + + cell = row.createCell(3); + cell.setCellValue(getMessageService().getMessage("label.learner.fileDescription")); + + cell = row.createCell(4); + cell.setCellValue(getMessageService().getMessage("label.learner.marks")); + + cell = row.createCell(5); + cell.setCellValue(getMessageService().getMessage("label.learner.comments")); + + while (iter.hasNext()) { + List list = (List) iter.next(); + dtoIter = list.iterator(); + + while (dtoIter.hasNext()) { + FileDetailsDTO dto = (FileDetailsDTO) dtoIter.next(); + if (!dto.isRemoved()) { + row = sheet.createRow(idx++); + + int count = 0; + + cell = row.createCell(count++); + cell.setCellValue(dto.getOwner().getFullName()); + + ++count; + + sheet.setColumnWidth(count, 8000); + + cell = row.createCell(count++); + cell.setCellValue(dto.getFilePath()); + + cell = row.createCell(count++); + cell.setCellValue(dto.getFileDescription()); + + cell = row.createCell(count++); + + String marks = dto.getMarks(); + cell.setCellValue(marks != null ? marks : ""); + + cell = row.createCell(count++); + cell.setCellValue(dto.getComments()); + } + } + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + wb.write(bos); + + // construct download file response header + String fileName = "marks" + sessionID + ".xls"; + String mineType = "application/vnd.ms-excel"; + String header = "attachment; filename=\"" + fileName + "\";"; + response.setContentType(mineType); + response.setHeader("Content-Disposition", header); + + byte[] data = bos.toByteArray(); + response.getOutputStream().write(data, 0, data.length); + response.getOutputStream().flush(); + } catch (Exception e) { + LamsDispatchAction.log.error(e); + errors = new ActionMessage("monitoring.download.error", e.toString()).toString(); + } + + if (errors != null) { + try { + PrintWriter out = response.getWriter(); + out.write(errors); + out.flush(); + } catch (IOException e) { + } + } + + return null; + } + + /** + * Set Submission Deadline + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + */ + public ActionForward setSubmissionDeadline(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + submitFilesService = getSubmitFilesService(); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + SubmitFilesContent content = submitFilesService.getSubmitFilesContent(contentID); + + Long dateParameter = WebUtil.readLongParam(request, SbmtConstants.ATTR_SUBMISSION_DEADLINE, true); + Date tzSubmissionDeadline = null; + String formattedDate = ""; + if (dateParameter != null) { + Date submissionDeadline = new Date(dateParameter); + HttpSession ss = SessionManager.getSession(); + UserDTO teacher = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone teacherTimeZone = teacher.getTimeZone(); + tzSubmissionDeadline = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, submissionDeadline); + formattedDate = DateUtil.convertToStringForJSON(tzSubmissionDeadline, request.getLocale()); + } + content.setSubmissionDeadline(tzSubmissionDeadline); + submitFilesService.saveOrUpdateContent(content); + + response.setContentType("text/plain;charset=utf-8"); + response.getWriter().print(formattedDate); + return null; + } + + // ********************************************************** + // Mark udpate/view methods + // ********************************************************** + /** + * Display special user's marks information. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward listMark(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + Long sessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); + Integer userID = WebUtil.readIntParam(request, "userID"); + + submitFilesService = getSubmitFilesService(); + // return FileDetailsDTO list according to the given userID and sessionID + List files = submitFilesService.getFilesUploadedByUser(userID, sessionID, request.getLocale(), true); + + request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID, sessionID); + request.setAttribute("report", files); + return mapping.findForward("listMark"); + } + + /** + * View mark of all learner from same tool content ID. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward listAllMarks(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + Long sessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); + submitFilesService = getSubmitFilesService(); + // return FileDetailsDTO list according to the given sessionID + Map userFilesMap = submitFilesService.getFilesUploadedBySession(sessionID, request.getLocale()); + request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID, sessionID); + // request.setAttribute("user",submitFilesService.getUserDetails(userID)); + request.setAttribute("reports", userFilesMap); + + return mapping.findForward("listAllMarks"); + + } + + /** + * Remove the original file created by the learner. Does not actually remove it from the content repository - merely + * makes it as removed. + */ + public ActionForward removeLearnerFile(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + return removeRestoreLearnerFile(mapping, form, request, response, true); + } + + /** + * Remove the original file created by the learner. Does not actually remove it from the content repository - merely + * makes it as removed. + */ + public ActionForward restoreLearnerFile(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + return removeRestoreLearnerFile(mapping, form, request, response, false); + } + + private ActionForward removeRestoreLearnerFile(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response, boolean remove) throws ServletException { + + UserDTO currentUser = (UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER); + + if (submitFilesService == null) { + submitFilesService = getSubmitFilesService(); + } + + Long sessionID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + Integer learnerUserID = WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID); + Long detailID = WebUtil.readLongParam(request, "detailID"); + + SubmissionDetails fileToProcess = submitFilesService.getSubmissionDetail(detailID); + + if (fileToProcess == null) { + StringBuilder builder = new StringBuilder("Unable to ").append(remove ? "remove" : "restore") + .append("file as file does not exist. Requested by user ").append(currentUser.getUserID()) + .append(" for file ").append(detailID).append(" for user ").append(learnerUserID); + log.error(builder.toString()); + throw new ServletException("Invalid call to " + (remove ? "remove" : "restore") + + " file. See the server log for more details."); + } else { + + if (!fileToProcess.getSubmitFileSession().getSessionID().equals(sessionID) + || !fileToProcess.getLearner().getUserID().equals(learnerUserID)) { + StringBuilder builder = new StringBuilder("Unable to ").append(remove ? "remove" : "restore") + .append("file as values in database do not match values in request. Requested by user ") + .append(currentUser.getUserID()).append(" for file ").append(detailID).append(" for user ") + .append(learnerUserID).append(" in session ").append(sessionID); + log.error(builder.toString()); + throw new ServletException("Invalid call to " + (remove ? "remove" : "restore") + + " file. See the server log for more details."); + } else { + + if (remove) { + submitFilesService.removeLearnerFile(detailID, currentUser); + notifyRemoveRestore(fileToProcess, "event.file.restore.subject", "event.file.restore.body", + "restore file"); + + } else { + submitFilesService.restoreLearnerFile(detailID, currentUser); + notifyRemoveRestore(fileToProcess, "event.file.delete.subject", "event.file.delete.body", + "delete file"); + } + + } + } + + List files = submitFilesService.getFilesUploadedByUser(learnerUserID, sessionID, request.getLocale(), true); + + request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID, sessionID); + request.setAttribute("report", files); + return mapping.findForward("listMark"); + } + + /** + * Notify the user by email of the file change. Need to do it here rather than in the service so that any issues are + * caught and logged + * without stuffing up the transaction. + */ + public void notifyRemoveRestore(SubmissionDetails detail, String i18nSubjectKey, String i18nBodyKey, + String errorSubject) { + Long contentID = detail.getSubmitFileSession().getContent().getContentID(); + Integer learnerID = detail.getLearner().getUserID(); + + // Can't just create a new subscription then call triggerForSingleUser() as + // it needs a subscription id, which doesn't exist for a subscription created in the same + // transaction. So reuse the existing RELEASE MARKS event and subscription (created when + // a file is uploaded) and override both the subject and the message. + + try { + boolean eventExists = submitFilesService.getEventNotificationService().eventExists( + SbmtConstants.TOOL_SIGNATURE, SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE, contentID); + + if (eventExists) { + submitFilesService.getEventNotificationService().triggerForSingleUser(SbmtConstants.TOOL_SIGNATURE, + SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE, contentID, learnerID, + submitFilesService.getLocalisedMessage(i18nSubjectKey, null), + submitFilesService.getLocalisedMessage(i18nBodyKey, new Object[] { detail.getFilePath() })); + } else { + log.error("Unable to notify user of " + errorSubject + ". contentID=" + contentID + " learner=" + + learnerID + " file " + detail.getFilePath() + " as " + + SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE + " event is missing"); + } + } catch (Exception e) { + log.error("Unable to notify user of " + errorSubject + ". contentID=" + contentID + " learner=" + learnerID + + " file " + detail.getFilePath() + " due to exception " + e.getMessage(), e); + } + } + + // ********************************************************** + // Private methods + // ********************************************************** + + private ISubmitFilesService getSubmitFilesService() { + return SubmitFilesServiceProxy.getSubmitFilesService(this.getServlet().getServletContext()); + } + + /** + * Return ResourceService bean. + */ + private MessageService getMessageService() { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + return (MessageService) wac.getBean("sbmtMessageService"); + } + + /** + * Save file mark information into HttpRequest + * + * @param request + * @param sessionID + * @param userID + * @param detailID + * @param updateMode + */ + private void setMarkPage(HttpServletRequest request, Long sessionID, Long userID, Long detailID, + String updateMode) { + + } + + /** + * Save Summary information into HttpRequest. + * + * @param request + * @param submitFilesSessionList + */ + private void summary(HttpServletRequest request, List submitFilesSessionList) { + SortedSet sessions = new TreeSet(this.new SessionComparator()); + + // build a map with all users in the submitFilesSessionList + Iterator it = submitFilesSessionList.iterator(); + while (it.hasNext()) { + SessionDTO sessionDto = new SessionDTO(); + SubmitFilesSession sfs = (SubmitFilesSession) it.next(); + + Long sessionID = sfs.getSessionID(); + sessionDto.setSessionID(sessionID); + sessionDto.setSessionName(sfs.getSessionName()); + sessions.add(sessionDto); + } + + // request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID,sessionID); + request.setAttribute("sessions", sessions); + } + +} \ No newline at end of file Index: lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/service/VoteService.java =================================================================== diff -u --- lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/service/VoteService.java (revision 0) +++ lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/service/VoteService.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,2048 @@ +/*************************************************************************** + * 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 version 2.0 + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.vote.service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.TreeSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; +import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learningdesign.DataFlowObject; +import org.lamsfoundation.lams.learningdesign.dao.IDataFlowDAO; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService; +import org.lamsfoundation.lams.learningdesign.service.ImportToolContentException; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; +import org.lamsfoundation.lams.rest.RestTags; +import org.lamsfoundation.lams.rest.ToolRestManager; +import org.lamsfoundation.lams.tool.IToolVO; +import org.lamsfoundation.lams.tool.SimpleURL; +import org.lamsfoundation.lams.tool.ToolCompletionStatus; +import org.lamsfoundation.lams.tool.ToolContentManager; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.ToolSessionExportOutputData; +import org.lamsfoundation.lams.tool.ToolSessionManager; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.service.ILamsToolService; +import org.lamsfoundation.lams.tool.vote.VoteAppConstants; +import org.lamsfoundation.lams.tool.vote.dao.IVoteContentDAO; +import org.lamsfoundation.lams.tool.vote.dao.IVoteQueContentDAO; +import org.lamsfoundation.lams.tool.vote.dao.IVoteSessionDAO; +import org.lamsfoundation.lams.tool.vote.dao.IVoteUserDAO; +import org.lamsfoundation.lams.tool.vote.dao.IVoteUsrAttemptDAO; +import org.lamsfoundation.lams.tool.vote.dto.OpenTextAnswerDTO; +import org.lamsfoundation.lams.tool.vote.dto.ReflectionDTO; +import org.lamsfoundation.lams.tool.vote.dto.SessionDTO; +import org.lamsfoundation.lams.tool.vote.dto.SessionNominationDTO; +import org.lamsfoundation.lams.tool.vote.dto.SummarySessionDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteGeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteMonitoredAnswersDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteMonitoredUserDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteQuestionDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteStatsDTO; +import org.lamsfoundation.lams.tool.vote.pojos.VoteContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteQueContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteQueUsr; +import org.lamsfoundation.lams.tool.vote.pojos.VoteSession; +import org.lamsfoundation.lams.tool.vote.pojos.VoteUsrAttempt; +import org.lamsfoundation.lams.tool.vote.util.VoteApplicationException; +import org.lamsfoundation.lams.tool.vote.util.VoteComparator; +import org.lamsfoundation.lams.tool.vote.util.VoteUtils; +import org.lamsfoundation.lams.tool.vote.web.action.MonitoringAction; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.JsonUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.audit.IAuditService; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.dao.DataAccessException; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * The POJO implementation of Voting service. All business logic of Voting tool is implemented in this class. It + * translates the request from presentation layer and performs appropriate database operation. + * + * @author Ozgur Demirtas + */ +public class VoteService + implements IVoteService, ToolContentManager, ToolSessionManager, VoteAppConstants, ToolRestManager { + private static Logger logger = Logger.getLogger(VoteService.class.getName()); + + private IVoteContentDAO voteContentDAO; + private IVoteQueContentDAO voteQueContentDAO; + private IVoteSessionDAO voteSessionDAO; + private IVoteUserDAO voteUserDAO; + private IVoteUsrAttemptDAO voteUsrAttemptDAO; + + private IUserManagementService userManagementService; + private ILearnerService learnerService; + private IAuditService auditService; + private ILamsToolService toolService; + private IExportToolContentService exportContentService; + + private ICoreNotebookService coreNotebookService; + private IToolContentHandler voteToolContentHandler = null; + private VoteOutputFactory voteOutputFactory; + private IDataFlowDAO dataFlowDAO; + + private MessageService messageService; + + public VoteService() { + } + + @Override + public boolean isUserGroupLeader(VoteQueUsr user, Long toolSessionId) { + + VoteSession session = getSessionBySessionId(toolSessionId); + VoteQueUsr groupLeader = session.getGroupLeader(); + boolean isUserLeader = (groupLeader != null) && user.getUid().equals(groupLeader.getUid()); + return isUserLeader; + } + + @Override + public VoteQueUsr checkLeaderSelectToolForSessionLeader(VoteQueUsr user, Long toolSessionId) { + if ((user == null) || (toolSessionId == null)) { + logger.info("user" + user + "or" + "toolSessionId" + toolSessionId + "is null"); + return null; + } + + VoteSession session = getSessionBySessionId(toolSessionId); + VoteQueUsr leader = session.getGroupLeader(); + // check leader select tool for a leader only in case QA tool doesn't know it. As otherwise it will screw + // up previous scratches done + if (leader == null) { + if (logger.isDebugEnabled()) { + logger.debug("If QA tool does not know it checking leader select tool for leader only" + leader); + } + Long leaderUserId = toolService.getLeaderUserId(toolSessionId, user.getQueUsrId().intValue()); + if (leaderUserId != null) { + + leader = getVoteUserBySession(leaderUserId, session.getUid()); + + // create new user in a DB + if (leader == null) { + if (logger.isDebugEnabled()) { + logger.debug("creating new user with userId: " + leaderUserId); + } + User leaderDto = (User) getUserManagementService().findById(User.class, leaderUserId.intValue()); + String userName = leaderDto.getLogin(); + String fullName = leaderDto.getFirstName() + " " + leaderDto.getLastName(); + leader = new VoteQueUsr(leaderUserId, userName, fullName, session, new TreeSet()); + voteUserDAO.saveVoteUser(user); + } + + // set group leader + session.setGroupLeader(leader); + voteSessionDAO.updateVoteSession(session); + } + } + + return leader; + } + + @Override + public void copyAnswersFromLeader(VoteQueUsr user, VoteQueUsr leader) { + + if ((user == null) || (leader == null) || user.getUid().equals(leader.getUid())) { + if (logger.isDebugEnabled()) { + logger.debug("User" + user + "or" + "leader" + leader + "or Userid and Leaderid is equal"); + return; + } + } + + List leaderAttempts = this.getAttemptsForUser(leader.getUid()); + List userAttempts = this.getAttemptsForUser(user.getUid()); + + for (VoteUsrAttempt leaderAttempt : leaderAttempts) { + + VoteQueContent question = leaderAttempt.getVoteQueContent(); + Date attempTime = leaderAttempt.getAttemptTime(); + String timeZone = leaderAttempt.getTimeZone(); + String userEntry = leaderAttempt.getUserEntry(); + + VoteUsrAttempt userAttempt = null; + for (VoteUsrAttempt userAttemptDb : userAttempts) { + if (userAttemptDb.getUid().equals(leaderAttempt.getUid())) { + userAttempt = userAttemptDb; + } + } + + // if response doesn't exist - create VoteUsrAttempt in the db + if (userAttempt == null) { + logger.info("Response does not exist hence creating VoteUsrAttempt in db"); + VoteUsrAttempt voteUsrAttempt = new VoteUsrAttempt(attempTime, timeZone, question, user, userEntry, + true); + voteUsrAttemptDAO.saveVoteUsrAttempt(voteUsrAttempt); + + // if it's been changed by the leader + } else if (leaderAttempt.getAttemptTime().compareTo(userAttempt.getAttemptTime()) != 0) { + logger.info("Incase of the change done by the leader"); + userAttempt.setUserEntry(userEntry); + userAttempt.setAttemptTime(attempTime); + userAttempt.setTimeZone(timeZone); + this.updateVoteUsrAttempt(userAttempt); + + // remove userAttempt from the list so we can know which one is redundant(presumably, leader has removed + // this one) + if (logger.isDebugEnabled()) { + logger.debug("Leader has removed the userAttempt" + userAttempt); + } + userAttempts.remove(userAttempt); + } + } + + // remove redundant ones + for (VoteUsrAttempt redundantUserAttempt : userAttempts) { + voteUsrAttemptDAO.removeVoteUsrAttempt(redundantUserAttempt); + } + } + + @Override + public VoteGeneralLearnerFlowDTO prepareChartData(HttpServletRequest request, Long toolContentID, + Long toolSessionUid, VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO) { + + VoteContent voteContent = this.getVoteContent(toolContentID); + + int entriesCount = 0; + List userEntries = null; + if (toolSessionUid != null) { + entriesCount = voteUsrAttemptDAO.getSessionEntriesCount(toolSessionUid); + if (voteContent.isAllowText()) { + userEntries = voteUsrAttemptDAO.getSessionOpenTextUserEntries(toolSessionUid); + } else { + userEntries = new ArrayList(0); + } + } + + Long mapIndex = 1L; + int totalStandardVotesCount = 0; + + Map mapStandardUserCount = new TreeMap(new VoteComparator()); + Map mapStandardNominationsHTMLedContent = new TreeMap(new VoteComparator()); + Map mapStandardQuestionUid = new TreeMap(new VoteComparator()); + Map mapStandardToolSessionUid = new TreeMap(new VoteComparator()); + Map mapStandardNominationsContent = new TreeMap(new VoteComparator()); + Map mapVoteRates = new TreeMap(new VoteComparator()); + + for (VoteQueContent question : voteContent.getVoteQueContents()) { + + mapStandardNominationsHTMLedContent.put(mapIndex, question.getQuestion()); + String noHTMLNomination = VoteUtils.stripHTML(question.getQuestion()); + mapStandardNominationsContent.put(mapIndex, noHTMLNomination); + + int votesCount = voteUsrAttemptDAO.getStandardAttemptsForQuestionContentAndSessionUid(question.getUid(), + toolSessionUid); + totalStandardVotesCount += votesCount; + mapStandardUserCount.put(mapIndex, new Long(votesCount)); + + mapStandardQuestionUid.put(mapIndex, question.getUid()); + mapStandardToolSessionUid.put(mapIndex, toolSessionUid); + + Double voteRate = (entriesCount != 0) ? ((votesCount * 100) / entriesCount) : 0d; + mapVoteRates.put(mapIndex, voteRate); + + // mapIndex++ + mapIndex = new Long(mapIndex + 1); + } + + // open votes + if (voteContent.isAllowText()) { + int userEnteredVotesCount = entriesCount - totalStandardVotesCount; + Double voteRate = (userEnteredVotesCount != 0) ? ((userEnteredVotesCount * 100) / entriesCount) : 0d; + mapVoteRates.put(mapIndex, voteRate); + + mapStandardNominationsContent.put(mapIndex, messageService.getMessage("label.open.vote")); + mapStandardNominationsHTMLedContent.put(mapIndex, messageService.getMessage("label.open.vote")); + mapStandardUserCount.put(mapIndex, new Long(userEnteredVotesCount)); + /** following are needed just for proper iteration in the summary jsp */ + mapStandardQuestionUid.put(mapIndex, 1L); + mapStandardToolSessionUid.put(mapIndex, 1L); + } + + voteGeneralLearnerFlowDTO.setMapStandardNominationsContent(mapStandardNominationsContent); + voteGeneralLearnerFlowDTO.setMapStandardNominationsHTMLedContent(mapStandardNominationsHTMLedContent); + voteGeneralLearnerFlowDTO.setMapStandardRatesContent(mapVoteRates); + voteGeneralLearnerFlowDTO.setMapStandardUserCount(mapStandardUserCount); + voteGeneralLearnerFlowDTO.setMapStandardToolSessionUid(mapStandardToolSessionUid); + voteGeneralLearnerFlowDTO.setMapStandardQuestionUid(mapStandardQuestionUid); + request.setAttribute(VoteAppConstants.VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + request.setAttribute(VoteAppConstants.LIST_USER_ENTRIES_CONTENT, userEntries); + + // return value is only used in VoteChartGeneratorAction + return voteGeneralLearnerFlowDTO; + } + + @SuppressWarnings("unused") + @Override + public LinkedList getSessionDTOs(Long toolContentID) { + + LinkedList sessionDTOs = new LinkedList(); + + VoteContent voteContent = this.getVoteContent(toolContentID); + for (VoteSession session : voteContent.getVoteSessions()) { + + SessionDTO sessionDTO = new SessionDTO(); + sessionDTO.setSessionId(session.getVoteSessionId().toString()); + sessionDTO.setSessionName(session.getSession_name()); + + int entriesCount = voteUsrAttemptDAO.getSessionEntriesCount(session.getUid()); + + Long mapIndex = 1L; + int totalStandardVotesCount = 0; + + Map mapVoteRates = new TreeMap(new VoteComparator()); + Map mapStandardUserCount = new TreeMap(new VoteComparator()); + Map mapStandardNominationsHTMLedContent = new TreeMap(new VoteComparator()); + Map mapStandardQuestionUid = new TreeMap(new VoteComparator()); + Map mapStandardToolSessionUid = new TreeMap(new VoteComparator()); + + for (VoteQueContent question : voteContent.getVoteQueContents()) { + mapStandardNominationsHTMLedContent.put(mapIndex, question.getQuestion()); + + int votesCount = voteUsrAttemptDAO.getStandardAttemptsForQuestionContentAndSessionUid(question.getUid(), + session.getUid()); + totalStandardVotesCount += votesCount; + mapStandardUserCount.put(mapIndex, new Long(votesCount)); + + mapStandardQuestionUid.put(mapIndex, question.getUid()); + mapStandardToolSessionUid.put(mapIndex, session.getUid()); + + Double voteRate = (entriesCount != 0) ? ((votesCount * 100) / entriesCount) : 0d; + mapVoteRates.put(mapIndex, voteRate); + + // mapIndex++ + mapIndex = new Long(mapIndex + 1); + } + + // open votes + if (voteContent.isAllowText()) { + int userEnteredVotesCount = entriesCount - totalStandardVotesCount; + Double voteRate = (userEnteredVotesCount != 0) ? ((userEnteredVotesCount * 100) / entriesCount) : 0d; + mapVoteRates.put(mapIndex, voteRate); + + mapStandardNominationsHTMLedContent.put(mapIndex, messageService.getMessage("label.open.vote")); + mapStandardUserCount.put(mapIndex, new Long(userEnteredVotesCount)); + /** following are needed just for proper iteration in the summary jsp */ + mapStandardQuestionUid.put(mapIndex, 1L); + mapStandardToolSessionUid.put(mapIndex, 1L); + } + + sessionDTO.setMapStandardNominationsHTMLedContent(mapStandardNominationsHTMLedContent); + sessionDTO.setMapStandardUserCount(mapStandardUserCount); + sessionDTO.setMapStandardRatesContent(mapVoteRates); + sessionDTO.setMapStandardQuestionUid(mapStandardQuestionUid); + sessionDTO.setMapStandardToolSessionUid(mapStandardToolSessionUid); + + List openVotes = this.getOpenVotes(voteContent.getUid(), + session.getVoteSessionId(), null); + sessionDTO.setOpenVotes(openVotes); + boolean isExistsOpenVote = openVotes.size() > 0; + sessionDTO.setExistsOpenVote(isExistsOpenVote); + + sessionDTOs.add(sessionDTO); + } + + // All groups total + if (sessionDTOs.size() > 1) { + SessionDTO totalSessionDTO = new SessionDTO(); + totalSessionDTO.setSessionId("0"); + totalSessionDTO.setSessionName(messageService.getMessage("label.all.groups.total")); + + List totalOpenVotes = new ArrayList(); + int totalPotentialUserCount = 0; + int totalCompletedSessionUserCount = 0; + int allSessionsVotesCount = 0; + Map totalMapStandardUserCount = new TreeMap(new VoteComparator()); + for (SessionDTO sessionDTO : sessionDTOs) { + + totalPotentialUserCount += sessionDTO.getSessionUserCount(); + totalCompletedSessionUserCount += sessionDTO.getCompletedSessionUserCount(); + + Long mapIndex = 1L; + for (VoteQueContent question : voteContent.getVoteQueContents()) { + Long votesCount = sessionDTO.getMapStandardUserCount().get(mapIndex); + Long oldTotalVotesCount = (totalMapStandardUserCount.get(mapIndex) != null) + ? totalMapStandardUserCount.get(mapIndex) + : 0L; + totalMapStandardUserCount.put(mapIndex, oldTotalVotesCount + votesCount); + + allSessionsVotesCount += votesCount; + + // mapIndex++ + mapIndex = new Long(mapIndex + 1); + } + + // open votes + if (voteContent.isAllowText()) { + Long votesCount = sessionDTO.getMapStandardUserCount().get(mapIndex); + Long oldTotalVotesCount = (totalMapStandardUserCount.get(mapIndex) != null) + ? totalMapStandardUserCount.get(mapIndex) + : 0L; + totalMapStandardUserCount.put(mapIndex, oldTotalVotesCount + votesCount); + + allSessionsVotesCount += votesCount; + } + + totalOpenVotes.addAll(sessionDTO.getOpenVotes()); + } + totalSessionDTO.setSessionUserCount(totalPotentialUserCount); + totalSessionDTO.setCompletedSessionUserCount(totalCompletedSessionUserCount); + totalSessionDTO.setOpenVotes(totalOpenVotes); + boolean isExistsOpenVote = totalOpenVotes.size() > 0; + totalSessionDTO.setExistsOpenVote(isExistsOpenVote); + totalSessionDTO.setMapStandardNominationsHTMLedContent( + sessionDTOs.get(0).getMapStandardNominationsHTMLedContent()); + totalSessionDTO.setMapStandardQuestionUid(sessionDTOs.get(0).getMapStandardQuestionUid()); + totalSessionDTO.setMapStandardToolSessionUid(sessionDTOs.get(0).getMapStandardToolSessionUid()); + totalSessionDTO.setMapStandardUserCount(totalMapStandardUserCount); + + // All groups total -- totalMapVoteRates part + Long mapIndex = 1L; + Map totalMapVoteRates = new TreeMap(new VoteComparator()); + int totalStandardVotesCount = 0; + for (VoteQueContent question : voteContent.getVoteQueContents()) { + + Long votesCount = totalMapStandardUserCount.get(mapIndex); + + double voteRate = (allSessionsVotesCount != 0) ? ((votesCount * 100) / allSessionsVotesCount) : 0d; + totalMapVoteRates.put(mapIndex, voteRate); + + totalStandardVotesCount += votesCount; + + // mapIndex++ + mapIndex = new Long(mapIndex + 1); + } + // open votes + if (voteContent.isAllowText()) { + int userEnteredVotesCount = allSessionsVotesCount - totalStandardVotesCount; + double voteRate = (userEnteredVotesCount != 0) ? ((userEnteredVotesCount * 100) / allSessionsVotesCount) + : 0; + totalMapVoteRates.put(mapIndex, voteRate); + } + totalSessionDTO.setMapStandardRatesContent(totalMapVoteRates); + + sessionDTOs.addFirst(totalSessionDTO); + } + + return sessionDTOs; + } + + @Override + public SortedSet getMonitoringSessionDTOs(Long toolContentID) { + + SortedSet sessionDTOs = new TreeSet(); + + VoteContent voteContent = this.getVoteContent(toolContentID); + for (VoteSession session : voteContent.getVoteSessions()) { + + SummarySessionDTO sessionDTO = new SummarySessionDTO(); + sessionDTO.setSessionName(session.getSession_name()); + sessionDTO.setSessionUid(session.getUid()); + sessionDTO.setToolSessionId(session.getVoteSessionId()); + sessionDTO.setNominations(new TreeSet()); + + int entriesCount = voteUsrAttemptDAO.getSessionEntriesCount(session.getUid()); + + int totalStandardVotesCount = 0; + + for (VoteQueContent question : voteContent.getVoteQueContents()) { + + SessionNominationDTO nominationDTO = new SessionNominationDTO(); + nominationDTO.setQuestionUid(question.getUid()); + nominationDTO.setNomination(question.getQuestion()); + + int votesCount = voteUsrAttemptDAO.getStandardAttemptsForQuestionContentAndSessionUid(question.getUid(), + session.getUid()); + totalStandardVotesCount += votesCount; + + nominationDTO.setNumberOfVotes(votesCount); + nominationDTO.setPercentageOfVotes((entriesCount != 0) ? ((votesCount * 100) / entriesCount) : 0d); + sessionDTO.getNominations().add(nominationDTO); + + } + + // open votes + if (voteContent.isAllowText()) { + int userEnteredVotesCount = entriesCount - totalStandardVotesCount; + Double voteRate = (userEnteredVotesCount != 0) ? ((userEnteredVotesCount * 100) / entriesCount) : 0d; + sessionDTO.setOpenTextNumberOfVotes(userEnteredVotesCount); + sessionDTO.setOpenTextPercentageOfVotes(voteRate); + } else { + sessionDTO.setOpenTextNumberOfVotes(0); + sessionDTO.setOpenTextPercentageOfVotes(0D); + } + + sessionDTOs.add(sessionDTO); + } + + // All groups total + if (sessionDTOs.size() > 1) { + SummarySessionDTO totalSessionDTO = new SummarySessionDTO(); + totalSessionDTO.setSessionUid(0L); + totalSessionDTO.setToolSessionId(0L); + totalSessionDTO.setSessionName(messageService.getMessage("label.all.groups.total")); + totalSessionDTO.setNominations(new TreeSet()); + + HashMap nominationsTotals = new HashMap(); + int totalOpenVotes = 0; + int totalVotes = 0; + for (SummarySessionDTO sessionDTO : sessionDTOs) { + + for (SessionNominationDTO nomination : sessionDTO.getNominations()) { + Long questionUid = nomination.getQuestionUid(); + SessionNominationDTO dto = nominationsTotals.get(questionUid); + if (dto == null) { + dto = new SessionNominationDTO(); + dto.setQuestionUid(questionUid); + dto.setNomination(nomination.getNomination()); + dto.setNumberOfVotes(0); + nominationsTotals.put(questionUid, dto); + totalSessionDTO.getNominations().add(dto); + } + totalVotes += nomination.getNumberOfVotes(); + dto.setNumberOfVotes(dto.getNumberOfVotes() + nomination.getNumberOfVotes()); + } + + totalVotes += sessionDTO.getOpenTextNumberOfVotes(); + totalOpenVotes += sessionDTO.getOpenTextNumberOfVotes(); + } + for (SessionNominationDTO nomination : totalSessionDTO.getNominations()) { + nomination.setPercentageOfVotes( + (totalVotes != 0) ? ((nomination.getNumberOfVotes() * 100) / totalVotes) : 0d); + } + totalSessionDTO.setOpenTextNumberOfVotes(totalOpenVotes); + totalSessionDTO + .setOpenTextPercentageOfVotes((totalVotes != 0) ? ((totalOpenVotes * 100) / totalVotes) : 0d); + sessionDTOs.add(totalSessionDTO); + } + + return sessionDTOs; + } + + /** + * Get the count of all the potential learners for the vote session. This will include the people that have never + * logged into the lesson. Not great, but it is a better estimate of how many users there will be eventually than + * the number of people already known to the tool. + * + * @param voteSessionId + * The tool session id + */ + private int getVoteSessionPotentialLearnersCount(Long sessionUid) { + VoteSession session = voteSessionDAO.getVoteSessionByUID(sessionUid); + if (session != null) { + return toolService.getCountUsersForActivity(session.getVoteSessionId()); + } else { + logger.error("Unable to find vote session record id=" + sessionUid + ". Returning 0 users."); + return 0; + } + } + + @Override + public List getOpenVotes(Long voteContentUid, Long currentSessionId, Long userId) { + Set userEntries = voteUsrAttemptDAO.getUserEntries(voteContentUid); + + List monitoredAnswersDTOs = new LinkedList(); + for (String userEntry : userEntries) { + + if ((userEntry == null) || (userEntry.length() == 0)) { + continue; + } + + VoteMonitoredAnswersDTO voteMonitoredAnswersDTO = new VoteMonitoredAnswersDTO(); + voteMonitoredAnswersDTO.setQuestion(userEntry); + + List userAttempts = voteUsrAttemptDAO.getUserAttempts(voteContentUid, userEntry); + List monitoredUserContainerDTOs = new LinkedList(); + + for (VoteUsrAttempt voteUsrAttempt : userAttempts) { + VoteMonitoredUserDTO voteMonitoredUserDTO = new VoteMonitoredUserDTO(); + + if (currentSessionId == null) { + voteMonitoredUserDTO.setAttemptTime(voteUsrAttempt.getAttemptTime()); + voteMonitoredUserDTO.setTimeZone(voteUsrAttempt.getTimeZone()); + voteMonitoredUserDTO.setUserName(voteUsrAttempt.getVoteQueUsr().getFullname()); + voteMonitoredUserDTO.setQueUsrId(voteUsrAttempt.getVoteQueUsr().getUid().toString()); + voteMonitoredUserDTO.setUserEntry(voteUsrAttempt.getUserEntry()); + voteMonitoredUserDTO.setUid(voteUsrAttempt.getUid().toString()); + voteMonitoredUserDTO.setVisible(new Boolean(voteUsrAttempt.isVisible()).toString()); + monitoredUserContainerDTOs.add(voteMonitoredUserDTO); + + } else { + // showUserEntriesBySession is true: the case with learner export portfolio + // show user entries by same same session and same user + Long userSessionId = voteUsrAttempt.getVoteQueUsr().getVoteSession().getVoteSessionId(); + + if (userId != null) { + if (userSessionId.equals(currentSessionId)) { + Long localUserId = voteUsrAttempt.getVoteQueUsr().getQueUsrId(); + if (userId.equals(localUserId)) { + voteMonitoredUserDTO.setAttemptTime(voteUsrAttempt.getAttemptTime()); + voteMonitoredUserDTO.setTimeZone(voteUsrAttempt.getTimeZone()); + voteMonitoredUserDTO.setUserName(voteUsrAttempt.getVoteQueUsr().getFullname()); + voteMonitoredUserDTO.setQueUsrId(voteUsrAttempt.getVoteQueUsr().getUid().toString()); + voteMonitoredUserDTO.setUserEntry(voteUsrAttempt.getUserEntry()); + monitoredUserContainerDTOs.add(voteMonitoredUserDTO); + voteMonitoredUserDTO.setUid(voteUsrAttempt.getUid().toString()); + voteMonitoredUserDTO.setVisible(new Boolean(voteUsrAttempt.isVisible()).toString()); + if (voteUsrAttempt.isVisible() == false) { + voteMonitoredAnswersDTO.setQuestion("Nomination Hidden"); + } + + } + } + } else { + // showUserEntriesByUserId is false + // show user entries by same session + if (userSessionId.equals(currentSessionId)) { + voteMonitoredUserDTO.setAttemptTime(voteUsrAttempt.getAttemptTime()); + voteMonitoredUserDTO.setTimeZone(voteUsrAttempt.getTimeZone()); + voteMonitoredUserDTO.setUserName(voteUsrAttempt.getVoteQueUsr().getFullname()); + voteMonitoredUserDTO.setQueUsrId(voteUsrAttempt.getVoteQueUsr().getUid().toString()); + voteMonitoredUserDTO.setUserEntry(voteUsrAttempt.getUserEntry()); + monitoredUserContainerDTOs.add(voteMonitoredUserDTO); + voteMonitoredUserDTO.setUid(voteUsrAttempt.getUid().toString()); + voteMonitoredUserDTO.setVisible(new Boolean(voteUsrAttempt.isVisible()).toString()); + } + } + } + + } + + if (monitoredUserContainerDTOs.size() > 0) { + Map mapMonitoredUserContainerDTO = MonitoringAction + .convertToVoteMonitoredUserDTOMap(monitoredUserContainerDTOs); + + voteMonitoredAnswersDTO.setQuestionAttempts(mapMonitoredUserContainerDTO); + monitoredAnswersDTOs.add(voteMonitoredAnswersDTO); + } + } + + return monitoredAnswersDTOs; + } + + @Override + public List getReflectionData(VoteContent voteContent, Long userID) { + List reflectionsContainerDTO = new LinkedList(); + + if (userID == null) { + for (Iterator sessionIter = voteContent.getVoteSessions().iterator(); sessionIter.hasNext();) { + VoteSession voteSession = sessionIter.next(); + + for (Iterator userIter = voteSession.getVoteQueUsers().iterator(); userIter.hasNext();) { + VoteQueUsr user = userIter.next(); + + NotebookEntry notebookEntry = this.getEntry(voteSession.getVoteSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, VoteAppConstants.MY_SIGNATURE, + new Integer(user.getQueUsrId().toString())); + + if (notebookEntry != null) { + ReflectionDTO reflectionDTO = new ReflectionDTO(); + reflectionDTO.setUserId(user.getQueUsrId().toString()); + reflectionDTO.setSessionId(voteSession.getVoteSessionId().toString()); + reflectionDTO.setUserName(user.getFullname()); + reflectionDTO.setReflectionUid(notebookEntry.getUid().toString()); + // String notebookEntryPresentable = VoteUtils.replaceNewLines(notebookEntry.getEntry()); + reflectionDTO.setEntry(notebookEntry.getEntry()); + reflectionsContainerDTO.add(reflectionDTO); + } + } + } + } else { + for (Iterator sessionIter = voteContent.getVoteSessions().iterator(); sessionIter.hasNext();) { + VoteSession voteSession = sessionIter.next(); + for (Iterator userIter = voteSession.getVoteQueUsers().iterator(); userIter.hasNext();) { + VoteQueUsr user = userIter.next(); + if (user.getQueUsrId().equals(userID)) { + NotebookEntry notebookEntry = this.getEntry(voteSession.getVoteSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, VoteAppConstants.MY_SIGNATURE, + new Integer(user.getQueUsrId().toString())); + + if (notebookEntry != null) { + ReflectionDTO reflectionDTO = new ReflectionDTO(); + reflectionDTO.setUserId(user.getQueUsrId().toString()); + reflectionDTO.setSessionId(voteSession.getVoteSessionId().toString()); + reflectionDTO.setUserName(user.getFullname()); + reflectionDTO.setReflectionUid(notebookEntry.getUid().toString()); + // String notebookEntryPresentable = VoteUtils.replaceNewLines(notebookEntry.getEntry()); + reflectionDTO.setEntry(notebookEntry.getEntry()); + reflectionsContainerDTO.add(reflectionDTO); + } + } + } + } + } + + return reflectionsContainerDTO; + } + + @Override + public VoteContent getVoteContent(Long toolContentID) { + return voteContentDAO.getVoteContentByContentId(toolContentID); + } + + @Override + public VoteQueContent getQuestionByDisplayOrder(final Long displayOrder, final Long voteContentUid) { + return voteQueContentDAO.getQuestionByDisplayOrder(displayOrder, voteContentUid); + } + + @Override + public VoteQueUsr getUserById(long voteQueUsrId) { + VoteQueUsr voteQueUsr = voteUserDAO.getVoteQueUsrById(voteQueUsrId); + return voteQueUsr; + } + + @Override + public List getAttemptsForQuestionContentAndSessionUid(final Long questionUid, + final Long voteSessionUid) { + return voteUsrAttemptDAO.getAttemptsForQuestionContentAndSessionUid(questionUid, voteSessionUid); + } + + @Override + public Set getAttemptsForUserAndSessionUseOpenAnswer(final Long userUid, final Long sessionUid) { + List list = voteUsrAttemptDAO.getAttemptsForUserAndSessionUseOpenAnswer(userUid, sessionUid); + + //String openAnswer = ""; + Set userEntries = new HashSet(); + if ((list != null) && (list.size() > 0)) { + Iterator listIterator = list.iterator(); + while (listIterator.hasNext()) { + VoteUsrAttempt attempt = listIterator.next(); + + Long questionUid = attempt.getVoteQueContent().getUid(); + if (!questionUid.toString().equals("1")) { + userEntries.add(attempt.getVoteQueContent().getQuestion()); + } else { + // this is a user entered vote + if (attempt.getUserEntry().length() > 0) { + if (attempt.isVisible()) { + userEntries.add(attempt.getUserEntry()); + } else { + userEntries.add(getMessageService().getMessage("label.hidden")); + } + } + + } + } + } + return userEntries; + } + + @Override + public Set getAttemptsForUserAndSession(final Long queUsrUid, final Long sessionUid) { + return voteUsrAttemptDAO.getAttemptsForUserAndSession(queUsrUid, sessionUid); + } + + @Override + public VoteQueContent getVoteQueContentByUID(Long uid) { + if (uid == null) { + return null; + } + + return voteQueContentDAO.getQuestionByUid(uid); + } + + @Override + public void saveOrUpdateVoteQueContent(VoteQueContent voteQueContent) { + voteQueContentDAO.saveOrUpdateQuestion(voteQueContent); + } + + @Override + public VoteContent createQuestions(List questionDTOs, VoteContent voteContent) { + + int displayOrder = 0; + for (VoteQuestionDTO questionDTO : questionDTOs) { + String currentQuestionText = questionDTO.getQuestion(); + + // skip empty questions + if (currentQuestionText.isEmpty()) { + continue; + } + + ++displayOrder; + + VoteQueContent question = getVoteQueContentByUID(questionDTO.getUid()); + + // in case question doesn't exist + if (question == null) { + question = new VoteQueContent(currentQuestionText, displayOrder, voteContent); + // adding a new question to content + if (logger.isDebugEnabled()) { + logger.debug("Adding a new question to content" + question); + } + voteContent.getVoteQueContents().add(question); + question.setVoteContent(voteContent); + + // in case question exists already + } else { + + question.setQuestion(currentQuestionText); + question.setDisplayOrder(displayOrder); + } + + saveOrUpdateVoteQueContent(question); + } + + return voteContent; + } + + @Override + public Map buildQuestionMap(VoteContent voteContent, Collection checkedOptions) { + Map mapQuestionsContent = new TreeMap(new VoteComparator()); + Set questions = voteContent.getVoteQueContents(); + + // should we add questions from data flow from other activities? + if (Boolean.TRUE.equals(voteContent.getAssignedDataFlowObject()) + && ((voteContent.getMaxExternalInputs() == null) || (voteContent.getExternalInputsAdded() == null) + || (voteContent.getExternalInputsAdded() < voteContent.getMaxExternalInputs()))) { + // If we are using tool input, we need to get it now and + // create questions. Once they are created, they will be not altered, no matter if another learner gets to + // this point and the tool input changed + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + long userId = toolUser.getUserID().longValue(); + + // We get whatever the source tool provides us with and try to create questions out of it + ToolOutput toolInput = getToolInput(voteContent.getVoteContentId(), new Long(userId).intValue()); + + Object value = toolInput.getValue().getComplex(); + short inputsAdded = voteContent.getExternalInputsAdded() == null ? 0 : voteContent.getExternalInputsAdded(); + Short maxInputs = voteContent.getMaxExternalInputs(); + Set existingNominations = voteContent.getVoteQueContents(); + // The input is an array (users) of arrays of strings (their answers) + if (value instanceof String[][]) { + if (value != null) { + String[][] usersAndAnswers = (String[][]) value; + int nominationIndex = voteContent.getVoteQueContents().size() + 1; + for (String[] userAnswers : usersAndAnswers) { + if (userAnswers != null) { + if ((maxInputs != null) && (inputsAdded >= maxInputs)) { + // if we reached the maximum number of inputs, i.e. number of students that will be + // taken + // into account + logger.info( + "We have reached max no of inputs,i.e number of students will be taken into account"); + break; + } + boolean anyAnswersAdded = false; + for (String questionText : userAnswers) { + if (!StringUtils.isBlank(questionText)) { + VoteQueContent nomination = new VoteQueContent(); + nomination.setDisplayOrder(nominationIndex); + nomination.setMcContent(voteContent); + nomination.setQuestion(questionText); + if (!VoteService.isNominationExists(nomination, existingNominations)) { + saveOrUpdateVoteQueContent(nomination); + voteContent.getVoteQueContents().add(nomination); + nominationIndex++; + anyAnswersAdded = true; + } + } + } + if (anyAnswersAdded) { + inputsAdded++; + } + } + } + } + } else if (value instanceof String[]) { + // the input is a list of strings (questions, for example) + int nominationIndex = voteContent.getVoteQueContents().size() + 1; + String[] userAnswers = (String[]) value; + for (String questionText : userAnswers) { + if ((maxInputs != null) && (inputsAdded >= maxInputs)) { + logger.info( + "We have reached max no of inputs,i.e number of students will be taken into account"); + // if we reached the maximum number of inputs, i.e. number of students that will be taken + // into account + break; + } + + if (!StringUtils.isBlank(questionText)) { + VoteQueContent nomination = new VoteQueContent(); + nomination.setDisplayOrder(nominationIndex); + nomination.setMcContent(voteContent); + nomination.setQuestion(questionText); + if (!VoteService.isNominationExists(nomination, existingNominations)) { + saveOrUpdateVoteQueContent(nomination); + voteContent.getVoteQueContents().add(nomination); + nominationIndex++; + inputsAdded++; + } + } + } + } else if ((value instanceof String) && !StringUtils.isBlank((String) value)) { + int nominationIndex = voteContent.getVoteQueContents().size() + 1; + VoteQueContent nomination = new VoteQueContent(); + nomination.setDisplayOrder(nominationIndex); + nomination.setMcContent(voteContent); + nomination.setQuestion((String) value); + if (!VoteService.isNominationExists(nomination, existingNominations)) { + saveOrUpdateVoteQueContent(nomination); + voteContent.getVoteQueContents().add(nomination); + } + } + if (value instanceof SimpleURL[][]) { + if (value != null) { + SimpleURL[][] usersAndUrls = (SimpleURL[][]) value; + int nominationIndex = voteContent.getVoteQueContents().size() + 1; + for (SimpleURL[] userUrls : usersAndUrls) { + if (userUrls != null) { + if ((maxInputs != null) && (inputsAdded >= maxInputs)) { + logger.info( + "We have reached max no of inputs,i.e number of students will be taken into account"); + // if we reached the maximum number of inputs, i.e. number of students that will be + // taken + // into account + break; + } + boolean anyAnswersAdded = false; + for (SimpleURL url : userUrls) { + if (url != null) { + VoteQueContent nomination = new VoteQueContent(); + nomination.setDisplayOrder(nominationIndex); + nomination.setMcContent(voteContent); + + String link = "" + url.getNameToDisplay() + ""; + nomination.setQuestion(link); + if (!VoteService.isNominationExists(nomination, existingNominations)) { + saveOrUpdateVoteQueContent(nomination); + voteContent.getVoteQueContents().add(nomination); + nominationIndex++; + anyAnswersAdded = true; + } + } + } + if (anyAnswersAdded) { + inputsAdded++; + } + } + } + } + } + + else if (value instanceof SimpleURL[]) { + // the input is a list of strings (questions, for example) + int nominationIndex = voteContent.getVoteQueContents().size() + 1; + SimpleURL[] userUrls = (SimpleURL[]) value; + for (SimpleURL url : userUrls) { + if ((maxInputs != null) && (inputsAdded >= maxInputs)) { + // if we reached the maximum number of inputs, i.e. number of students that will be taken + // into account + break; + } + if (url != null) { + VoteQueContent nomination = new VoteQueContent(); + nomination.setDisplayOrder(nominationIndex); + nomination.setMcContent(voteContent); + + String link = "" + url.getNameToDisplay() + ""; + nomination.setQuestion(link); + if (!VoteService.isNominationExists(nomination, existingNominations)) { + saveOrUpdateVoteQueContent(nomination); + voteContent.getVoteQueContents().add(nomination); + nominationIndex++; + inputsAdded++; + } + } + } + } else if (value instanceof SimpleURL) { + int nominationIndex = voteContent.getVoteQueContents().size() + 1; + VoteQueContent nomination = new VoteQueContent(); + nomination.setDisplayOrder(nominationIndex); + + SimpleURL url = (SimpleURL) value; + String link = "" + url.getNameToDisplay() + ""; + nomination.setQuestion(link); + if (!VoteService.isNominationExists(nomination, existingNominations)) { + nomination.setMcContent(voteContent); + saveOrUpdateVoteQueContent(nomination); + voteContent.getVoteQueContents().add(nomination); + } + } + + voteContent.setExternalInputsAdded(inputsAdded); + saveVoteContent(voteContent); + questions = voteContent.getVoteQueContents(); + } + + for (VoteQueContent question : questions) { + String displayOrder = "" + question.getDisplayOrder(); + if (((checkedOptions == null) || checkedOptions.contains(displayOrder)) && !displayOrder.equals("0")) { + /* add the question to the questions Map in the displayOrder */ + mapQuestionsContent.put(displayOrder.toString(), question.getQuestion()); + } + } + + return mapQuestionsContent; + } + + private static boolean isNominationExists(VoteQueContent nomination, Set existingNominations) { + if ((existingNominations != null) && (nomination != null)) { + for (VoteQueContent existingNomination : existingNominations) { + if ((existingNomination.getQuestion() != null) + && existingNomination.getQuestion().equals(nomination.getQuestion())) { + return true; + } + } + } + return false; + } + + @Override + public List getUserBySessionOnly(final VoteSession voteSession) { + return voteUserDAO.getUserBySessionOnly(voteSession); + } + + @Override + public VoteSession getVoteSessionByUID(Long uid) { + return voteSessionDAO.getVoteSessionByUID(uid); + } + + @Override + public void createVoteQueUsr(VoteQueUsr voteQueUsr) { + voteUserDAO.saveVoteUser(voteQueUsr); + } + + @Override + public VoteQueUsr getVoteUserBySession(final Long queUsrId, final Long sessionUid) { + return voteUserDAO.getVoteUserBySession(queUsrId, sessionUid); + } + + @Override + public void updateVoteUser(VoteQueUsr voteUser) { + voteUserDAO.updateVoteUser(voteUser); + } + + @Override + public VoteQueUsr getUserByUserId(Long userID) { + VoteQueUsr voteQueUsr = voteUserDAO.getUserByUserId(userID); + return voteQueUsr; + } + + @Override + public VoteUsrAttempt getAttemptByUID(Long uid) { + return voteUsrAttemptDAO.getAttemptByUID(uid); + } + + @Override + public void updateVoteUsrAttempt(VoteUsrAttempt voteUsrAttempt) { + voteUsrAttemptDAO.updateVoteUsrAttempt(voteUsrAttempt); + } + + @Override + public void removeAttemptsForUserandSession(final Long queUsrId, final Long sessionUid) { + voteUsrAttemptDAO.removeAttemptsForUserandSession(queUsrId, sessionUid); + } + + @Override + public List getAttemptsForUser(final Long userUid) { + return voteUsrAttemptDAO.getAttemptsForUser(userUid); + } + + @Override + public void createAttempt(VoteQueUsr voteQueUsr, Map mapGeneralCheckedOptionsContent, + String userEntry, VoteSession voteSession, Long voteContentUid) { + + Date attempTime = new Date(System.currentTimeMillis()); + String timeZone = TimeZone.getDefault().getDisplayName(); + + //in case of free entry + if (mapGeneralCheckedOptionsContent.size() == 0) { + logger.info("In case of free entry"); + VoteQueContent defaultContentFirstQuestion = voteQueContentDAO.getDefaultVoteContentFirstQuestion(); + createAttempt(defaultContentFirstQuestion, voteQueUsr, attempTime, timeZone, userEntry, voteSession); + + //if the question is selected + } else if (voteContentUid != null) { + logger.info("In case of question is selected"); + + for (String key : mapGeneralCheckedOptionsContent.keySet()) { + Long questionDisplayOrder = new Long(key); + + VoteQueContent question = getQuestionByDisplayOrder(questionDisplayOrder, voteContentUid); + createAttempt(question, voteQueUsr, attempTime, timeZone, userEntry, voteSession); + } + } + + } + + private void createAttempt(VoteQueContent question, VoteQueUsr user, Date attempTime, String timeZone, + String userEntry, VoteSession session) { + + if (question != null) { + VoteUsrAttempt existingAttempt = voteUsrAttemptDAO.getAttemptForUserAndQuestionContentAndSession( + user.getQueUsrId(), question.getVoteContentId(), session.getUid()); + + if (existingAttempt != null) { + existingAttempt.setUserEntry(userEntry); + existingAttempt.setAttemptTime(attempTime); + existingAttempt.setTimeZone(timeZone); + updateVoteUsrAttempt(existingAttempt); + } else { + VoteUsrAttempt voteUsrAttempt = new VoteUsrAttempt(attempTime, timeZone, question, user, userEntry, + true); + voteUsrAttemptDAO.saveVoteUsrAttempt(voteUsrAttempt); + } + } + } + + @Override + public VoteQueContent getQuestionByUid(Long uid) { + return voteQueContentDAO.getQuestionByUid(uid); + } + + @Override + public void removeVoteQueContent(VoteQueContent voteQueContent) { + voteQueContentDAO.removeQuestion(voteQueContent); + } + + @Override + public VoteSession getSessionBySessionId(Long voteSessionId) { + return voteSessionDAO.getSessionBySessionId(voteSessionId); + } + + @Override + public void updateVote(VoteContent vote) { + voteContentDAO.updateVoteContent(vote); + } + + @Override + public int countSessionComplete() { + return voteSessionDAO.countSessionComplete(); + } + + /** + * logs hiding of a user entered vote + */ + @Override + public void hideOpenVote(VoteUsrAttempt voteUsrAttempt) { + auditService.logHideEntry(VoteAppConstants.MY_SIGNATURE, voteUsrAttempt.getQueUsrId(), + voteUsrAttempt.getVoteQueUsr().getUsername(), voteUsrAttempt.getUserEntry()); + } + + /** + * logs showing of a user entered vote + */ + @Override + public void showOpenVote(VoteUsrAttempt voteUsrAttempt) { + auditService.logShowEntry(VoteAppConstants.MY_SIGNATURE, voteUsrAttempt.getQueUsrId(), + voteUsrAttempt.getVoteQueUsr().getUsername(), voteUsrAttempt.getUserEntry()); + } + + @Override + public void saveVoteContent(VoteContent vote) { + voteContentDAO.saveVoteContent(vote); + } + + @Override + public List getSessionsFromContent(VoteContent voteContent) { + return voteSessionDAO.getSessionsFromContent(voteContent); + } + + @Override + public int getTotalNumberOfUsers() { + return voteUserDAO.getTotalNumberOfUsers(); + } + + @Override + public List getAttemptsForUserAndQuestionContent(final Long userUid, final Long questionUid) { + try { + return voteUsrAttemptDAO.getAttemptsForUserAndQuestionContent(userUid, questionUid); + } catch (DataAccessException e) { + throw new VoteApplicationException( + "Exception occured when lams is getting vote voteUsrRespDAO by user id and que content id: " + + e.getMessage(), + e); + } + } + + @Override + public boolean studentActivityOccurredGlobal(VoteContent voteContent) { + return !voteContent.getVoteSessions().isEmpty(); + } + + @Override + public void recalculateUserAnswers(VoteContent content, Set oldQuestions, + List questionDTOs, List deletedQuestions) { + + // create list of modified questions + List modifiedQuestions = new ArrayList(); + for (VoteQueContent oldQuestion : oldQuestions) { + for (VoteQuestionDTO questionDTO : questionDTOs) { + if (oldQuestion.getUid().equals(questionDTO.getUid())) { + + // question is different + if (!oldQuestion.getQuestion().equals(questionDTO.getQuestion())) { + modifiedQuestions.add(questionDTO); + } + } + } + } + + Set sessionList = content.getVoteSessions(); + for (VoteSession session : sessionList) { + Set sessionUsers = session.getVoteQueUsers(); + + for (VoteQueUsr user : sessionUsers) { + + // get all finished user results + List userAttempts = this.getAttemptsForUser(user.getUid()); + Iterator iter = userAttempts.iterator(); + while (iter.hasNext()) { + VoteUsrAttempt userAttempt = iter.next(); + + VoteQueContent question = userAttempt.getVoteQueContent(); + + boolean isRemoveQuestionResult = false; + + // [+] if the question is modified + for (VoteQuestionDTO modifiedQuestion : modifiedQuestions) { + if (question.getUid().equals(modifiedQuestion.getUid())) { + isRemoveQuestionResult = true; + break; + } + } + + // [+] if the question was removed + for (VoteQuestionDTO deletedQuestion : deletedQuestions) { + if (question.getUid().equals(deletedQuestion.getUid())) { + isRemoveQuestionResult = true; + break; + } + } + + if (isRemoveQuestionResult) { + iter.remove(); + voteUsrAttemptDAO.removeVoteUsrAttempt(userAttempt); + } + + // [+] doing nothing if the new question was added + + } + + } + } + + } + + @Override + public void copyToolContent(Long fromContentId, Long toContentId) throws ToolException { + if (logger.isDebugEnabled()) { + logger.debug("Copy tool content fromContentId" + fromContentId + " and toContentId " + toContentId); + } + if (fromContentId == null) { + // attempt retrieving tool's default content id with signatute VoteAppConstants.MY_SIGNATURE + long defaultContentId = getToolDefaultContentIdBySignature(VoteAppConstants.MY_SIGNATURE); + fromContentId = new Long(defaultContentId); + } + + if (toContentId == null) { + logger.error("throwing ToolException: toContentId is null"); + throw new ToolException("toContentId is missing"); + } + + VoteContent fromContent = voteContentDAO.getVoteContentByContentId(fromContentId); + + if (fromContent == null) { + // attempt retrieving tool's default content id with signatute VoteAppConstants.MY_SIGNATURE + long defaultContentId = getToolDefaultContentIdBySignature(VoteAppConstants.MY_SIGNATURE); + fromContentId = new Long(defaultContentId); + + fromContent = voteContentDAO.getVoteContentByContentId(fromContentId); + } + + VoteContent toContent = VoteContent.newInstance(fromContent, toContentId); + if (toContent == null) { + logger.error("throwing ToolException: WARNING!, retrieved toContent is null."); + throw new ToolException("WARNING! Fail to create toContent. Can't continue!"); + } else { + voteContentDAO.saveVoteContent(toContent); + } + } + + // @SuppressWarnings("unchecked") + @Override + public void removeToolContent(Long toolContentId) throws ToolException { + VoteContent voteContent = voteContentDAO.getVoteContentByContentId(toolContentId); + if (voteContent == null) { + logger.warn("Can not remove the tool content as it does not exist, ID: " + toolContentId); + return; + } + + for (VoteSession session : voteContent.getVoteSessions()) { + List entries = coreNotebookService.getEntry(session.getVoteSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, VoteAppConstants.MY_SIGNATURE); + for (NotebookEntry entry : entries) { + coreNotebookService.deleteEntry(entry); + } + } + + voteContentDAO.delete(voteContent); + } + + // @SuppressWarnings("unchecked") + @Override + public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException { + if (logger.isDebugEnabled()) { + logger.debug("Removing Vote attempts for user ID " + userId + " and toolContentId " + toolContentId); + } + + VoteContent voteContent = voteContentDAO.getVoteContentByContentId(toolContentId); + if (voteContent == null) { + logger.warn("Did not find activity with toolContentId: " + toolContentId + " to remove learner content"); + return; + } + + for (VoteSession session : voteContent.getVoteSessions()) { + VoteQueUsr user = voteUserDAO.getVoteUserBySession(userId.longValue(), session.getUid()); + if (user != null) { + voteUsrAttemptDAO.removeAttemptsForUserandSession(user.getUid(), session.getUid()); + + NotebookEntry entry = getEntry(session.getVoteSessionId(), CoreNotebookConstants.NOTEBOOK_TOOL, + VoteAppConstants.MY_SIGNATURE, userId); + if (entry != null) { + voteContentDAO.delete(entry); + } + + voteUserDAO.removeVoteUser(user); + } + } + } + + @Override + public void exportToolContent(Long toolContentID, String rootPath) throws DataMissingException, ToolException { + VoteContent toolContentObj = voteContentDAO.getVoteContentByContentId(toolContentID); + if (toolContentObj == null) { + long defaultContentId = getToolDefaultContentIdBySignature(VoteAppConstants.MY_SIGNATURE); + toolContentObj = voteContentDAO.getVoteContentByContentId(defaultContentId); + } + + if (toolContentObj == null) { + logger.error("Unable to find default content for the voting tool"); + throw new DataMissingException("Unable to find default content for the voting tool"); + } + + try { + // set ToolContentHandler as null to avoid copy file node in repository again. + toolContentObj = VoteContent.newInstance(toolContentObj, toolContentID); + + // clear unnecessary information attach + toolContentObj.setVoteSessions(null); + exportContentService.exportToolContent(toolContentID, toolContentObj, voteToolContentHandler, rootPath); + } catch (ExportToolContentException e) { + throw new ToolException(e); + } + } + + @Override + public void importToolContent(Long toolContentID, Integer newUserUid, String toolContentPath, String fromVersion, + String toVersion) throws ToolException { + try { + if (logger.isDebugEnabled()) { + logger.debug("Import tool Content : newUserUid" + newUserUid + " and toolContentID " + toolContentID + + "and toolContentPath" + toolContentPath + "and fromVersion" + fromVersion + "and toVersion" + + toVersion); + } + + // register version filter class + exportContentService.registerImportVersionFilterClass(VoteImportContentVersionFilter.class); + + Object toolPOJO = exportContentService.importToolContent(toolContentPath, voteToolContentHandler, + fromVersion, toVersion); + if (!(toolPOJO instanceof VoteContent)) { + logger.error("Import Vote tool content failed. Deserialized object is " + toolPOJO); + throw new ImportToolContentException( + "Import Vote tool content failed. Deserialized object is " + toolPOJO); + } + VoteContent toolContentObj = (VoteContent) toolPOJO; + + // reset it to new toolContentID + toolContentObj.setVoteContentId(toolContentID); + toolContentObj.setCreatedBy(newUserUid); + + voteContentDAO.saveVoteContent(toolContentObj); + } catch (ImportToolContentException e) { + logger.error("Error importing the tool content", e); + throw new ToolException(e); + } + } + + @Override + public void resetDefineLater(Long toolContentId) throws DataMissingException, ToolException { + VoteContent voteContent = getVoteContent(toolContentId); + if (voteContent == null) { + logger.error("throwing DataMissingException: WARNING!: retrieved voteContent is null."); + throw new DataMissingException("voteContent is missing"); + } + voteContent.setDefineLater(false); + saveVoteContent(voteContent); + } + + @Override + public void createToolSession(Long toolSessionID, String toolSessionName, Long toolContentID) throws ToolException { + + if (toolSessionID == null) { + logger.error("toolSessionID is null"); + throw new ToolException("toolSessionID is missing"); + } + + VoteContent voteContent = voteContentDAO.getVoteContentByContentId(toolContentID); + + /* + * create a new a new tool session if it does not already exist in the tool session table + */ + VoteSession voteSession = getSessionBySessionId(toolSessionID); + if (voteSession == null) { + try { + voteSession = new VoteSession(toolSessionID, new Date(System.currentTimeMillis()), + VoteSession.INCOMPLETE, toolSessionName, voteContent, new TreeSet()); + + voteSessionDAO.saveVoteSession(voteSession); + + } catch (Exception e) { + logger.error("Error creating new toolsession in the db"); + throw new ToolException("Error creating new toolsession in the db: " + e); + } + } + } + + @Override + public void removeToolSession(Long toolSessionID) throws DataMissingException, ToolException { + if (toolSessionID == null) { + logger.error("toolSessionID is null"); + throw new DataMissingException("toolSessionID is missing"); + } + + VoteSession voteSession = null; + try { + voteSession = getSessionBySessionId(toolSessionID); + } catch (VoteApplicationException e) { + logger.error("error retrieving voteSession:"); + throw new DataMissingException("error retrieving voteSession: " + e); + } catch (Exception e) { + logger.error("error retrieving voteSession:"); + throw new ToolException("error retrieving voteSession: " + e); + } + + if (voteSession == null) { + logger.error("voteSession is null"); + throw new DataMissingException("voteSession is missing"); + } + + try { + voteSessionDAO.removeVoteSession(voteSession); + } catch (VoteApplicationException e) { + throw new ToolException("error deleting voteSession:" + e); + } + } + + @Override + public String leaveToolSession(Long toolSessionID, Long learnerId) throws DataMissingException, ToolException { + + if (learnerService == null) { + return "dummyNextUrl"; + } + + if (learnerId == null) { + logger.error("learnerId is null"); + throw new DataMissingException("learnerId is missing"); + } + + if (toolSessionID == null) { + logger.error("toolSessionID is null"); + throw new DataMissingException("toolSessionID is missing"); + } + + VoteSession voteSession = null; + try { + voteSession = getSessionBySessionId(toolSessionID); + } catch (VoteApplicationException e) { + logger.error("error retrieving voteSession"); + throw new DataMissingException("error retrieving voteSession: " + e); + } catch (Exception e) { + throw new ToolException("error retrieving voteSession: " + e); + } + voteSession.setSessionStatus(VoteAppConstants.COMPLETED); + voteSessionDAO.updateVoteSession(voteSession); + + String nextUrl = learnerService.completeToolSession(toolSessionID, learnerId); + if (nextUrl == null) { + logger.error("nextUrl is null"); + throw new ToolException("nextUrl is null"); + } + return nextUrl; + } + + @Override + public ToolSessionExportOutputData exportToolSession(Long toolSessionID) + throws DataMissingException, ToolException { + throw new ToolException("not yet implemented"); + } + + @Override + public ToolSessionExportOutputData exportToolSession(List toolSessionIDs) + throws DataMissingException, ToolException { + throw new ToolException("not yet implemented"); + + } + + @Override + public IToolVO getToolBySignature(String toolSignature) { + IToolVO tool = toolService.getToolBySignature(toolSignature); + return tool; + } + + @Override + public long getToolDefaultContentIdBySignature(String toolSignature) { + long contentId = 0; + contentId = toolService.getToolDefaultContentIdBySignature(toolSignature); + return contentId; + } + + @Override + public List getToolSessionsForContent(VoteContent vote) { + List listToolSessionIds = voteSessionDAO.getSessionsFromContent(vote); + return listToolSessionIds; + } + + @Override + public boolean isGroupedActivity(long toolContentID) { + return toolService.isGroupedActivity(toolContentID); + } + + @Override + public void auditLogStartEditingActivityInMonitor(long toolContentID) { + toolService.auditLogStartEditingActivityInMonitor(toolContentID); + } + + @Override + public SortedMap getToolOutputDefinitions(Long toolContentId, int definitionType) + throws ToolException { + VoteContent content = getVoteContent(toolContentId); + if (content == null) { + long defaultToolContentId = getToolDefaultContentIdBySignature(VoteAppConstants.MY_SIGNATURE); + content = getVoteContent(defaultToolContentId); + } + return getVoteOutputFactory().getToolOutputDefinitions(content, definitionType); + } + + @Override + public String getToolContentTitle(Long toolContentId) { + return getVoteContent(toolContentId).getTitle(); + } + + @Override + public boolean isContentEdited(Long toolContentId) { + return getVoteContent(toolContentId).isDefineLater(); + } + + @Override + public boolean isReadOnly(Long toolContentId) { + VoteContent voteContent = voteContentDAO.getVoteContentByContentId(toolContentId); + for (VoteSession session : voteContent.getVoteSessions()) { + if (!session.getVoteQueUsers().isEmpty()) { + return true; + } + } + + return false; + } + + @Override + public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { + return voteOutputFactory.getToolOutput(names, this, toolSessionId, learnerId); + } + + @Override + public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { + return voteOutputFactory.getToolOutput(name, this, toolSessionId, learnerId); + } + + @Override + public List getToolOutputs(String name, Long toolContentId) { + return new ArrayList(); + } + + @Override + public void forceCompleteUser(Long toolSessionId, User user) { + Long userId = user.getUserId().longValue(); + + VoteSession session = getSessionBySessionId(toolSessionId); + if ((session == null) || (session.getVoteContent() == null)) { + return; + } + VoteContent content = session.getVoteContent(); + + // copy answers only in case leader aware feature is ON + if (content.isUseSelectLeaderToolOuput()) { + + VoteQueUsr voteUser = voteUserDAO.getVoteUserBySession(userId, toolSessionId); + // create user if he hasn't accessed this activity yet + if (voteUser == null) { + String userName = user.getLogin(); + String fullName = user.getFirstName() + " " + user.getLastName(); + + voteUser = new VoteQueUsr(userId, userName, fullName, session, new TreeSet()); + createVoteQueUsr(voteUser); + } + + VoteQueUsr groupLeader = session.getGroupLeader(); + + // check if leader has submitted answers + if ((groupLeader != null) && groupLeader.isResponseFinalised()) { + + // we need to make sure specified user has the same scratches as a leader + copyAnswersFromLeader(voteUser, groupLeader); + } + + } + + } + + @Override + public Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry) { + return coreNotebookService.createNotebookEntry(id, idType, signature, userID, "", entry); + } + + @Override + public NotebookEntry getEntry(Long id, Integer idType, String signature, Integer userID) { + + List list = coreNotebookService.getEntry(id, idType, signature, userID); + if ((list == null) || list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public List getAllQuestionsSorted(final long voteContentId) { + return voteQueContentDAO.getAllQuestionsSorted(voteContentId); + } + + /******** Tablesorter methods ************/ + /** + * Gets the basic details about an attempt for a nomination. questionUid must not be null, sessionUid may be NULL. + * This is + * unusual for these methods - usually sessionId may not be null. In this case if sessionUid is null then you get + * the values for the whole class, not just the group. + * + * Will return List<[login (String), fullname(String), attemptTime(Timestamp]> + */ + @Override + public List getUserAttemptsForTablesorter(Long sessionUid, Long questionUid, int page, int size, + int sorting, String searchString) { + return voteUsrAttemptDAO.getUserAttemptsForTablesorter(sessionUid, questionUid, page, size, sorting, + searchString); + } + + @Override + public int getCountUsersBySession(Long sessionUid, Long questionUid, String searchString) { + return voteUsrAttemptDAO.getCountUsersBySession(sessionUid, questionUid, searchString); + } + + @Override + public List getUserReflectionsForTablesorter(Long sessionUid, int page, int size, int sorting, + String searchString) { + return voteUsrAttemptDAO.getUserReflectionsForTablesorter(sessionUid, page, size, sorting, searchString, + getCoreNotebookService()); + } + + @Override + public List getStatisticsBySession(Long toolContentId) { + + List stats = voteUsrAttemptDAO.getStatisticsBySession(toolContentId); + for (VoteStatsDTO stat : stats) { + stat.setCountAllUsers(getVoteSessionPotentialLearnersCount(stat.getSessionUid())); + } + return stats; + } + + /** Gets the details for the open text nominations */ + @Override + public List getUserOpenTextAttemptsForTablesorter(Long sessionUid, Long contentUid, int page, + int size, int sorting, String searchStringVote, String searchStringUsername) { + return voteUsrAttemptDAO.getUserOpenTextAttemptsForTablesorter(sessionUid, contentUid, page, size, sorting, + searchStringVote, searchStringUsername); + } + + @Override + public int getCountUsersForOpenTextEntries(Long sessionUid, Long contentUid, String searchStringVote, + String searchStringUsername) { + return voteUsrAttemptDAO.getCountUsersForOpenTextEntries(sessionUid, contentUid, searchStringVote, + searchStringUsername); + } + + /** + * @return Returns the toolService. + */ + public ILamsToolService getToolService() { + return toolService; + } + + /** + * @return Returns the userManagementService. + */ + public IUserManagementService getUserManagementService() { + return userManagementService; + } + + public void setUserManagementService(IUserManagementService userManagementService) { + this.userManagementService = userManagementService; + } + + public void setToolService(ILamsToolService toolService) { + this.toolService = toolService; + } + + /** + * @return Returns the voteToolContentHandler. + */ + public IToolContentHandler getVoteToolContentHandler() { + return voteToolContentHandler; + } + + /** + * @param voteToolContentHandler + * The voteToolContentHandler to set. + */ + public void setVoteToolContentHandler(IToolContentHandler voteToolContentHandler) { + this.voteToolContentHandler = voteToolContentHandler; + } + + /** + * @return Returns the learnerService. + */ + public ILearnerService getLearnerService() { + return learnerService; + } + + /** + * @param learnerService + * The learnerService to set. + */ + public void setLearnerService(ILearnerService learnerService) { + this.learnerService = learnerService; + } + + /** + * @return Returns the voteContentDAO. + */ + public IVoteContentDAO getVoteContentDAO() { + return voteContentDAO; + } + + /** + * @param voteContentDAO + * The voteContentDAO to set. + */ + public void setVoteContentDAO(IVoteContentDAO voteContentDAO) { + this.voteContentDAO = voteContentDAO; + } + + /** + * @return Returns the voteQueContentDAO. + */ + public IVoteQueContentDAO getVoteQueContentDAO() { + return voteQueContentDAO; + } + + /** + * @param voteQueContentDAO + * The voteQueContentDAO to set. + */ + public void setVoteQueContentDAO(IVoteQueContentDAO voteQueContentDAO) { + this.voteQueContentDAO = voteQueContentDAO; + } + + /** + * @return Returns the voteSessionDAO. + */ + public IVoteSessionDAO getVoteSessionDAO() { + return voteSessionDAO; + } + + /** + * @param voteSessionDAO + * The voteSessionDAO to set. + */ + public void setVoteSessionDAO(IVoteSessionDAO voteSessionDAO) { + this.voteSessionDAO = voteSessionDAO; + } + + /** + * @return Returns the voteUserDAO. + */ + public IVoteUserDAO getVoteUserDAO() { + return voteUserDAO; + } + + /** + * @param voteUserDAO + * The voteUserDAO to set. + */ + public void setVoteUserDAO(IVoteUserDAO voteUserDAO) { + this.voteUserDAO = voteUserDAO; + } + + /** + * @return Returns the voteUsrAttemptDAO. + */ + public IVoteUsrAttemptDAO getVoteUsrAttemptDAO() { + return voteUsrAttemptDAO; + } + + /** + * @param voteUsrAttemptDAO + * The voteUsrAttemptDAO to set. + */ + public void setVoteUsrAttemptDAO(IVoteUsrAttemptDAO voteUsrAttemptDAO) { + this.voteUsrAttemptDAO = voteUsrAttemptDAO; + } + + /** + * @return Returns the auditService. + */ + public IAuditService getAuditService() { + return auditService; + } + + /** + * @param auditService + * The auditService to set. + */ + public void setAuditService(IAuditService auditService) { + this.auditService = auditService; + } + + public IExportToolContentService getExportContentService() { + return exportContentService; + } + + public void setExportContentService(IExportToolContentService exportContentService) { + this.exportContentService = exportContentService; + } + + /** + * @return Returns the coreNotebookService. + */ + public ICoreNotebookService getCoreNotebookService() { + return coreNotebookService; + } + + /** + * @param coreNotebookService + * The coreNotebookService to set. + */ + public void setCoreNotebookService(ICoreNotebookService coreNotebookService) { + this.coreNotebookService = coreNotebookService; + } + + public VoteOutputFactory getVoteOutputFactory() { + return voteOutputFactory; + } + + public void setVoteOutputFactory(VoteOutputFactory voteOutputFactory) { + this.voteOutputFactory = voteOutputFactory; + } + + /** + * @return Returns the MessageService. + */ + @Override + public MessageService getMessageService() { + return messageService; + } + + /** + * @param messageService + * The MessageService to set. + */ + public void setMessageService(MessageService messageService) { + this.messageService = messageService; + } + + @Override + public void removeQuestionsFromCache(VoteContent voteContent) { + voteContentDAO.removeQuestionsFromCache(voteContent); + } + + @Override + public void removeVoteContentFromCache(VoteContent voteContent) { + voteContentDAO.removeVoteContentFromCache(voteContent); + } + + public void setDataFlowDAO(IDataFlowDAO dataFlowDAO) { + this.dataFlowDAO = dataFlowDAO; + } + + @Override + public ToolOutput getToolInput(Long requestingToolContentId, Integer learnerId) { + // just forwarding to learner service + return learnerService.getToolInput(requestingToolContentId, VoteAppConstants.DATA_FLOW_OBJECT_ASSIGMENT_ID, + learnerId); + } + + @Override + public void saveDataFlowObjectAssigment(DataFlowObject assignedDataFlowObject) { + // this also should be done in learner service, but for simplicity... + if (assignedDataFlowObject != null) { + assignedDataFlowObject.setToolAssigmentId(VoteAppConstants.DATA_FLOW_OBJECT_ASSIGMENT_ID); + dataFlowDAO.update(assignedDataFlowObject); + } + } + + @Override + public DataFlowObject getAssignedDataFlowObject(Long toolContentId) { + return dataFlowDAO.getAssignedDataFlowObject(toolContentId, VoteAppConstants.DATA_FLOW_OBJECT_ASSIGMENT_ID); + } + + @Override + public List getDataFlowObjects(Long toolContentId) { + return dataFlowDAO.getDataFlowObjectsByToolContentId(toolContentId); + } + + @SuppressWarnings("rawtypes") + @Override + public Class[] getSupportedToolOutputDefinitionClasses(int definitionType) { + return getVoteOutputFactory().getSupportedDefinitionClasses(definitionType); + } + + @Override + public ToolCompletionStatus getCompletionStatus(Long learnerId, Long toolSessionId) { + VoteSession session = getSessionBySessionId(toolSessionId); + VoteQueUsr learner = getVoteUserBySession(learnerId, session.getUid()); + if (learner == null) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); + } + + Date startDate = null; + Date endDate = null; + Set attempts = learner.getVoteUsrAttempts(); // expect only one + for (VoteUsrAttempt item : attempts) { + Date newDate = item.getAttemptTime(); + if (newDate != null) { + if (startDate == null || newDate.before(startDate)) { + startDate = newDate; + } + if (endDate == null || newDate.after(endDate)) { + endDate = newDate; + } + } + } + + if (learner.isResponseFinalised()) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, startDate, endDate); + } else { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, startDate, null); + } + } + + // ****************** REST methods ************************* + + /** + * Rest call to create a new Vote content. Required fields in toolContentJSON: "title", "instructions", "answers". + * The "answers" entry should be a ArrayNode of Strings. + */ + @Override + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { + if (logger.isDebugEnabled()) { + logger.debug("Rest call to create a new Vote content for userID" + userID + " and toolContentID " + + toolContentID); + } + Date updateDate = new Date(); + + VoteContent vote = new VoteContent(); + vote.setVoteContentId(toolContentID); + vote.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + vote.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); + vote.setCreatedBy(userID); + vote.setCreationDate(updateDate); + vote.setUpdateDate(updateDate); + + vote.setAllowText(JsonUtil.optBoolean(toolContentJSON, "allowText", Boolean.FALSE)); + vote.setDefineLater(false); + vote.setLockOnFinish(JsonUtil.optBoolean(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); + vote.setMaxNominationCount(JsonUtil.optString(toolContentJSON, "maxNominations", "1")); + vote.setMinNominationCount(JsonUtil.optString(toolContentJSON, "minNominations", "1")); + vote.setReflect(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + vote.setReflectionSubject(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + vote.setShowResults(JsonUtil.optBoolean(toolContentJSON, "showResults", Boolean.TRUE)); + vote.setUseSelectLeaderToolOuput( + JsonUtil.optBoolean(toolContentJSON, RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, Boolean.FALSE)); + + // Is the data flow functionality actually used anywhere? + vote.setAssignedDataFlowObject(JsonUtil.optBoolean(toolContentJSON, "assignedDataFlowObject")); + Integer externalInputsAdded = JsonUtil.optInt(toolContentJSON, "externalInputsAdded"); + if (externalInputsAdded != null) { + vote.setExternalInputsAdded(externalInputsAdded.shortValue()); + } + vote.setMaxExternalInputs(JsonUtil.optInt(toolContentJSON, "maxInputs", 0).shortValue()); + + // submissionDeadline is set in monitoring + + // **************************** Nomination entries ********************* + ArrayNode answers = JsonUtil.optArray(toolContentJSON, RestTags.ANSWERS); + //Set newAnswersSet = vote.getVoteQueContents(); + for (int i = 0; i < answers.size(); i++) { + // String answerJSONData = (String) answers.get(i); + VoteQueContent answer = new VoteQueContent(); + answer.setDisplayOrder(i + 1); + answer.setMcContent(vote); + answer.setQuestion(answers.get(i).asText()); + answer.setVoteContent(vote); + vote.getVoteQueContents().add(answer); + } + + saveVoteContent(vote); + + } + +} \ No newline at end of file Index: lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/LearningAction.java =================================================================== diff -u --- lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/LearningAction.java (revision 0) +++ lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/LearningAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,1086 @@ +/*************************************************************************** + * 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 version 2.0 + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.vote.web.action; + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.TreeSet; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.tool.ToolAccessMode; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.vote.VoteAppConstants; +import org.lamsfoundation.lams.tool.vote.dto.VoteGeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.vote.pojos.VoteContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteQueContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteQueUsr; +import org.lamsfoundation.lams.tool.vote.pojos.VoteSession; +import org.lamsfoundation.lams.tool.vote.pojos.VoteUsrAttempt; +import org.lamsfoundation.lams.tool.vote.service.IVoteService; +import org.lamsfoundation.lams.tool.vote.service.VoteServiceProxy; +import org.lamsfoundation.lams.tool.vote.util.VoteApplicationException; +import org.lamsfoundation.lams.tool.vote.util.VoteComparator; +import org.lamsfoundation.lams.tool.vote.util.VoteUtils; +import org.lamsfoundation.lams.tool.vote.web.form.VoteLearningForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Ozgur Demirtas + */ +public class LearningAction extends LamsDispatchAction implements VoteAppConstants { + private static Logger logger = Logger.getLogger(LearningAction.class.getName()); + + private static IVoteService voteService; + + /** + * + * main content/question content management and workflow logic + * + * if the passed toolContentID exists in the db, we need to get the relevant + * data into the Map if not, create the default Map + */ + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + + repopulateRequestParameters(request, voteLearningForm); + + VoteUtils.cleanUpUserExceptions(request); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + voteLearningForm.setMinNominationCountReached(new Boolean(false).toString()); + return null; + } + + public ActionForward viewAllResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteUtils.cleanUpUserExceptions(request); + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + voteLearningForm.setMinNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMinNominationCountReached(new Boolean(false).toString()); + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + repopulateRequestParameters(request, voteLearningForm); + + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + logger.info("Tool session ID" + toolSessionID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter(USER_ID); + voteLearningForm.setUserID(userID); + + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + VoteContent voteContent = voteSession.getVoteContent(); + + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + + Long toolContentID = voteContent.getVoteContentId(); + + Long toolSessionUid = voteSession.getUid(); + + VoteQueUsr existingVoteQueUsr = voteService.getVoteUserBySession(new Long(userID), voteSession.getUid()); + + existingVoteQueUsr.setFinalScreenRequested(true); + voteService.updateVoteUser(existingVoteQueUsr); + + Set userAttempts = voteService.getAttemptsForUserAndSession(existingVoteQueUsr.getUid(), + toolSessionUid); + request.setAttribute(LIST_GENERAL_CHECKED_OPTIONS_CONTENT, userAttempts); + + voteService.prepareChartData(request, toolContentID, toolSessionUid, voteGeneralLearnerFlowDTO); + + voteGeneralLearnerFlowDTO.setReflection(new Boolean(voteContent.isReflect()).toString()); + //String reflectionSubject = VoteUtils.replaceNewLines(voteContent.getReflectionSubject()); + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + + voteLearningForm.resetCommands(); + + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + LearningWebUtil.putActivityPositionInRequestByToolSessionId(new Long(toolSessionID), request, + getServlet().getServletContext()); + + return (mapping.findForward(ALL_NOMINATIONS)); + } + + public ActionForward viewAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteUtils.cleanUpUserExceptions(request); + + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + voteLearningForm.setMinNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMinNominationCountReached(new Boolean(false).toString()); + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + repopulateRequestParameters(request, voteLearningForm); + + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + logger.info("Tool session id :" + toolSessionID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter(USER_ID); + logger.info("User id :" + userID); + voteLearningForm.setUserID(userID); + + String revisitingUser = request.getParameter(REVISITING_USER); + voteLearningForm.setRevisitingUser(revisitingUser); + + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + VoteContent voteContent = voteSession.getVoteContent(); + + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + + if (revisitingUser.equals("true")) { + /* get back login user DTO */ + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + long userId = toolUser.getUserID().longValue(); + VoteQueUsr voteQueUsr = voteService.getUserByUserId(userId); + + List attempts = voteService.getAttemptsForUser(voteQueUsr.getUid()); + + Map mapQuestionsContent = new TreeMap(new VoteComparator()); + Iterator listIterator = attempts.iterator(); + int order = 0; + while (listIterator.hasNext()) { + VoteUsrAttempt attempt = listIterator.next(); + VoteQueContent voteQueContent = attempt.getVoteQueContent(); + order++; + if (voteQueContent != null) { + mapQuestionsContent.put(new Integer(order).toString(), voteQueContent.getQuestion()); + } + } + request.setAttribute(MAP_GENERAL_CHECKED_OPTIONS_CONTENT, mapQuestionsContent); + } else { + //this is not a revisiting user + logger.info("If not a revisiting user"); + } + + voteLearningForm.resetCommands(); + + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + LearningWebUtil.putActivityPositionInRequestByToolSessionId(new Long(toolSessionID), request, + getServlet().getServletContext()); + return (mapping.findForward(VIEW_ANSWERS)); + } + + public ActionForward redoQuestionsOk(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteUtils.cleanUpUserExceptions(request); + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + + repopulateRequestParameters(request, voteLearningForm); + + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + logger.info("Tool session id:" + toolSessionID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter(USER_ID); + logger.info("User id:" + userID); + voteLearningForm.setUserID(userID); + + String revisitingUser = request.getParameter(REVISITING_USER); + voteLearningForm.setRevisitingUser(revisitingUser); + + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + voteLearningForm.setMinNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMinNominationCountReached(new Boolean(false).toString()); + + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + VoteContent voteContent = voteSession.getVoteContent(); + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + + voteGeneralLearnerFlowDTO.setReflection(new Boolean(voteContent.isReflect()).toString()); + //String reflectionSubject = VoteUtils.replaceNewLines(voteContent.getReflectionSubject()); + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + + voteLearningForm.resetCommands(); + + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + return redoQuestions(mapping, form, request, response); + } + + public ActionForward learnerFinished(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + voteLearningForm.setMinNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMinNominationCountReached(new Boolean(false).toString()); + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + repopulateRequestParameters(request, voteLearningForm); + + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + logger.info("Tool Session id :" + toolSessionID); + voteLearningForm.setToolSessionID(toolSessionID); + + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + String userID = request.getParameter(USER_ID); + logger.info("User id:" + userID); + voteLearningForm.setUserID(userID); + + VoteQueUsr voteQueUsr = voteService.getVoteUserBySession(new Long(userID), voteSession.getUid()); + + voteQueUsr.setResponseFinalised(true); + if (!voteSession.getVoteContent().isShowResults()) { + // if not isShowResults then we will have skipped the final screen. + voteQueUsr.setFinalScreenRequested(true); + } + voteService.updateVoteUser(voteQueUsr); + + String revisitingUser = request.getParameter(REVISITING_USER); + voteLearningForm.setRevisitingUser(revisitingUser); + + VoteContent voteContent = voteSession.getVoteContent(); + + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + + voteGeneralLearnerFlowDTO.setReflection(new Boolean(voteContent.isReflect()).toString()); + //String reflectionSubject = VoteUtils.replaceNewLines(voteContent.getReflectionSubject()); + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + VoteUtils.cleanUpUserExceptions(request); + + String nextUrl = null; + try { + nextUrl = voteService.leaveToolSession(new Long(toolSessionID), new Long(userID)); + } catch (DataMissingException e) { + logger.error("failure getting nextUrl: " + e); + voteLearningForm.resetCommands(); + //throw new ServletException(e); + return (mapping.findForward(LEARNING_STARTER)); + } catch (ToolException e) { + logger.error("failure getting nextUrl: " + e); + voteLearningForm.resetCommands(); + //throw new ServletException(e); + return (mapping.findForward(LEARNING_STARTER)); + } catch (Exception e) { + logger.error("unknown exception getting nextUrl: " + e); + voteLearningForm.resetCommands(); + //throw new ServletException(e); + return (mapping.findForward(LEARNING_STARTER)); + } + + voteLearningForm.resetCommands(); + + /* pay attention here */ + response.sendRedirect(nextUrl); + + return null; + + } + + public ActionForward continueOptionsCombined(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteUtils.cleanUpUserExceptions(request); + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + repopulateRequestParameters(request, voteLearningForm); + + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + logger.info("Tool session id:" + toolSessionID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter(USER_ID); + logger.info("User id:" + userID); + voteLearningForm.setUserID(userID); + + String maxNominationCount = request.getParameter(MAX_NOMINATION_COUNT); + voteLearningForm.setMaxNominationCount(maxNominationCount); + + String minNominationCount = request.getParameter(MIN_NOMINATION_COUNT); + voteLearningForm.setMinNominationCount(minNominationCount); + + String userEntry = request.getParameter(USER_ENTRY); + voteLearningForm.setUserEntry(userEntry); + + VoteSession session = voteService.getSessionBySessionId(new Long(toolSessionID)); + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + voteLearningForm.setMinNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMinNominationCountReached(new Boolean(false).toString()); + + Collection voteDisplayOrderIds = voteLearningForm.votesAsCollection(); + + // check number of votes + int castVoteCount = voteDisplayOrderIds != null ? voteDisplayOrderIds.size() : 0; + if ((userEntry != null) && (userEntry.length() > 0)) { + ++castVoteCount; + } + + int intMaxNominationCount = 0; + if (maxNominationCount != null) { + intMaxNominationCount = new Integer(maxNominationCount).intValue(); + } + + if (castVoteCount > intMaxNominationCount) { + voteLearningForm.setMaxNominationCountReached(new Boolean(true).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(true).toString()); + persistInRequestError(request, "error.maxNominationCount.reached"); + logger.error("You have selected too many nominations."); + return (mapping.findForward(LOAD_LEARNER)); + } + + VoteContent voteContent = session.getVoteContent(); + + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + + Long toolContentID = voteContent.getVoteContentId(); + Long voteContentUid = voteContent.getUid(); + + boolean userEntryAvailable = false; + if ((userEntry != null) && (userEntry.length() > 0)) { + userEntryAvailable = true; + } + + Long toolSessionUid = session.getUid(); + + VoteQueUsr user = voteService.getVoteUserBySession(new Long(userID), session.getUid()); + if (user == null) { + throw new VoteApplicationException( + "User with userId= " + userID + " and sessionUid= " + session.getUid() + " doesn't exist."); + } + + voteService.removeAttemptsForUserandSession(user.getUid(), session.getUid()); + + /* + * to minimize changes to working code, convert the String[] array to the mapGeneralCheckedOptionsContent + * structure + */ + Map mapGeneralCheckedOptionsContent = voteService.buildQuestionMap(voteContent, + voteDisplayOrderIds); + + if (mapGeneralCheckedOptionsContent.size() > 0) { + voteService.createAttempt(user, mapGeneralCheckedOptionsContent, "", session, voteContentUid); + } + + if ((mapGeneralCheckedOptionsContent.size() == 0 && (userEntryAvailable == true))) { + Map mapLeanerCheckedOptionsContent = new TreeMap(new VoteComparator()); + + if (userEntry.length() > 0) { + voteService.createAttempt(user, mapLeanerCheckedOptionsContent, userEntry, session, voteContentUid); + } + } + + if ((mapGeneralCheckedOptionsContent.size() > 0) && (userEntryAvailable == true)) { + Map mapLeanerCheckedOptionsContent = new TreeMap(new VoteComparator()); + + if (userEntry.length() > 0) { + voteService.createAttempt(user, mapLeanerCheckedOptionsContent, userEntry, session, voteContentUid); + } + } + + /* put the map in the request ready for the next screen */ + request.setAttribute(MAP_GENERAL_CHECKED_OPTIONS_CONTENT, mapGeneralCheckedOptionsContent); + voteLearningForm.setMapGeneralCheckedOptionsContent(mapGeneralCheckedOptionsContent); + voteGeneralLearnerFlowDTO.setMapGeneralCheckedOptionsContent(mapGeneralCheckedOptionsContent); + + voteLearningForm.setNominationsSubmited(new Boolean(true).toString()); + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(true).toString()); + + voteService.prepareChartData(request, toolContentID, toolSessionUid, voteGeneralLearnerFlowDTO); + + voteGeneralLearnerFlowDTO.setReflection(new Boolean(voteContent.isReflect()).toString()); + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + + voteLearningForm.resetCommands(); + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + return (mapping.findForward(INDIVIDUAL_REPORT)); + } + + public ActionForward redoQuestions(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteUtils.cleanUpUserExceptions(request); + + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + repopulateRequestParameters(request, voteLearningForm); + + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter(USER_ID); + voteLearningForm.setUserID(userID); + + String revisitingUser = request.getParameter(REVISITING_USER); + voteLearningForm.setRevisitingUser(revisitingUser); + + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + + VoteContent voteContent = voteSession.getVoteContent(); + + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + + voteLearningForm.setNominationsSubmited(new Boolean(false).toString()); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setNominationsSubmited(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + + Map mapQuestionsContent = voteService.buildQuestionMap(voteContent, null); + request.setAttribute(MAP_QUESTION_CONTENT_LEARNER, mapQuestionsContent); + + Map mapGeneralCheckedOptionsContent = new TreeMap(new VoteComparator()); + request.setAttribute(MAP_GENERAL_CHECKED_OPTIONS_CONTENT, mapGeneralCheckedOptionsContent); + + voteLearningForm.setUserEntry(""); + + voteGeneralLearnerFlowDTO.setReflection(new Boolean(voteContent.isReflect()).toString()); + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + voteLearningForm.resetCommands(); + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + return (mapping.findForward(LOAD_LEARNER)); + } + + /** + * checks Leader Progress + */ + public ActionForward checkLeaderProgress(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + Long toolSessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + + VoteSession session = voteService.getSessionBySessionId(toolSessionId); + VoteQueUsr leader = session.getGroupLeader(); + logger.info("Leader :" + leader); + + boolean isLeaderResponseFinalized = leader.isResponseFinalised(); + + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put("isLeaderResponseFinalized", isLeaderResponseFinalized); + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(ObjectNode); + return null; + } + + public ActionForward submitReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + + repopulateRequestParameters(request, voteLearningForm); + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + logger.info("Tool Session Id" + toolSessionID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + logger.info("User Id:" + userID); + voteLearningForm.setUserID(userID); + + String reflectionEntry = request.getParameter(ENTRY_TEXT); + logger.info("reflection entry: " + reflectionEntry); + + voteService.createNotebookEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, MY_SIGNATURE, + new Integer(userID), reflectionEntry); + + voteLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + return learnerFinished(mapping, form, request, response); + } + + public ActionForward forwardtoReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + logger.info("toolSessionID:" + toolSessionID); + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + + VoteContent voteContent = voteSession.getVoteContent(); + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + + //String reflectionSubject = voteContent.getReflectionSubject(); + //reflectionSubject = VoteUtils.replaceNewLines(reflectionSubject); + + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + + String userID = request.getParameter("userID"); + logger.info("User Id :" + userID); + voteLearningForm.setUserID(userID); + + NotebookEntry notebookEntry = voteService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + MY_SIGNATURE, new Integer(userID)); + + if (notebookEntry != null) { + String notebookEntryPresentable = notebookEntry.getEntry(); + voteGeneralLearnerFlowDTO.setNotebookEntry(notebookEntryPresentable); + voteLearningForm.setEntryText(notebookEntryPresentable); + } + + request.setAttribute(VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + voteLearningForm.resetCommands(); + + LearningWebUtil.putActivityPositionInRequestByToolSessionId(new Long(toolSessionID), request, + getServlet().getServletContext()); + + return (mapping.findForward(NOTEBOOK)); + } + + protected void repopulateRequestParameters(HttpServletRequest request, VoteLearningForm voteLearningForm) { + String toolSessionID = request.getParameter(TOOL_SESSION_ID); + voteLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter(USER_ID); + voteLearningForm.setUserID(userID); + + String revisitingUser = request.getParameter(REVISITING_USER); + voteLearningForm.setRevisitingUser(revisitingUser); + + String previewOnly = request.getParameter(PREVIEW_ONLY); + voteLearningForm.setPreviewOnly(previewOnly); + + String maxNominationCount = request.getParameter(MAX_NOMINATION_COUNT); + voteLearningForm.setMaxNominationCount(maxNominationCount); + + String minNominationCount = request.getParameter(MIN_NOMINATION_COUNT); + voteLearningForm.setMinNominationCount(minNominationCount); + + String useSelectLeaderToolOuput = request.getParameter(USE_SELECT_LEADER_TOOL_OUTPUT); + voteLearningForm.setUseSelectLeaderToolOuput(useSelectLeaderToolOuput); + + String allowTextEntry = request.getParameter(ALLOW_TEXT_ENTRY); + voteLearningForm.setAllowTextEntry(allowTextEntry); + + String showResults = request.getParameter(SHOW_RESULTS); + voteLearningForm.setShowResults(showResults); + + String lockOnFinish = request.getParameter(LOCK_ON_FINISH); + voteLearningForm.setLockOnFinish(lockOnFinish); + + String reportViewOnly = request.getParameter(REPORT_VIEW_ONLY); + voteLearningForm.setReportViewOnly(reportViewOnly); + + String userEntry = request.getParameter(USER_ENTRY); + voteLearningForm.setUserEntry(userEntry); + + String groupLeaderName = request.getParameter(ATTR_GROUP_LEADER_NAME); + voteLearningForm.setGroupLeaderName(groupLeaderName); + + String groupLeaderUserId = request.getParameter(ATTR_GROUP_LEADER_USER_ID); + voteLearningForm.setGroupLeaderUserId(groupLeaderUserId); + + boolean isUserLeader = WebUtil.readBooleanParam(request, "userLeader"); + voteLearningForm.setIsUserLeader(isUserLeader); + } + + /* + * By now, the passed tool session id MUST exist in the db through the calling of: public void + * createToolSession(Long toolSessionID, Long toolContentId) by the container. + * + * + * make sure this session exists in tool's session table by now. + */ + public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, VoteApplicationException { + + VoteUtils.cleanUpUserExceptions(request); + + if (voteService == null) { + voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + } + + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + VoteLearningForm voteLearningForm = (VoteLearningForm) form; + + voteLearningForm.setRevisitingUser(new Boolean(false).toString()); + voteLearningForm.setUserEntry(""); + voteLearningForm.setCastVoteCount(0); + voteLearningForm.setMaxNominationCountReached(new Boolean(false).toString()); + + voteGeneralLearnerFlowDTO.setRevisitingUser(new Boolean(false).toString()); + voteGeneralLearnerFlowDTO.setUserEntry(""); + voteGeneralLearnerFlowDTO.setCastVoteCount("0"); + voteGeneralLearnerFlowDTO.setMaxNominationCountReached(new Boolean(false).toString()); + + ActionForward validateParameters = validateParameters(request, mapping, voteLearningForm); + if (validateParameters != null) { + return validateParameters; + } + + String toolSessionID = voteLearningForm.getToolSessionID(); + + /* + * by now, we made sure that the passed tool session id exists in the db as a new record Make sure we can + * retrieve it and the relavent content + */ + + VoteSession voteSession = voteService.getSessionBySessionId(new Long(toolSessionID)); + + if (voteSession == null) { + VoteUtils.cleanUpUserExceptions(request); + logger.error("error: The tool expects voteSession."); + return mapping.findForward(VoteAppConstants.ERROR_LIST); + } + + /* + * find out what content this tool session is referring to get the content for this tool session Each passed + * tool session id points to a particular content. Many to one mapping. + */ + VoteContent voteContent = voteSession.getVoteContent(); + if (voteContent == null) { + VoteUtils.cleanUpUserExceptions(request); + logger.error("error: The tool expects voteContent."); + persistInRequestError(request, "error.content.doesNotExist"); + return mapping.findForward(VoteAppConstants.ERROR_LIST); + } + + /* + * The content we retrieved above must have been created before in Authoring time. And the passed tool session + * id already refers to it. + */ + setupAttributes(request, voteContent, voteLearningForm, voteGeneralLearnerFlowDTO); + + voteLearningForm.setToolContentID(voteContent.getVoteContentId().toString()); + voteGeneralLearnerFlowDTO.setToolContentID(voteContent.getVoteContentId().toString()); + + voteLearningForm.setToolContentUID(voteContent.getUid().toString()); + voteGeneralLearnerFlowDTO.setToolContentUID(voteContent.getUid().toString()); + + voteGeneralLearnerFlowDTO.setReflection(new Boolean(voteContent.isReflect()).toString()); + //String reflectionSubject = VoteUtils.replaceNewLines(voteContent.getReflectionSubject()); + voteGeneralLearnerFlowDTO.setReflectionSubject(voteContent.getReflectionSubject()); + + String mode = voteLearningForm.getLearningMode(); + voteGeneralLearnerFlowDTO.setLearningMode(mode); + + String userId = voteLearningForm.getUserID(); + NotebookEntry notebookEntry = voteService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + VoteAppConstants.MY_SIGNATURE, new Integer(userId)); + if (notebookEntry != null) { + //String notebookEntryPresentable = VoteUtils.replaceNewLines(notebookEntry.getEntry()); + voteGeneralLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); + } + + Map mapQuestions = voteService.buildQuestionMap(voteContent, null); + request.setAttribute(VoteAppConstants.MAP_QUESTION_CONTENT_LEARNER, mapQuestions); + + request.setAttribute(VoteAppConstants.VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + VoteQueUsr user = null; + if ((mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())) { + // monitoring mode - user is specified in URL + // user may be null if the user was force completed. + user = getSpecifiedUser(toolSessionID, WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID, false)); + } else { + user = getCurrentUser(toolSessionID); + } + + // check if there is submission deadline + Date submissionDeadline = voteContent.getSubmissionDeadline(); + + if (submissionDeadline != null) { + + request.setAttribute(VoteAppConstants.ATTR_SUBMISSION_DEADLINE, submissionDeadline); + HttpSession ss = SessionManager.getSession(); + UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone learnerTimeZone = learnerDto.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); + Date currentLearnerDate = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, new Date()); + voteGeneralLearnerFlowDTO.setSubmissionDeadline(tzSubmissionDeadline); + + // calculate whether deadline has passed, and if so forward to "submissionDeadline" + if (currentLearnerDate.after(tzSubmissionDeadline)) { + return mapping.findForward("submissionDeadline"); + } + } + + LearningWebUtil.putActivityPositionInRequestByToolSessionId(new Long(toolSessionID), request, + getServlet().getServletContext()); + + /* find out if the content is being modified at the moment. */ + if (voteContent.isDefineLater()) { + VoteUtils.cleanUpUserExceptions(request); + return mapping.findForward(VoteAppConstants.DEFINE_LATER); + } + + //process group leader + VoteQueUsr groupLeader = null; + if (voteContent.isUseSelectLeaderToolOuput()) { + groupLeader = voteService.checkLeaderSelectToolForSessionLeader(user, new Long(toolSessionID)); + + // forwards to the leaderSelection page + if (groupLeader == null && !mode.equals(ToolAccessMode.TEACHER.toString())) { + + Set groupUsers = voteSession.getVoteQueUsers(); + request.setAttribute(ATTR_GROUP_USERS, groupUsers); + request.setAttribute(TOOL_SESSION_ID, toolSessionID); + request.setAttribute(ATTR_CONTENT, voteContent); + + return mapping.findForward(WAIT_FOR_LEADER); + } + + // check if leader has submitted all answers + if (groupLeader.isResponseFinalised() && !mode.equals(ToolAccessMode.TEACHER.toString())) { + + // in case user joins the lesson after leader has answers some answers already - we need to make sure + // he has the same scratches as leader + voteService.copyAnswersFromLeader(user, groupLeader); + + user.setFinalScreenRequested(true); + user.setResponseFinalised(true); + voteService.updateVoteUser(user); + } + + // store group leader information + voteLearningForm.setGroupLeaderName(groupLeader.getFullname()); + voteLearningForm.setGroupLeaderUserId( + groupLeader.getQueUsrId() != null ? groupLeader.getQueUsrId().toString() : ""); + boolean isUserLeader = voteService.isUserGroupLeader(user, new Long(toolSessionID)); + voteLearningForm.setIsUserLeader(isUserLeader); + } + + if (mode.equals("teacher")) { + + Long sessionUid = user.getVoteSessionId(); + putMapQuestionsContentIntoRequest(request, voteService, user); + Set userAttempts = voteService.getAttemptsForUserAndSessionUseOpenAnswer(user.getUid(), sessionUid); + request.setAttribute(VoteAppConstants.LIST_GENERAL_CHECKED_OPTIONS_CONTENT, userAttempts); + + // since this is progress view, present a screen which can not be edited + voteLearningForm.setReportViewOnly(new Boolean(true).toString()); + voteGeneralLearnerFlowDTO.setReportViewOnly(new Boolean(true).toString()); + + voteService.prepareChartData(request, voteContent.getVoteContentId(), voteSession.getUid(), + voteGeneralLearnerFlowDTO); + + boolean isGroupedActivity = voteService.isGroupedActivity(new Long(voteLearningForm.getToolContentID())); + request.setAttribute("isGroupedActivity", isGroupedActivity); + + return mapping.findForward(VoteAppConstants.EXIT_PAGE); + } + + /* + * the user's session id AND user id exists in the tool tables goto this screen if the OverAll Results scren has + * been already called up by this user + */ + if (user.isFinalScreenRequested()) { + Long sessionUid = user.getVoteSessionId(); + VoteSession voteUserSession = voteService.getVoteSessionByUID(sessionUid); + String userSessionId = voteUserSession.getVoteSessionId().toString(); + + if (toolSessionID.toString().equals(userSessionId)) { + // the learner has already responsed to this content, just generate a read-only report. Use redo + // questions for this + putMapQuestionsContentIntoRequest(request, voteService, user); + + boolean isResponseFinalised = user.isResponseFinalised(); + if (isResponseFinalised) { + // since the response is finalised present a screen which can not be edited + voteLearningForm.setReportViewOnly(new Boolean(true).toString()); + voteGeneralLearnerFlowDTO.setReportViewOnly(new Boolean(true).toString()); + } + + Set userAttempts = voteService.getAttemptsForUserAndSessionUseOpenAnswer(user.getUid(), + sessionUid); + request.setAttribute(VoteAppConstants.LIST_GENERAL_CHECKED_OPTIONS_CONTENT, userAttempts); + + voteService.prepareChartData(request, voteContent.getVoteContentId(), voteSession.getUid(), + voteGeneralLearnerFlowDTO); + + String isContentLockOnFinish = voteLearningForm.getLockOnFinish(); + if (isContentLockOnFinish.equals(new Boolean(true).toString()) && isResponseFinalised == true) { + // user with session id: userSessionId should not redo votes. session is locked + return mapping.findForward(VoteAppConstants.EXIT_PAGE); + } + + voteLearningForm.setRevisitingUser(new Boolean(true).toString()); + voteGeneralLearnerFlowDTO.setRevisitingUser(new Boolean(true).toString()); + request.setAttribute(VoteAppConstants.VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + if (isContentLockOnFinish.equals(new Boolean(false).toString()) && isResponseFinalised == true) { + // isContentLockOnFinish is false, enable redo of votes + return mapping.findForward(VoteAppConstants.REVISITED_ALL_NOMINATIONS); + } + + return mapping.findForward(VoteAppConstants.ALL_NOMINATIONS); + } + } + // presenting standard learner screen.. + return mapping.findForward(VoteAppConstants.LOAD_LEARNER); + } + + /** + * Build the attempts map and put it in the request, based on the supplied user. If the user is null then the map + * will be set but it will be empty TODO This shouldn't go in the request, it should go in our special session map. + */ + private void putMapQuestionsContentIntoRequest(HttpServletRequest request, IVoteService voteService, + VoteQueUsr user) { + List attempts = null; + if (user != null) { + attempts = voteService.getAttemptsForUser(user.getUid()); + } + Map localMapQuestionsContent = new TreeMap(new VoteComparator()); + + if (attempts != null) { + + Iterator listIterator = attempts.iterator(); + int order = 0; + while (listIterator.hasNext()) { + VoteUsrAttempt attempt = listIterator.next(); + VoteQueContent voteQueContent = attempt.getVoteQueContent(); + order++; + if (voteQueContent != null) { + String entry = voteQueContent.getQuestion(); + + String questionUid = attempt.getVoteQueContent().getUid().toString(); + if (entry != null) { + if (entry.equals("sample nomination") && questionUid.equals("1")) { + localMapQuestionsContent.put(new Integer(order).toString(), attempt.getUserEntry()); + } else { + localMapQuestionsContent.put(new Integer(order).toString(), voteQueContent.getQuestion()); + } + } + } + } + } + + request.setAttribute(VoteAppConstants.MAP_GENERAL_CHECKED_OPTIONS_CONTENT, localMapQuestionsContent); + } + + /** + * sets up session scope attributes based on content linked to the passed tool session id + * setupAttributes(HttpServletRequest request, VoteContent voteContent) + * + * @param request + * @param voteContent + */ + protected void setupAttributes(HttpServletRequest request, VoteContent voteContent, + VoteLearningForm voteLearningForm, VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO) { + + Map mapGeneralCheckedOptionsContent = new TreeMap(new VoteComparator()); + request.setAttribute(VoteAppConstants.MAP_GENERAL_CHECKED_OPTIONS_CONTENT, mapGeneralCheckedOptionsContent); + + voteLearningForm.setActivityTitle(voteContent.getTitle()); + voteLearningForm.setActivityInstructions(voteContent.getInstructions()); + voteLearningForm.setMaxNominationCount(voteContent.getMaxNominationCount()); + voteLearningForm.setMinNominationCount(voteContent.getMinNominationCount()); + voteLearningForm.setUseSelectLeaderToolOuput(new Boolean(voteContent.isUseSelectLeaderToolOuput()).toString()); + voteLearningForm.setAllowTextEntry(new Boolean(voteContent.isAllowText()).toString()); + voteLearningForm.setShowResults(new Boolean(voteContent.isShowResults()).toString()); + voteLearningForm.setLockOnFinish(new Boolean(voteContent.isLockOnFinish()).toString()); + + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + voteGeneralLearnerFlowDTO.setMaxNominationCount(voteContent.getMaxNominationCount()); + voteGeneralLearnerFlowDTO.setMinNominationCount(voteContent.getMinNominationCount()); + voteGeneralLearnerFlowDTO + .setUseSelectLeaderToolOuput(new Boolean(voteContent.isUseSelectLeaderToolOuput()).toString()); + voteGeneralLearnerFlowDTO.setAllowTextEntry(new Boolean(voteContent.isAllowText()).toString()); + voteGeneralLearnerFlowDTO.setLockOnFinish(new Boolean(voteContent.isLockOnFinish()).toString()); + voteGeneralLearnerFlowDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralLearnerFlowDTO.setActivityInstructions(voteContent.getInstructions()); + } + + protected ActionForward validateParameters(HttpServletRequest request, ActionMapping mapping, + VoteLearningForm voteLearningForm) { + /* + * obtain and setup the current user's data + */ + + String userID = ""; + HttpSession ss = SessionManager.getSession(); + + if (ss != null) { + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + if (user != null && user.getUserID() != null) { + userID = user.getUserID().toString(); + logger.info("User Id : " + userID); + voteLearningForm.setUserID(userID); + } + } + + /* + * process incoming tool session id and later derive toolContentId from it. + */ + String strToolSessionId = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + long toolSessionID = 0; + if (strToolSessionId == null || strToolSessionId.length() == 0) { + VoteUtils.cleanUpUserExceptions(request); + // persistInRequestError(request, "error.toolSessionId.required"); + logger.error("error.toolSessionId.required"); + return mapping.findForward(VoteAppConstants.ERROR_LIST); + } else { + try { + toolSessionID = new Long(strToolSessionId).longValue(); + voteLearningForm.setToolSessionID(new Long(toolSessionID).toString()); + } catch (NumberFormatException e) { + VoteUtils.cleanUpUserExceptions(request); + // persistInRequestError(request, "error.sessionId.numberFormatException"); + logger.error("add error.sessionId.numberFormatException to ActionMessages."); + return mapping.findForward(VoteAppConstants.ERROR_LIST); + } + } + + /* mode can be learner, teacher or author */ + String mode = request.getParameter(VoteAppConstants.MODE); + + if (mode == null || mode.length() == 0) { + VoteUtils.cleanUpUserExceptions(request); + logger.error("mode missing: "); + return mapping.findForward(VoteAppConstants.ERROR_LIST); + } + + if (!mode.equals("learner") && !mode.equals("teacher") && !mode.equals("author")) { + VoteUtils.cleanUpUserExceptions(request); + logger.error("mode invalid: "); + return mapping.findForward(VoteAppConstants.ERROR_LIST); + } + voteLearningForm.setLearningMode(mode); + + return null; + } + + boolean isSessionCompleted(String userSessionId, IVoteService voteService) { + VoteSession voteSession = voteService.getSessionBySessionId(new Long(userSessionId)); + if (voteSession.getSessionStatus() != null + && voteSession.getSessionStatus().equals(VoteAppConstants.COMPLETED)) { + return true; + } + return false; + } + + /** + * persists error messages to request scope + * + * @param request + * @param message + */ + public void persistInRequestError(HttpServletRequest request, String message) { + ActionMessages errors = new ActionMessages(); + errors.add(Globals.ERROR_KEY, new ActionMessage(message)); + saveErrors(request, errors); + } + + private VoteQueUsr getCurrentUser(String toolSessionId) { + + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = new Long(toolUser.getUserID().longValue()); + + VoteSession session = voteService.getSessionBySessionId(new Long(toolSessionId)); + VoteQueUsr user = voteService.getVoteUserBySession(userId, session.getUid()); + if (user == null) { + String userName = toolUser.getLogin(); + String fullName = toolUser.getFirstName() + " " + toolUser.getLastName(); + + user = new VoteQueUsr(userId, userName, fullName, session, new TreeSet()); + voteService.createVoteQueUsr(user); + } + + return user; + } + + private VoteQueUsr getSpecifiedUser(String toolSessionId, Integer userId) { + VoteSession session = voteService.getSessionBySessionId(new Long(toolSessionId)); + VoteQueUsr user = voteService.getVoteUserBySession(new Long(userId.intValue()), session.getUid()); + if (user == null) { + logger.error("Unable to find specified user for Vote activity. Screens are likely to fail. SessionId=" + + new Long(toolSessionId) + " UserId=" + userId); + } + return user; + } +} \ No newline at end of file Index: lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/MonitoringAction.java =================================================================== diff -u --- lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/MonitoringAction.java (revision 0) +++ lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/MonitoringAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,555 @@ +/*************************************************************************** + * 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 version 2.0 + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.vote.web.action; + +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TimeZone; +import java.util.TreeMap; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; +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.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.vote.VoteAppConstants; +import org.lamsfoundation.lams.tool.vote.dto.OpenTextAnswerDTO; +import org.lamsfoundation.lams.tool.vote.dto.SummarySessionDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteGeneralAuthoringDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteGeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteGeneralMonitoringDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteMonitoredUserDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteQuestionDTO; +import org.lamsfoundation.lams.tool.vote.pojos.VoteContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteQueContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteUsrAttempt; +import org.lamsfoundation.lams.tool.vote.service.IVoteService; +import org.lamsfoundation.lams.tool.vote.service.VoteServiceProxy; +import org.lamsfoundation.lams.tool.vote.util.VoteApplicationException; +import org.lamsfoundation.lams.tool.vote.util.VoteComparator; +import org.lamsfoundation.lams.tool.vote.util.VoteUtils; +import org.lamsfoundation.lams.tool.vote.web.form.VoteMonitoringForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.web.util.SessionMap; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Ozgur Demirtas + */ +public class MonitoringAction extends LamsDispatchAction implements VoteAppConstants { + private static Logger logger = Logger.getLogger(MonitoringAction.class.getName()); + + /** + * main content/question content management and workflow logic + */ + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + VoteUtils.cleanUpUserExceptions(request); + return null; + } + + public ActionForward hideOpenVote(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + return toggleHideShow(request, response, false); + } + + public ActionForward showOpenVote(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + return toggleHideShow(request, response, true); + } + + private ActionForward toggleHideShow(HttpServletRequest request, HttpServletResponse response, boolean show) + throws IOException, ServletException, ToolException { + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + Long currentUid = WebUtil.readLongParam(request, "currentUid"); + logger.info("Current Uid" + currentUid); + + VoteUsrAttempt voteUsrAttempt = voteService.getAttemptByUID(currentUid); + + voteUsrAttempt.setVisible(show); + voteService.updateVoteUsrAttempt(voteUsrAttempt); + String nextActionMethod; + if (show) { + nextActionMethod = "hideOptionVote"; + voteService.showOpenVote(voteUsrAttempt); + } else { + nextActionMethod = "showOpenVote"; + voteService.hideOpenVote(voteUsrAttempt); + } + + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("currentUid", currentUid); + responsedata.put("nextActionMethod", nextActionMethod); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + + public ActionForward getVoteNomination(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + VoteMonitoringForm voteMonitoringForm = (VoteMonitoringForm) form; + voteMonitoringForm.setVoteService(voteService); + + VoteGeneralMonitoringDTO voteGeneralMonitoringDTO = new VoteGeneralMonitoringDTO(); + MonitoringAction.repopulateRequestParameters(request, voteMonitoringForm, voteGeneralMonitoringDTO); + + Long questionUid = WebUtil.readLongParam(request, VoteAppConstants.ATTR_QUESTION_UID, false); + Long sessionUid = WebUtil.readLongParam(request, VoteAppConstants.ATTR_SESSION_UID, true); + + VoteQueContent nomination = voteService.getQuestionByUid(questionUid); + request.setAttribute("nominationText", nomination.getQuestion()); + + request.setAttribute(VoteAppConstants.VOTE_GENERAL_MONITORING_DTO, voteGeneralMonitoringDTO); + request.setAttribute(VoteAppConstants.ATTR_QUESTION_UID, questionUid); + if (sessionUid != null) { + request.setAttribute(VoteAppConstants.ATTR_SESSION_UID, sessionUid); + } + return mapping.findForward(VoteAppConstants.VOTE_NOMINATION_VIEWER); + } + + public ActionForward getVoteNominationsJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + Long sessionUid = WebUtil.readLongParam(request, VoteAppConstants.ATTR_SESSION_UID, true); + if (sessionUid == 0L) { + sessionUid = null; + logger.info("Setting sessionUid to null"); + } + + Long questionUid = WebUtil.readLongParam(request, VoteAppConstants.ATTR_QUESTION_UID, false); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByName = WebUtil.readIntParam(request, "column[0]", true); + Integer sortByDate = WebUtil.readIntParam(request, "column[1]", true); + String searchString = request.getParameter("fcol[0]"); + + int sorting = VoteAppConstants.SORT_BY_DEFAULT; + if (sortByName != null) { + sorting = sortByName.equals(0) ? VoteAppConstants.SORT_BY_NAME_ASC : VoteAppConstants.SORT_BY_NAME_DESC; + } else if (sortByDate != null) { + sorting = sortByDate.equals(0) ? VoteAppConstants.SORT_BY_DATE_ASC : VoteAppConstants.SORT_BY_DATE_DESC; + } + + //return user list according to the given sessionID + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + List users = voteService.getUserAttemptsForTablesorter(sessionUid, questionUid, page, size, sorting, + searchString); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("total_rows", voteService.getCountUsersBySession(sessionUid, questionUid, searchString)); + + for (Object[] userAndAnswers : users) { + + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put(VoteAppConstants.ATTR_USER_NAME, StringEscapeUtils.escapeHtml((String) userAndAnswers[1])); + responseRow.put(VoteAppConstants.ATTR_ATTEMPT_TIME, + DateUtil.convertToStringForJSON((Date) userAndAnswers[2], request.getLocale())); + responseRow.put(VoteAppConstants.ATTR_ATTEMPT_TIME_TIMEAGO, + DateUtil.convertToStringForTimeagoJSON((Date) userAndAnswers[2])); + rows.add(responseRow); + } + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + + public ActionForward getReflectionsJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + Long sessionUid = WebUtil.readLongParam(request, VoteAppConstants.ATTR_SESSION_UID, true); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByName = WebUtil.readIntParam(request, "column[0]", true); + String searchString = request.getParameter("fcol[0]"); + + int sorting = VoteAppConstants.SORT_BY_DEFAULT; + if (sortByName != null) { + sorting = sortByName.equals(0) ? VoteAppConstants.SORT_BY_NAME_ASC : VoteAppConstants.SORT_BY_NAME_DESC; + } + + //return user list according to the given sessionID + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + List users = voteService.getUserReflectionsForTablesorter(sessionUid, page, size, sorting, + searchString); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("total_rows", voteService.getCountUsersBySession(sessionUid, null, searchString)); + + for (Object[] userAndReflection : users) { + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put(VoteAppConstants.ATTR_USER_NAME, + StringEscapeUtils.escapeHtml((String) userAndReflection[1])); + if (userAndReflection.length > 2 && userAndReflection[2] != null) { + String reflection = StringEscapeUtils.escapeHtml((String) userAndReflection[2]); + responseRow.put(VoteAppConstants.NOTEBOOK, reflection.replaceAll("\n", "
")); + } + rows.add(responseRow); + } + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + + public ActionForward statistics(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + Long toolContentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + request.setAttribute("isGroupedActivity", voteService.isGroupedActivity(toolContentID)); + request.setAttribute(VoteAppConstants.VOTE_STATS_DTO, voteService.getStatisticsBySession(toolContentID)); + return mapping.findForward(VoteAppConstants.STATISTICS); + } + + public ActionForward getOpenTextNominationsJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + Long sessionUid = WebUtil.readLongParam(request, VoteAppConstants.ATTR_SESSION_UID, true); + if (sessionUid == 0L) { + logger.info("Setting sessionUid to null"); + sessionUid = null; + } + + Long contentUid = WebUtil.readLongParam(request, VoteAppConstants.TOOL_CONTENT_UID, false); + + // paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByEntry = WebUtil.readIntParam(request, "column[0]", true); + Integer sortByName = WebUtil.readIntParam(request, "column[1]", true); + Integer sortByDate = WebUtil.readIntParam(request, "column[2]", true); + Integer sortByVisible = WebUtil.readIntParam(request, "column[3]", true); + String searchStringVote = request.getParameter("fcol[0]"); + String searchStringUsername = request.getParameter("fcol[1]"); + + int sorting = VoteAppConstants.SORT_BY_DEFAULT; + if (sortByEntry != null) { + sorting = sortByEntry.equals(0) ? VoteAppConstants.SORT_BY_ENTRY_ASC : VoteAppConstants.SORT_BY_ENTRY_DESC; + } + if (sortByName != null) { + sorting = sortByName.equals(0) ? VoteAppConstants.SORT_BY_NAME_ASC : VoteAppConstants.SORT_BY_NAME_DESC; + } else if (sortByDate != null) { + sorting = sortByDate.equals(0) ? VoteAppConstants.SORT_BY_DATE_ASC : VoteAppConstants.SORT_BY_DATE_DESC; + } else if (sortByVisible != null) { + sorting = sortByVisible.equals(0) ? VoteAppConstants.SORT_BY_VISIBLE_ASC + : VoteAppConstants.SORT_BY_VISIBLE_DESC; + } + + //return user list according to the given sessionID + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + List users = voteService.getUserOpenTextAttemptsForTablesorter(sessionUid, contentUid, page, + size, sorting, searchStringVote, searchStringUsername); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("total_rows", voteService.getCountUsersForOpenTextEntries(sessionUid, contentUid, + searchStringVote, searchStringUsername)); + + for (OpenTextAnswerDTO userAndAttempt : users) { + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + + responseRow.put("uid", userAndAttempt.getUserUid()); + responseRow.put(VoteAppConstants.ATTR_USER_NAME, + StringEscapeUtils.escapeHtml(userAndAttempt.getFullName())); + + responseRow.put("userEntryUid", userAndAttempt.getUserEntryUid()); + responseRow.put("userEntry", StringEscapeUtils.escapeHtml(userAndAttempt.getUserEntry())); + responseRow.put(VoteAppConstants.ATTR_ATTEMPT_TIME, + DateUtil.convertToStringForJSON(userAndAttempt.getAttemptTime(), request.getLocale())); + responseRow.put(VoteAppConstants.ATTR_ATTEMPT_TIME_TIMEAGO, + DateUtil.convertToStringForTimeagoJSON(userAndAttempt.getAttemptTime())); + responseRow.put("visible", userAndAttempt.isVisible()); + + rows.add(responseRow); + } + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + + public ActionForward openNotebook(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + IVoteService VoteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + //String uid = request.getParameter("uid"); + + String userId = request.getParameter("userId"); + + String userName = request.getParameter("userName"); + + String sessionId = request.getParameter("sessionId"); + + NotebookEntry notebookEntry = VoteService.getEntry(new Long(sessionId), CoreNotebookConstants.NOTEBOOK_TOOL, + VoteAppConstants.MY_SIGNATURE, new Integer(userId)); + + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = new VoteGeneralLearnerFlowDTO(); + if (notebookEntry != null) { + //String notebookEntryPresentable = VoteUtils.replaceNewLines(notebookEntry.getEntry()); + voteGeneralLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); + voteGeneralLearnerFlowDTO.setUserName(userName); + } + request.setAttribute(VoteAppConstants.VOTE_GENERAL_LEARNER_FLOW_DTO, voteGeneralLearnerFlowDTO); + + return mapping.findForward(VoteAppConstants.LEARNER_NOTEBOOK); + } + + /** + * Set Submission Deadline + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + */ + public ActionForward setSubmissionDeadline(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + VoteContent voteContent = voteService.getVoteContent(contentID); + + Long dateParameter = WebUtil.readLongParam(request, VoteAppConstants.ATTR_SUBMISSION_DEADLINE, true); + Date tzSubmissionDeadline = null; + String formattedDate = ""; + if (dateParameter != null) { + Date submissionDeadline = new Date(dateParameter); + HttpSession ss = SessionManager.getSession(); + org.lamsfoundation.lams.usermanagement.dto.UserDTO teacher = (org.lamsfoundation.lams.usermanagement.dto.UserDTO) ss + .getAttribute(AttributeNames.USER); + TimeZone teacherTimeZone = teacher.getTimeZone(); + tzSubmissionDeadline = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, submissionDeadline); + formattedDate = DateUtil.convertToStringForJSON(tzSubmissionDeadline, request.getLocale()); + } + voteContent.setSubmissionDeadline(tzSubmissionDeadline); + voteService.updateVote(voteContent); + response.setContentType("text/plain;charset=utf-8"); + response.getWriter().print(formattedDate); + return null; + } + + public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, VoteApplicationException { + VoteUtils.cleanUpUserExceptions(request); + + IVoteService voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + + VoteMonitoringForm voteMonitoringForm = (VoteMonitoringForm) form; + + VoteGeneralAuthoringDTO voteGeneralAuthoringDTO = new VoteGeneralAuthoringDTO(); + VoteGeneralMonitoringDTO voteGeneralMonitoringDTO = new VoteGeneralMonitoringDTO(); + request.setAttribute(VoteAppConstants.VOTE_GENERAL_AUTHORING_DTO, voteGeneralAuthoringDTO); + request.setAttribute(VoteAppConstants.VOTE_GENERAL_MONITORING_DTO, voteGeneralMonitoringDTO); + + ActionForward validateParameters = validateParameters(request, mapping, voteMonitoringForm); + if (validateParameters != null) { + return validateParameters; + } + + // initialiseMonitoringData + voteGeneralMonitoringDTO.setRequestLearningReport(Boolean.FALSE.toString()); + + /* we have made sure TOOL_CONTENT_ID is passed */ + String toolContentID = voteMonitoringForm.getToolContentID(); + logger.warn("Make sure ToolContentId is passed" + toolContentID); + VoteContent voteContent = voteService.getVoteContent(new Long(toolContentID)); + + if (voteContent == null) { + VoteUtils.cleanUpUserExceptions(request); + logger.error("Vote Content does not exist"); + voteGeneralMonitoringDTO.setUserExceptionContentDoesNotExist(Boolean.TRUE.toString()); + return (mapping.findForward(VoteAppConstants.ERROR_LIST)); + } + + voteGeneralMonitoringDTO.setActivityTitle(voteContent.getTitle()); + voteGeneralMonitoringDTO.setActivityInstructions(voteContent.getInstructions()); + + /* this section is related to summary tab. Starts here. */ + + SortedSet sessionDTOs = voteService.getMonitoringSessionDTOs(new Long(toolContentID)); + request.setAttribute("sessionDTOs", sessionDTOs); + + request.setAttribute(VoteAppConstants.VOTE_GENERAL_MONITORING_DTO, voteGeneralMonitoringDTO); + + // setting up the advanced summary for LDEV-1662 + request.setAttribute("useSelectLeaderToolOuput", voteContent.isUseSelectLeaderToolOuput()); + request.setAttribute("lockOnFinish", voteContent.isLockOnFinish()); + request.setAttribute("allowText", voteContent.isAllowText()); + request.setAttribute("maxNominationCount", voteContent.getMaxNominationCount()); + request.setAttribute("minNominationCount", voteContent.getMinNominationCount()); + request.setAttribute("showResults", voteContent.isShowResults()); + request.setAttribute("reflect", voteContent.isReflect()); + request.setAttribute("reflectionSubject", voteContent.getReflectionSubject()); + request.setAttribute("toolContentID", voteContent.getVoteContentId()); + + // setting up the SubmissionDeadline + if (voteContent.getSubmissionDeadline() != null) { + Date submissionDeadline = voteContent.getSubmissionDeadline(); + HttpSession ss = SessionManager.getSession(); + UserDTO teacher = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone teacherTimeZone = teacher.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(teacherTimeZone, submissionDeadline); + request.setAttribute(VoteAppConstants.ATTR_SUBMISSION_DEADLINE, tzSubmissionDeadline.getTime()); + // use the unconverted time, as convertToStringForJSON() does the timezone conversion if needed + request.setAttribute(VoteAppConstants.ATTR_SUBMISSION_DEADLINE_DATESTRING, + DateUtil.convertToStringForJSON(submissionDeadline, request.getLocale())); + } + + voteMonitoringForm.setCurrentTab("1"); + voteGeneralMonitoringDTO.setCurrentTab("1"); + + if (sessionDTOs.size() > 0) { + VoteUtils.cleanUpUserExceptions(request); + voteGeneralMonitoringDTO.setUserExceptionContentInUse(Boolean.TRUE.toString()); + } + + /* + * get the nominations section is needed for the Edit tab's View Only mode, starts here + */ + SessionMap sessionMap = new SessionMap<>(); + sessionMap.put(VoteAppConstants.ACTIVITY_TITLE_KEY, voteContent.getTitle()); + sessionMap.put(VoteAppConstants.ACTIVITY_INSTRUCTIONS_KEY, voteContent.getInstructions()); + + voteMonitoringForm.setHttpSessionID(sessionMap.getSessionID()); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + + List listQuestionDTO = new LinkedList(); + + Iterator queIterator = voteContent.getVoteQueContents().iterator(); + while (queIterator.hasNext()) { + VoteQuestionDTO voteQuestionDTO = new VoteQuestionDTO(); + + VoteQueContent voteQueContent = queIterator.next(); + if (voteQueContent != null) { + + voteQuestionDTO.setQuestion(voteQueContent.getQuestion()); + voteQuestionDTO.setDisplayOrder(new Integer(voteQueContent.getDisplayOrder()).toString()); + listQuestionDTO.add(voteQuestionDTO); + } + } + + request.setAttribute(VoteAppConstants.LIST_QUESTION_DTO, listQuestionDTO); + sessionMap.put(VoteAppConstants.LIST_QUESTION_DTO, listQuestionDTO); + + // this section is needed for Edit Activity screen + voteGeneralAuthoringDTO.setActivityTitle(voteGeneralMonitoringDTO.getActivityTitle()); + voteGeneralAuthoringDTO.setActivityInstructions(voteGeneralMonitoringDTO.getActivityInstructions()); + + MonitoringAction.repopulateRequestParameters(request, voteMonitoringForm, voteGeneralMonitoringDTO); + + boolean isGroupedActivity = voteService.isGroupedActivity(new Long(toolContentID)); + request.setAttribute("isGroupedActivity", isGroupedActivity); + request.setAttribute("isAllowText", voteContent.isAllowText()); + + return mapping.findForward(VoteAppConstants.LOAD_MONITORING); + } + + private ActionForward validateParameters(HttpServletRequest request, ActionMapping mapping, + VoteMonitoringForm voteMonitoringForm) { + + String strToolContentId = request.getParameter(AttributeNames.PARAM_TOOL_CONTENT_ID); + + if ((strToolContentId == null) || (strToolContentId.length() == 0)) { + VoteUtils.cleanUpUserExceptions(request); + return (mapping.findForward(VoteAppConstants.ERROR_LIST)); + } else { + try { + voteMonitoringForm.setToolContentID(strToolContentId); + } catch (NumberFormatException e) { + logger.error("Number Format Exception"); + VoteUtils.cleanUpUserExceptions(request); + return (mapping.findForward(VoteAppConstants.ERROR_LIST)); + } + } + return null; + } + + public static Map convertToVoteMonitoredUserDTOMap(List list) { + Map map = new TreeMap(new VoteComparator()); + + Iterator listIterator = list.iterator(); + Long mapIndex = new Long(1); + + while (listIterator.hasNext()) { + ; + VoteMonitoredUserDTO data = listIterator.next(); + + map.put(mapIndex.toString(), data); + mapIndex = new Long(mapIndex.longValue() + 1); + } + return map; + } + + public static void repopulateRequestParameters(HttpServletRequest request, VoteMonitoringForm voteMonitoringForm, + VoteGeneralMonitoringDTO voteGeneralMonitoringDTO) { + + String toolContentID = request.getParameter(VoteAppConstants.TOOL_CONTENT_ID); + voteMonitoringForm.setToolContentID(toolContentID); + voteGeneralMonitoringDTO.setToolContentID(toolContentID); + + String responseId = request.getParameter(VoteAppConstants.RESPONSE_ID); + voteMonitoringForm.setResponseId(responseId); + voteGeneralMonitoringDTO.setResponseId(responseId); + + String currentUid = request.getParameter(VoteAppConstants.CURRENT_UID); + voteMonitoringForm.setCurrentUid(currentUid); + } +} Index: lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/VoteChartGeneratorAction.java =================================================================== diff -u --- lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/VoteChartGeneratorAction.java (revision 0) +++ lams_tool_vote/src/java/org/lamsfoundation/lams/tool/vote/web/action/VoteChartGeneratorAction.java (revision 2c03060b238558d183472f0066ba003c76d00fd0) @@ -0,0 +1,121 @@ +/*************************************************************************** + * 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 version 2.0 + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.vote.web.action; + +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +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.lamsfoundation.lams.tool.vote.dto.SessionDTO; +import org.lamsfoundation.lams.tool.vote.dto.VoteGeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.vote.pojos.VoteContent; +import org.lamsfoundation.lams.tool.vote.pojos.VoteSession; +import org.lamsfoundation.lams.tool.vote.service.IVoteService; +import org.lamsfoundation.lams.tool.vote.service.VoteServiceProxy; +import org.lamsfoundation.lams.tool.vote.util.VoteUtils; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.util.AttributeNames; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Prepares data for charts. + * + * @author Marcin Cieslak + */ +public class VoteChartGeneratorAction extends LamsDispatchAction { + private static Logger logger = Logger.getLogger(VoteChartGeneratorAction.class.getName()); + private static IVoteService voteService; + + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + String currentSessionId = request.getParameter("currentSessionId"); + + Map nominationNames = new HashMap<>(); + Map nominationVotes = new HashMap<>(); + + //request for the all session summary + if ("0".equals(currentSessionId)) { + long toolContentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + LinkedList sessionDTOs = getVoteService().getSessionDTOs(toolContentID); + + // check allSessionsSummary exists + SessionDTO allSessionsSummary = sessionDTOs.getFirst(); + if ("0".equals(allSessionsSummary.getSessionId())) { + nominationNames = allSessionsSummary.getMapStandardNominationsHTMLedContent(); + nominationVotes = allSessionsSummary.getMapStandardRatesContent(); + + //replace all html tags + for (Long index : nominationNames.keySet()) { + String name = nominationNames.get(index); + String noHTMLNomination = VoteUtils.stripHTML(name); + nominationNames.put(index, noHTMLNomination); + } + } + + //sessionId should not be blank + } else if (!StringUtils.isBlank(currentSessionId)) { + logger.warn("Session Id should not be blank"); + VoteSession voteSession = getVoteService().getSessionBySessionId(new Long(currentSessionId)); + VoteContent voteContent = voteSession.getVoteContent(); + + VoteGeneralLearnerFlowDTO voteGeneralLearnerFlowDTO = getVoteService().prepareChartData(request, + voteContent.getVoteContentId(), voteSession.getUid(), new VoteGeneralLearnerFlowDTO()); + + nominationNames = voteGeneralLearnerFlowDTO.getMapStandardNominationsContent(); + nominationVotes = voteGeneralLearnerFlowDTO.getMapStandardRatesContent(); + } + + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + for (Long index : nominationNames.keySet()) { + ObjectNode nomination = JsonNodeFactory.instance.objectNode(); + // nominations' names and values go separately + nomination.put("name", nominationNames.get(index)); + nomination.put("value", nominationVotes.get(index)); + responseJSON.withArray("data").add(nomination); + } + + response.setContentType("application/json;charset=utf-8"); + response.getWriter().write(responseJSON.toString()); + return null; + } + + private IVoteService getVoteService() { + if (voteService == null) { + voteService = VoteServiceProxy.getVoteService(getServlet().getServletContext()); + } + return voteService; + } +} \ No newline at end of file