Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/util/SurveyWebUtils.java =================================================================== diff -u -r0138aabe01dc8f301e7c727bd39e97424b4fa38a -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/util/SurveyWebUtils.java (.../SurveyWebUtils.java) (revision 0138aabe01dc8f301e7c727bd39e97424b4fa38a) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/util/SurveyWebUtils.java (.../SurveyWebUtils.java) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -25,7 +25,7 @@ package org.lamsfoundation.lams.tool.survey.util; import org.lamsfoundation.lams.tool.survey.model.Survey; -import org.lamsfoundation.lams.tool.survey.web.action.MonitoringAction; +import org.lamsfoundation.lams.tool.survey.web.controller.MonitoringAction; /** * Contains helper methods used by the Action Servlets Fisheye: Tag 92cf398e695b34f71b03ecba27659e4b214920d8 refers to a dead (removed) revision in file `lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/action/AuthoringAction.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 92cf398e695b34f71b03ecba27659e4b214920d8 refers to a dead (removed) revision in file `lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/action/AuthoringConditionAction.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 92cf398e695b34f71b03ecba27659e4b214920d8 refers to a dead (removed) revision in file `lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/action/ChartAction.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 92cf398e695b34f71b03ecba27659e4b214920d8 refers to a dead (removed) revision in file `lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/action/ClearSessionAction.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 92cf398e695b34f71b03ecba27659e4b214920d8 refers to a dead (removed) revision in file `lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/action/LearningAction.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 92cf398e695b34f71b03ecba27659e4b214920d8 refers to a dead (removed) revision in file `lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/action/MonitoringAction.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/AuthoringConditionAction.java =================================================================== diff -u --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/AuthoringConditionAction.java (revision 0) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/AuthoringConditionAction.java (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,476 @@ +/**************************************************************** + * 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.survey.web.controller; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionErrors; +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.util.LabelValueBean; +import org.lamsfoundation.lams.learningdesign.TextSearchConditionComparator; +import org.lamsfoundation.lams.tool.survey.SurveyConstants; +import org.lamsfoundation.lams.tool.survey.model.SurveyCondition; +import org.lamsfoundation.lams.tool.survey.model.SurveyQuestion; +import org.lamsfoundation.lams.tool.survey.service.ISurveyService; +import org.lamsfoundation.lams.tool.survey.util.QuestionsComparator; +import org.lamsfoundation.lams.tool.survey.web.form.SurveyConditionForm; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.util.SessionMap; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * Auxiliary action in author mode. It contains operations with SurveyCondition. The rest of operations are located in + * AuthoringAction action. + * + * @author Marcin Cieslak + * @see org.lamsfoundation.lams.tool.survey.web.controller.AuthoringAction + */ +public class AuthoringConditionAction extends Action { + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + + String param = mapping.getParameter(); + + if (param.equals("newConditionInit")) { + return newConditionInit(mapping, form, request, response); + } + if (param.equals("editCondition")) { + return editCondition(mapping, form, request, response); + } + if (param.equals("saveOrUpdateCondition")) { + return saveOrUpdateCondition(mapping, form, request, response); + } + if (param.equals("removeCondition")) { + return removeCondition(mapping, form, request, response); + } + if (param.equals("upCondition")) { + return upCondition(mapping, form, request, response); + } + if (param.equals("downCondition")) { + return downCondition(mapping, form, request, response); + } + return null; + } + + /** + * Display empty page for a new condition. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward newConditionInit(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + populateFormWithPossibleItems(form, request); + ((SurveyConditionForm) form).setOrderId(-1); + return mapping.findForward("addcondition"); + } + + /** + * Display edit page for an existing condition. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward editCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + SurveyConditionForm SurveyConditionForm = (SurveyConditionForm) form; + String sessionMapID = SurveyConditionForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int orderId = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ORDER_ID), -1); + SurveyCondition condition = null; + if (orderId != -1) { + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + List conditionList = new ArrayList(conditionSet); + condition = conditionList.get(orderId); + if (condition != null) { + populateConditionToForm(orderId, condition, SurveyConditionForm, request); + } + } + + populateFormWithPossibleItems(form, request); + return condition == null ? null : mapping.findForward("addcondition"); + } + + /** + * This method will get necessary information from condition form and save or update into HttpSession + * condition list. Notice, this save is not persist them into database, just save HttpSession + * temporarily. Only they will be persist when the entire authoring page is being persisted. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + */ + private ActionForward saveOrUpdateCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + SurveyConditionForm conditionForm = (SurveyConditionForm) form; + ActionErrors errors = validateSurveyCondition(conditionForm, request); + + if (!errors.isEmpty()) { + populateFormWithPossibleItems(form, request); + this.addErrors(request, errors); + return mapping.findForward("addcondition"); + } + + try { + extractFormToSurveyCondition(request, conditionForm); + } catch (Exception e) { + + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.condition", e.getMessage())); + if (!errors.isEmpty()) { + populateFormWithPossibleItems(form, request); + this.addErrors(request, errors); + return mapping.findForward("addcondition"); + } + } + + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, conditionForm.getSessionMapID()); + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + /** + * Remove condition from HttpSession list and update page display. As authoring rule, all persist only happen when + * user submit whole page. So this remove is just impact HttpSession values. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward removeCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int orderId = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ORDER_ID), -1); + if (orderId != -1) { + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + List conditionList = new ArrayList(conditionSet); + SurveyCondition condition = conditionList.remove(orderId); + for (SurveyCondition otherCondition : conditionSet) { + if (otherCondition.getOrderId() > orderId) { + otherCondition.setOrderId(otherCondition.getOrderId() - 1); + } + } + conditionSet.clear(); + conditionSet.addAll(conditionList); + // add to delList + List deletedList = getDeletedSurveyConditionList(sessionMap); + deletedList.add(condition); + } + + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return mapping.findForward(SurveyConstants.SUCCESS); + } + + /** + * Move up current item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward upCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + return switchItem(mapping, request, true); + } + + /** + * Move down current item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward downCondition(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + return switchItem(mapping, request, false); + } + + private ActionForward switchItem(ActionMapping mapping, HttpServletRequest request, boolean up) { + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int orderId = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ORDER_ID), -1); + if (orderId != -1) { + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + List conditionList = new ArrayList(conditionSet); + // get current and the target item, and switch their sequnece + SurveyCondition condition = conditionList.get(orderId); + SurveyCondition repCondition; + if (up) { + repCondition = conditionList.get(--orderId); + } else { + repCondition = conditionList.get(++orderId); + } + int upSeqId = repCondition.getOrderId(); + repCondition.setOrderId(condition.getOrderId()); + condition.setOrderId(upSeqId); + + // put back list, it will be sorted again + conditionSet.clear(); + conditionSet.addAll(conditionList); + } + + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return mapping.findForward(SurveyConstants.SUCCESS); + } + + // ************************************************************************************* + // Private methods for internal needs + // ************************************************************************************* + /** + * Return SurveyService bean. + */ + private ISurveyService getSurveyService() { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + return (ISurveyService) wac.getBean(SurveyConstants.SURVEY_SERVICE); + } + + /** + * List containing survey conditions. + * + * @param request + * @return + */ + private SortedSet getSurveyConditionSet(SessionMap sessionMap) { + SortedSet list = (SortedSet) sessionMap + .get(SurveyConstants.ATTR_CONDITION_SET); + if (list == null) { + list = new TreeSet(new TextSearchConditionComparator()); + sessionMap.put(SurveyConstants.ATTR_CONDITION_SET, list); + } + return list; + } + + private SortedSet getSurveyQuestionSet(SessionMap sessionMap) { + SortedSet list = (SortedSet) sessionMap.get(SurveyConstants.ATTR_QUESTION_LIST); + if (list == null) { + list = new TreeSet(new QuestionsComparator()); + sessionMap.put(SurveyConstants.ATTR_QUESTION_LIST, list); + } + return list; + } + + /** + * Get the deleted condition list, which could be persisted or non-persisted items. + * + * @param request + * @return + */ + private List getDeletedSurveyConditionList(SessionMap sessionMap) { + return getListFromSession(sessionMap, SurveyConstants.ATTR_DELETED_CONDITION_LIST); + } + + /** + * Get java.util.List from HttpSession by given name. + * + * @param request + * @param name + * @return + */ + private List getListFromSession(SessionMap sessionMap, String name) { + List list = (List) sessionMap.get(name); + if (list == null) { + list = new ArrayList(); + sessionMap.put(name, list); + } + return list; + } + + /** + * This method will populate condition information to its form for edit use. + * + * @param orderId + * @param condition + * @param form + * @param request + */ + private void populateConditionToForm(int orderId, SurveyCondition condition, SurveyConditionForm form, + HttpServletRequest request) { + form.populateForm(condition); + if (orderId >= 0) { + form.setOrderId(orderId + 1); + } + } + + /** + * This method will populate questions to choose to the form for edit use. + * + * @param sequenceId + * @param condition + * @param form + * @param request + */ + private void populateFormWithPossibleItems(ActionForm form, HttpServletRequest request) { + SurveyConditionForm conditionForm = (SurveyConditionForm) form; + // get back sessionMAP + String sessionMapID = conditionForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + Set questions = getSurveyQuestionSet(sessionMap); + + // Initialise the LabelValueBeans in the possibleOptions array. + + List lvBeans = new LinkedList(); + int i = 0; + for (SurveyQuestion question : questions) { + if (question.getType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + lvBeans.add( + new LabelValueBean(question.getShortTitle(), new Integer(question.getSequenceId()).toString())); + } + } + conditionForm.setPossibleItems(lvBeans.toArray(new LabelValueBean[] {})); + } + + /** + * Extract form content to SurveyCondition. + * + * @param request + * @param form + * @throws QaException + */ + private void extractFormToSurveyCondition(HttpServletRequest request, SurveyConditionForm form) throws Exception { + + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(form.getSessionMapID()); + // check whether it is "edit(old item)" or "add(new item)" + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + int orderId = form.getOrderId(); + SurveyCondition condition = null; + + if (orderId == -1) { // add + String properConditionName = getSurveyService().createConditionName(conditionSet); + condition = form.extractCondition(); + condition.setName(properConditionName); + int maxOrderId = 1; + if (conditionSet != null && conditionSet.size() > 0) { + SurveyCondition last = conditionSet.last(); + maxOrderId = last.getOrderId() + 1; + } + condition.setOrderId(maxOrderId); + conditionSet.add(condition); + } else { // edit + List conditionList = new ArrayList(conditionSet); + condition = conditionList.get(orderId - 1); + form.extractCondition(condition); + } + + Integer[] selectedItems = form.getSelectedItems(); + Set conditionQuestions = new TreeSet(new QuestionsComparator()); + Set questions = getSurveyQuestionSet(sessionMap); + + for (Integer selectedItem : selectedItems) { + for (SurveyQuestion question : questions) { + if (selectedItem.equals(new Integer(question.getSequenceId()))) { + conditionQuestions.add(question); + } + } + } + condition.setQuestions(conditionQuestions); + } + + /** + * Validate SurveyCondition + * + * @param conditionForm + * @return + */ + private ActionErrors validateSurveyCondition(SurveyConditionForm conditionForm, HttpServletRequest request) { + ActionErrors errors = new ActionErrors(); + + String formConditionName = conditionForm.getDisplayName(); + if (StringUtils.isBlank(formConditionName)) { + + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.condition.name.blank")); + } else { + + Integer formConditionOrderId = conditionForm.getOrderId(); + + String sessionMapID = conditionForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + for (SurveyCondition condition : conditionSet) { + if (formConditionName.equals(condition.getDisplayName()) + && !formConditionOrderId.equals(condition.getOrderId())) { + + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.condition.duplicated.name")); + break; + } + } + } + + // should be selected at least one question + Integer[] selectedItems = conditionForm.getSelectedItems(); + if (selectedItems == null || selectedItems.length == 0) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.condition.no.questions.selected")); + } + + return errors; + } + + private ActionMessages validate(SurveyConditionForm form, ActionMapping mapping, HttpServletRequest request) { + return new ActionMessages(); + } +} \ No newline at end of file Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/AuthoringController.java =================================================================== diff -u --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/AuthoringController.java (revision 0) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/AuthoringController.java (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,963 @@ +/**************************************************************** + * 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.survey.web.controller; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +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.beanutils.PropertyUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.apache.log4j.Logger; +import org.apache.struts.action.ActionErrors; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.lamsfoundation.lams.authoring.web.AuthoringConstants; +import org.lamsfoundation.lams.learningdesign.TextSearchConditionComparator; +import org.lamsfoundation.lams.tool.ToolAccessMode; +import org.lamsfoundation.lams.tool.survey.SurveyConstants; +import org.lamsfoundation.lams.tool.survey.model.Survey; +import org.lamsfoundation.lams.tool.survey.model.SurveyCondition; +import org.lamsfoundation.lams.tool.survey.model.SurveyOption; +import org.lamsfoundation.lams.tool.survey.model.SurveyQuestion; +import org.lamsfoundation.lams.tool.survey.model.SurveyUser; +import org.lamsfoundation.lams.tool.survey.service.ISurveyService; +import org.lamsfoundation.lams.tool.survey.service.SurveyApplicationException; +import org.lamsfoundation.lams.tool.survey.util.QuestionsComparator; +import org.lamsfoundation.lams.tool.survey.util.SurveyWebUtils; +import org.lamsfoundation.lams.tool.survey.web.form.QuestionForm; +import org.lamsfoundation.lams.tool.survey.web.form.SurveyForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.web.util.SessionMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Controller; +import org.springframework.validation.Errors; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * @author Steve.Ni + */ +@Controller +@RequestMapping("/authoring") +public class AuthoringController { + private static final int INIT_INSTRUCTION_COUNT = 2; + private static final String INSTRUCTION_ITEM_DESC_PREFIX = "instructionItemDesc"; + private static final String INSTRUCTION_ITEM_COUNT = "instructionCount"; + private static final int SHORT_TITLE_LENGTH = 60; + + private static Logger log = Logger.getLogger(AuthoringController.class); + + @Autowired + @Qualifier("lasurvSurveyService") + private ISurveyService surveyService; + + /** + * Remove survey item from HttpSession list and update page display. As authoring rule, all persist only happen when + * user submit whole page. So this remove is just impact HttpSession values. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/removeItem") + public String removeItem(HttpServletRequest request) { + + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + int itemIdx = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ITEM_INDEX), -1); + if (itemIdx != -1) { + SortedSet surveyList = getSurveyItemList(sessionMap); + List rList = new ArrayList<>(surveyList); + SurveyQuestion item = rList.remove(itemIdx); + surveyList.clear(); + surveyList.addAll(rList); + // add to delList + List delList = getDeletedSurveyItemList(sessionMap); + delList.add(item); + + SortedSet list = getSurveyConditionSet(sessionMap); + Iterator conditionIter = list.iterator(); + + while (conditionIter.hasNext()) { + SurveyCondition condition = conditionIter.next(); + Set questions = condition.getQuestions(); + if (questions.contains(item)) { + questions.remove(item); + } + } + } + + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return "pages/authoring/parts/itemlist"; + } + + /** + * Move up current item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/upItem") + public String upItem(HttpServletRequest request) { + + return switchItem(request, true); + } + + /** + * Move down current item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping(path = "/downItem") + public String downItem(HttpServletRequest request) { + + return switchItem(request, false); + } + + @RequestMapping("/switchItem") + public String switchItem(HttpServletRequest request, boolean up) { + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + int itemIdx = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ITEM_INDEX), -1); + if (itemIdx != -1) { + SortedSet surveyList = getSurveyItemList(sessionMap); + List rList = new ArrayList<>(surveyList); + // get current and the target item, and switch their sequnece + SurveyQuestion item = rList.get(itemIdx); + SurveyQuestion repItem; + if (up) { + repItem = rList.get(--itemIdx); + } else { + repItem = rList.get(++itemIdx); + } + int upSeqId = repItem.getSequenceId(); + repItem.setSequenceId(item.getSequenceId()); + item.setSequenceId(upSeqId); + + // put back list, it will be sorted again + surveyList.clear(); + surveyList.addAll(rList); + } + + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return "pages/authoring/parts/itemlist"; + } + + /** + * Display edit page for existed survey item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/editItemInit") + public String editItemInit(QuestionForm surveyItemForm, HttpServletRequest request) { + + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + int itemIdx = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ITEM_INDEX), -1); + SurveyQuestion item = null; + if (itemIdx != -1) { + SortedSet surveyList = getSurveyItemList(sessionMap); + List rList = new ArrayList<>(surveyList); + item = rList.get(itemIdx); + if (item != null) { + populateItemToForm(itemIdx, item, surveyItemForm, request); + } + } + request.setAttribute("surveyItemForm", surveyItemForm); + if (surveyItemForm.getItemType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + return "pages/authoring/parts/addopenquestion"; + } else { + return "pages/authoring/parts/addchoicequestion"; + } + } + + /** + * Display empty page for new survey item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/newItemInit") + public String newItemlInit(QuestionForm questionForm, HttpServletRequest request) { + + List instructionList = new ArrayList(AuthoringController.INIT_INSTRUCTION_COUNT); + for (int idx = 0; idx < AuthoringController.INIT_INSTRUCTION_COUNT; idx++) { + instructionList.add(""); + } + request.setAttribute("instructionList", instructionList); + if (questionForm.getItemType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + return "pages/authoring/parts/addopenquestion"; + } else { + return "pages/authoring/parts/addchoicequestion"; + } + } + + /** + * Create a new question based on existing one. + */ + @RequestMapping("/copyItemInit") + public String copyItemlInit(QuestionForm surveyItemForm, HttpServletRequest request) { + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + int itemIdx = NumberUtils.stringToInt(request.getParameter(SurveyConstants.PARAM_ITEM_INDEX), -1); + SortedSet surveyList = getSurveyItemList(sessionMap); + List rList = new ArrayList<>(surveyList); + SurveyQuestion item = rList.get(itemIdx); + if (item != null) { + populateItemToForm(-1, item, surveyItemForm, request); + surveyItemForm.setItemIndex(null); + } + request.setAttribute("surveyItemForm", surveyItemForm); + if (surveyItemForm.getItemType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + return "pages/authoring/parts/addopenquestion"; + } else { + return "pages/authoring/parts/addchoicequestion"; + } + } + + /** + * This method will get necessary information from survey item form and save or update into HttpSession + * SurveyItemList. Notice, this save is not persist them into database, just save HttpSession + * temporarily. Only they will be persist when the entire authoring page is being persisted. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + */ + @RequestMapping("/saveOrUpdateItem") + public String saveOrUpdateItem(@ModelAttribute("surveyItemForm") QuestionForm surveyItemForm, Errors errors, HttpServletRequest request) + throws Exception { + // get instructions: + List instructionList = getInstructionsFromRequest(request); + + validateSurveyItem(surveyItemForm, instructionList, errors); + + if (errors.hasErrors()) { + // add at least 2 instruction list + for (int idx = instructionList.size(); idx < 2; idx++) { + instructionList.add(""); + } + request.setAttribute(SurveyConstants.ATTR_INSTRUCTION_LIST, instructionList); + if (surveyItemForm.getItemType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + return "pages/authoring/parts/addopenquestion"; + } else { + return "pages/authoring/parts/addchoicequestion"; + } + } + + try { + extractFormToSurveyItem(request, instructionList, surveyItemForm); + } catch (Exception e) { + AuthoringController.log.error("Uploading failed. The exception is " + e.toString()); + throw e; + } + // set session map ID so that itemlist.jsp can get sessionMAP + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, surveyItemForm.getSessionMapID()); + request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, surveyItemForm.getContentFolderID()); + // return null to close this window + return "pages/authoring/parts/itemlist"; + } + + /** + * Read survey data from database and put them into HttpSession. It will redirect to init.do directly after this + * method run successfully. + * + * This method will avoid read database again and lost un-saved resouce item lost when user "refresh page", + * + * @throws ServletException + * + */ + @RequestMapping("/start") + public String start(SurveyForm startForm, HttpServletRequest request) throws Exception { + + ToolAccessMode mode = WebUtil.readToolAccessModeAuthorDefaulted(request); + request.setAttribute(AttributeNames.ATTR_MODE, mode.toString()); + + // save toolContentID into HTTPSession + Long contentId = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID)); + + // get back the survey and item list and display them on page + ISurveyService service = surveyService; + + List questions = null; + Survey survey = null; + + // Get contentFolderID and save to form. + String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID); + startForm.setContentFolderID(contentFolderID); + + // initial Session Map + SessionMap sessionMap = new SessionMap<>(); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + startForm.setSessionMapID(sessionMap.getSessionID()); + + survey = service.getSurveyByContentId(contentId); + // if survey does not exist, try to use default content instead. + if (survey == null) { + survey = service.getDefaultContent(contentId); + if (survey.getQuestions() != null) { + questions = new ArrayList<>(survey.getQuestions()); + } else { + questions = null; + } + } else { + questions = new ArrayList<>(survey.getQuestions()); + } + + startForm.setSurvey(survey); + + // init it to avoid null exception in following handling + if (questions == null) { + questions = new ArrayList(); + } else { + SurveyUser surveyUser = null; + // handle system default question: createBy is null, now set it to current user + for (SurveyQuestion question : questions) { + if (question.getCreateBy() == null) { + if (surveyUser == null) { + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + surveyUser = new SurveyUser(user, survey); + } + question.setCreateBy(surveyUser); + } + } + } + // init survey item list + SortedSet surveyItemList = getSurveyItemList(sessionMap); + surveyItemList.clear(); + retriveQuestionListForDisplay(questions); + surveyItemList.addAll(questions); + + // init condition set + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + conditionSet.clear(); + conditionSet.addAll(survey.getConditions()); + + sessionMap.put(SurveyConstants.ATTR_SURVEY_FORM, startForm); + request.getSession().setAttribute(AttributeNames.PARAM_NOTIFY_CLOSE_URL, + request.getParameter(AttributeNames.PARAM_NOTIFY_CLOSE_URL)); + request.setAttribute("startForm", startForm); + return "pages/authoring/start"; + } + + @RequestMapping("/definelater") + public String definelater(SurveyForm surveyForm, HttpServletRequest request, HttpServletResponse response) + throws Exception { + + // update define later flag to true + Long contentId = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID)); + ISurveyService service = surveyService; + Survey survey = service.getSurveyByContentId(contentId); + + boolean isEditable = SurveyWebUtils.isSurveyEditable(survey); + if (!isEditable) { + request.setAttribute(SurveyConstants.PAGE_EDITABLE, new Boolean(isEditable)); + return "error"; + } + + if (!survey.isContentInUse()) { + survey.setDefineLater(true); + service.saveOrUpdateSurvey(survey); + + // audit log the teacher has started editing activity in monitor + service.auditLogStartEditingActivityInMonitor(contentId); + } + + request.setAttribute(AttributeNames.ATTR_MODE, ToolAccessMode.TEACHER.toString()); + + // save toolContentID into HTTPSession + contentId = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID)); + + // get back the survey and item list and display them on page + service = surveyService; + + List questions = null; + survey = null; + + // Get contentFolderID and save to form. + String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID); + surveyForm.setContentFolderID(contentFolderID); + + // initial Session Map + SessionMap sessionMap = new SessionMap<>(); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + surveyForm.setSessionMapID(sessionMap.getSessionID()); + + survey = service.getSurveyByContentId(contentId); + // if survey does not exist, try to use default content instead. + if (survey == null) { + survey = service.getDefaultContent(contentId); + if (survey.getQuestions() != null) { + questions = new ArrayList<>(survey.getQuestions()); + } else { + questions = null; + } + } else { + questions = new ArrayList<>(survey.getQuestions()); + } + + surveyForm.setSurvey(survey); + + // init it to avoid null exception in following handling + if (questions == null) { + questions = new ArrayList(); + } else { + SurveyUser surveyUser = null; + // handle system default question: createBy is null, now set it to current user + for (SurveyQuestion question : questions) { + if (question.getCreateBy() == null) { + if (surveyUser == null) { + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + surveyUser = new SurveyUser(user, survey); + } + question.setCreateBy(surveyUser); + } + } + } + // init survey item list + SortedSet surveyItemList = getSurveyItemList(sessionMap); + surveyItemList.clear(); + retriveQuestionListForDisplay(questions); + surveyItemList.addAll(questions); + + // init condition set + SortedSet conditionSet = getSurveyConditionSet(sessionMap); + conditionSet.clear(); + conditionSet.addAll(survey.getConditions()); + + sessionMap.put(SurveyConstants.ATTR_SURVEY_FORM, surveyForm); + request.getSession().setAttribute(AttributeNames.PARAM_NOTIFY_CLOSE_URL, + request.getParameter(AttributeNames.PARAM_NOTIFY_CLOSE_URL)); + return "pages/authoring/start"; + } + + /** + * Display same entire authoring page content from HttpSession variable. + * + * @param mapping + * @param authoringForm + * @param request + * @param response + * @return + * @throws ServletException + */ + @RequestMapping("/init") + public String initPage(SurveyForm startForm, HttpServletRequest request) throws ServletException { + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + SurveyForm existForm = (SurveyForm) sessionMap.get(SurveyConstants.ATTR_SURVEY_FORM); + + try { + PropertyUtils.copyProperties(startForm, existForm); + } catch (Exception e) { + throw new ServletException(e); + } + + ToolAccessMode mode = WebUtil.readToolAccessModeAuthorDefaulted(request); + request.setAttribute(AttributeNames.ATTR_MODE, mode.toString()); + request.setAttribute("authoringForm", startForm); + return "pages/authoring/authoring"; + } + + /** + * This method will persist all inforamtion in this authoring page, include all survey item, information etc. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + */ + @RequestMapping("/update") + public String updateContent(SurveyForm authoringForm, HttpServletRequest request) throws Exception { + + // get back sessionMAP + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(authoringForm.getSessionMapID()); + + ToolAccessMode mode = WebUtil.readToolAccessModeAuthorDefaulted(request); + request.setAttribute(AttributeNames.ATTR_MODE, mode.toString()); + + Survey survey = authoringForm.getSurvey(); + ISurveyService service = surveyService; + + // **********************************Get Survey PO********************* + Survey surveyPO = service.getSurveyByContentId(authoringForm.getSurvey().getContentId()); + if (surveyPO == null) { + // new Survey, create it. + surveyPO = survey; + surveyPO.setCreated(new Timestamp(new Date().getTime())); + surveyPO.setUpdated(new Timestamp(new Date().getTime())); + + } else { + Long uid = surveyPO.getUid(); + PropertyUtils.copyProperties(surveyPO, survey); + // get back UID + surveyPO.setUid(uid); + + // if it's a teacher - change define later status + if (mode.isTeacher()) { + surveyPO.setDefineLater(false); + } + + surveyPO.setUpdated(new Timestamp(new Date().getTime())); + } + + // *******************************Handle user******************* + // try to get form system session + HttpSession ss = SessionManager.getSession(); + // get back login user DTO + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + SurveyUser surveyUser = service.getUserByIDAndContent(new Long(user.getUserID().intValue()), + authoringForm.getSurvey().getContentId()); + if (surveyUser == null) { + surveyUser = new SurveyUser(user, surveyPO); + } + + surveyPO.setCreatedBy(surveyUser); + + // ************************* Handle survey questions ******************* + Set questionList = new LinkedHashSet(); + SortedSet topics = getSurveyItemList(sessionMap); + Iterator iter = topics.iterator(); + while (iter.hasNext()) { + SurveyQuestion item = (SurveyQuestion) iter.next(); + if (item != null) { + // This flushs user UID info to message if this user is a new user. + item.setCreateBy(surveyUser); + questionList.add(item); + } + } + surveyPO.setQuestions(questionList); + // delete instruction file from database. + List delSurveyItemList = getDeletedSurveyItemList(sessionMap); + iter = delSurveyItemList.iterator(); + while (iter.hasNext()) { + SurveyQuestion item = (SurveyQuestion) iter.next(); + iter.remove(); + if (item.getUid() != null) { + service.deleteQuestion(item.getUid()); + } + } + + // ******************************** Handle conditions **************** + Set conditions = getSurveyConditionSet(sessionMap); + List delConditions = getDeletedSurveyConditionList(sessionMap); + + // delete conditions that don't contain any questions + Iterator conditionIter = conditions.iterator(); + while (conditionIter.hasNext()) { + SurveyCondition condition = conditionIter.next(); + if (condition.getQuestions().isEmpty()) { + conditionIter.remove(); + delConditions.add(condition); + + //reorder remaining conditions + for (SurveyCondition otherCondition : conditions) { + if (otherCondition.getOrderId() > condition.getOrderId()) { + otherCondition.setOrderId(otherCondition.getOrderId() - 1); + } + } + } + } + surveyPO.setConditions(conditions); + + //permanently remove conditions from DB + iter = delConditions.iterator(); + while (iter.hasNext()) { + SurveyCondition condition = (SurveyCondition) iter.next(); + iter.remove(); + service.deleteCondition(condition); + } + + // finally persist surveyPO again + service.saveOrUpdateSurvey(surveyPO); + + authoringForm.setSurvey(surveyPO); + + request.setAttribute(AuthoringConstants.LAMS_AUTHORING_SUCCESS_FLAG, Boolean.TRUE); + return "pages/authoring/authoring"; + } + + // ************************************************************************************* + // Private method + // ************************************************************************************* + + /** + * List save current survey items. + * + * @param request + * @return + */ + private SortedSet getSurveyItemList(SessionMap sessionMap) { + SortedSet list = (SortedSet) sessionMap.get(SurveyConstants.ATTR_QUESTION_LIST); + if (list == null) { + list = new TreeSet<>(new QuestionsComparator()); + sessionMap.put(SurveyConstants.ATTR_QUESTION_LIST, list); + } + return list; + } + + /** + * Set of conditions. + * + * @param request + * @return + */ + private SortedSet getSurveyConditionSet(SessionMap sessionMap) { + SortedSet set = (SortedSet) sessionMap + .get(SurveyConstants.ATTR_CONDITION_SET); + if (set == null) { + set = new TreeSet<>(new TextSearchConditionComparator()); + sessionMap.put(SurveyConstants.ATTR_CONDITION_SET, set); + } + return set; + } + + /** + * List save deleted survey items, which could be persisted or non-persisted items. + * + * @param request + * @return + */ + private List getDeletedSurveyItemList(SessionMap sessionMap) { + return getListFromSession(sessionMap, SurveyConstants.ATTR_DELETED_QUESTION_LIST); + } + + /** + * Get java.util.List from HttpSession by given name. + * + * @param request + * @param name + * @return + */ + private List getListFromSession(SessionMap sessionMap, String name) { + List list = (List) sessionMap.get(name); + if (list == null) { + list = new ArrayList(); + sessionMap.put(name, list); + } + return list; + } + + /** + * Get survey items instruction from HttpRequest + * + * @param request + */ + private List getInstructionsFromRequest(HttpServletRequest request) { + String list = request.getParameter("instructionList"); + List instructionList = new ArrayList<>(); + // for open text entry question + if (list == null) { + return instructionList; + } + + String[] params = list.split("&"); + Map paramMap = new HashMap<>(); + String[] pair; + for (String item : params) { + pair = item.split("="); + if (pair == null || pair.length != 2) { + continue; + } + try { + paramMap.put(pair[0], URLDecoder.decode(pair[1], "UTF-8")); + } catch (UnsupportedEncodingException e) { + AuthoringController.log.error("Error occurs when decode instruction string:" + e.toString()); + } + } + + int count = NumberUtils.stringToInt(paramMap.get(AuthoringController.INSTRUCTION_ITEM_COUNT)); + for (int idx = 0; idx < count; idx++) { + String item = paramMap.get(AuthoringController.INSTRUCTION_ITEM_DESC_PREFIX + idx); + if (item == null) { + continue; + } + instructionList.add(item); + } + return instructionList; + } + + /** + * This method will populate survey item information to its form for edit use. + * + * @param itemIdx + * @param item + * @param form + * @param request + */ + private void populateItemToForm(int itemIdx, SurveyQuestion item, QuestionForm form, HttpServletRequest request) { + if (itemIdx >= 0) { + form.setItemIndex(new Integer(itemIdx).toString()); + } + + // set questions + form.setQuestion(item); + + // set options + Set instructionList = item.getOptions(); + List instructions = new ArrayList(); + for (SurveyOption in : instructionList) { + instructions.add(in.getDescription()); + } + + request.setAttribute(SurveyConstants.ATTR_INSTRUCTION_LIST, instructions); + + } + + /** + * Extract web from content to survey item. + * + * @param request + * @param instructionList + * @param itemForm + * @throws SurveyApplicationException + */ + private void extractFormToSurveyItem(HttpServletRequest request, List instructionList, + QuestionForm itemForm) throws Exception { + /* + * BE CAREFUL: This method will copy nessary info from request form to a old or new SurveyItem instance. It gets + * all info EXCEPT SurveyItem.createDate and SurveyItem.createBy, which need be set when persisting this survey + * item. + */ + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(itemForm.getSessionMapID()); + // check whether it is "edit(old item)" or "add(new item)" + SortedSet surveyList = getSurveyItemList(sessionMap); + int itemIdx = NumberUtils.stringToInt(itemForm.getItemIndex(), -1); + SurveyQuestion item = itemForm.getQuestion(); + + if (itemIdx == -1) { // add + item.setCreateDate(new Timestamp(new Date().getTime())); + int maxSeq = 1; + if (surveyList != null && surveyList.size() > 0) { + SurveyQuestion last = surveyList.last(); + maxSeq = last.getSequenceId() + 1; + } + item.setSequenceId(maxSeq); + surveyList.add(item); + } else { // edit + List rList = new ArrayList<>(surveyList); + item = rList.get(itemIdx); + item.setDescription(itemForm.getQuestion().getDescription()); + item.setOptional(itemForm.getQuestion().isOptional()); + item.setAppendText(itemForm.getQuestion().isAppendText()); + item.setAllowMultipleAnswer(itemForm.getQuestion().isAllowMultipleAnswer()); + + } + item.updateShortTitleFromDescription(); + short type = getQuestionType(itemForm); + item.setType(type); + + // set instrcutions + Set instructions = new LinkedHashSet(); + int idx = 0; + for (String ins : instructionList) { + SurveyOption rii = new SurveyOption(); + rii.setDescription(ins); + rii.setSequenceId(idx++); + instructions.add(rii); + } + item.setOptions(instructions); + + } + + private short getQuestionType(QuestionForm itemForm) { + // set question type + short type; + if (itemForm.getItemType() == SurveyConstants.SURVEY_TYPE_TEXT_ENTRY) { + type = SurveyConstants.SURVEY_TYPE_TEXT_ENTRY; + } else if (itemForm.getQuestion().isAllowMultipleAnswer()) { + type = SurveyConstants.SURVEY_TYPE_MULTIPLE_CHOICES; + } else { + type = SurveyConstants.SURVEY_TYPE_SINGLE_CHOICE; + } + return type; + } + + private void retriveQuestionListForDisplay(List list) { + for (SurveyQuestion item : list) { + item.updateShortTitleFromDescription(); + } + } + + /** + * Vaidate survey item regards to their type (url/file/learning object/website zip file) + * + * @param itemForm + * @param instructionList + * @return + */ + private ActionErrors validateSurveyItem(QuestionForm itemForm, List instructionList) { + ActionErrors errors = new ActionErrors(); + if (StringUtils.isBlank(itemForm.getQuestion().getDescription())) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(SurveyConstants.ERROR_MSG_DESC_BLANK)); + } + + short type = getQuestionType(itemForm); + if (type != SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + if (instructionList == null || instructionList.size() < 2) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(SurveyConstants.ERROR_MSG_LESS_OPTIONS)); + } + } + + return errors; + } + + /** + * Ajax call, will add one more input line for new survey item instruction. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/newInstruction") + public String newInstruction(HttpServletRequest request) { + int count = NumberUtils.stringToInt(request.getParameter(AuthoringController.INSTRUCTION_ITEM_COUNT), 0); + List instructionList = new ArrayList(++count); + for (int idx = 0; idx < count; idx++) { + String item = request.getParameter(AuthoringController.INSTRUCTION_ITEM_DESC_PREFIX + idx); + if (item == null) { + instructionList.add(""); + } else { + instructionList.add(item); + } + } + request.setAttribute(SurveyConstants.ATTR_INSTRUCTION_LIST, instructionList); + return "pages/authoring/parts/instructions"; + } + + /** + * Ajax call, remove the given line of instruction of survey item. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/removeInstruction") + public String removeInstruction(HttpServletRequest request) { + int count = NumberUtils.stringToInt(request.getParameter(AuthoringController.INSTRUCTION_ITEM_COUNT), 0); + int removeIdx = NumberUtils.stringToInt(request.getParameter("removeIdx"), -1); + List instructionList = new ArrayList(count - 1); + for (int idx = 0; idx < count; idx++) { + String item = request.getParameter(AuthoringController.INSTRUCTION_ITEM_DESC_PREFIX + idx); + if (idx == removeIdx) { + continue; + } + if (item == null) { + instructionList.add(""); + } else { + instructionList.add(item); + } + } + request.setAttribute(SurveyConstants.ATTR_INSTRUCTION_LIST, instructionList); + return "pages/authoring/parts/instructions"; + } + + /** + * Get the deleted condition list, which could be persisted or non-persisted items. + * + * @param request + * @return + */ + private List getDeletedSurveyConditionList(SessionMap sessionMap) { + return getListFromSession(sessionMap, SurveyConstants.ATTR_DELETED_CONDITION_LIST); + } + + private void validateSurveyItem(QuestionForm itemForm, List instructionList, Errors errors) { + if (StringUtils.isBlank(itemForm.getQuestion().getDescription())) { + errors.reject(SurveyConstants.ERROR_MSG_DESC_BLANK); + } + + short type = getQuestionType(itemForm); + if (type != SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + if (instructionList == null || instructionList.size() < 2) { + errors.reject(SurveyConstants.ERROR_MSG_LESS_OPTIONS); + } + } + } +} Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/ChartAction.java =================================================================== diff -u --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/ChartAction.java (revision 0) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/ChartAction.java (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,109 @@ +/**************************************************************** + * 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.survey.web.controller; + +import java.io.IOException; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +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.apache.struts.util.MessageResources; +import org.lamsfoundation.lams.tool.survey.SurveyConstants; +import org.lamsfoundation.lams.tool.survey.dto.AnswerDTO; +import org.lamsfoundation.lams.tool.survey.model.SurveyOption; +import org.lamsfoundation.lams.tool.survey.service.ISurveyService; +import org.lamsfoundation.lams.util.WebUtil; +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.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Display chart image by request. + * + * @author Steve.Ni + */ +public class ChartAction extends Action { + + private static Logger logger = Logger.getLogger(ChartAction.class); + + private static ISurveyService surveyService; + private MessageResources resource; + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + resource = getResources(request); + + Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + Long questionUid = WebUtil.readLongParam(request, SurveyConstants.ATTR_QUESTION_UID); + + // if excludeUserId received exclude this user's answers + AnswerDTO answer = getSurveyService().getQuestionResponse(sessionId, questionUid); + if (answer.getType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + ChartAction.logger.error("Error question type : Text entry can not generate chart."); + response.getWriter().print(resource.getMessage(SurveyConstants.ERROR_MSG_CHART_ERROR)); + return null; + } + + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + Set options = answer.getOptions(); + for (SurveyOption option : options) { + ObjectNode nomination = JsonNodeFactory.instance.objectNode(); + // nominations' names and values go separately + nomination.put("name", option.getDescription()); + nomination.put("value", (Double) option.getResponse()); + responseJSON.withArray("data").add(nomination); + } + + if (answer.isAppendText()) { + ObjectNode nomination = JsonNodeFactory.instance.objectNode(); + nomination.put("name", resource.getMessage(SurveyConstants.MSG_OPEN_RESPONSE)); + nomination.put("value", (Double) answer.getOpenResponse()); + responseJSON.withArray("data").add(nomination); + } + + response.setContentType("application/json;charset=utf-8"); + response.getWriter().write(responseJSON.toString()); + return null; + } + + private ISurveyService getSurveyService() { + if (ChartAction.surveyService == null) { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + ChartAction.surveyService = (ISurveyService) wac.getBean(SurveyConstants.SURVEY_SERVICE); + } + return ChartAction.surveyService; + } +} \ No newline at end of file Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/ClearSessionAction.java =================================================================== diff -u --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/ClearSessionAction.java (revision 0) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/ClearSessionAction.java (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,48 @@ +/**************************************************************** + * 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.survey.web.controller; + +import javax.servlet.http.HttpSession; + +import org.lamsfoundation.lams.authoring.web.LamsAuthoringFinishAction; +import org.lamsfoundation.lams.tool.ToolAccessMode; + +/** + * This class give a chance to clear HttpSession when user save/close authoring page. + * + * @author Steve.Ni + * + * @version $Revision$ + */ +public class ClearSessionAction extends LamsAuthoringFinishAction { + + @Override + public void clearSession(String customiseSessionID, HttpSession session, ToolAccessMode mode) { + if (mode.isAuthor()) { + session.removeAttribute(customiseSessionID); + } + } + +} Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/LearningAction.java =================================================================== diff -u --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/LearningAction.java (revision 0) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/LearningAction.java (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,751 @@ +/**************************************************************** + * 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.survey.web.controller; + +import java.io.IOException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +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.action.Action; +import org.apache.struts.action.ActionErrors; +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.ActionRedirect; +import org.lamsfoundation.lams.learning.web.bean.ActivityPositionDTO; +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.survey.SurveyConstants; +import org.lamsfoundation.lams.tool.survey.dto.AnswerDTO; +import org.lamsfoundation.lams.tool.survey.model.Survey; +import org.lamsfoundation.lams.tool.survey.model.SurveyAnswer; +import org.lamsfoundation.lams.tool.survey.model.SurveyQuestion; +import org.lamsfoundation.lams.tool.survey.model.SurveySession; +import org.lamsfoundation.lams.tool.survey.model.SurveyUser; +import org.lamsfoundation.lams.tool.survey.service.ISurveyService; +import org.lamsfoundation.lams.tool.survey.service.SurveyApplicationException; +import org.lamsfoundation.lams.tool.survey.util.IntegerComparator; +import org.lamsfoundation.lams.tool.survey.util.SurveyWebUtils; +import org.lamsfoundation.lams.tool.survey.web.form.AnswerForm; +import org.lamsfoundation.lams.tool.survey.web.form.ReflectionForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.web.util.SessionMap; +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 Steve.Ni + * + * @version $Revision$ + */ +public class LearningAction extends Action { + + private static Logger log = Logger.getLogger(LearningAction.class); + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + + String param = mapping.getParameter(); + // -----------------------Survey Learner function --------------------------- + if (param.equals("start")) { + return start(mapping, form, request, response); + } + if (param.equals("previousQuestion")) { + return previousQuestion(mapping, form, request, response); + } + if (param.equals("nextQuestion")) { + return nextQuestion(mapping, form, request, response); + } + if (param.equals("doSurvey")) { + return doSurvey(mapping, form, request, response); + } + + if (param.equals("retake")) { + return retake(mapping, form, request, response); + } + + if (param.equals("showOtherUsersAnswers")) { + return showOtherUsersAnswers(mapping, form, request, response); + } + + if (param.equals("getOpenResponses")) { + return getOpenResponses(mapping, form, request, response); + } + + if (param.equals("finish")) { + return finish(mapping, form, request, response); + } + + // ================ Reflection ======================= + if (param.equals("newReflection")) { + return newReflection(mapping, form, request, response); + } + if (param.equals("submitReflection")) { + return submitReflection(mapping, form, request, response); + } + + return mapping.findForward(SurveyConstants.ERROR); + } + + /** + * Read survey data from database and put them into HttpSession. It will redirect to init.do directly after this + * method run successfully. + * + * This method will avoid read database again and lost un-saved resouce item lost when user "refresh page", + * + */ + private ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + AnswerForm answerForm = (AnswerForm) form; + // initial Session Map + SessionMap sessionMap = new SessionMap<>(); + String sessionMapID = sessionMap.getSessionID(); + request.getSession().setAttribute(sessionMapID, sessionMap); + answerForm.setSessionMapID(sessionMapID); + + // save toolContentID into HTTPSession + ToolAccessMode mode = WebUtil.readToolAccessModeParam(request, AttributeNames.PARAM_MODE, true); + Long sessionId = new Long(request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID)); + // it will be use when submissionDeadline or lock on finish page. + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + + // get back the survey and question list and display them on page + ISurveyService service = getSurveyService(); + SurveyUser surveyUser = null; + if ((mode != null) && mode.isTeacher()) { + // monitoring mode - user is specified in URL + surveyUser = getSpecifiedUser(service, sessionId, + WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID, false)); + // setting Learner + Long userID = WebUtil.readLongParam(request, AttributeNames.PARAM_USER_ID, true); + answerForm.setUserID(userID); + } else { + surveyUser = getCurrentUser(service, sessionId); + } + + List answers = service.getQuestionAnswers(sessionId, surveyUser.getUid()); + Survey survey = service.getSurveyBySessionId(sessionId); + + // get notebook entry + String entryText = new String(); + NotebookEntry notebookEntry = service.getEntry(sessionId, CoreNotebookConstants.NOTEBOOK_TOOL, + SurveyConstants.TOOL_SIGNATURE, surveyUser.getUserId().intValue()); + + if (notebookEntry != null) { + entryText = notebookEntry.getEntry(); + } + + // get session from shared session. + HttpSession ss = SessionManager.getSession(); + + // basic information + sessionMap.put(SurveyConstants.ATTR_TITLE, survey.getTitle()); + sessionMap.put(SurveyConstants.ATTR_SURVEY_INSTRUCTION, survey.getInstructions()); + // check whehter finish lock is on/off + boolean lock = survey.getLockWhenFinished() && surveyUser.isSessionFinished(); + sessionMap.put(SurveyConstants.ATTR_FINISH_LOCK, lock); + sessionMap.put(SurveyConstants.ATTR_LOCK_ON_FINISH, survey.getLockWhenFinished()); + sessionMap.put(SurveyConstants.ATTR_SHOW_ON_ONE_PAGE, survey.isShowOnePage()); + sessionMap.put(SurveyConstants.ATTR_SHOW_OTHER_USERS_ANSWERS, survey.isShowOtherUsersAnswers()); + sessionMap.put(SurveyConstants.ATTR_USER_FINISHED, surveyUser.isSessionFinished()); + sessionMap.put(SurveyConstants.ATTR_USER, surveyUser); + + sessionMap.put(AttributeNames.PARAM_TOOL_SESSION_ID, sessionId); + sessionMap.put(AttributeNames.ATTR_MODE, mode); + // reflection information + sessionMap.put(SurveyConstants.ATTR_REFLECTION_ON, survey.isReflectOnActivity()); + sessionMap.put(SurveyConstants.ATTR_REFLECTION_INSTRUCTION, survey.getReflectInstructions()); + sessionMap.put(SurveyConstants.ATTR_REFLECTION_ENTRY, entryText); + + // add define later support + if (survey.isDefineLater()) { + return mapping.findForward(SurveyConstants.DEFINE_LATER); + } + + // set contentInUse flag to true! + survey.setContentInUse(true); + survey.setDefineLater(false); + service.saveOrUpdateSurvey(survey); + + ActivityPositionDTO activityPosition = LearningWebUtil.putActivityPositionInRequestByToolSessionId(sessionId, + request, getServlet().getServletContext()); + sessionMap.put(AttributeNames.ATTR_ACTIVITY_POSITION, activityPosition); + + // check if there is submission deadline + Date submissionDeadline = survey.getSubmissionDeadline(); + if (submissionDeadline != null) { + // store submission deadline to sessionMap + sessionMap.put(SurveyConstants.ATTR_SUBMISSION_DEADLINE, submissionDeadline); + + UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone learnerTimeZone = learnerDto.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); + Date currentLearnerDate = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, new Date()); + + // calculate whether submission deadline has passed, and if so forward to "submissionDeadline" + if (currentLearnerDate.after(tzSubmissionDeadline)) { + return mapping.findForward("submissionDeadline"); + } + } + + // init survey item list + SortedMap surveyItemList = getQuestionList(sessionMap); + surveyItemList.clear(); + if (answers != null) { + for (AnswerDTO answer : answers) { + surveyItemList.put(answer.getSequenceId(), answer); + } + } + if (survey.isShowOnePage()) { + answerForm.setQuestionSeqID(null); + } else { + if (surveyItemList.size() > 0) { + answerForm.setQuestionSeqID(surveyItemList.firstKey()); + } + } + sessionMap.put(SurveyConstants.ATTR_TOTAL_QUESTIONS, surveyItemList.size()); + answerForm.setCurrentIdx(1); + + if (surveyItemList.size() < 2) { + answerForm.setPosition(SurveyConstants.POSITION_ONLY_ONE); + } else { + answerForm.setPosition(SurveyConstants.POSITION_FIRST); + } + + // if session is finished go to result pages. + if (surveyUser.isSessionFinished() && !survey.isShowOtherUsersAnswers()) { + return mapping.findForward(SurveyConstants.FORWARD_RESULT); + + //if show other users is ON and response is finalized - show results page with other users answers + } else if (survey.isShowOtherUsersAnswers() && surveyUser.isResponseFinalized()) { + ActionRedirect redirect = new ActionRedirect(mapping.findForwardConfig("resultOtherUsers")); + redirect.addParameter(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return redirect; + + } else { + return mapping.findForward(SurveyConstants.SUCCESS); + } + } + + private ActionForward nextQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + AnswerForm answerForm = (AnswerForm) form; + Integer questionSeqID = answerForm.getQuestionSeqID(); + String sessionMapID = answerForm.getSessionMapID(); + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + SortedMap surveyItemMap = getQuestionList(sessionMap); + + ActionErrors errors = getAnswer(request, surveyItemMap.get(questionSeqID)); + if (!errors.isEmpty()) { + return mapping.getInputForward(); + } + + // go to next question + boolean next = false; + for (Map.Entry entry : surveyItemMap.entrySet()) { + if (entry.getKey().equals(questionSeqID)) { + next = true; + // failure tolerance: if arrive last one + questionSeqID = entry.getKey(); + continue; + } + if (next) { + questionSeqID = entry.getKey(); + break; + } + } + // get current question index of total questions + int currIdx = new ArrayList<>(surveyItemMap.keySet()).indexOf(questionSeqID) + 1; + answerForm.setCurrentIdx(currIdx); + // failure tolerance + if (questionSeqID.equals(surveyItemMap.lastKey())) { + answerForm.setPosition(SurveyConstants.POSITION_LAST); + } else { + answerForm.setPosition(SurveyConstants.POSITION_INSIDE); + } + answerForm.setQuestionSeqID(questionSeqID); + return mapping.findForward(SurveyConstants.SUCCESS); + } + + private ActionForward previousQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + AnswerForm answerForm = (AnswerForm) form; + Integer questionSeqID = answerForm.getQuestionSeqID(); + String sessionMapID = answerForm.getSessionMapID(); + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + SortedMap surveyItemMap = getQuestionList(sessionMap); + + ActionErrors errors = getAnswer(request, surveyItemMap.get(questionSeqID)); + if (!errors.isEmpty()) { + return mapping.getInputForward(); + } + + SortedMap subMap = surveyItemMap.headMap(questionSeqID); + if (subMap.isEmpty()) { + questionSeqID = surveyItemMap.firstKey(); + } else { + questionSeqID = subMap.lastKey(); + } + + // get current question index of total questions + int currIdx = new ArrayList<>(surveyItemMap.keySet()).indexOf(questionSeqID) + 1; + answerForm.setCurrentIdx(currIdx); + + if (questionSeqID.equals(surveyItemMap.firstKey())) { + answerForm.setPosition(SurveyConstants.POSITION_FIRST); + } else { + answerForm.setPosition(SurveyConstants.POSITION_INSIDE); + } + answerForm.setQuestionSeqID(questionSeqID); + return mapping.findForward(SurveyConstants.SUCCESS); + } + + private ActionForward retake(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + AnswerForm answerForm = (AnswerForm) form; + Integer questionSeqID = answerForm.getQuestionSeqID(); + + String sessionMapID = answerForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + SortedMap surveyItemMap = getQuestionList(sessionMap); + Collection surveyItemList = surveyItemMap.values(); + + if (surveyItemList.size() < 2 || (questionSeqID != null && questionSeqID > 0)) { + answerForm.setPosition(SurveyConstants.POSITION_ONLY_ONE); + } else { + answerForm.setPosition(SurveyConstants.POSITION_FIRST); + } + if (questionSeqID == null || questionSeqID <= 0) { + Boolean onePage = (Boolean) sessionMap.get(SurveyConstants.ATTR_SHOW_ON_ONE_PAGE); + if (!onePage && surveyItemList.size() > 0) { + answerForm.setQuestionSeqID(surveyItemMap.firstKey()); + questionSeqID = surveyItemMap.firstKey(); + } + } + + // get current question index of total questions + int currIdx = new ArrayList<>(surveyItemMap.keySet()).indexOf(questionSeqID) + 1; + answerForm.setCurrentIdx(currIdx); + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + private ActionForward showOtherUsersAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + ISurveyService service = getSurveyService(); + String sessionMapID = request.getParameter("sessionMapID"); + request.setAttribute("sessionMapID", sessionMapID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + SortedMap surveyItemMap = getQuestionList(sessionMap); + Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); + + List answerDtos = new ArrayList<>(); + for (SurveyQuestion question : surveyItemMap.values()) { + AnswerDTO answerDto = service.getQuestionResponse(sessionId, question.getUid()); + answerDtos.add(answerDto); + } + request.setAttribute("answerDtos", answerDtos); + + SurveyUser surveyLearner = (SurveyUser) sessionMap.get(SurveyConstants.ATTR_USER); + service.setResponseFinalized(surveyLearner.getUid()); + + int countFinishedUser = service.getCountFinishedUsers(sessionId); + request.setAttribute(SurveyConstants.ATTR_COUNT_FINISHED_USERS, countFinishedUser); + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + /** + * Get OpenResponses. + */ + private ActionForward getOpenResponses(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse res) throws IOException, ServletException { + ISurveyService service = getSurveyService(); + + Long questionUid = WebUtil.readLongParam(request, "questionUid"); + Long sessionId = WebUtil.readLongParam(request, "sessionId"); + + //paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer isSort1 = WebUtil.readIntParam(request, "column[0]", true); + + int sorting = SurveyConstants.SORT_BY_DEAFAULT; + if (isSort1 != null && isSort1.equals(0)) { + sorting = SurveyConstants.SORT_BY_ANSWER_ASC; + } else if (isSort1 != null && isSort1.equals(1)) { + sorting = SurveyConstants.SORT_BY_ANSWER_DESC; + } + + List responses = service.getOpenResponsesForTablesorter(sessionId, questionUid, page, size, sorting); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + responcedata.put("total_rows", service.getCountResponsesBySessionAndQuestion(sessionId, questionUid)); + + for (String response : responses) { + //ArrayNode cell=JsonNodeFactory.instance.arrayNode(); + //cell.put(HtmlUtils.htmlEscape(user.getFirstName()) + " " + HtmlUtils.htmlEscape(user.getLastName()) + " [" + HtmlUtils.htmlEscape(user.getLogin()) + "]"); + + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put("answer", StringEscapeUtils.escapeCsv(response)); +// responseRow.put("attemptTime", response.getAttemptTime()); + + rows.add(responseRow); + } + responcedata.set("rows", rows); + res.setContentType("application/json;charset=utf-8"); + res.getWriter().print(new String(responcedata.toString())); + return null; + } + + private ActionForward doSurvey(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + ISurveyService service = getSurveyService(); + + AnswerForm answerForm = (AnswerForm) form; + Integer questionSeqID = answerForm.getQuestionSeqID(); + String sessionMapID = answerForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + // validate + SortedMap surveyItemMap = getQuestionList(sessionMap); + Collection surveyItemList = surveyItemMap.values(); + + SurveyUser surveyLearner = (SurveyUser) sessionMap.get(SurveyConstants.ATTR_USER); + Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); + + ActionErrors errors; + if ((questionSeqID == null) || questionSeqID.equals(0)) { + errors = getAnswers(request); + } else { + errors = getAnswer(request, surveyItemMap.get(questionSeqID)); + } + if (!errors.isEmpty()) { + return mapping.getInputForward(); + } + + List answerList = new ArrayList<>(); + for (AnswerDTO question : surveyItemList) { + if (question.getAnswer() != null) { + question.getAnswer().setUser(surveyLearner); + answerList.add(question.getAnswer()); + } + } + + service.updateAnswerList(answerList); + + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMapID); + + Survey survey = service.getSurveyBySessionId(sessionId); + if (survey.isNotifyTeachersOnAnswerSumbit()) { + service.notifyTeachersOnAnswerSumbit(sessionId, surveyLearner); + } + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + /** + * Finish learning session. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward finish(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + // get back SessionMap + String sessionMapID = request.getParameter(SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + + // get mode and ToolSessionID from sessionMAP + Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); + + ISurveyService service = getSurveyService(); + // get sessionId from HttpServletRequest + String nextActivityUrl = null; + try { + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userID = new Long(user.getUserID().longValue()); + + nextActivityUrl = service.finishToolSession(sessionId, userID); + request.setAttribute(SurveyConstants.ATTR_NEXT_ACTIVITY_URL, nextActivityUrl); + } catch (SurveyApplicationException e) { + LearningAction.log.error("Failed get next activity url:" + e.getMessage()); + } + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + /** + * Display empty reflection form. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward newReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + // get session value + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + + ReflectionForm refForm = (ReflectionForm) form; + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + + refForm.setUserID(user.getUserID()); + refForm.setSessionMapID(sessionMapID); + + // get the existing reflection entry + ISurveyService submitFilesService = getSurveyService(); + + SessionMap map = (SessionMap) request.getSession().getAttribute(sessionMapID); + Long toolSessionID = (Long) map.get(AttributeNames.PARAM_TOOL_SESSION_ID); + NotebookEntry entry = submitFilesService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL, + SurveyConstants.TOOL_SIGNATURE, user.getUserID()); + + if (entry != null) { + refForm.setEntryText(entry.getEntry()); + } + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + /** + * Submit reflection form input database. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward submitReflection(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + ReflectionForm refForm = (ReflectionForm) form; + Integer userId = refForm.getUserID(); + + String sessionMapID = WebUtil.readStrParam(request, SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); + + ISurveyService service = getSurveyService(); + + // check for existing notebook entry + NotebookEntry entry = service.getEntry(sessionId, CoreNotebookConstants.NOTEBOOK_TOOL, + SurveyConstants.TOOL_SIGNATURE, userId); + + if (entry == null) { + // create new entry + service.createNotebookEntry(sessionId, CoreNotebookConstants.NOTEBOOK_TOOL, SurveyConstants.TOOL_SIGNATURE, + userId, refForm.getEntryText()); + } else { + // update existing entry + entry.setEntry(refForm.getEntryText()); + entry.setLastModified(new Date()); + service.updateEntry(entry); + } + + return finish(mapping, form, request, response); + } + + // ************************************************************************************* + // Private method + // ************************************************************************************* + /** + * Get answer by special question. + */ + private ActionErrors getAnswer(HttpServletRequest request, AnswerDTO answerDto) { + ActionErrors errors = new ActionErrors(); + // get sessionMap + String sessionMapID = request.getParameter(SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + Long sessionID = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); + + SurveyAnswer answer = getAnswerFromPage(request, answerDto, sessionID); + answerDto.setAnswer(answer); + validateAnswers(request, answerDto, errors, answer); + if (!errors.isEmpty()) { + addErrors(request, errors); + } + return errors; + } + + /** + * Get all answer for all questions in this page + * + * @param request + * @return + */ + private ActionErrors getAnswers(HttpServletRequest request) { + ActionErrors errors = new ActionErrors(); + // get sessionMap + String sessionMapID = request.getParameter(SurveyConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + Long sessionID = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); + Collection answerDtoList = getQuestionList(sessionMap).values(); + + for (AnswerDTO answerDto : answerDtoList) { + SurveyAnswer answer = getAnswerFromPage(request, answerDto, sessionID); + answerDto.setAnswer(answer); + validateAnswers(request, answerDto, errors, answer); + } + if (!errors.isEmpty()) { + addErrors(request, errors); + } + return errors; + } + + private void validateAnswers(HttpServletRequest request, AnswerDTO question, ActionErrors errors, + SurveyAnswer answer) { + boolean isAnswerEmpty = ((answer.getChoices() == null) && StringUtils.isBlank(answer.getAnswerText())); + + // for mandatory questions, answer can not be null. + if (!question.isOptional() && isAnswerEmpty) { + errors.add(SurveyConstants.ERROR_MSG_KEY + question.getUid(), + new ActionMessage(SurveyConstants.ERROR_MSG_MANDATORY_QUESTION)); + } + if ((question.getType() == SurveyConstants.QUESTION_TYPE_SINGLE_CHOICE) && question.isAppendText() + && !isAnswerEmpty) { + // for single choice, user only can choose one option or open text (if it has) + if (!StringUtils.isBlank(answer.getAnswerChoices()) && !StringUtils.isBlank(answer.getAnswerText())) { + errors.add(SurveyConstants.ERROR_MSG_KEY + question.getUid(), + new ActionMessage(SurveyConstants.ERROR_MSG_SINGLE_CHOICE)); + } + } + } + + private SurveyAnswer getAnswerFromPage(HttpServletRequest request, AnswerDTO question, Long sessionID) { + + String[] choiceList = request.getParameterValues(SurveyConstants.PREFIX_QUESTION_CHOICE + question.getUid()); + String textEntry = request.getParameter(SurveyConstants.PREFIX_QUESTION_TEXT + question.getUid()); + + SurveyAnswer answer = question.getAnswer(); + if (answer == null) { + answer = new SurveyAnswer(); + } + answer.setAnswerChoices(SurveyWebUtils.getChoicesStr(choiceList)); + answer.setChoices(choiceList); + + answer.setAnswerText(textEntry); + + ISurveyService service = getSurveyService(); + answer.setUser(getCurrentUser(service, sessionID)); + answer.setUpdateDate(new Timestamp(new Date().getTime())); + answer.setSurveyQuestion(question); + return answer; + } + + private ISurveyService getSurveyService() { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + return (ISurveyService) wac.getBean(SurveyConstants.SURVEY_SERVICE); + } + + /** + * List save current survey items. + * + * @param request + * @return + */ + private SortedMap getQuestionList(SessionMap sessionMap) { + SortedMap list = (SortedMap) sessionMap + .get(SurveyConstants.ATTR_QUESTION_LIST); + if (list == null) { + list = new TreeMap<>(new IntegerComparator()); + sessionMap.put(SurveyConstants.ATTR_QUESTION_LIST, list); + } + return list; + } + + private SurveyUser getCurrentUser(ISurveyService service, Long sessionId) { + // try to get form system session + HttpSession ss = SessionManager.getSession(); + // get back login user DTO + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + SurveyUser surveyUser = service.getUserByIDAndSession(new Long(user.getUserID().intValue()), sessionId); + + if (surveyUser == null) { + SurveySession session = service.getSurveySessionBySessionId(sessionId); + surveyUser = new SurveyUser(user, session); + service.createUser(surveyUser); + } + return surveyUser; + } + + private SurveyUser getSpecifiedUser(ISurveyService service, Long sessionId, Integer userId) { + return service.getUserByIDAndSession(new Long(userId.intValue()), sessionId); + } + +} Index: lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/MonitoringAction.java =================================================================== diff -u --- lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/MonitoringAction.java (revision 0) +++ lams_tool_survey/src/java/org/lamsfoundation/lams/tool/survey/web/controller/MonitoringAction.java (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,597 @@ +/**************************************************************** + * 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.survey.web.controller; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.SortedMap; +import java.util.TimeZone; + +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +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.StringUtils; +import org.apache.log4j.Logger; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +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.apache.struts.action.ActionMessage; +import org.lamsfoundation.lams.tool.survey.SurveyConstants; +import org.lamsfoundation.lams.tool.survey.dto.AnswerDTO; +import org.lamsfoundation.lams.tool.survey.model.Survey; +import org.lamsfoundation.lams.tool.survey.model.SurveyOption; +import org.lamsfoundation.lams.tool.survey.model.SurveyQuestion; +import org.lamsfoundation.lams.tool.survey.model.SurveySession; +import org.lamsfoundation.lams.tool.survey.model.SurveyUser; +import org.lamsfoundation.lams.tool.survey.service.ISurveyService; +import org.lamsfoundation.lams.tool.survey.util.SurveyWebUtils; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +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.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.lamsfoundation.lams.web.util.SessionMap; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.springframework.web.util.HtmlUtils; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +public class MonitoringAction extends Action { + + public ISurveyService surveyService; + private static final String MSG_LABEL_QUESTION = "label.question"; + private static final String MSG_LABEL_OPEN_RESPONSE = "label.open.response"; + private static final String MSG_LABEL_SESSION_NAME = "label.session.name"; + private static final String MSG_LABEL_POSSIBLE_ANSWERS = "message.possible.answers"; + private static final String MSG_LABEL_LEARNER_NAME = "monitoring.label.user.name"; + private static final String MSG_LABEL_LOGIN = "monitoring.label.user.loginname"; + private static final String MSG_LABEL_TIMESTAMP = "label.timestamp"; + + public static Logger log = Logger.getLogger(MonitoringAction.class); + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + String param = mapping.getParameter(); + + if (param.equals("summary")) { + return summary(mapping, form, request, response); + } + + if (param.equals("listAnswers")) { + return listAnswers(mapping, form, request, response); + } + if (param.equals("getAnswersJSON")) { + return getAnswersJSON(mapping, form, request, response); + } + + if (param.equals("listReflections")) { + return listReflections(mapping, form, request, response); + } + if (param.equals("getReflectionsJSON")) { + return getReflectionsJSON(mapping, form, request, response); + } + + if (param.equals("exportSurvey")) { + return exportSurvey(mapping, form, request, response); + } + + if (param.equals("setSubmissionDeadline")) { + return setSubmissionDeadline(mapping, form, request, response); + } + + return mapping.findForward(SurveyConstants.ERROR); + } + + /** + * Summary page action. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + + private ActionForward summary(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + // get session from shared session. + HttpSession ss = SessionManager.getSession(); + + // initial Session Map + SessionMap sessionMap = new SessionMap(); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + request.setAttribute(SurveyConstants.ATTR_SESSION_MAP_ID, sessionMap.getSessionID()); + // save contentFolderID into session + sessionMap.put(AttributeNames.PARAM_CONTENT_FOLDER_ID, + WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID)); + + request.setAttribute("initialTabId", WebUtil.readLongParam(request, AttributeNames.PARAM_CURRENT_TAB, true)); + + Long contentId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + ISurveyService service = getSurveyService(); + + // get summary + SortedMap> summary = service.getSummary(contentId); + + // get survey + Survey survey = service.getSurveyByContentId(contentId); + + // get statistic + SortedMap statis = service.getStatistic(contentId); + + // cache into sessionMap + sessionMap.put(SurveyConstants.ATTR_SUMMARY_LIST, summary); + sessionMap.put(SurveyConstants.ATTR_STATISTIC_LIST, statis); + sessionMap.put(SurveyConstants.PAGE_EDITABLE, new Boolean(SurveyWebUtils.isSurveyEditable(survey))); + sessionMap.put(SurveyConstants.ATTR_SURVEY, survey); + sessionMap.put(AttributeNames.PARAM_TOOL_CONTENT_ID, contentId); + sessionMap.put(SurveyConstants.ATTR_IS_GROUPED_ACTIVITY, service.isGroupedActivity(contentId)); + + // check if there is submission deadline + Date submissionDeadline = survey.getSubmissionDeadline(); + + if (submissionDeadline != null) { + + UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone learnerTimeZone = learnerDto.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); + MonitoringAction.log.info("Time:" + tzSubmissionDeadline.getTime()); + // store submission deadline to sessionMap + sessionMap.put(SurveyConstants.ATTR_SUBMISSION_DEADLINE, tzSubmissionDeadline.getTime()); + sessionMap.put(SurveyConstants.ATTR_SUBMISSION_DEADLINE_DATESTRING, + DateUtil.convertToStringForJSON(submissionDeadline, request.getLocale())); + } + + return mapping.findForward(SurveyConstants.SUCCESS); + } + + private ActionForward listAnswers(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + Long questionUid = WebUtil.readLongParam(request, SurveyConstants.ATTR_QUESTION_UID); + + // get user list + ISurveyService service = getSurveyService(); + SurveyQuestion question = service.getQuestion(questionUid); + request.setAttribute(SurveyConstants.ATTR_QUESTION, question); + request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID, sessionId); + return mapping.findForward(SurveyConstants.SUCCESS); + } + + private ActionForward getAnswersJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + Long questionUid = WebUtil.readLongParam(request, SurveyConstants.ATTR_QUESTION_UID); + + // 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 = SurveyConstants.SORT_BY_DEAFAULT; + if (sortByName != null) { + sorting = sortByName.equals(0) ? SurveyConstants.SORT_BY_NAME_ASC : SurveyConstants.SORT_BY_NAME_DESC; + } + + // return user list according to the given sessionID + ISurveyService service = getSurveyService(); + SurveyQuestion question = service.getQuestion(questionUid); + List users = service.getQuestionAnswersForTablesorter(sessionId, questionUid, page, size, sorting, + searchString); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); + responsedata.put("total_rows", service.getCountUsersBySession(sessionId, searchString)); + + for (Object[] userAndAnswers : users) { + + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + + SurveyUser user = (SurveyUser) userAndAnswers[0]; + responseRow.put(SurveyConstants.ATTR_USER_NAME, + HtmlUtils.htmlEscape(user.getLastName() + " " + user.getFirstName())); + responseRow.put(SurveyConstants.ATTR_USER_ID, user.getUserId()); + + if (userAndAnswers.length > 1 && userAndAnswers[1] != null) { + responseRow.put("choices", + JsonUtil.readArray(SurveyWebUtils.getChoiceList((String) userAndAnswers[1]))); + } + if (userAndAnswers.length > 2 && userAndAnswers[2] != null) { + // Data is handled differently in learner depending on whether + // it is an extra text added + // to a multiple choice, or a free text entry. So need to handle + // the output differently. + // See learner/result.jsp and its handling of question.type == 3 + // vs question.appendText + String answer; + if (question.getType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + // don't escape as it was escaped & BR'd before saving + answer = (String) userAndAnswers[2]; + } else { + // need to escape it, as it isn't escaped in the database + answer = HtmlUtils.htmlEscape((String) userAndAnswers[2]); + answer = answer.replaceAll("\n", "
"); + } + responseRow.put("answerText", answer); + } + if (userAndAnswers.length > 3 && userAndAnswers[3] != null) { + responseRow.put(SurveyConstants.ATTR_PORTRAIT_ID, ((Number) userAndAnswers[3]).longValue()); + } + rows.add(responseRow); + } + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + + private ActionForward listReflections(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + + ISurveyService service = getSurveyService(); + Survey survey = service.getSurveyBySessionId(sessionId); + + request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID, sessionId); + return mapping.findForward(SurveyConstants.SUCCESS); + } + + private ActionForward getReflectionsJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + Long sessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_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 = SurveyConstants.SORT_BY_DEAFAULT; + if (sortByName != null) { + sorting = sortByName.equals(0) ? SurveyConstants.SORT_BY_NAME_ASC : SurveyConstants.SORT_BY_NAME_DESC; + } + + // return user list according to the given sessionID + ISurveyService service = getSurveyService(); + List users = service.getUserReflectionsForTablesorter(sessionId, page, size, sorting, searchString); + + 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(); + + SurveyUser user = (SurveyUser) userAndReflection[0]; + responseRow.put(SurveyConstants.ATTR_USER_NAME, + HtmlUtils.htmlEscape(user.getLastName() + " " + user.getFirstName())); + responseRow.put(SurveyConstants.ATTR_USER_ID, user.getUserId()); + + if (userAndReflection.length > 1 && userAndReflection[1] != null) { + String reflection = HtmlUtils.htmlEscape((String) userAndReflection[1]); + responseRow.put(SurveyConstants.ATTR_REFLECTION, reflection.replaceAll("\n", "
")); + } + + if (userAndReflection.length > 2 && userAndReflection[2] != null) { + responseRow.put(SurveyConstants.ATTR_PORTRAIT_ID, ((Number) userAndReflection[2]).longValue()); + } + + rows.add(responseRow); + } + responsedata.set("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responsedata.toString())); + return null; + } + + /** + * Export Excel format survey data. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward exportSurvey(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + Long toolSessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); + + ISurveyService service = getSurveyService(); + + SortedMap>> groupList = service + .exportBySessionId(toolSessionID); + String errors = null; + MessageService resource = getMessageService(); + try { + // create an empty excel file + Workbook workbook = new SXSSFWorkbook(); + + // Date format for the timestamp field + CellStyle dateStyle = workbook.createCellStyle(); + dateStyle.setDataFormat((short) 0x16); // long date/time format e.g. DD/MM/YYYY MM:HH + + Sheet sheet = workbook.createSheet("Survey"); + sheet.setColumnWidth(0, 5000); + Row row; + Cell cell; + int idx = 0; + Set>>> entries = groupList.entrySet(); + for (Entry>> entry : entries) { + SurveySession session = entry.getKey(); + SortedMap> map = entry.getValue(); + // display survey title, instruction and questions + Survey survey = session.getSurvey(); + // survey title + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(SurveyWebUtils.removeHTMLTags(survey.getTitle())); + + // survey instruction + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(SurveyWebUtils.removeHTMLTags(survey.getInstructions())); + + // display 2 empty row + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(""); + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(""); + + // display session name + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_SESSION_NAME)); + cell = row.createCell(1); + cell.setCellValue(SurveyWebUtils.removeHTMLTags(session.getSessionName())); + + // begin to display question and its answers + Set>> questionEntries = map.entrySet(); + int questionIdx = 0; + for (Entry> questionEntry : questionEntries) { + // display 1 empty row + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(""); + + questionIdx++; + SurveyQuestion question = questionEntry.getKey(); + List answers = questionEntry.getValue(); + + // display question content + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_QUESTION) + " " + questionIdx); + cell = row.createCell(1); + cell.setCellValue(SurveyWebUtils.removeHTMLTags(question.getDescription())); + + // display options content + Set options = question.getOptions(); + + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_POSSIBLE_ANSWERS)); + + int optionIdx = 0; + for (SurveyOption option : options) { + optionIdx++; + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(SurveyConstants.OPTION_SHORT_HEADER + optionIdx); + cell = row.createCell(1); + cell.setCellValue(SurveyWebUtils.removeHTMLTags(option.getDescription())); + } + if (question.isAppendText() || question.getType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + optionIdx++; + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(SurveyConstants.OPTION_SHORT_HEADER + optionIdx); + cell = row.createCell(1); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_OPEN_RESPONSE)); + } + + // display 1 empty row + row = sheet.createRow(idx++); + cell = row.createCell(0); + cell.setCellValue(""); + + // ////////////////////////// + // display answer list + // ////////////////////////// + // first display option title : a1 , a2, a3 etc + + int cellIdx = 0; + row = sheet.createRow(idx++); + cell = row.createCell(cellIdx); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_LOGIN)); + cellIdx++; + cell = row.createCell(cellIdx); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_LEARNER_NAME)); + cellIdx++; + cell = row.createCell(cellIdx); + cell.setCellValue(resource.getMessage(MonitoringAction.MSG_LABEL_TIMESTAMP)); + + int optionsNum = options.size(); + + int iterOpts; + for (iterOpts = 1; iterOpts <= optionsNum; iterOpts++) { + cellIdx++; + cell = row.createCell(cellIdx); + cell.setCellValue(SurveyConstants.OPTION_SHORT_HEADER + iterOpts); + } + + // display all users' answers for this question in multiple + // rows + for (AnswerDTO answer : answers) { + row = sheet.createRow(idx++); + cellIdx = 0; + cell = row.createCell(cellIdx); + cell.setCellValue(answer.getReplier().getLoginName()); + cellIdx++; + cell = row.createCell(cellIdx); + cell.setCellValue( + answer.getReplier().getLastName() + ", " + answer.getReplier().getFirstName()); + cellIdx++; + cell = row.createCell(cellIdx); + cell.setCellStyle(dateStyle); + cell.setCellValue(answer.getAnswer().getUpdateDate()); + // for answer's options + for (SurveyOption option : options) { + cellIdx++; + cell = row.createCell(cellIdx); + if (answer.getAnswer() == null) { + break; + } + String[] choices = answer.getAnswer().getChoices(); + for (String choice : choices) { + if (StringUtils.equals(choice, option.getUid().toString())) { + cell.setCellValue("X"); + } + } + } + // for textEntry option + if (question.isAppendText() || question.getType() == SurveyConstants.QUESTION_TYPE_TEXT_ENTRY) { + cell = row.createCell(++cellIdx); + if (answer.getAnswer() != null) { + cell.setCellValue(SurveyWebUtils.removeHTMLTags(answer.getAnswer().getAnswerText())); + } + } + + } + } + } + + // 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); + + String fileName = "lams_survey_" + toolSessionID + ".xlsx"; + response.setContentType("application/x-download"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName); + + ServletOutputStream out = response.getOutputStream(); + workbook.write(out); + out.close(); + + } catch (Exception e) { + MonitoringAction.log.error(e); + errors = new ActionMessage("error.monitoring.export.excel", 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 { + surveyService = getSurveyService(); + + Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + Survey survey = surveyService.getSurveyByContentId(contentID); + + Long dateParameter = WebUtil.readLongParam(request, SurveyConstants.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()); + } + survey.setSubmissionDeadline(tzSubmissionDeadline); + surveyService.saveOrUpdateSurvey(survey); + + response.setContentType("text/plain;charset=utf-8"); + response.getWriter().print(formattedDate); + return null; + } + + // ************************************************************************************* + // Private method + // ************************************************************************************* + private ISurveyService getSurveyService() { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + return (ISurveyService) wac.getBean(SurveyConstants.SURVEY_SERVICE); + } + + /** + * Return ResourceService bean. + */ + private MessageService getMessageService() { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + return (MessageService) wac.getBean("lasurvMessageService"); + } +} Index: lams_tool_survey/web/WEB-INF/spring-servlet.xml =================================================================== diff -u --- lams_tool_survey/web/WEB-INF/spring-servlet.xml (revision 0) +++ lams_tool_survey/web/WEB-INF/spring-servlet.xml (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file Index: lams_tool_survey/web/WEB-INF/web.xml =================================================================== diff -u -rac280c8fb2043ec90a0b7756ede0c7ab64c089d8 -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/WEB-INF/web.xml (.../web.xml) (revision ac280c8fb2043ec90a0b7756ede0c7ab64c089d8) +++ lams_tool_survey/web/WEB-INF/web.xml (.../web.xml) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -8,17 +8,21 @@ Shared Surveys tool - javax.servlet.jsp.jstl.fmt.localizationContext - org.lamsfoundation.lams.tool.survey.ApplicationResources + javax.servlet.jsp.jstl.fmt.localizationContext + + org.lamsfoundation.lams.tool.survey.ApplicationResources + contextConfigLocation - classpath:/org/lamsfoundation/lams/tool/survey/dbupdates/autopatchContext.xml + classpath:/org/lamsfoundation/lams/tool/survey/dbupdates/autopatchContext.xml + locatorFactorySelector - classpath:/org/lamsfoundation/lams/beanRefContext.xml + classpath:/org/lamsfoundation/lams/beanRefContext.xml + parentContextKey @@ -74,30 +78,17 @@ - action - org.apache.struts.action.ActionServlet - - config - /WEB-INF/struts-config.xml - - - debug - 999 - - - detail - 1 - - - validate - true - - 2 + spring + + org.springframework.web.servlet.DispatcherServlet + + 1 Connector - net.fckeditor.connector.ConnectorServlet + net.fckeditor.connector.ConnectorServlet + baseDir /UserFiles/ @@ -114,7 +105,8 @@ Instructions Download Instructions Download download - org.lamsfoundation.lams.contentrepository.client.ToolDownload + org.lamsfoundation.lams.contentrepository.client.ToolDownload + toolContentHandlerBeanName lasurvSurveyToolContentHandler @@ -123,13 +115,14 @@ - action + spring *.do Connector - /ckeditor/filemanager/browser/default/connectors/jsp/connector + /ckeditor/filemanager/browser/default/connectors/jsp/connector + @@ -206,13 +199,13 @@ - + Secure content /* GET - POST + POST LEARNER @@ -228,7 +221,7 @@ /authoring/* /pages/authoring/* GET - POST + POST AUTHOR @@ -243,7 +236,7 @@ /pages/monitoring/* /definelater.do GET - POST + POST MONITOR Index: lams_tool_survey/web/common/messages.jsp =================================================================== diff -u -raf1051520a59e1945b25b8be64c5c6a0f7820baf -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/common/messages.jsp (.../messages.jsp) (revision af1051520a59e1945b25b8be64c5c6a0f7820baf) +++ lams_tool_survey/web/common/messages.jsp (.../messages.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -1,8 +1,2 @@ <%-- Error Messages --%> - - - -
-
-
-
\ No newline at end of file + \ No newline at end of file Index: lams_tool_survey/web/common/taglibs.jsp =================================================================== diff -u -r9d26aaf34391eb58df037978365deda31de85c1b -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/common/taglibs.jsp (.../taglibs.jsp) (revision 9d26aaf34391eb58df037978365deda31de85c1b) +++ lams_tool_survey/web/common/taglibs.jsp (.../taglibs.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -1,11 +1,7 @@ <%@ page language="java" errorPage="/error.jsp" pageEncoding="UTF-8" contentType="text/html;charset=utf-8" %> -<%@ taglib uri="tags-bean" prefix="bean" %> -<%@ taglib uri="tags-html" prefix="html" %> -<%@ taglib uri="tags-logic" prefix="logic" %> <%@ taglib uri="tags-function" prefix="fn" %> <%@ taglib uri="tags-core" prefix="c" %> <%@ taglib uri="tags-fmt" prefix="fmt" %> <%@ taglib uri="tags-xml" prefix="x" %> <%@ taglib uri="tags-lams" prefix="lams" %> - - +<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> \ No newline at end of file Index: lams_tool_survey/web/pages/authoring/addCondition.jsp =================================================================== diff -u -rc43a7c4f1389ad2b5fdc526aa736be11ab5ad271 -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/pages/authoring/addCondition.jsp (.../addCondition.jsp) (revision c43a7c4f1389ad2b5fdc526aa736be11ab5ad271) +++ lams_tool_survey/web/pages/authoring/addCondition.jsp (.../addCondition.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -10,29 +10,27 @@
<%@ include file="/common/messages.jsp"%> - - + +
- +
<%-- Text search form fields are being included --%>

- +
-
+ -
+
Index: lams_tool_survey/web/pages/authoring/advance.jsp =================================================================== diff -u -r1c9c204c7d6fad2a083eac4250d68aabce949b53 -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/pages/authoring/advance.jsp (.../advance.jsp) (revision 1c9c204c7d6fad2a083eac4250d68aabce949b53) +++ lams_tool_survey/web/pages/authoring/advance.jsp (.../advance.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -1,20 +1,19 @@ <%@ include file="/common/taglibs.jsp"%> -
@@ -25,7 +24,7 @@
@@ -36,20 +35,20 @@
- +
Index: lams_tool_survey/web/pages/authoring/authoring.jsp =================================================================== diff -u -rb47369533cc464d433b2a4306e8cc0bd3f8ecaa1 -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/pages/authoring/authoring.jsp (.../authoring.jsp) (revision b47369533cc464d433b2a4306e8cc0bd3f8ecaa1) +++ lams_tool_survey/web/pages/authoring/authoring.jsp (.../authoring.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -30,13 +30,12 @@ - - - - - - - + + + + + + @@ -67,15 +66,15 @@ + toolSignature="<%=SurveyConstants.TOOL_SIGNATURE%>" toolContentID="${authoringForm.survey.contentId}" + customiseSessionID="${authoringForm.sessionMapID}" accessMode="${mode}" defineLater="${mode=='teacher'}" + contentFolderID="${authoringForm.contentFolderID}" /> - + Index: lams_tool_survey/web/pages/authoring/basic.jsp =================================================================== diff -u -rf4d9fb8cc51c25fecdd0eac1dcf5f5efc916cdf8 -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/pages/authoring/basic.jsp (.../basic.jsp) (revision f4d9fb8cc51c25fecdd0eac1dcf5f5efc916cdf8) +++ lams_tool_survey/web/pages/authoring/basic.jsp (.../basic.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -1,7 +1,4 @@ <%@ include file="/common/taglibs.jsp"%> - + src="includes/javascript/surveyitem.js">
@@ -17,28 +17,25 @@ <%@ include file="/common/messages.jsp"%> - - + <%-- This field is not belong STRUTS form --%> - - - + + + <%-- This value should be 1 or 2 --%> - +
- +
@@ -50,22 +47,20 @@
- + <%@ include file="instructions.jsp"%> Index: lams_tool_survey/web/pages/authoring/parts/addopenquestion.jsp =================================================================== diff -u -rabf29b8232cd38898e6dd99b5a5aa4e3f673a42b -r92cf398e695b34f71b03ecba27659e4b214920d8 --- lams_tool_survey/web/pages/authoring/parts/addopenquestion.jsp (.../addopenquestion.jsp) (revision abf29b8232cd38898e6dd99b5a5aa4e3f673a42b) +++ lams_tool_survey/web/pages/authoring/parts/addopenquestion.jsp (.../addopenquestion.jsp) (revision 92cf398e695b34f71b03ecba27659e4b214920d8) @@ -4,7 +4,7 @@ var removeInstructionUrl = ""; var addInstructionUrl = ""; - +