Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaAdminController.java =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaAdminController.java (.../QaAdminController.java) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaAdminController.java (.../QaAdminController.java) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -1,377 +1,372 @@ -///**************************************************************** -// * Copyright (C) 2008 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.qa.web.controller; -// -//import java.io.IOException; -//import java.io.OutputStream; -//import java.io.StringReader; -//import java.util.SortedSet; -//import java.util.TreeSet; -// -//import javax.servlet.http.HttpServletRequest; -//import javax.servlet.http.HttpServletResponse; -//import javax.xml.parsers.DocumentBuilder; -//import javax.xml.parsers.DocumentBuilderFactory; -//import javax.xml.parsers.ParserConfigurationException; -// -//import org.apache.log4j.Logger; -//import org.apache.struts.action.ActionForm; -//import org.apache.struts.action.ActionForward; -//import org.apache.struts.action.ActionMapping; -//import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; -//import org.lamsfoundation.lams.tool.qa.QaConfigItem; -//import org.lamsfoundation.lams.tool.qa.QaWizardCategory; -//import org.lamsfoundation.lams.tool.qa.QaWizardCognitiveSkill; -//import org.lamsfoundation.lams.tool.qa.QaWizardQuestion; -//import org.lamsfoundation.lams.tool.qa.service.IQaService; -//import org.lamsfoundation.lams.tool.qa.web.form.QaAdminForm; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.stereotype.Controller; -//import org.springframework.web.bind.annotation.RequestMapping; -//import org.w3c.dom.Document; -//import org.w3c.dom.Element; -//import org.w3c.dom.NamedNodeMap; -//import org.w3c.dom.NodeList; -//import org.xml.sax.InputSource; -//import org.xml.sax.SAXException; -// -//import com.thoughtworks.xstream.XStream; -//import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider; -//import com.thoughtworks.xstream.security.AnyTypePermission; -// -///** -// * Handles the admin page for question and answer which includes the settings -// * and items for the q&a question wizard -// * -// * @author lfoxton -// * -// * -// */ -//@Controller -//@RequestMapping("/laqa11admin") -//public class QaAdminController { -// -// private static Logger logger = Logger.getLogger(QaAdminController.class.getName()); -// -// public static final String ATTR_CATEGORIES = "categories"; -// public static final String ATTR_CATEGORY = "category"; -// public static final String ATTR_QUESTION = "question"; -// public static final String ATTR_SKILL = "skill"; -// public static final String ATTR_TITLE = "title"; -// public static final String ATTR_UID = "uid"; -// public static final String NULL = "null"; -// public static final String FILE_EXPORT = "qa-wizard.xml"; -// -// @Autowired -// private IQaService qaService; -// -// /** -// * Sets up the admin page -// */ -// @RequestMapping("/") -// public String unspecified(QaAdminForm adminForm, HttpServletRequest request) { -// -// QaConfigItem enableQaWizard = qaService.getConfigItem(QaConfigItem.KEY_ENABLE_QAWIZARD); -// if (enableQaWizard != null) { -// adminForm.setQaWizardEnabled(enableQaWizard.getConfigValue()); -// } -// -// request.setAttribute("error", false); -// request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); -// -// return "admin/config"; -// } -// -// /** -// * Saves admin page, if the wizard is enabled, saves the wizard content -// * -// * @param mapping -// * @param form -// * @param request -// * @param response -// * @return -// */ -// @RequestMapping("/saveContent") -// public String saveContent(QaAdminForm adminForm, HttpServletRequest request) { -// -// QaConfigItem enableQaWizard = qaService.getConfigItem(QaConfigItem.KEY_ENABLE_QAWIZARD); -// -// if (adminForm.getQaWizardEnabled() != null && adminForm.getQaWizardEnabled()) { -// enableQaWizard.setConfigValue(QaAdminForm.TRUE); -// -// // get the wizard content and save -// if (adminForm.getSerialiseXML() != null && !adminForm.getSerialiseXML().trim().equals("")) { -// updateWizardFromXML(adminForm.getSerialiseXML().trim()); -// } -// -// // remove any wizard items that were removed -// removeWizardItems(adminForm.getDeleteCategoriesCSV(), adminForm.getDeleteSkillsCSV(), -// adminForm.getDeleteQuestionsCSV()); -// } else { -// enableQaWizard.setConfigValue(QaAdminForm.FALSE); -// } -// qaService.saveOrUpdateConfigItem(enableQaWizard); -// -// request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); -// request.setAttribute("savedSuccess", true); -// return "admin/config"; -// -// } -// -// /** -// * Gets the complete set of wizard categories -// * -// * @return -// */ -// public SortedSet getQaWizardCategories() { -// return qaService.getWizardCategories(); -// } -// -// /** -// * Removes all the removed wizard items from the db using CSV values -// * -// * @param categoriesCSV -// * @param skillsCSV -// * @param questionsCSV -// */ -// public void removeWizardItems(String categoriesCSV, String skillsCSV, String questionsCSV) { -// -// // remove categories -// if (categoriesCSV != null && !categoriesCSV.equals("")) { -// String categoryUIDs[] = categoriesCSV.split(","); -// for (int i = 0; i < categoryUIDs.length; i++) { -// qaService.deleteWizardCategoryByUID(Long.parseLong(categoryUIDs[i])); -// } -// } -// -// // remove skills -// if (skillsCSV != null && !skillsCSV.equals("")) { -// String skillUIDs[] = skillsCSV.split(","); -// for (int i = 0; i < skillUIDs.length; i++) { -// qaService.deleteWizardSkillByUID(Long.parseLong(skillUIDs[i])); -// } -// } -// -// // remove questions -// if (questionsCSV != null && !questionsCSV.equals("")) { -// String questionUIDs[] = questionsCSV.split(","); -// for (int i = 0; i < questionUIDs.length; i++) { -// qaService.deleteWizardQuestionByUID(Long.parseLong(questionUIDs[i])); -// } -// } -// } -// -// /** -// * Saves all the wizard items from the xml serialisation sent from the form -// * -// * @param xmlStr -// */ -// @SuppressWarnings("unchecked") -// public void updateWizardFromXML(String xmlStr) { -// //SortedSet currentCategories = getQaWizardCategories(); -// SortedSet newCategories = new TreeSet<>(); -// try { -// DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); -// DocumentBuilder db = dbf.newDocumentBuilder(); -// Document document = db.parse(new InputSource(new StringReader(xmlStr))); -// -// // Get a list of category nodes -// NodeList categoryNodeList = document.getElementsByTagName(ATTR_CATEGORY); -// -// for (int i = 0; i < categoryNodeList.getLength(); i++) { -// -// Element categoryElement = (Element) categoryNodeList.item(i); -// -// // Get the attributes for this category -// NamedNodeMap categoryNamedNode = categoryNodeList.item(i).getAttributes(); -// -// QaWizardCategory category = new QaWizardCategory(); -// category.setTitle(categoryNamedNode.getNamedItem(ATTR_TITLE).getNodeValue()); -// category.setCognitiveSkills(new TreeSet()); -// -// if (categoryNamedNode.getNamedItem(ATTR_UID).getNodeValue() != null -// && !categoryNamedNode.getNamedItem(ATTR_UID).getNodeValue().equals(NULL)) { -// category.setUid(Long.parseLong(categoryNamedNode.getNamedItem(ATTR_UID).getNodeValue())); -// } -// -// // Get a list of cognitive skill nodes -// NodeList skillNodeList = categoryElement.getElementsByTagName(ATTR_SKILL); -// for (int j = 0; j < skillNodeList.getLength(); j++) { -// Element skillElement = (Element) skillNodeList.item(j); -// -// // Get the attributes for this skill -// NamedNodeMap skillNamedNode = skillNodeList.item(j).getAttributes(); -// -// // Create the skill and add attributes from the node -// QaWizardCognitiveSkill skill = new QaWizardCognitiveSkill(); -// skill.setCategory(category); -// skill.setTitle(skillNamedNode.getNamedItem(ATTR_TITLE).getNodeValue()); -// skill.setQuestions(new TreeSet()); -// -// if (skillNamedNode.getNamedItem(ATTR_UID).getNodeValue() != null -// && !skillNamedNode.getNamedItem(ATTR_UID).getNodeValue().equals(NULL)) { -// skill.setUid(Long.parseLong(skillNamedNode.getNamedItem(ATTR_UID).getNodeValue())); -// } -// -// // add the skill to the parent category -// category.getCognitiveSkills().add(skill); -// -// // Get a list of questions for this skill -// NodeList questionNodeList = skillElement.getElementsByTagName(ATTR_QUESTION); -// for (int k = 0; k < questionNodeList.getLength(); k++) { -// // Get the attributes for this question -// NamedNodeMap questionNamedNode = questionNodeList.item(k).getAttributes(); -// -// // Create the question, and add attributes from the node -// QaWizardQuestion question = new QaWizardQuestion(); -// question.setQuestion(questionNamedNode.getNamedItem(ATTR_QUESTION).getNodeValue()); -// -// if (questionNamedNode.getNamedItem(ATTR_UID).getNodeValue() != null -// && !questionNamedNode.getNamedItem(ATTR_UID).getNodeValue().equals(NULL)) { -// question.setUid(Long.parseLong(questionNamedNode.getNamedItem(ATTR_UID).getNodeValue())); -// } -// -// // add the question to the parent cognitive skill -// skill.getQuestions().add(question); -// } -// } -// newCategories.add(category); -// } -// -// } catch (ParserConfigurationException e) { -// logger.error("Could not parse wizard serialise xml", e); -// } catch (SAXException e) { -// logger.error("Could not parse wizard serialise xml", e); -// } catch (IOException e) { -// logger.error("Could not parse wizard serialise xml", e); -// } -// -// qaService.saveOrUpdateQaWizardCategories(newCategories); -// } -// -// /** -// * Exports the wizard categories list so it can be imported elsewhere The -// * export format is the same xml format used by the export ld servlet -// * -// * @param mapping -// * @param form -// * @param request -// * @param response -// * @return -// */ -// @RequestMapping("/exportWizard") -// public String exportWizard(HttpServletResponse response) throws Exception { -// -// // now start the export -// SortedSet exportCategories = new TreeSet<>(); -// for (QaWizardCategory category : getQaWizardCategories()) { -// exportCategories.add((QaWizardCategory) category.clone()); -// } -// -// // exporting XML -// XStream designXml = new XStream(new SunUnsafeReflectionProvider()); -// designXml.addPermission(AnyTypePermission.ANY); -// String exportXml = designXml.toXML(exportCategories); -// -// response.setContentType("application/x-download"); -// response.setHeader("Content-Disposition", "attachment;filename=" + FILE_EXPORT); -// OutputStream out = null; -// try { -// out = response.getOutputStream(); -// out.write(exportXml.getBytes()); -// response.setContentLength(exportXml.getBytes().length); -// out.flush(); -// } catch (Exception e) { -// logger.error("Exception occured writing out file:" + e.getMessage()); -// throw new ExportToolContentException(e); -// } finally { -// try { -// if (out != null) { -// out.close(); -// } -// } catch (Exception e) { -// logger.error("Error Closing file. File already written out - no exception being thrown.", e); -// } -// } -// -// return null; -// } -// -// /** -// * Imports the wizard model from an xml file and replaces the current model -// * First, saves the configurations, then performs the import using xstream -// * -// * @param mapping -// * @param form -// * @param request -// * @param response -// * @return -// */ -// @SuppressWarnings("unchecked") -// public ActionForward importWizard(ActionMapping mapping, ActionForm form, HttpServletRequest request, -// HttpServletResponse response) { -// QaAdminForm adminForm = (QaAdminForm) form; -// -// // First save the config items -// QaConfigItem enableQaWizard = qaService.getConfigItem(QaConfigItem.KEY_ENABLE_QAWIZARD); -// -// if (adminForm.getQaWizardEnabled() != null && adminForm.getQaWizardEnabled()) { -// enableQaWizard.setConfigValue(QaAdminForm.TRUE); -// -// // get the wizard content and save -// if (adminForm.getSerialiseXML() != null && !adminForm.getSerialiseXML().trim().equals("")) { -// updateWizardFromXML(adminForm.getSerialiseXML().trim()); -// } -// -// // remove any wizard items that were removed -// removeWizardItems(adminForm.getDeleteCategoriesCSV(), adminForm.getDeleteSkillsCSV(), -// adminForm.getDeleteQuestionsCSV()); -// } else { -// enableQaWizard.setConfigValue(QaAdminForm.FALSE); -// } -// qaService.saveOrUpdateConfigItem(enableQaWizard); -// -// // Now perform the import -// try { -// String xml = new String(adminForm.getImportFile().getFileData()); -// XStream conversionXml = new XStream(new SunUnsafeReflectionProvider()); -// conversionXml.addPermission(AnyTypePermission.ANY); -// SortedSet exportCategories = (SortedSet) conversionXml.fromXML(xml); -// -// qaService.deleteAllWizardCategories(); -// qaService.saveOrUpdateQaWizardCategories(exportCategories); -// } catch (Exception e) { -// logger.error("Failed to import wizard model", e); -// request.setAttribute("error", true); -// request.setAttribute("errorKey", "wizard.import.error"); -// request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); -// return mapping.findForward("config"); -// } -// -// request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); -// request.setAttribute("savedSuccess", true); -// return mapping.findForward("config"); -// -// } -// -//} +/**************************************************************** + * Copyright (C) 2008 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.qa.web.controller; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.tool.qa.QaConfigItem; +import org.lamsfoundation.lams.tool.qa.QaWizardCategory; +import org.lamsfoundation.lams.tool.qa.QaWizardCognitiveSkill; +import org.lamsfoundation.lams.tool.qa.QaWizardQuestion; +import org.lamsfoundation.lams.tool.qa.service.IQaService; +import org.lamsfoundation.lams.tool.qa.web.form.QaAdminForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider; +import com.thoughtworks.xstream.security.AnyTypePermission; + +/** + * Handles the admin page for question and answer which includes the settings + * and items for the q&a question wizard + * + * @author lfoxton + * + * + */ +@Controller +@RequestMapping("/laqa11admin") +public class QaAdminController { + + private static Logger logger = Logger.getLogger(QaAdminController.class.getName()); + + public static final String ATTR_CATEGORIES = "categories"; + public static final String ATTR_CATEGORY = "category"; + public static final String ATTR_QUESTION = "question"; + public static final String ATTR_SKILL = "skill"; + public static final String ATTR_TITLE = "title"; + public static final String ATTR_UID = "uid"; + public static final String NULL = "null"; + public static final String FILE_EXPORT = "qa-wizard.xml"; + + @Autowired + private IQaService qaService; + + /** + * Sets up the admin page + */ + @RequestMapping("/") + public String unspecified(QaAdminForm adminForm, HttpServletRequest request) { + + QaConfigItem enableQaWizard = qaService.getConfigItem(QaConfigItem.KEY_ENABLE_QAWIZARD); + if (enableQaWizard != null) { + adminForm.setQaWizardEnabled(enableQaWizard.getConfigValue()); + } + + request.setAttribute("error", false); + request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); + + return "admin/config"; + } + + /** + * Saves admin page, if the wizard is enabled, saves the wizard content + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/saveContent") + public String saveContent(QaAdminForm adminForm, HttpServletRequest request) { + + QaConfigItem enableQaWizard = qaService.getConfigItem(QaConfigItem.KEY_ENABLE_QAWIZARD); + + if (adminForm.getQaWizardEnabled() != null && adminForm.getQaWizardEnabled()) { + enableQaWizard.setConfigValue(QaAdminForm.TRUE); + + // get the wizard content and save + if (adminForm.getSerialiseXML() != null && !adminForm.getSerialiseXML().trim().equals("")) { + updateWizardFromXML(adminForm.getSerialiseXML().trim()); + } + + // remove any wizard items that were removed + removeWizardItems(adminForm.getDeleteCategoriesCSV(), adminForm.getDeleteSkillsCSV(), + adminForm.getDeleteQuestionsCSV()); + } else { + enableQaWizard.setConfigValue(QaAdminForm.FALSE); + } + qaService.saveOrUpdateConfigItem(enableQaWizard); + + request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); + request.setAttribute("savedSuccess", true); + return "admin/config"; + + } + + /** + * Gets the complete set of wizard categories + * + * @return + */ + public SortedSet getQaWizardCategories() { + return qaService.getWizardCategories(); + } + + /** + * Removes all the removed wizard items from the db using CSV values + * + * @param categoriesCSV + * @param skillsCSV + * @param questionsCSV + */ + public void removeWizardItems(String categoriesCSV, String skillsCSV, String questionsCSV) { + + // remove categories + if (categoriesCSV != null && !categoriesCSV.equals("")) { + String categoryUIDs[] = categoriesCSV.split(","); + for (int i = 0; i < categoryUIDs.length; i++) { + qaService.deleteWizardCategoryByUID(Long.parseLong(categoryUIDs[i])); + } + } + + // remove skills + if (skillsCSV != null && !skillsCSV.equals("")) { + String skillUIDs[] = skillsCSV.split(","); + for (int i = 0; i < skillUIDs.length; i++) { + qaService.deleteWizardSkillByUID(Long.parseLong(skillUIDs[i])); + } + } + + // remove questions + if (questionsCSV != null && !questionsCSV.equals("")) { + String questionUIDs[] = questionsCSV.split(","); + for (int i = 0; i < questionUIDs.length; i++) { + qaService.deleteWizardQuestionByUID(Long.parseLong(questionUIDs[i])); + } + } + } + + /** + * Saves all the wizard items from the xml serialisation sent from the form + * + * @param xmlStr + */ + @SuppressWarnings("unchecked") + public void updateWizardFromXML(String xmlStr) { + //SortedSet currentCategories = getQaWizardCategories(); + SortedSet newCategories = new TreeSet<>(); + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document document = db.parse(new InputSource(new StringReader(xmlStr))); + + // Get a list of category nodes + NodeList categoryNodeList = document.getElementsByTagName(ATTR_CATEGORY); + + for (int i = 0; i < categoryNodeList.getLength(); i++) { + + Element categoryElement = (Element) categoryNodeList.item(i); + + // Get the attributes for this category + NamedNodeMap categoryNamedNode = categoryNodeList.item(i).getAttributes(); + + QaWizardCategory category = new QaWizardCategory(); + category.setTitle(categoryNamedNode.getNamedItem(ATTR_TITLE).getNodeValue()); + category.setCognitiveSkills(new TreeSet()); + + if (categoryNamedNode.getNamedItem(ATTR_UID).getNodeValue() != null + && !categoryNamedNode.getNamedItem(ATTR_UID).getNodeValue().equals(NULL)) { + category.setUid(Long.parseLong(categoryNamedNode.getNamedItem(ATTR_UID).getNodeValue())); + } + + // Get a list of cognitive skill nodes + NodeList skillNodeList = categoryElement.getElementsByTagName(ATTR_SKILL); + for (int j = 0; j < skillNodeList.getLength(); j++) { + Element skillElement = (Element) skillNodeList.item(j); + + // Get the attributes for this skill + NamedNodeMap skillNamedNode = skillNodeList.item(j).getAttributes(); + + // Create the skill and add attributes from the node + QaWizardCognitiveSkill skill = new QaWizardCognitiveSkill(); + skill.setCategory(category); + skill.setTitle(skillNamedNode.getNamedItem(ATTR_TITLE).getNodeValue()); + skill.setQuestions(new TreeSet()); + + if (skillNamedNode.getNamedItem(ATTR_UID).getNodeValue() != null + && !skillNamedNode.getNamedItem(ATTR_UID).getNodeValue().equals(NULL)) { + skill.setUid(Long.parseLong(skillNamedNode.getNamedItem(ATTR_UID).getNodeValue())); + } + + // add the skill to the parent category + category.getCognitiveSkills().add(skill); + + // Get a list of questions for this skill + NodeList questionNodeList = skillElement.getElementsByTagName(ATTR_QUESTION); + for (int k = 0; k < questionNodeList.getLength(); k++) { + // Get the attributes for this question + NamedNodeMap questionNamedNode = questionNodeList.item(k).getAttributes(); + + // Create the question, and add attributes from the node + QaWizardQuestion question = new QaWizardQuestion(); + question.setQuestion(questionNamedNode.getNamedItem(ATTR_QUESTION).getNodeValue()); + + if (questionNamedNode.getNamedItem(ATTR_UID).getNodeValue() != null + && !questionNamedNode.getNamedItem(ATTR_UID).getNodeValue().equals(NULL)) { + question.setUid(Long.parseLong(questionNamedNode.getNamedItem(ATTR_UID).getNodeValue())); + } + + // add the question to the parent cognitive skill + skill.getQuestions().add(question); + } + } + newCategories.add(category); + } + + } catch (ParserConfigurationException e) { + logger.error("Could not parse wizard serialise xml", e); + } catch (SAXException e) { + logger.error("Could not parse wizard serialise xml", e); + } catch (IOException e) { + logger.error("Could not parse wizard serialise xml", e); + } + + qaService.saveOrUpdateQaWizardCategories(newCategories); + } + + /** + * Exports the wizard categories list so it can be imported elsewhere The + * export format is the same xml format used by the export ld servlet + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @RequestMapping("/exportWizard") + public String exportWizard(HttpServletResponse response) throws Exception { + + // now start the export + SortedSet exportCategories = new TreeSet<>(); + for (QaWizardCategory category : getQaWizardCategories()) { + exportCategories.add((QaWizardCategory) category.clone()); + } + + // exporting XML + XStream designXml = new XStream(new SunUnsafeReflectionProvider()); + designXml.addPermission(AnyTypePermission.ANY); + String exportXml = designXml.toXML(exportCategories); + + response.setContentType("application/x-download"); + response.setHeader("Content-Disposition", "attachment;filename=" + FILE_EXPORT); + OutputStream out = null; + try { + out = response.getOutputStream(); + out.write(exportXml.getBytes()); + response.setContentLength(exportXml.getBytes().length); + out.flush(); + } catch (Exception e) { + logger.error("Exception occured writing out file:" + e.getMessage()); + throw new ExportToolContentException(e); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (Exception e) { + logger.error("Error Closing file. File already written out - no exception being thrown.", e); + } + } + + return null; + } + + /** + * Imports the wizard model from an xml file and replaces the current model + * First, saves the configurations, then performs the import using xstream + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + @SuppressWarnings("unchecked") + public String importWizard(QaAdminForm adminForm, HttpServletRequest request) { + + // First save the config items + QaConfigItem enableQaWizard = qaService.getConfigItem(QaConfigItem.KEY_ENABLE_QAWIZARD); + + if (adminForm.getQaWizardEnabled() != null && adminForm.getQaWizardEnabled()) { + enableQaWizard.setConfigValue(QaAdminForm.TRUE); + + // get the wizard content and save + if (adminForm.getSerialiseXML() != null && !adminForm.getSerialiseXML().trim().equals("")) { + updateWizardFromXML(adminForm.getSerialiseXML().trim()); + } + + // remove any wizard items that were removed + removeWizardItems(adminForm.getDeleteCategoriesCSV(), adminForm.getDeleteSkillsCSV(), + adminForm.getDeleteQuestionsCSV()); + } else { + enableQaWizard.setConfigValue(QaAdminForm.FALSE); + } + qaService.saveOrUpdateConfigItem(enableQaWizard); + + // Now perform the import + try { + String xml = new String(adminForm.getImportFile().getFileData()); + XStream conversionXml = new XStream(new SunUnsafeReflectionProvider()); + conversionXml.addPermission(AnyTypePermission.ANY); + SortedSet exportCategories = (SortedSet) conversionXml.fromXML(xml); + + qaService.deleteAllWizardCategories(); + qaService.saveOrUpdateQaWizardCategories(exportCategories); + } catch (Exception e) { + logger.error("Failed to import wizard model", e); + request.setAttribute("error", true); + request.setAttribute("errorKey", "wizard.import.error"); + request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); + return "admin/config"; + } + + request.setAttribute(ATTR_CATEGORIES, getQaWizardCategories()); + request.setAttribute("savedSuccess", true); + return "admin/config"; + + } + +} Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaAuthoringConditionController.java =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaAuthoringConditionController.java (.../QaAuthoringConditionController.java) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaAuthoringConditionController.java (.../QaAuthoringConditionController.java) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -1,442 +1,441 @@ -///**************************************************************** -// * 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.qa.web.controller; -// -//import java.util.ArrayList; -//import java.util.LinkedList; -//import java.util.List; -//import java.util.SortedSet; -//import java.util.TreeSet; -// -//import javax.servlet.ServletException; -//import javax.servlet.http.HttpServletRequest; -// -//import org.apache.commons.lang.StringUtils; -//import org.apache.commons.lang.math.NumberUtils; -//import org.apache.struts.action.ActionForm; -//import org.apache.struts.util.LabelValueBean; -//import org.lamsfoundation.lams.learningdesign.TextSearchConditionComparator; -//import org.lamsfoundation.lams.tool.qa.QaAppConstants; -//import org.lamsfoundation.lams.tool.qa.QaCondition; -//import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; -//import org.lamsfoundation.lams.tool.qa.service.IQaService; -//import org.lamsfoundation.lams.tool.qa.web.form.QaConditionForm; -//import org.lamsfoundation.lams.util.MessageService; -//import org.lamsfoundation.lams.util.WebUtil; -//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.util.LinkedMultiValueMap; -//import org.springframework.util.MultiValueMap; -//import org.springframework.web.bind.annotation.RequestMapping; -//import org.springframework.web.bind.annotation.RequestMethod; -// -///** -// * Auxiliary action in author mode. It contains operations with QaCondition. The -// * rest of operations are located in QaAction action. -// * -// * @author Marcin Cieslak -// * @see org.lamsfoundation.lams.tool.qa.web.controller.QaAction -// */ -//@Controller -//@RequestMapping("/authoringConditions") -//public class QaAuthoringConditionController { -// -// @Autowired -// private IQaService qaService; -// -// @Autowired -// @Qualifier("qaMessageService") -// private MessageService messageService; -// -// /** -// * Display empty page for a new condition. -// * -// * @param QaConditionForm -// * @param request -// * @return -// */ -// @RequestMapping("/newConditionInit") -// private String newConditionInit(QaConditionForm QaConditionForm, HttpServletRequest request) { -// -// populateFormWithPossibleItems(QaConditionForm, request); -// QaConditionForm.setOrderId(-1); -// return "authoring/addCondition"; -// } -// -// /** -// * Display edit page for an existing condition. -// * -// * @param QaConditionForm -// * @param request -// * @return -// */ -// @RequestMapping("/editCondition") -// private String editCondition(QaConditionForm QaConditionForm, HttpServletRequest request) { -// -// String sessionMapID = QaConditionForm.getSessionMapID(); -// SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); -// -// int orderId = NumberUtils.stringToInt(request.getParameter(QaAppConstants.PARAM_ORDER_ID), -1); -// QaCondition condition = null; -// if (orderId != -1) { -// SortedSet conditionSet = getQaConditionSet(sessionMap); -// List conditionList = new ArrayList<>(conditionSet); -// condition = conditionList.get(orderId); -// if (condition != null) { -// populateConditionToForm(orderId, condition, QaConditionForm, request); -// } -// } -// -// populateFormWithPossibleItems(QaConditionForm, request); -// return condition == null ? null : "authoring/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 QaConditionForm -// * @param request -// * @return -// * @throws ServletException -// */ -// @RequestMapping(value = "/saveOrUpdateCondition", method = RequestMethod.POST) -// private String saveOrUpdateCondition(QaConditionForm QaConditionForm, HttpServletRequest request) { -// -// MultiValueMap errorMap = validateQaCondition(QaConditionForm, request); -// -// if (!errorMap.isEmpty()) { -// populateFormWithPossibleItems(QaConditionForm, request); -// request.setAttribute("errorMap", errorMap); -// return "authoring/addCondition"; -// } -// -// try { -// extractFormToQaCondition(request, QaConditionForm); -// } catch (Exception e) { -// -// errorMap.add("GLOBAL", messageService.getMessage("error.condition", new Object[] { e.getMessage() })); -// if (!errorMap.isEmpty()) { -// populateFormWithPossibleItems(QaConditionForm, request); -// request.setAttribute("errorMap", errorMap); -// return "authoring/addCondition"; -// } -// } -// -// request.setAttribute(QaAppConstants.ATTR_SESSION_MAP_ID, QaConditionForm.getSessionMapID()); -// -// return "authoring/conditionList"; -// } -// -// /** -// * 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 request -// * @return -// */ -// @RequestMapping("/removeCondition") -// private String removeCondition(HttpServletRequest request) { -// -// // get back sessionMAP -// String sessionMapID = WebUtil.readStrParam(request, QaAppConstants.ATTR_SESSION_MAP_ID); -// SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); -// -// int orderId = NumberUtils.stringToInt(request.getParameter(QaAppConstants.PARAM_ORDER_ID), -1); -// if (orderId != -1) { -// SortedSet conditionSet = getQaConditionSet(sessionMap); -// List conditionList = new ArrayList<>(conditionSet); -// QaCondition condition = conditionList.remove(orderId); -// for (QaCondition otherCondition : conditionSet) { -// if (otherCondition.getOrderId() > orderId) { -// otherCondition.setOrderId(otherCondition.getOrderId() - 1); -// } -// } -// conditionSet.clear(); -// conditionSet.addAll(conditionList); -// // add to delList -// List deletedList = getDeletedQaConditionList(sessionMap); -// deletedList.add(condition); -// } -// -// request.setAttribute(QaAppConstants.ATTR_SESSION_MAP_ID, sessionMapID); -// return "authoring/conditionList"; -// } -// -// /** -// * Move up current item. -// * -// * @param request -// * @return -// */ -// @RequestMapping("/upCondition") -// private String upCondition(HttpServletRequest request) { -// return switchItem(request, true); -// } -// -// /** -// * Move down current item. -// * -// * @param request -// * @return -// */ -// @RequestMapping("/downCondition") -// private String downCondition(HttpServletRequest request) { -// return switchItem(request, false); -// } -// -// private String switchItem(HttpServletRequest request, boolean up) { -// // get back sessionMAP -// String sessionMapID = WebUtil.readStrParam(request, QaAppConstants.ATTR_SESSION_MAP_ID); -// SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); -// -// int orderId = NumberUtils.stringToInt(request.getParameter(QaAppConstants.PARAM_ORDER_ID), -1); -// if (orderId != -1) { -// SortedSet conditionSet = getQaConditionSet(sessionMap); -// List conditionList = new ArrayList<>(conditionSet); -// // get current and the target item, and switch their sequnece -// QaCondition condition = conditionList.get(orderId); -// QaCondition 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(QaAppConstants.ATTR_SESSION_MAP_ID, sessionMapID); -// return "authoring/conditionList"; -// } -// -// // ************************************************************************************* -// // Private methods for internal needs -// // ************************************************************************************* -// -// /** -// * List save current taskList items. -// * -// * @param request -// * @return -// */ -// private SortedSet getQaConditionSet(SessionMap sessionMap) { -// SortedSet list = (SortedSet) sessionMap.get(QaAppConstants.ATTR_CONDITION_SET); -// if (list == null) { -// list = new TreeSet<>(new TextSearchConditionComparator()); -// sessionMap.put(QaAppConstants.ATTR_CONDITION_SET, list); -// } -// return list; -// } -// -// /** -// * List save current taskList items. -// * -// * @param request -// * @return -// */ -// private List getQuestionList(SessionMap sessionMap) { -// List list = (List) sessionMap.get(QaAppConstants.LIST_QUESTION_DTOS); -// if (list == null) { -// list = new LinkedList<>(); -// sessionMap.put(QaAppConstants.LIST_QUESTION_DTOS, list); -// } -// return list; -// } -// -// /** -// * Get the deleted condition list, which could be persisted or non-persisted -// * items. -// * -// * @param request -// * @return -// */ -// private List getDeletedQaConditionList(SessionMap sessionMap) { -// return getListFromSession(sessionMap, QaAppConstants.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, QaCondition condition, QaConditionForm 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) { -// QaConditionForm conditionForm = (QaConditionForm) form; -// // get back sessionMAP -// String sessionMapID = conditionForm.getSessionMapID(); -// SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); -// -// List questions = getQuestionList(sessionMap); -// -// // Initialise the LabelValueBeans in the possibleOptions array. -// LabelValueBean[] lvBeans = new LabelValueBean[questions.size()]; -// -// int i = 0; -// for (QaQuestionDTO question : questions) { -// String nonHTMLQuestion = question.getQuestion(); -// if (nonHTMLQuestion != null) { -// nonHTMLQuestion = WebUtil.removeHTMLtags(nonHTMLQuestion); -// // we don't want to cite the whole question, so we just leave some first characters; it should be enough -// // to recognise the question by a teacher -// if (nonHTMLQuestion.length() > QaAppConstants.QUESTION_CUTOFF_INDEX) { -// nonHTMLQuestion = nonHTMLQuestion.substring(0, QaAppConstants.QUESTION_CUTOFF_INDEX) + "..."; -// } -// } -// lvBeans[i++] = new LabelValueBean(nonHTMLQuestion, new Integer(question.getDisplayOrder()).toString()); -// } -// conditionForm.setPossibleItems(lvBeans); -// } -// -// /** -// * Extract form content to QaCondition. -// * -// * @param request -// * @param form -// * @throws QaException -// */ -// private void extractFormToQaCondition(HttpServletRequest request, QaConditionForm form) throws Exception { -// -// SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(form.getSessionMapID()); -// // check whether it is "edit(old item)" or "add(new item)" -// SortedSet conditionSet = getQaConditionSet(sessionMap); -// int orderId = form.getOrderId(); -// QaCondition condition = null; -// -// if (orderId == -1) { // add -// String properConditionName = qaService.createConditionName(conditionSet); -// condition = form.extractCondition(); -// condition.setName(properConditionName); -// int maxOrderId = 1; -// if (conditionSet != null && conditionSet.size() > 0) { -// QaCondition 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(); -// List questions = getQuestionList(sessionMap); -// -// condition.temporaryQuestionDTOSet.clear(); -// for (Integer selectedItem : selectedItems) { -// for (QaQuestionDTO question : questions) { -// if (selectedItem.equals(new Integer(question.getDisplayOrder()))) { -// condition.temporaryQuestionDTOSet.add(question); -// } -// } -// } -// -// } -// -// /** -// * Validate QaCondition -// * -// * @param QaConditionForm -// * @return -// */ -// private MultiValueMap validateQaCondition(QaConditionForm QaConditionForm, -// HttpServletRequest request) { -// MultiValueMap errorMap = new LinkedMultiValueMap<>(); -// -// String formConditionName = QaConditionForm.getDisplayName(); -// if (StringUtils.isBlank(formConditionName)) { -// -// errorMap.add("GLOBAL", messageService.getMessage("error.condition.name.blank")); -// } else { -// -// Integer formConditionOrderId = QaConditionForm.getOrderId(); -// -// String sessionMapID = QaConditionForm.getSessionMapID(); -// SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); -// SortedSet conditionSet = getQaConditionSet(sessionMap); -// for (QaCondition condition : conditionSet) { -// if (formConditionName.equals(condition.getDisplayName()) -// && !formConditionOrderId.equals(condition.getOrderId())) { -// -// errorMap.add("GLOBAL", messageService.getMessage("error.condition.duplicated.name")); -// break; -// } -// } -// } -// -// // should be selected at least one question -// Integer[] selectedItems = QaConditionForm.getSelectedItems(); -// if (selectedItems == null || selectedItems.length == 0) { -// errorMap.add("GLOBAL", messageService.getMessage("error.condition.no.questions.selected")); -// } -// -// return errorMap; -// } -// -//} \ No newline at end of file +/**************************************************************** + * 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.qa.web.controller; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.apache.struts.action.ActionForm; +import org.apache.struts.util.LabelValueBean; +import org.lamsfoundation.lams.learningdesign.TextSearchConditionComparator; +import org.lamsfoundation.lams.tool.qa.QaAppConstants; +import org.lamsfoundation.lams.tool.qa.QaCondition; +import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; +import org.lamsfoundation.lams.tool.qa.service.IQaService; +import org.lamsfoundation.lams.tool.qa.web.form.QaConditionForm; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; +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.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Auxiliary action in author mode. It contains operations with QaCondition. The + * rest of operations are located in QaAction action. + * + * @author Marcin Cieslak + * @see org.lamsfoundation.lams.tool.qa.web.controller.QaAction + */ +@Controller +@RequestMapping("/authoringConditions") +public class QaAuthoringConditionController { + + @Autowired + private IQaService qaService; + + @Autowired + @Qualifier("qaMessageService") + private MessageService messageService; + + /** + * Display empty page for a new condition. + * + * @param QaConditionForm + * @param request + * @return + */ + @RequestMapping("/newConditionInit") + private String newConditionInit(QaConditionForm QaConditionForm, HttpServletRequest request) { + + populateFormWithPossibleItems(QaConditionForm, request); + QaConditionForm.setOrderId(-1); + return "authoring/addCondition"; + } + + /** + * Display edit page for an existing condition. + * + * @param QaConditionForm + * @param request + * @return + */ + @RequestMapping("/editCondition") + private String editCondition(QaConditionForm QaConditionForm, HttpServletRequest request) { + + String sessionMapID = QaConditionForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int orderId = NumberUtils.stringToInt(request.getParameter(QaAppConstants.PARAM_ORDER_ID), -1); + QaCondition condition = null; + if (orderId != -1) { + SortedSet conditionSet = getQaConditionSet(sessionMap); + List conditionList = new ArrayList<>(conditionSet); + condition = conditionList.get(orderId); + if (condition != null) { + populateConditionToForm(orderId, condition, QaConditionForm, request); + } + } + + populateFormWithPossibleItems(QaConditionForm, request); + return condition == null ? null : "authoring/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 QaConditionForm + * @param request + * @return + * @throws ServletException + */ + @RequestMapping(value = "/saveOrUpdateCondition", method = RequestMethod.POST) + private String saveOrUpdateCondition(QaConditionForm QaConditionForm, HttpServletRequest request) { + + MultiValueMap errorMap = validateQaCondition(QaConditionForm, request); + + if (!errorMap.isEmpty()) { + populateFormWithPossibleItems(QaConditionForm, request); + request.setAttribute("errorMap", errorMap); + return "authoring/addCondition"; + } + + try { + extractFormToQaCondition(request, QaConditionForm); + } catch (Exception e) { + + errorMap.add("GLOBAL", messageService.getMessage("error.condition", new Object[] { e.getMessage() })); + if (!errorMap.isEmpty()) { + populateFormWithPossibleItems(QaConditionForm, request); + request.setAttribute("errorMap", errorMap); + return "authoring/addCondition"; + } + } + + request.setAttribute(QaAppConstants.ATTR_SESSION_MAP_ID, QaConditionForm.getSessionMapID()); + + return "authoring/conditionList"; + } + + /** + * 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 request + * @return + */ + @RequestMapping("/removeCondition") + private String removeCondition(HttpServletRequest request) { + + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, QaAppConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int orderId = NumberUtils.stringToInt(request.getParameter(QaAppConstants.PARAM_ORDER_ID), -1); + if (orderId != -1) { + SortedSet conditionSet = getQaConditionSet(sessionMap); + List conditionList = new ArrayList<>(conditionSet); + QaCondition condition = conditionList.remove(orderId); + for (QaCondition otherCondition : conditionSet) { + if (otherCondition.getOrderId() > orderId) { + otherCondition.setOrderId(otherCondition.getOrderId() - 1); + } + } + conditionSet.clear(); + conditionSet.addAll(conditionList); + // add to delList + List deletedList = getDeletedQaConditionList(sessionMap); + deletedList.add(condition); + } + + request.setAttribute(QaAppConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return "authoring/conditionList"; + } + + /** + * Move up current item. + * + * @param request + * @return + */ + @RequestMapping("/upCondition") + private String upCondition(HttpServletRequest request) { + return switchItem(request, true); + } + + /** + * Move down current item. + * + * @param request + * @return + */ + @RequestMapping("/downCondition") + private String downCondition(HttpServletRequest request) { + return switchItem(request, false); + } + + private String switchItem(HttpServletRequest request, boolean up) { + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, QaAppConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int orderId = NumberUtils.stringToInt(request.getParameter(QaAppConstants.PARAM_ORDER_ID), -1); + if (orderId != -1) { + SortedSet conditionSet = getQaConditionSet(sessionMap); + List conditionList = new ArrayList<>(conditionSet); + // get current and the target item, and switch their sequnece + QaCondition condition = conditionList.get(orderId); + QaCondition 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(QaAppConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return "authoring/conditionList"; + } + + // ************************************************************************************* + // Private methods for internal needs + // ************************************************************************************* + + /** + * List save current taskList items. + * + * @param request + * @return + */ + private SortedSet getQaConditionSet(SessionMap sessionMap) { + SortedSet list = (SortedSet) sessionMap.get(QaAppConstants.ATTR_CONDITION_SET); + if (list == null) { + list = new TreeSet<>(new TextSearchConditionComparator()); + sessionMap.put(QaAppConstants.ATTR_CONDITION_SET, list); + } + return list; + } + + /** + * List save current taskList items. + * + * @param request + * @return + */ + private List getQuestionList(SessionMap sessionMap) { + List list = (List) sessionMap.get(QaAppConstants.LIST_QUESTION_DTOS); + if (list == null) { + list = new LinkedList<>(); + sessionMap.put(QaAppConstants.LIST_QUESTION_DTOS, list); + } + return list; + } + + /** + * Get the deleted condition list, which could be persisted or non-persisted + * items. + * + * @param request + * @return + */ + private List getDeletedQaConditionList(SessionMap sessionMap) { + return getListFromSession(sessionMap, QaAppConstants.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, QaCondition condition, QaConditionForm 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(QaConditionForm QaConditionForm, HttpServletRequest request) { + // get back sessionMAP + String sessionMapID = QaConditionForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + List questions = getQuestionList(sessionMap); + + // Initialise the LabelValueBeans in the possibleOptions array. + LabelValueBean[] lvBeans = new LabelValueBean[questions.size()]; + + int i = 0; + for (QaQuestionDTO question : questions) { + String nonHTMLQuestion = question.getQuestion(); + if (nonHTMLQuestion != null) { + nonHTMLQuestion = WebUtil.removeHTMLtags(nonHTMLQuestion); + // we don't want to cite the whole question, so we just leave some first characters; it should be enough + // to recognise the question by a teacher + if (nonHTMLQuestion.length() > QaAppConstants.QUESTION_CUTOFF_INDEX) { + nonHTMLQuestion = nonHTMLQuestion.substring(0, QaAppConstants.QUESTION_CUTOFF_INDEX) + "..."; + } + } + lvBeans[i++] = new LabelValueBean(nonHTMLQuestion, new Integer(question.getDisplayOrder()).toString()); + } + QaConditionForm.setPossibleItems(lvBeans); + } + + /** + * Extract form content to QaCondition. + * + * @param request + * @param form + * @throws QaException + */ + private void extractFormToQaCondition(HttpServletRequest request, QaConditionForm form) throws Exception { + + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(form.getSessionMapID()); + // check whether it is "edit(old item)" or "add(new item)" + SortedSet conditionSet = getQaConditionSet(sessionMap); + int orderId = form.getOrderId(); + QaCondition condition = null; + + if (orderId == -1) { // add + String properConditionName = qaService.createConditionName(conditionSet); + condition = form.extractCondition(); + condition.setName(properConditionName); + int maxOrderId = 1; + if (conditionSet != null && conditionSet.size() > 0) { + QaCondition 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(); + List questions = getQuestionList(sessionMap); + + condition.temporaryQuestionDTOSet.clear(); + for (Integer selectedItem : selectedItems) { + for (QaQuestionDTO question : questions) { + if (selectedItem.equals(new Integer(question.getDisplayOrder()))) { + condition.temporaryQuestionDTOSet.add(question); + } + } + } + + } + + /** + * Validate QaCondition + * + * @param QaConditionForm + * @return + */ + private MultiValueMap validateQaCondition(QaConditionForm QaConditionForm, + HttpServletRequest request) { + MultiValueMap errorMap = new LinkedMultiValueMap<>(); + + String formConditionName = QaConditionForm.getDisplayName(); + if (StringUtils.isBlank(formConditionName)) { + + errorMap.add("GLOBAL", messageService.getMessage("error.condition.name.blank")); + } else { + + Integer formConditionOrderId = QaConditionForm.getOrderId(); + + String sessionMapID = QaConditionForm.getSessionMapID(); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + SortedSet conditionSet = getQaConditionSet(sessionMap); + for (QaCondition condition : conditionSet) { + if (formConditionName.equals(condition.getDisplayName()) + && !formConditionOrderId.equals(condition.getOrderId())) { + + errorMap.add("GLOBAL", messageService.getMessage("error.condition.duplicated.name")); + break; + } + } + } + + // should be selected at least one question + Integer[] selectedItems = QaConditionForm.getSelectedItems(); + if (selectedItems == null || selectedItems.length == 0) { + errorMap.add("GLOBAL", messageService.getMessage("error.condition.no.questions.selected")); + } + + return errorMap; + } + +} \ No newline at end of file Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaLearningController.java =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaLearningController.java (.../QaLearningController.java) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaLearningController.java (.../QaLearningController.java) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -1,1149 +1,1500 @@ -///*************************************************************************** -//Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) -//License Information: http://lamsfoundation.org/licensing/lams/2.0/ -// -//This program is free software; you can redistribute it and/or modify -//it under the terms of the GNU General Public License version 2 as -//published by the Free Software Foundation. -// -//This program is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. -// -//You should have received a copy of the GNU General Public License -//along with this program; if not, write to the Free Software -//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -//USA -// -//http://www.gnu.org/licenses/gpl.txt -// * ***********************************************************************/ -// -//package org.lamsfoundation.lams.tool.qa.web.controller; -// -//import java.io.IOException; -//import java.util.Date; -//import java.util.Iterator; -//import java.util.LinkedList; -//import java.util.List; -//import java.util.Map; -//import java.util.Set; -//import java.util.TimeZone; -//import java.util.TreeMap; -// -//import javax.servlet.ServletException; -//import javax.servlet.http.HttpServletRequest; -//import javax.servlet.http.HttpServletResponse; -//import javax.servlet.http.HttpSession; -// -//import org.apache.commons.lang.StringEscapeUtils; -//import org.apache.commons.lang.StringUtils; -//import org.apache.log4j.Logger; -//import org.apache.struts.Globals; -//import org.apache.struts.action.ActionForm; -//import org.lamsfoundation.lams.notebook.model.NotebookEntry; -//import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; -//import org.lamsfoundation.lams.rating.dto.ItemRatingCriteriaDTO; -//import org.lamsfoundation.lams.rating.dto.ItemRatingDTO; -//import org.lamsfoundation.lams.rating.dto.RatingCommentDTO; -//import org.lamsfoundation.lams.rating.model.LearnerItemRatingCriteria; -//import org.lamsfoundation.lams.tool.exception.ToolException; -//import org.lamsfoundation.lams.tool.qa.QaAppConstants; -//import org.lamsfoundation.lams.tool.qa.QaContent; -//import org.lamsfoundation.lams.tool.qa.QaQueContent; -//import org.lamsfoundation.lams.tool.qa.QaQueUsr; -//import org.lamsfoundation.lams.tool.qa.QaSession; -//import org.lamsfoundation.lams.tool.qa.QaUsrResp; -//import org.lamsfoundation.lams.tool.qa.dto.GeneralLearnerFlowDTO; -//import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; -//import org.lamsfoundation.lams.tool.qa.service.IQaService; -//import org.lamsfoundation.lams.tool.qa.util.LearningUtil; -//import org.lamsfoundation.lams.tool.qa.util.QaComparator; -//import org.lamsfoundation.lams.tool.qa.util.QaStringComparator; -//import org.lamsfoundation.lams.tool.qa.web.form.QaLearningForm; -//import org.lamsfoundation.lams.usermanagement.dto.UserDTO; -//import org.lamsfoundation.lams.util.DateUtil; -//import org.lamsfoundation.lams.util.MessageService; -//import org.lamsfoundation.lams.util.ValidationUtil; -//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.util.LinkedMultiValueMap; -//import org.springframework.util.MultiValueMap; -//import org.springframework.web.bind.annotation.RequestMapping; -// -//import com.fasterxml.jackson.databind.node.ArrayNode; -//import com.fasterxml.jackson.databind.node.JsonNodeFactory; -//import com.fasterxml.jackson.databind.node.ObjectNode; -// -///** -// * @author Ozgur Demirtas -// */ -//@Controller -//@RequestMapping("/learning") -//public class QaLearningController implements QaAppConstants { -// private static Logger logger = Logger.getLogger(QaLearningController.class.getName()); -// -// @Autowired -// private IQaService qaService; -// -// @Autowired -// @Qualifier("qaMessageService") -// private MessageService messageService; -// -// @RequestMapping("/") -// public String unspecified() throws IOException, ServletException, ToolException { -// QaLearningController.logger.warn("dispatching unspecified..."); -// return null; -// } -// -// /** -// * submits users responses -// * -// * @param mapping -// * @param form -// * @param request -// * @param response -// * @return -// * @throws IOException -// * @throws ServletException -// */ -// @RequestMapping("/submitAnswersContent") -// public String submitAnswersContent(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// QaContent qaContent = qaSession.getQaContent(); -// -// QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); -// //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) -// if (qaQueUsr.isResponseFinalized()) { -// String redirectURL = "redirect:/learning/learningStarter.do"; -// redirectURL = WebUtil.appendParameterToURL(redirectURL, AttributeNames.PARAM_TOOL_SESSION_ID, -// toolSessionID.toString()); -// redirectURL = WebUtil.appendParameterToURL(redirectURL, QaAppConstants.MODE, "learner"); -// return redirectURL; -// } -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// -// String totalQuestionCount = generalLearnerFlowDTO.getTotalQuestionCount().toString(); -// int intTotalQuestionCount = new Integer(totalQuestionCount).intValue(); -// -// String questionListingMode = generalLearnerFlowDTO.getQuestionListingMode(); -// -// Map mapAnswers = new TreeMap(new QaComparator()); -// Map mapAnswersPresentable = new TreeMap(new QaComparator()); -// -// String forwardName = QaAppConstants.INDIVIDUAL_LEARNER_RESULTS; -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// SessionMap sessionMap = (SessionMap) request.getSession() -// .getAttribute(httpSessionID); -// -// MultiValueMap errorMap = new LinkedMultiValueMap<>(); -// /* if the listing mode is QUESTION_LISTING_MODE_COMBINED populate the answers here */ -// if (questionListingMode.equalsIgnoreCase(QaAppConstants.QUESTION_LISTING_MODE_COMBINED)) { -// -// for (int questionIndex = QaAppConstants.INITIAL_QUESTION_COUNT -// .intValue(); questionIndex <= intTotalQuestionCount; questionIndex++) { -// // TestHarness can not send "answerX" fields, so stick to the original, unfiltered field -// boolean isTestHarness = Boolean.valueOf(request.getParameter("testHarness")); -// String answerParamName = "answer" + questionIndex + (isTestHarness ? "__textarea" : ""); -// String answer = request.getParameter(answerParamName); -// -// Integer questionIndexInteger = new Integer(questionIndex); -// mapAnswers.put(questionIndexInteger.toString(), answer); -// mapAnswersPresentable.put(questionIndexInteger.toString(), answer); -// -// //validate -// errorMap = validateQuestionAnswer(answer, questionIndexInteger, generalLearnerFlowDTO); -// -// // store -// if (errorMap.isEmpty()) { -// qaService.updateResponseWithNewAnswer(answer, toolSessionID, new Long(questionIndex), false); -// } -// } -// -// } else { -// Object[] results = storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, true); -// mapAnswers = (Map) results[0]; -// errorMap = (MultiValueMap) results[1]; -// -// mapAnswersPresentable = (Map) sessionMap.get(QaAppConstants.MAP_ALL_RESULTS_KEY); -// mapAnswersPresentable = QaLearningController.removeNewLinesMap(mapAnswersPresentable); -// } -// -// //finalize response so user won't need to edit his answers again, if coming back to the activity after leaving activity at this point -// if (errorMap.isEmpty()) { -// qaQueUsr.setResponseFinalized(true); -// qaService.updateUser(qaQueUsr); -// -// //in case of errors - prompt learner to enter answers again -// } else { -// request.setAttribute("errorMap", errorMap); -// forwardName = QaAppConstants.LOAD_LEARNER; -// } -// -// generalLearnerFlowDTO.setMapAnswers(mapAnswers); -// generalLearnerFlowDTO.setMapAnswersPresentable(mapAnswersPresentable); -// -// /* mapAnswers will be used in the viewAllAnswers screen */ -// if (sessionMap == null) { -// sessionMap = new SessionMap<>(); -// } -// -// sessionMap.put(QaAppConstants.MAP_ALL_RESULTS_KEY, mapAnswers); -// request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); -// qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); -// qaLearningForm.resetAll(); -// generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); -// -// boolean lockWhenFinished = qaContent.isLockWhenFinished(); -// generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); -// generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); -// generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); -// -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// -// // notify teachers on response submit -// if (errorMap.isEmpty() && qaContent.isNotifyTeachersOnResponseSubmit()) { -// qaService.notifyTeachersOnResponseSubmit(new Long(toolSessionID)); -// } -// -// return "learning/AnswersContent"; -// } -// -// @RequestMapping("/checkLeaderProgress") -// public String checkLeaderProgress(HttpServletRequest request, HttpServletResponse response) throws IOException { -// -// Long toolSessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); -// -// QaSession session = qaService.getSessionById(toolSessionId); -// QaQueUsr leader = session.getGroupLeader(); -// -// boolean isLeaderResponseFinalized = leader.isResponseFinalized(); -// -// ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); -// ObjectNode.put("isLeaderResponseFinalized", isLeaderResponseFinalized); -// response.setContentType("application/x-json;charset=utf-8"); -// response.getWriter().print(ObjectNode); -// return null; -// } -// -// /** -// * auto saves responses -// * -// * @param mapping -// * @param form -// * @param request -// * @param response -// * @return -// * @throws IOException -// * @throws ServletException -// */ -// @RequestMapping("/autoSaveAnswers") -// public String autoSaveAnswers(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException { -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// -// QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); -// //prohibit users from autosaving answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) -// if (qaQueUsr.isResponseFinalized()) { -// return null; -// } -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// QaContent qaContent = qaSession.getQaContent(); -// int intTotalQuestionCount = qaContent.getQaQueContents().size(); -// -// if (!qaContent.isQuestionsSequenced()) { -// -// for (int questionIndex = QaAppConstants.INITIAL_QUESTION_COUNT -// .intValue(); questionIndex <= intTotalQuestionCount; questionIndex++) { -// String newAnswer = request.getParameter("answer" + questionIndex); -// qaService.updateResponseWithNewAnswer(newAnswer, toolSessionID, new Long(questionIndex), true); -// } -// -// } else { -// String currentQuestionIndex = qaLearningForm.getCurrentQuestionIndex(); -// String newAnswer = qaLearningForm.getAnswer(); -// QaQueContent currentQuestion = qaService.getQuestionByContentAndDisplayOrder(new Long(currentQuestionIndex), -// qaContent.getUid()); -// -// boolean isRequiredQuestionMissed = currentQuestion.isRequired() && isEmpty(newAnswer); -// if (!isRequiredQuestionMissed) { -// qaService.updateResponseWithNewAnswer(newAnswer, toolSessionID, new Long(currentQuestionIndex), true); -// } -// } -// return null; -// } -// -// /** -// * enables retaking the activity -// * -// * @param mapping -// * @param form -// * @param request -// * @param response -// * @return -// * @throws IOException -// * @throws ServletException -// */ -// @RequestMapping("/redoQuestions") -// public String redoQuestions(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// QaContent qaContent = qaSession.getQaContent(); -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// -// qaLearningForm.setCurrentQuestionIndex(new Integer(1).toString()); -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// -// SessionMap sessionMap = (SessionMap) request.getSession() -// .getAttribute(httpSessionID); -// request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); -// qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); -// generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); -// generalLearnerFlowDTO.setToolContentID(qaContent.getQaContentId().toString()); -// -// // create mapQuestions -// Map mapQuestions = generalLearnerFlowDTO.getMapQuestionContentLearner(); -// generalLearnerFlowDTO.setMapQuestions(mapQuestions); -// generalLearnerFlowDTO.setTotalQuestionCount(new Integer(mapQuestions.size())); -// generalLearnerFlowDTO.setRemainingQuestionCount(new Integer(mapQuestions.size()).toString()); -// qaLearningForm.setTotalQuestionCount(new Integer(mapQuestions.size()).toString()); -// -// //in order to track whether redo button is pressed store this info -// QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); -// qaQueUsr.setResponseFinalized(false); -// qaService.updateUser(qaQueUsr); -// -// // populate answers -// LearningUtil.populateAnswers(sessionMap, qaContent, qaQueUsr, mapQuestions, generalLearnerFlowDTO, qaService); -// -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// qaLearningForm.resetAll(); -// return "learning/AnswersContent"; -// } -// -// /** -// * Stores all results and moves onto the next step. If view other users answers = true, then goes to the view all -// * answers screen, otherwise goes straight to the reflection screen (if any). -// * -// * @return Learner Report for a session -// * @throws IOException -// * @throws ServletException -// */ -// @RequestMapping("/storeAllResults") -// public String storeAllResults(QaLearningForm qaLearningForm, HttpServletRequest request, -// HttpServletResponse response) throws IOException, ServletException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// String userID = request.getParameter("userID"); -// QaQueUsr user = qaService.getUserByIdAndSession(new Long(userID), new Long(toolSessionID)); -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// QaContent qaContent = qaSession.getQaContent(); -// -// // LearningUtil.storeResponses(mapAnswers, qaService, toolContentID, new Long(toolSessionID)); -// -// qaLearningForm.resetUserActions(); -// qaLearningForm.setSubmitAnswersContent(null); -// -// if (qaContent.isShowOtherAnswers()) { -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// generalLearnerFlowDTO.setHttpSessionID(httpSessionID); -// -// /** Set up the data for the view all answers screen */ -// QaLearningController.refreshSummaryData(request, qaContent, qaSession, qaService, httpSessionID, user, -// generalLearnerFlowDTO); -// -// generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); -// generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(false).toString()); -// -// generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); -// -// qaLearningForm.resetAll(); -// -// boolean lockWhenFinished = qaContent.isLockWhenFinished(); -// generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); -// generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); -// -// boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); -// generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); -// -// boolean allowRichEditor = qaContent.isAllowRichEditor(); -// generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); -// generalLearnerFlowDTO.setUserUid(user.getQueUsrId().toString()); -// -// boolean usernameVisible = qaContent.isUsernameVisible(); -// generalLearnerFlowDTO.setUserNameVisible(new Boolean(usernameVisible).toString()); -// -// NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), -// CoreNotebookConstants.NOTEBOOK_TOOL, QaAppConstants.MY_SIGNATURE, new Integer(userID)); -// -// if (notebookEntry != null) { -// // String notebookEntryPresentable=QaUtils.replaceNewLines(notebookEntry.getEntry()); -// String notebookEntryPresentable = notebookEntry.getEntry(); -// qaLearningForm.setEntryText(notebookEntryPresentable); -// } -// -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// return "learning/LearnerRep"; -// -// } else if (qaContent.isReflect()) { -// return forwardtoReflection(request, qaContent, toolSessionID, userID, qaLearningForm); -// -// } else { -// return endLearning(qaLearningForm, request, response); -// } -// } -// -// /** -// * @param qaLearningForm -// * @param request -// * @return -// * @throws IOException -// * @throws ServletException -// */ -// @RequestMapping("/refreshAllResults") -// public String refreshAllResults(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// qaLearningForm.setToolSessionID(toolSessionID); -// -// String userID = request.getParameter("userID"); -// QaQueUsr user = qaService.getUserByIdAndSession(new Long(userID), new Long(toolSessionID)); -// -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// -// QaContent qaContent = qaSession.getQaContent(); -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// qaLearningForm.setHttpSessionID(httpSessionID); -// generalLearnerFlowDTO.setHttpSessionID(httpSessionID); -// SessionMap sessionMap = (SessionMap) request.getSession() -// .getAttribute(httpSessionID); -// -// /* recreate the users and responses */ -// qaLearningForm.resetUserActions(); -// qaLearningForm.setSubmitAnswersContent(null); -// -// QaLearningController.refreshSummaryData(request, qaContent, qaSession, qaService, httpSessionID, user, -// generalLearnerFlowDTO); -// -// generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); -// generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(false).toString()); -// -// generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); -// // generalLearnerFlowDTO.setNotebookEntriesVisible(new Boolean(false).toString()); -// -// qaLearningForm.resetAll(); -// -// boolean lockWhenFinished; -// boolean noReeditAllowed; -// if (sessionMap.get("noRefresh") != null && (boolean) sessionMap.get("noRefresh")) { -// lockWhenFinished = true; -// noReeditAllowed = true; -// } else { -// lockWhenFinished = qaContent.isLockWhenFinished(); -// noReeditAllowed = qaContent.isNoReeditAllowed(); -// } -// generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); -// generalLearnerFlowDTO.setNoReeditAllowed(noReeditAllowed); -// -// boolean allowRichEditor = qaContent.isAllowRichEditor(); -// generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); -// -// boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); -// generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); -// -// QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); -// generalLearnerFlowDTO.setUserUid(qaQueUsr.getQueUsrId().toString()); -// -// boolean usernameVisible = qaContent.isUsernameVisible(); -// generalLearnerFlowDTO.setUserNameVisible(new Boolean(usernameVisible).toString()); -// -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// -// return "learning/LearnerRep"; -// } -// -// /** -// * moves to the next question and modifies the map ActionForward -// * -// * @param qaLearningForm -// * @param request -// * @return -// * @throws IOException -// * @throws ServletException -// * @throws ToolException -// */ -// @RequestMapping("/getNextQuestion") -// public String getNextQuestion(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException, ToolException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// qaLearningForm.setToolSessionID(toolSessionID); -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// qaLearningForm.setHttpSessionID(httpSessionID); -// -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// QaContent qaContent = qaSession.getQaContent(); -// -// QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); -// //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) -// if (qaQueUsr.isResponseFinalized()) { -// String redirectURL = "redirect:learning/learningIndex.jsp"; -// redirectURL = WebUtil.appendParameterToURL(redirectURL, AttributeNames.PARAM_TOOL_SESSION_ID, -// toolSessionID.toString()); -// redirectURL = WebUtil.appendParameterToURL(redirectURL, QaAppConstants.MODE, "learner"); -// return redirectURL; -// } -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// -// storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, true); -// -// qaLearningForm.resetAll(); -// return "learning/AnswersContent"; -// } -// -// /** -// * Get the answer from the form and copy into DTO. Set up the next question. If the current question is required and -// * the answer is blank, then just persist the error and don't change questions. -// * -// * @param form -// * @param request -// * @param generalLearnerFlowDTO -// * @param getNextQuestion -// * @return -// */ -// private Object[] storeSequentialAnswer(ActionForm form, HttpServletRequest request, -// GeneralLearnerFlowDTO generalLearnerFlowDTO, boolean getNextQuestion) { -// QaLearningForm qaLearningForm = (QaLearningForm) form; -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// SessionMap sessionMap = (SessionMap) request.getSession() -// .getAttribute(httpSessionID); -// -// String currentQuestionIndex = qaLearningForm.getCurrentQuestionIndex(); -// -// Map mapAnswers = (Map) sessionMap.get(QaAppConstants.MAP_ALL_RESULTS_KEY); -// if (mapAnswers == null) { -// mapAnswers = new TreeMap(new QaComparator()); -// } -// -// String newAnswer = qaLearningForm.getAnswer(); -// Map mapSequentialAnswers = (Map) sessionMap -// .get(QaAppConstants.MAP_SEQUENTIAL_ANSWERS_KEY); -// if (mapSequentialAnswers.size() >= new Integer(currentQuestionIndex).intValue()) { -// mapSequentialAnswers.remove(new Long(currentQuestionIndex).toString()); -// } -// mapSequentialAnswers.put(new Long(currentQuestionIndex).toString(), newAnswer); -// mapAnswers.put(currentQuestionIndex, newAnswer); -// -// int nextQuestionOffset = getNextQuestion ? 1 : -1; -// -// // validation only if trying to go to the next question -// MultiValueMap errorMap = new LinkedMultiValueMap<>(); -// if (getNextQuestion) { -// errorMap = validateQuestionAnswer(newAnswer, new Integer(currentQuestionIndex), generalLearnerFlowDTO); -// } -// -// // store -// if (errorMap.isEmpty()) { -// qaService.updateResponseWithNewAnswer(newAnswer, qaLearningForm.getToolSessionID(), -// new Long(currentQuestionIndex), false); -// } else { -// request.setAttribute("errorMap", errorMap); -// nextQuestionOffset = 0; -// } -// -// int intCurrentQuestionIndex = new Integer(currentQuestionIndex).intValue() + nextQuestionOffset; -// String currentAnswer = ""; -// if (mapAnswers.size() >= intCurrentQuestionIndex) { -// currentAnswer = mapAnswers.get(new Long(intCurrentQuestionIndex).toString()); -// } -// generalLearnerFlowDTO.setCurrentAnswer(currentAnswer); -// -// // currentQuestionIndex will be: -// generalLearnerFlowDTO.setCurrentQuestionIndex(new Integer(intCurrentQuestionIndex)); -// -// String totalQuestionCount = qaLearningForm.getTotalQuestionCount(); -// -// int remainingQuestionCount = new Long(totalQuestionCount).intValue() -// - new Integer(currentQuestionIndex).intValue() + 1; -// String userFeedback = ""; -// if (remainingQuestionCount != 0) { -// userFeedback = "Remaining question count: " + remainingQuestionCount; -// } else { -// userFeedback = "End of the questions."; -// } -// generalLearnerFlowDTO.setUserFeedback(userFeedback); -// generalLearnerFlowDTO.setRemainingQuestionCount("" + remainingQuestionCount); -// -// qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ -// -// sessionMap.put(QaAppConstants.MAP_ALL_RESULTS_KEY, mapAnswers); -// sessionMap.put(QaAppConstants.MAP_SEQUENTIAL_ANSWERS_KEY, mapSequentialAnswers); -// request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); -// qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); -// generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); -// -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// -// return new Object[] { mapSequentialAnswers, errorMap }; -// } -// -// private MultiValueMap validateQuestionAnswer(String newAnswer, Integer questionIndex, -// GeneralLearnerFlowDTO generalLearnerFlowDTO) { -// MultiValueMap errorMap = new LinkedMultiValueMap<>(); -// -// Map questionMap = generalLearnerFlowDTO.getMapQuestionContentLearner(); -// QaQuestionDTO dto = questionMap.get(questionIndex); -// -// // if so, check if the answer is blank and generate an error if it is blank. -// boolean isRequiredQuestionMissed = dto.isRequired() && isEmpty(newAnswer); -// if (isRequiredQuestionMissed) { -// errorMap.add(Globals.ERROR_KEY, -// messageService.getMessage("error.required", new Object[] { questionIndex })); -// } -// -// boolean isMinWordsLimitReached = ValidationUtil.isMinWordsLimitReached(newAnswer, dto.getMinWordsLimit(), -// Boolean.parseBoolean(generalLearnerFlowDTO.getAllowRichEditor())); -// if (!isMinWordsLimitReached) { -// errorMap.add(Globals.ERROR_KEY, messageService.getMessage("label.minimum.number.words", -// ": " + new Object[] { dto.getMinWordsLimit() })); -// } -// -// return errorMap; -// } -// -// /** -// * Is this string empty? Need to strip out all HTML tags first otherwise an empty DIV might look like a valid answer -// * Smileys and math functions only put in an img tag so explicitly look for that. -// */ -// private boolean isEmpty(String answer) { -// if ((answer != null) && ((answer.indexOf(" -1) || (answer.indexOf(" -1))) { -// return false; -// } else { -// return StringUtils.isBlank(WebUtil.removeHTMLtags(answer)); -// } -// } -// -// /** -// * moves to the previous question and modifies the map ActionForward -// * -// * @param qaLearningForm -// * @param request -// * @return -// * @throws IOException -// * @throws ServletException -// * @throws ToolException -// */ -// @RequestMapping("/getPreviousQuestion") -// public String getPreviousQuestion(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException, ToolException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// qaLearningForm.setHttpSessionID(httpSessionID); -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// qaLearningForm.setToolSessionID(toolSessionID); -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// QaContent qaContent = qaSession.getQaContent(); -// -// QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); -// //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) -// if (qaQueUsr.isResponseFinalized()) { -// String redirectURL = "redirect:learning/learningIndex.jsp"; -// redirectURL = WebUtil.appendParameterToURL(redirectURL, AttributeNames.PARAM_TOOL_SESSION_ID, -// toolSessionID.toString()); -// redirectURL = WebUtil.appendParameterToURL(redirectURL, QaAppConstants.MODE, "learner"); -// return redirectURL; -// } -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// -// storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, false); -// -// qaLearningForm.resetAll(); -// return "learning/AnswersContent"; -// } -// -// /** -// * finishes the user's tool activity -// * -// * @param request -// * @param qaService -// * @param response -// * @throws IOException -// * @throws ToolException -// */ -// @RequestMapping("/endLearning") -// public String endLearning(QaLearningForm qaLearningForm, HttpServletRequest request, HttpServletResponse response) -// throws IOException, ServletException, ToolException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// qaLearningForm.setToolSessionID(toolSessionID); -// -// String userID = request.getParameter("userID"); -// qaLearningForm.setUserID(userID); -// -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// -// QaQueUsr qaQueUsr = qaService.getUserByIdAndSession(new Long(userID), qaSession.getQaSessionId()); -// qaQueUsr.setLearnerFinished(true); -// qaService.updateUser(qaQueUsr); -// -// /* -// * The learner is done with the tool session. The tool needs to clean-up. -// */ -// HttpSession ss = SessionManager.getSession(); -// /* get back login user DTO */ -// UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); -// -// qaSession.setSession_end_date(new Date(System.currentTimeMillis())); -// qaSession.setSession_status(QaAppConstants.COMPLETED); -// qaService.updateSession(qaSession); -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// // request.getSession().removeAttribute(httpSessionID); -// qaLearningForm.setHttpSessionID(httpSessionID); -// -// qaLearningForm.resetAll(); -// -// String nextActivityUrl = qaService.leaveToolSession(new Long(toolSessionID), -// new Long(user.getUserID().longValue())); -// response.sendRedirect(nextActivityUrl); -// -// return null; -// } -// -// /** -// * -// * @param qaLearningForm -// * @param request -// * @param response -// * @return -// * @throws IOException -// * @throws ServletException -// * @throws ToolException -// */ -// @RequestMapping("/submitReflection") -// public String submitReflection(QaLearningForm qaLearningForm, HttpServletRequest request, -// HttpServletResponse response) throws IOException, ServletException, ToolException { -// -// LearningUtil.saveFormRequestData(request, qaLearningForm); -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// -// qaLearningForm.setHttpSessionID(httpSessionID); -// -// String toolSessionIDString = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// qaLearningForm.setToolSessionID(toolSessionIDString); -// Long toolSessionID = new Long(toolSessionIDString); -// -// String userIDString = request.getParameter("userID"); -// qaLearningForm.setUserID(userIDString); -// Integer userID = new Integer(userIDString); -// -// String reflectionEntry = request.getParameter(QaAppConstants.ENTRY_TEXT); -// -// // check for existing notebook entry -// NotebookEntry entry = qaService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL, MY_SIGNATURE, -// userID); -// -// if (entry == null) { -// // create new entry -// qaService.createNotebookEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL, -// QaAppConstants.MY_SIGNATURE, userID, reflectionEntry); -// -// } else { -// // update existing entry -// entry.setEntry(reflectionEntry); -// entry.setLastModified(new Date()); -// qaService.updateEntry(entry); -// } -// -// qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ -// return endLearning(qaLearningForm, request, response); -// } -// -// /** -// * -// * @param qaLearningForm -// * @param request -// * @return -// * @throws IOException -// * @throws ServletException -// * @throws ToolException -// */ -// @RequestMapping("/forwardtoReflection") -// public String forwardtoReflection(QaLearningForm qaLearningForm, HttpServletRequest request) -// throws IOException, ServletException, ToolException { -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// -// qaLearningForm.setHttpSessionID(httpSessionID); -// -// String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// -// QaContent qaContent = qaSession.getQaContent(); -// -// String userID = request.getParameter("userID"); -// qaLearningForm.setUserID(userID); -// -// return forwardtoReflection(request, qaContent, toolSessionID, userID, qaLearningForm); -// } -// -// @RequestMapping("/forwardtoReflection") -// private String forwardtoReflection(HttpServletRequest request, QaContent qaContent, String toolSessionID, -// String userID, QaLearningForm qaLearningForm) { -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = new GeneralLearnerFlowDTO(); -// generalLearnerFlowDTO.setActivityTitle(qaContent.getTitle()); -// String reflectionSubject = qaContent.getReflectionSubject(); -// // reflectionSubject = QaUtils.replaceNewLines(reflectionSubject); -// generalLearnerFlowDTO.setReflectionSubject(reflectionSubject); -// -// // attempt getting notebookEntry -// NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, -// QaAppConstants.MY_SIGNATURE, new Integer(userID)); -// -// if (notebookEntry != null) { -// // String notebookEntryPresentable=QaUtils.replaceNewLines(notebookEntry.getEntry()); -// String notebookEntryPresentable = notebookEntry.getEntry(); -// generalLearnerFlowDTO.setNotebookEntry(notebookEntryPresentable); -// qaLearningForm.setEntryText(notebookEntryPresentable); -// } -// -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ -// -// qaLearningForm.resetAll(); -// return "learning/Notebook"; -// } -// -// /** -// * populates data for summary screen, view all results screen. -// * -// * User id is needed if isUserNamesVisible is false && learnerRequest is true, as it is required to work out if the -// * data being analysed is the current user. -// */ -// public static void refreshSummaryData(HttpServletRequest request, QaContent qaContent, QaSession qaSession, -// IQaService qaService, String httpSessionID, QaQueUsr user, GeneralLearnerFlowDTO generalLearnerFlowDTO) { -// -// SessionMap sessionMap = (SessionMap) request.getSession() -// .getAttribute(httpSessionID); -// Long userId = user.getQueUsrId(); -// Set questions = qaContent.getQaQueContents(); -// generalLearnerFlowDTO.setQuestions(questions); -// generalLearnerFlowDTO.setUserNameVisible(new Boolean(qaContent.isUsernameVisible()).toString()); -// -// // potentially empty list if the user starts the lesson after the time restriction has expired. -// List userResponses = qaService.getResponsesByUserUid(user.getUid()); -// -// //handle rating criterias -// int commentsMinWordsLimit = 0; -// boolean isCommentsEnabled = false; -// int countRatedQuestions = 0; -// if (qaContent.isAllowRateAnswers()) { -// -// if (userResponses.isEmpty()) { -// Set criterias = qaContent.getRatingCriterias(); -// for (LearnerItemRatingCriteria criteria : criterias) { -// if (criteria.isCommentRating()) { -// isCommentsEnabled = true; -// break; -// } -// } -// -// } else { -// // create itemIds list -// List itemIds = new LinkedList<>(); -// for (QaUsrResp responseIter : userResponses) { -// itemIds.add(responseIter.getResponseId()); -// } -// -// List itemRatingDtos = qaService.getRatingCriteriaDtos(qaContent.getQaContentId(), -// qaSession.getQaSessionId(), itemIds, true, userId); -// sessionMap.put(AttributeNames.ATTR_ITEM_RATING_DTOS, itemRatingDtos); -// -// if (itemRatingDtos.size() > 0) { -// commentsMinWordsLimit = itemRatingDtos.get(0).getCommentsMinWordsLimit(); -// isCommentsEnabled = itemRatingDtos.get(0).isCommentsEnabled(); -// } -// -// //map itemRatingDto to corresponding response -// for (QaUsrResp response : userResponses) { -// -// //find corresponding itemRatingDto -// ItemRatingDTO itemRatingDto = null; -// for (ItemRatingDTO itemRatingDtoIter : itemRatingDtos) { -// if (itemRatingDtoIter.getItemId().equals(response.getResponseId())) { -// itemRatingDto = itemRatingDtoIter; -// break; -// } -// } -// -// response.setItemRatingDto(itemRatingDto); -// } -// -// // store how many items are rated -// countRatedQuestions = qaService.getCountItemsRatedByUser(qaContent.getQaContentId(), userId.intValue()); -// } -// } -// -// request.setAttribute(TOOL_SESSION_ID, qaSession.getQaSessionId()); -// -// sessionMap.put("commentsMinWordsLimit", commentsMinWordsLimit); -// sessionMap.put("isCommentsEnabled", isCommentsEnabled); -// sessionMap.put(AttributeNames.ATTR_COUNT_RATED_ITEMS, countRatedQuestions); -// -// generalLearnerFlowDTO.setUserResponses(userResponses); -// generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); -// } -// -// /** -// * Refreshes user list. -// */ -// @RequestMapping("/getResponses") -// public String getResponses(HttpServletRequest request, HttpServletResponse res) -// throws IOException, ServletException { -// -// // teacher timezone -// HttpSession ss = SessionManager.getSession(); -// UserDTO userDto = (UserDTO) ss.getAttribute(AttributeNames.USER); -// TimeZone userTimeZone = userDto.getTimeZone(); -// -// boolean isAllowRateAnswers = WebUtil.readBooleanParam(request, "isAllowRateAnswers"); -// boolean isAllowRichEditor = WebUtil.readBooleanParam(request, "isAllowRichEditor"); -// boolean isOnlyLeadersIncluded = WebUtil.readBooleanParam(request, "isOnlyLeadersIncluded", false); -// Long qaContentId = WebUtil.readLongParam(request, "qaContentId"); -// -// Long questionUid = WebUtil.readLongParam(request, "questionUid"); -// Long qaSessionId = WebUtil.readLongParam(request, "qaSessionId"); -// -// //in case of monitoring we show all results. in case of learning - don't show results from the current user -// boolean isMonitoring = WebUtil.readBooleanParam(request, "isMonitoring", false); -// Long userId = isMonitoring ? -1 : WebUtil.readLongParam(request, "userId"); -// -// //paging parameters of tablesorter -// int size = WebUtil.readIntParam(request, "size"); -// int page = WebUtil.readIntParam(request, "page"); -// Integer sortByCol1 = WebUtil.readIntParam(request, "column[0]", true); -// Integer sortByCol2 = WebUtil.readIntParam(request, "column[1]", true); -// String searchString = request.getParameter("fcol[0]"); -// -// int sorting = QaAppConstants.SORT_BY_NO; -// if (sortByCol1 != null) { -// if (isMonitoring) { -// sorting = sortByCol1.equals(0) ? QaAppConstants.SORT_BY_USERNAME_ASC -// : QaAppConstants.SORT_BY_USERNAME_DESC; -// } else { -// sorting = sortByCol1.equals(0) ? QaAppConstants.SORT_BY_ANSWER_ASC : QaAppConstants.SORT_BY_ANSWER_DESC; -// } -// -// } else if (sortByCol2 != null) { -// sorting = sortByCol2.equals(0) ? QaAppConstants.SORT_BY_RATING_ASC : QaAppConstants.SORT_BY_RATING_DESC; -// -// } else if (!isMonitoring) { -// // Is it learner and comment only? If so sort by number of comments. -// QaSession qaSession = qaService.getSessionById(qaSessionId); -// Set criterias = qaSession.getQaContent().getRatingCriterias(); -// boolean hasComment = false; -// boolean hasRating = false; -// for (LearnerItemRatingCriteria criteria : criterias) { -// if (criteria.isCommentRating()) { -// hasComment = true; -// } else { -// hasRating = true; -// } -// } -// if (hasComment && !hasRating) { -// sorting = QaAppConstants.SORT_BY_COMMENT_COUNT; -// } -// } -// -// List responses = qaService.getResponsesForTablesorter(qaContentId, qaSessionId, questionUid, userId, -// isOnlyLeadersIncluded, page, size, sorting, searchString); -// -// ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); -// ArrayNode rows = JsonNodeFactory.instance.arrayNode(); -// -// responcedata.put("total_rows", qaService.getCountResponsesBySessionAndQuestion(qaSessionId, questionUid, userId, -// isOnlyLeadersIncluded, searchString)); -// -// // handle rating criterias - even though we may have searched on ratings earlier we can't use the average ratings -// // calculated as they may have been averages over more than one criteria. -// List itemRatingDtos = null; -// if (isAllowRateAnswers && !responses.isEmpty()) { -// //create itemIds list -// List itemIds = new LinkedList<>(); -// for (QaUsrResp response : responses) { -// itemIds.add(response.getResponseId()); -// } -// -// //all comments required only for monitoring -// boolean isCommentsByOtherUsersRequired = isMonitoring; -// itemRatingDtos = qaService.getRatingCriteriaDtos(qaContentId, qaSessionId, itemIds, -// isCommentsByOtherUsersRequired, userId); -// -// // store how many items are rated -// int countRatedQuestions = qaService.getCountItemsRatedByUser(qaContentId, userId.intValue()); -// responcedata.put(AttributeNames.ATTR_COUNT_RATED_ITEMS, countRatedQuestions); -// } -// -// for (QaUsrResp response : responses) { -// QaQueUsr user = response.getQaQueUser(); -// -// /* -// * LDEV-3891: This code has been commented out, as the escapeCsv puts double quotes in the string, which -// * goes through to the -// * client and wrecks img src entries. It appears the browser cannot process the string with all the double -// * quotes. -// * This is the second time it is being fixed - the escapeCsv was removed in LDEV-3448 and then added back in -// * when Peer Review was added (LDEV-3480). If escapeCsv needs to be added in again, make sure it does not -// * break -// * learner added images being seen in monitoring. -// * //remove leading and trailing quotes -// * String answer = StringEscapeUtils.escapeCsv(response.getAnswer()); -// * if (isAllowRichEditor && answer.startsWith("\"") && answer.length() >= 3) { -// * answer = answer.substring(1, answer.length() - 1); -// * } -// */ -// -// ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); -// responseRow.put("responseUid", response.getResponseId().toString()); -// responseRow.put("answer", response.getAnswer()); -// responseRow.put("userName", StringEscapeUtils.escapeCsv(user.getFullname())); -// responseRow.put("visible", new Boolean(response.isVisible()).toString()); -// responseRow.put("userID", user.getQueUsrId()); -// responseRow.put("portraitId", response.getPortraitId()); -// -// // format attemptTime - got straight from server time to other timezones in formatter -// // as trying to convert dates runs into tz issues - any Date object created is still -// // in the server time zone. -// Date attemptTime = response.getAttemptTime(); -// responseRow.put("attemptTime", DateUtil.convertToStringForJSON(attemptTime, request.getLocale())); -// responseRow.put("timeAgo", DateUtil.convertToStringForTimeagoJSON(attemptTime)); -// -// if (isAllowRateAnswers) { -// -// //find corresponding itemRatingDto -// ItemRatingDTO itemRatingDto = null; -// for (ItemRatingDTO itemRatingDtoIter : itemRatingDtos) { -// if (response.getResponseId().equals(itemRatingDtoIter.getItemId())) { -// itemRatingDto = itemRatingDtoIter; -// break; -// } -// } -// -// boolean isItemAuthoredByUser = response.getQaQueUser().getQueUsrId().equals(userId); -// responseRow.put("isItemAuthoredByUser", isItemAuthoredByUser); -// -// ArrayNode criteriasRows = JsonNodeFactory.instance.arrayNode(); -// for (ItemRatingCriteriaDTO criteriaDto : itemRatingDto.getCriteriaDtos()) { -// ObjectNode criteriasRow = JsonNodeFactory.instance.objectNode(); -// criteriasRow.put("ratingCriteriaId", criteriaDto.getRatingCriteria().getRatingCriteriaId()); -// criteriasRow.put("title", criteriaDto.getRatingCriteria().getTitle()); -// criteriasRow.put("averageRating", criteriaDto.getAverageRating()); -// criteriasRow.put("numberOfVotes", criteriaDto.getNumberOfVotes()); -// criteriasRow.put("userRating", criteriaDto.getUserRating()); -// -// criteriasRows.add(criteriasRow); -// } -// responseRow.set("criteriaDtos", criteriasRows); -// -// //handle comments -// responseRow.put("commentsCriteriaId", itemRatingDto.getCommentsCriteriaId()); -// String commentPostedByUser = itemRatingDto.getCommentPostedByUser() == null ? "" -// : itemRatingDto.getCommentPostedByUser().getComment(); -// responseRow.put("commentPostedByUser", commentPostedByUser); -// if (itemRatingDto.getCommentDtos() != null) { -// -// ArrayNode comments = JsonNodeFactory.instance.arrayNode(); -// for (RatingCommentDTO commentDto : itemRatingDto.getCommentDtos()) { -// ObjectNode comment = JsonNodeFactory.instance.objectNode(); -// comment.put("comment", StringEscapeUtils.escapeCsv(commentDto.getComment())); -// -// if (isMonitoring) { -// // format attemptTime -// Date postedDate = commentDto.getPostedDate(); -// postedDate = DateUtil.convertToTimeZoneFromDefault(userTimeZone, postedDate); -// comment.put("postedDate", DateUtil.convertToStringForJSON(postedDate, request.getLocale())); -// -// comment.put("userFullName", StringEscapeUtils.escapeCsv(commentDto.getUserFullName())); -// } -// -// comments.add(comment); -// } -// responseRow.set("comments", comments); -// } -// } -// -// rows.add(responseRow); -// } -// responcedata.set("rows", rows); -// -// res.setContentType("application/json;charset=utf-8"); -// res.getWriter().print(new String(responcedata.toString())); -// return null; -// } -// -// private static Map removeNewLinesMap(Map map) { -// Map newMap = new TreeMap(new QaStringComparator()); -// -// Iterator itMap = map.entrySet().iterator(); -// while (itMap.hasNext()) { -// Map.Entry pairs = (Map.Entry) itMap.next(); -// String newText = ""; -// if (pairs.getValue().toString() != null) { -// newText = pairs.getValue().toString().replaceAll("\n", "
"); -// } -// newMap.put(pairs.getKey(), newText); -// } -// return newMap; -// } -// -// private QaQueUsr getCurrentUser(String toolSessionID) { -// -// // get back login user DTO -// HttpSession ss = SessionManager.getSession(); -// UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); -// Long userId = new Long(toolUser.getUserID().longValue()); -// -// return qaService.getUserByIdAndSession(userId, new Long(toolSessionID)); -// } -// -//} +/*************************************************************************** +Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) +License Information: http://lamsfoundation.org/licensing/lams/2.0/ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +USA + +http://www.gnu.org/licenses/gpl.txt + * ***********************************************************************/ + +package org.lamsfoundation.lams.tool.qa.web.controller; + +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.TreeMap; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.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.rating.dto.ItemRatingCriteriaDTO; +import org.lamsfoundation.lams.rating.dto.ItemRatingDTO; +import org.lamsfoundation.lams.rating.dto.RatingCommentDTO; +import org.lamsfoundation.lams.rating.model.LearnerItemRatingCriteria; +import org.lamsfoundation.lams.tool.ToolAccessMode; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.qa.QaAppConstants; +import org.lamsfoundation.lams.tool.qa.QaContent; +import org.lamsfoundation.lams.tool.qa.QaQueContent; +import org.lamsfoundation.lams.tool.qa.QaQueUsr; +import org.lamsfoundation.lams.tool.qa.QaSession; +import org.lamsfoundation.lams.tool.qa.QaUsrResp; +import org.lamsfoundation.lams.tool.qa.dto.GeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; +import org.lamsfoundation.lams.tool.qa.service.IQaService; +import org.lamsfoundation.lams.tool.qa.service.QaServiceProxy; +import org.lamsfoundation.lams.tool.qa.util.LearningUtil; +import org.lamsfoundation.lams.tool.qa.util.QaApplicationException; +import org.lamsfoundation.lams.tool.qa.util.QaComparator; +import org.lamsfoundation.lams.tool.qa.util.QaStringComparator; +import org.lamsfoundation.lams.tool.qa.util.QaUtils; +import org.lamsfoundation.lams.tool.qa.web.form.QaLearningForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.ValidationUtil; +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.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * @author Ozgur Demirtas + */ +@Controller +@RequestMapping("/learning") +public class QaLearningController implements QaAppConstants { + private static Logger logger = Logger.getLogger(QaLearningController.class.getName()); + + @Autowired + private IQaService qaService; + + @Autowired + @Qualifier("qaMessageService") + private MessageService messageService; + + @RequestMapping("/") + public String unspecified() throws IOException, ServletException, ToolException { + QaLearningController.logger.warn("dispatching unspecified..."); + return null; + } + + @RequestMapping("/learning") + public String execute(QaLearningForm qaLearningForm, HttpServletRequest request) throws IOException, ServletException, QaApplicationException { + + QaUtils.cleanUpSessionAbsolute(request); + + /* validate learning mode parameters */ + validateParameters(request, qaLearningForm); + String mode = qaLearningForm.getMode(); + String toolSessionID = qaLearningForm.getToolSessionID(); + + /* + * By now, the passed tool session id MUST exist in the db by calling: + * public void createToolSession(Long toolSessionId, Long toolContentId) by the core. + * + * make sure this session exists in tool's session table by now. + */ + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + if (qaSession == null) { + QaUtils.cleanUpSessionAbsolute(request); + throw new ServletException("No session found"); + } + + QaContent qaContent = qaSession.getQaContent(); + if (qaContent == null) { + QaUtils.cleanUpSessionAbsolute(request); + throw new ServletException("No QA content found"); + } + + QaQueUsr user = null; + if ((mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())) { + // monitoring mode - user is specified in URL + // assessmentUser may be null if the user was force completed. + user = getSpecifiedUser(toolSessionID, WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID, false)); + } else { + user = getCurrentUser(toolSessionID); + } + Long userId = user.getQueUsrId(); + qaLearningForm.setUserID(user.getQueUsrId().toString()); + + QaQueUsr groupLeader = null; + if (qaContent.isUseSelectLeaderToolOuput()) { + groupLeader = qaService.checkLeaderSelectToolForSessionLeader(user, new Long(toolSessionID).longValue()); + + // forwards to the leaderSelection page + if (groupLeader == null && !mode.equals(ToolAccessMode.TEACHER.toString())) { + + List groupUsers = qaService.getUsersBySessionId(new Long(toolSessionID).longValue()); + request.setAttribute(ATTR_GROUP_USERS, groupUsers); + request.setAttribute(TOOL_SESSION_ID, toolSessionID); + request.setAttribute(ATTR_CONTENT, qaContent); + + return "learning/WaitForLeader"; + } + + // check if leader has submitted all answers + if (groupLeader.isResponseFinalized() && !mode.equals(ToolAccessMode.TEACHER.toString())) { + + // in case user joins the lesson after leader has answers some answers already - we need to make sure + // he has the same scratches as leader + qaService.copyAnswersFromLeader(user, groupLeader); + + user.setResponseFinalized(true); + qaService.updateUser(user); + } + } + + /* holds the question contents for a given tool session and relevant content */ + Map mapQuestionStrings = new TreeMap(new QaComparator()); + Map mapQuestions = new TreeMap(); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + SessionMap sessionMap = httpSessionID == null ? null + : (SessionMap) request.getSession().getAttribute(httpSessionID); + if (sessionMap == null) { + sessionMap = new SessionMap(); + Map mapSequentialAnswers = new HashMap(); + sessionMap.put(MAP_SEQUENTIAL_ANSWERS_KEY, mapSequentialAnswers); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + + sessionMap.put(AttributeNames.ATTR_LEARNER_CONTENT_FOLDER, + qaService.getLearnerContentFolder(new Long(toolSessionID), user.getQueUsrId())); + } + String sessionMapId = sessionMap.getSessionID(); + sessionMap.put(IS_DISABLED, qaContent.isLockWhenFinished() && user.isLearnerFinished() + || (mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())); + + sessionMap.put(ATTR_GROUP_LEADER, groupLeader); + boolean isUserLeader = qaService.isUserGroupLeader(user, new Long(toolSessionID)); + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + sessionMap.put(ATTR_IS_USER_LEADER, isUserLeader); + sessionMap.put(AttributeNames.ATTR_MODE, mode); + sessionMap.put(ATTR_CONTENT, qaContent); + sessionMap.put(AttributeNames.USER, user); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + generalLearnerFlowDTO.setUserUid(user.getQueUsrId().toString()); + generalLearnerFlowDTO.setHttpSessionID(sessionMapId); + generalLearnerFlowDTO.setToolSessionID(toolSessionID); + generalLearnerFlowDTO.setToolContentID(qaContent.getQaContentId().toString()); + generalLearnerFlowDTO.setReportTitleLearner(qaContent.getReportTitle()); + + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + generalLearnerFlowDTO.setReflectionSubject(qaContent.getReflectionSubject()); + + NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + MY_SIGNATURE, userId.intValue()); + if (notebookEntry != null) { + //String notebookEntryPresentable = QaUtils.replaceNewLines(notebookEntry.getEntry()); + qaLearningForm.setEntryText(notebookEntry.getEntry()); + generalLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); + } + + /* + * Is the tool activity been checked as Define Later in the property inspector? + */ + if (qaContent.isDefineLater()) { + QaUtils.cleanUpSessionAbsolute(request); + return (mapping.findForward(DEFINE_LATER)); + } + + ActivityPositionDTO activityPosition = LearningWebUtil.putActivityPositionInRequestByToolSessionId( + new Long(toolSessionID), request, getServlet().getServletContext()); + sessionMap.put(AttributeNames.ATTR_ACTIVITY_POSITION, activityPosition); + + /* + * fetch question content from content + */ + Iterator contentIterator = qaContent.getQaQueContents().iterator(); + while (contentIterator.hasNext()) { + QaQueContent qaQuestion = (QaQueContent) contentIterator.next(); + if (qaQuestion != null) { + int displayOrder = qaQuestion.getDisplayOrder(); + + if (displayOrder != 0) { + /* + * add the question to the questions Map in the displayOrder + */ + QaQuestionDTO questionDTO = new QaQuestionDTO(qaQuestion); + mapQuestions.put(displayOrder, questionDTO); + + mapQuestionStrings.put(new Integer(displayOrder).toString(), qaQuestion.getQuestion()); + + } + } + } + generalLearnerFlowDTO.setMapQuestions(mapQuestionStrings); + generalLearnerFlowDTO.setMapQuestionContentLearner(mapQuestions); + generalLearnerFlowDTO.setTotalQuestionCount(new Integer(mapQuestions.size())); + qaLearningForm.setTotalQuestionCount(new Integer(mapQuestions.size()).toString()); + + String feedBackType = ""; + if (qaContent.isQuestionsSequenced()) { + feedBackType = FEEDBACK_TYPE_SEQUENTIAL; + } else { + feedBackType = FEEDBACK_TYPE_COMBINED; + } + String userFeedback = feedBackType + generalLearnerFlowDTO.getTotalQuestionCount() + QUESTIONS; + generalLearnerFlowDTO.setUserFeedback(userFeedback); + + generalLearnerFlowDTO.setRemainingQuestionCount(generalLearnerFlowDTO.getTotalQuestionCount().toString()); + generalLearnerFlowDTO.setInitialScreen(new Boolean(true).toString()); + + request.setAttribute(GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + /* + * by now, we know that the mode is either teacher or learner + * check if the mode is teacher and request is for Learner Progress + */ + if (mode.equals("teacher")) { + //start generating learner progress report for toolSessionID + + /* + * the report should have the all entries for the users in this tool session, + * and display under the "my answers" section the answers for the user id in the url + */ +// Long learnerProgressUserId = WebUtil.readLongParam(request, AttributeNames.PARAM_USER_ID, false); + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); + generalLearnerFlowDTO.setTeacherViewOnly(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, + generalLearnerFlowDTO); + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return (mapping.findForward(LEARNER_REP)); + } + + //check if there is submission deadline + Date submissionDeadline = qaContent.getSubmissionDeadline(); + if (submissionDeadline != null) { + // store submission deadline to sessionMap + sessionMap.put(QaAppConstants.ATTR_SUBMISSION_DEADLINE, submissionDeadline); + + HttpSession ss = SessionManager.getSession(); + UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone learnerTimeZone = learnerDto.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); + Date currentLearnerDate = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, new Date()); + + // calculate whether submission deadline has passed, and if so forward to "submissionDeadline" + if (currentLearnerDate.after(tzSubmissionDeadline)) { + + //if ShowOtherAnswersAfterDeadline is enabled - show others answers + if (qaContent.isShowOtherAnswersAfterDeadline()) { + generalLearnerFlowDTO.setLockWhenFinished(Boolean.TRUE.toString()); + generalLearnerFlowDTO.setNoReeditAllowed(true); + //only for ActionForward refreshAllResults(..) method + sessionMap.put("noRefresh", true); + /* + * the report should have all the users' entries OR the report should have only the current + * session's entries + */ + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, + generalLearnerFlowDTO); + + if (user.isLearnerFinished()) { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(true).toString()); + return (mapping.findForward(REVISITED_LEARNER_REP)); + } else { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(false).toString()); + return (mapping.findForward(LEARNER_REP)); + } + + // show submissionDeadline page otherwise + } else { + return mapping.findForward("submissionDeadline"); + } + } + } + + /* + * Verify that userId does not already exist in the db. + * If it does exist and the passed tool session id exists in the db, that means the user already responded to + * the content and + * his answers must be displayed read-only + * + * if the user's tool session id AND user id exists in the tool tables go to learner's report. + */ + /* + * if the 'All Responses' has been clicked no more user entry is accepted, and isResponseFinalized() returns + * true + */ + Long currentToolSessionID = new Long(qaLearningForm.getToolSessionID()); + + //if Response is Finalized + if (user.isResponseFinalized()) { + QaSession checkSession = user.getQaSession(); + + if (checkSession != null) { + Long checkQaSessionId = checkSession.getQaSessionId(); + + if (checkQaSessionId.toString().equals(currentToolSessionID.toString())) { + + // the learner is in the same session and has already responsed to this content + + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(qaContent.isLockWhenFinished()).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + /* + * the report should have all the users' entries OR the report should have only the current + * session's entries + */ + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, + generalLearnerFlowDTO); + + if (user.isLearnerFinished()) { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(true).toString()); + return (mapping.findForward(REVISITED_LEARNER_REP)); + } else { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(false).toString()); + return (mapping.findForward(LEARNER_REP)); + } + } + } + } + + //**---- showing AnswersContent.jsp ----** + LearningUtil.populateAnswers(sessionMap, qaContent, user, mapQuestions, generalLearnerFlowDTO, qaService); + + return (mapping.findForward(LOAD_LEARNER)); + } + + /** + * validates the learning mode parameters + * + * @param request + * @param mapping + * @return ActionForward + */ + protected void validateParameters(HttpServletRequest request, + QaLearningForm qaLearningForm) { + /* + * process incoming tool session id and later derive toolContentId from it. + */ + String strToolSessionId = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + long toolSessionId = 0; + if ((strToolSessionId == null) || (strToolSessionId.length() == 0)) { + MultiValueMap errorMap = new LinkedMultiValueMap<>(); + errorMap.add(Globals.ERROR_KEY, messageService.getMessage("error.toolSessionId.required")); + logger.error("error.toolSessionId.required"); + request.setAttribute("errorMap", errorMap); + return; + } else { + try { + toolSessionId = new Long(strToolSessionId).longValue(); + qaLearningForm.setToolSessionID(new Long(toolSessionId).toString()); + } catch (NumberFormatException e) { + logger.error("add error.sessionId.numberFormatException to ActionMessages."); + return; + } + } + + /* mode can be learner, teacher or author */ + String mode = request.getParameter(MODE); + if ((mode == null) || (mode.length() == 0)) { + logger.error("Mode is empty"); + return; + } + if ((!mode.equals("learner")) && (!mode.equals("teacher")) && (!mode.equals("author"))) { + logger.error("Wrong mode"); + return; + } + qaLearningForm.setMode(mode); + } + + + private QaQueUsr getSpecifiedUser(String toolSessionId, Integer userId) { + QaQueUsr qaUser = qaService.getUserByIdAndSession(userId.longValue(), new Long(toolSessionId)); + if (qaUser == null) { + qaUser = qaService.createUser(new Long(toolSessionId), userId); + } + return qaUser; + } +// END OF STARTER + + /** + * submits users responses + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + @RequestMapping("/submitAnswersContent") + public String submitAnswersContent(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + String redirectURL = "redirect:/learning/learningStarter.do"; + redirectURL = WebUtil.appendParameterToURL(redirectURL, AttributeNames.PARAM_TOOL_SESSION_ID, + toolSessionID.toString()); + redirectURL = WebUtil.appendParameterToURL(redirectURL, QaAppConstants.MODE, "learner"); + return redirectURL; + } + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + String totalQuestionCount = generalLearnerFlowDTO.getTotalQuestionCount().toString(); + int intTotalQuestionCount = new Integer(totalQuestionCount).intValue(); + + String questionListingMode = generalLearnerFlowDTO.getQuestionListingMode(); + + Map mapAnswers = new TreeMap(new QaComparator()); + Map mapAnswersPresentable = new TreeMap(new QaComparator()); + + String forwardName = QaAppConstants.INDIVIDUAL_LEARNER_RESULTS; + + String httpSessionID = qaLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + MultiValueMap errorMap = new LinkedMultiValueMap<>(); + /* if the listing mode is QUESTION_LISTING_MODE_COMBINED populate the answers here */ + if (questionListingMode.equalsIgnoreCase(QaAppConstants.QUESTION_LISTING_MODE_COMBINED)) { + + for (int questionIndex = QaAppConstants.INITIAL_QUESTION_COUNT + .intValue(); questionIndex <= intTotalQuestionCount; questionIndex++) { + // TestHarness can not send "answerX" fields, so stick to the original, unfiltered field + boolean isTestHarness = Boolean.valueOf(request.getParameter("testHarness")); + String answerParamName = "answer" + questionIndex + (isTestHarness ? "__textarea" : ""); + String answer = request.getParameter(answerParamName); + + Integer questionIndexInteger = new Integer(questionIndex); + mapAnswers.put(questionIndexInteger.toString(), answer); + mapAnswersPresentable.put(questionIndexInteger.toString(), answer); + + //validate + errorMap = validateQuestionAnswer(answer, questionIndexInteger, generalLearnerFlowDTO); + + // store + if (errorMap.isEmpty()) { + qaService.updateResponseWithNewAnswer(answer, toolSessionID, new Long(questionIndex), false); + } + } + + } else { + Object[] results = storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, true); + mapAnswers = (Map) results[0]; + errorMap = (MultiValueMap) results[1]; + + mapAnswersPresentable = (Map) sessionMap.get(QaAppConstants.MAP_ALL_RESULTS_KEY); + mapAnswersPresentable = QaLearningController.removeNewLinesMap(mapAnswersPresentable); + } + + //finalize response so user won't need to edit his answers again, if coming back to the activity after leaving activity at this point + if (errorMap.isEmpty()) { + qaQueUsr.setResponseFinalized(true); + qaService.updateUser(qaQueUsr); + + //in case of errors - prompt learner to enter answers again + } else { + request.setAttribute("errorMap", errorMap); + forwardName = QaAppConstants.LOAD_LEARNER; + } + + generalLearnerFlowDTO.setMapAnswers(mapAnswers); + generalLearnerFlowDTO.setMapAnswersPresentable(mapAnswersPresentable); + + /* mapAnswers will be used in the viewAllAnswers screen */ + if (sessionMap == null) { + sessionMap = new SessionMap<>(); + } + + sessionMap.put(QaAppConstants.MAP_ALL_RESULTS_KEY, mapAnswers); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + qaLearningForm.resetAll(); + generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); + + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + // notify teachers on response submit + if (errorMap.isEmpty() && qaContent.isNotifyTeachersOnResponseSubmit()) { + qaService.notifyTeachersOnResponseSubmit(new Long(toolSessionID)); + } + + return "learning/AnswersContent"; + } + + @RequestMapping("/checkLeaderProgress") + public String checkLeaderProgress(HttpServletRequest request, HttpServletResponse response) throws IOException { + + Long toolSessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID); + + QaSession session = qaService.getSessionById(toolSessionId); + QaQueUsr leader = session.getGroupLeader(); + + boolean isLeaderResponseFinalized = leader.isResponseFinalized(); + + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put("isLeaderResponseFinalized", isLeaderResponseFinalized); + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(ObjectNode); + return null; + } + + /** + * auto saves responses + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + @RequestMapping("/autoSaveAnswers") + public String autoSaveAnswers(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException { + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from autosaving answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + return null; + } + + LearningUtil.saveFormRequestData(request, qaLearningForm); + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + int intTotalQuestionCount = qaContent.getQaQueContents().size(); + + if (!qaContent.isQuestionsSequenced()) { + + for (int questionIndex = QaAppConstants.INITIAL_QUESTION_COUNT + .intValue(); questionIndex <= intTotalQuestionCount; questionIndex++) { + String newAnswer = request.getParameter("answer" + questionIndex); + qaService.updateResponseWithNewAnswer(newAnswer, toolSessionID, new Long(questionIndex), true); + } + + } else { + String currentQuestionIndex = qaLearningForm.getCurrentQuestionIndex(); + String newAnswer = qaLearningForm.getAnswer(); + QaQueContent currentQuestion = qaService.getQuestionByContentAndDisplayOrder(new Long(currentQuestionIndex), + qaContent.getUid()); + + boolean isRequiredQuestionMissed = currentQuestion.isRequired() && isEmpty(newAnswer); + if (!isRequiredQuestionMissed) { + qaService.updateResponseWithNewAnswer(newAnswer, toolSessionID, new Long(currentQuestionIndex), true); + } + } + return null; + } + + /** + * enables retaking the activity + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + @RequestMapping("/redoQuestions") + public String redoQuestions(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + qaLearningForm.setCurrentQuestionIndex(new Integer(1).toString()); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); + generalLearnerFlowDTO.setToolContentID(qaContent.getQaContentId().toString()); + + // create mapQuestions + Map mapQuestions = generalLearnerFlowDTO.getMapQuestionContentLearner(); + generalLearnerFlowDTO.setMapQuestions(mapQuestions); + generalLearnerFlowDTO.setTotalQuestionCount(new Integer(mapQuestions.size())); + generalLearnerFlowDTO.setRemainingQuestionCount(new Integer(mapQuestions.size()).toString()); + qaLearningForm.setTotalQuestionCount(new Integer(mapQuestions.size()).toString()); + + //in order to track whether redo button is pressed store this info + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + qaQueUsr.setResponseFinalized(false); + qaService.updateUser(qaQueUsr); + + // populate answers + LearningUtil.populateAnswers(sessionMap, qaContent, qaQueUsr, mapQuestions, generalLearnerFlowDTO, qaService); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + qaLearningForm.resetAll(); + return "learning/AnswersContent"; + } + + /** + * Stores all results and moves onto the next step. If view other users answers = true, then goes to the view all + * answers screen, otherwise goes straight to the reflection screen (if any). + * + * @return Learner Report for a session + * @throws IOException + * @throws ServletException + */ + @RequestMapping("/storeAllResults") + public String storeAllResults(QaLearningForm qaLearningForm, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + String userID = request.getParameter("userID"); + QaQueUsr user = qaService.getUserByIdAndSession(new Long(userID), new Long(toolSessionID)); + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + // LearningUtil.storeResponses(mapAnswers, qaService, toolContentID, new Long(toolSessionID)); + + qaLearningForm.resetUserActions(); + qaLearningForm.setSubmitAnswersContent(null); + + if (qaContent.isShowOtherAnswers()) { + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + String httpSessionID = qaLearningForm.getHttpSessionID(); + generalLearnerFlowDTO.setHttpSessionID(httpSessionID); + + /** Set up the data for the view all answers screen */ + QaLearningController.refreshSummaryData(request, qaContent, qaSession, qaService, httpSessionID, user, + generalLearnerFlowDTO); + + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(false).toString()); + + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + + qaLearningForm.resetAll(); + + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + + boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); + generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); + + boolean allowRichEditor = qaContent.isAllowRichEditor(); + generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); + generalLearnerFlowDTO.setUserUid(user.getQueUsrId().toString()); + + boolean usernameVisible = qaContent.isUsernameVisible(); + generalLearnerFlowDTO.setUserNameVisible(new Boolean(usernameVisible).toString()); + + NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), + CoreNotebookConstants.NOTEBOOK_TOOL, QaAppConstants.MY_SIGNATURE, new Integer(userID)); + + if (notebookEntry != null) { + // String notebookEntryPresentable=QaUtils.replaceNewLines(notebookEntry.getEntry()); + String notebookEntryPresentable = notebookEntry.getEntry(); + qaLearningForm.setEntryText(notebookEntryPresentable); + } + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + return "learning/LearnerRep"; + + } else if (qaContent.isReflect()) { + return forwardtoReflection(request, qaContent, toolSessionID, userID, qaLearningForm); + + } else { + return endLearning(qaLearningForm, request, response); + } + } + + /** + * @param qaLearningForm + * @param request + * @return + * @throws IOException + * @throws ServletException + */ + @RequestMapping("/refreshAllResults") + public String refreshAllResults(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + QaQueUsr user = qaService.getUserByIdAndSession(new Long(userID), new Long(toolSessionID)); + + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaContent qaContent = qaSession.getQaContent(); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + qaLearningForm.setHttpSessionID(httpSessionID); + generalLearnerFlowDTO.setHttpSessionID(httpSessionID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + /* recreate the users and responses */ + qaLearningForm.resetUserActions(); + qaLearningForm.setSubmitAnswersContent(null); + + QaLearningController.refreshSummaryData(request, qaContent, qaSession, qaService, httpSessionID, user, + generalLearnerFlowDTO); + + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(false).toString()); + + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + // generalLearnerFlowDTO.setNotebookEntriesVisible(new Boolean(false).toString()); + + qaLearningForm.resetAll(); + + boolean lockWhenFinished; + boolean noReeditAllowed; + if (sessionMap.get("noRefresh") != null && (boolean) sessionMap.get("noRefresh")) { + lockWhenFinished = true; + noReeditAllowed = true; + } else { + lockWhenFinished = qaContent.isLockWhenFinished(); + noReeditAllowed = qaContent.isNoReeditAllowed(); + } + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(noReeditAllowed); + + boolean allowRichEditor = qaContent.isAllowRichEditor(); + generalLearnerFlowDTO.setAllowRichEditor(new Boolean(allowRichEditor).toString()); + + boolean useSelectLeaderToolOuput = qaContent.isUseSelectLeaderToolOuput(); + generalLearnerFlowDTO.setUseSelectLeaderToolOuput(new Boolean(useSelectLeaderToolOuput).toString()); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + generalLearnerFlowDTO.setUserUid(qaQueUsr.getQueUsrId().toString()); + + boolean usernameVisible = qaContent.isUsernameVisible(); + generalLearnerFlowDTO.setUserNameVisible(new Boolean(usernameVisible).toString()); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return "learning/LearnerRep"; + } + + /** + * moves to the next question and modifies the map ActionForward + * + * @param qaLearningForm + * @param request + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + @RequestMapping("/getNextQuestion") + public String getNextQuestion(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException, ToolException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + String httpSessionID = qaLearningForm.getHttpSessionID(); + qaLearningForm.setHttpSessionID(httpSessionID); + + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + String redirectURL = "redirect:learning/learningIndex.jsp"; + redirectURL = WebUtil.appendParameterToURL(redirectURL, AttributeNames.PARAM_TOOL_SESSION_ID, + toolSessionID.toString()); + redirectURL = WebUtil.appendParameterToURL(redirectURL, QaAppConstants.MODE, "learner"); + return redirectURL; + } + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, true); + + qaLearningForm.resetAll(); + return "learning/AnswersContent"; + } + + /** + * Get the answer from the form and copy into DTO. Set up the next question. If the current question is required and + * the answer is blank, then just persist the error and don't change questions. + * + * @param form + * @param request + * @param generalLearnerFlowDTO + * @param getNextQuestion + * @return + */ + private Object[] storeSequentialAnswer(QaLearningForm qaLearningForm, HttpServletRequest request, + GeneralLearnerFlowDTO generalLearnerFlowDTO, boolean getNextQuestion) { + String httpSessionID = qaLearningForm.getHttpSessionID(); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + + String currentQuestionIndex = qaLearningForm.getCurrentQuestionIndex(); + + Map mapAnswers = (Map) sessionMap.get(QaAppConstants.MAP_ALL_RESULTS_KEY); + if (mapAnswers == null) { + mapAnswers = new TreeMap(new QaComparator()); + } + + String newAnswer = qaLearningForm.getAnswer(); + Map mapSequentialAnswers = (Map) sessionMap + .get(QaAppConstants.MAP_SEQUENTIAL_ANSWERS_KEY); + if (mapSequentialAnswers.size() >= new Integer(currentQuestionIndex).intValue()) { + mapSequentialAnswers.remove(new Long(currentQuestionIndex).toString()); + } + mapSequentialAnswers.put(new Long(currentQuestionIndex).toString(), newAnswer); + mapAnswers.put(currentQuestionIndex, newAnswer); + + int nextQuestionOffset = getNextQuestion ? 1 : -1; + + // validation only if trying to go to the next question + MultiValueMap errorMap = new LinkedMultiValueMap<>(); + if (getNextQuestion) { + errorMap = validateQuestionAnswer(newAnswer, new Integer(currentQuestionIndex), generalLearnerFlowDTO); + } + + // store + if (errorMap.isEmpty()) { + qaService.updateResponseWithNewAnswer(newAnswer, qaLearningForm.getToolSessionID(), + new Long(currentQuestionIndex), false); + } else { + request.setAttribute("errorMap", errorMap); + nextQuestionOffset = 0; + } + + int intCurrentQuestionIndex = new Integer(currentQuestionIndex).intValue() + nextQuestionOffset; + String currentAnswer = ""; + if (mapAnswers.size() >= intCurrentQuestionIndex) { + currentAnswer = mapAnswers.get(new Long(intCurrentQuestionIndex).toString()); + } + generalLearnerFlowDTO.setCurrentAnswer(currentAnswer); + + // currentQuestionIndex will be: + generalLearnerFlowDTO.setCurrentQuestionIndex(new Integer(intCurrentQuestionIndex)); + + String totalQuestionCount = qaLearningForm.getTotalQuestionCount(); + + int remainingQuestionCount = new Long(totalQuestionCount).intValue() + - new Integer(currentQuestionIndex).intValue() + 1; + String userFeedback = ""; + if (remainingQuestionCount != 0) { + userFeedback = "Remaining question count: " + remainingQuestionCount; + } else { + userFeedback = "End of the questions."; + } + generalLearnerFlowDTO.setUserFeedback(userFeedback); + generalLearnerFlowDTO.setRemainingQuestionCount("" + remainingQuestionCount); + + qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + + sessionMap.put(QaAppConstants.MAP_ALL_RESULTS_KEY, mapAnswers); + sessionMap.put(QaAppConstants.MAP_SEQUENTIAL_ANSWERS_KEY, mapSequentialAnswers); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + generalLearnerFlowDTO.setHttpSessionID(sessionMap.getSessionID()); + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return new Object[] { mapSequentialAnswers, errorMap }; + } + + private MultiValueMap validateQuestionAnswer(String newAnswer, Integer questionIndex, + GeneralLearnerFlowDTO generalLearnerFlowDTO) { + MultiValueMap errorMap = new LinkedMultiValueMap<>(); + + Map questionMap = generalLearnerFlowDTO.getMapQuestionContentLearner(); + QaQuestionDTO dto = questionMap.get(questionIndex); + + // if so, check if the answer is blank and generate an error if it is blank. + boolean isRequiredQuestionMissed = dto.isRequired() && isEmpty(newAnswer); + if (isRequiredQuestionMissed) { + errorMap.add(Globals.ERROR_KEY, + messageService.getMessage("error.required", new Object[] { questionIndex })); + } + + boolean isMinWordsLimitReached = ValidationUtil.isMinWordsLimitReached(newAnswer, dto.getMinWordsLimit(), + Boolean.parseBoolean(generalLearnerFlowDTO.getAllowRichEditor())); + if (!isMinWordsLimitReached) { + errorMap.add(Globals.ERROR_KEY, messageService.getMessage("label.minimum.number.words", + ": " + new Object[] { dto.getMinWordsLimit() })); + } + + return errorMap; + } + + /** + * Is this string empty? Need to strip out all HTML tags first otherwise an empty DIV might look like a valid answer + * Smileys and math functions only put in an img tag so explicitly look for that. + */ + private boolean isEmpty(String answer) { + if ((answer != null) && ((answer.indexOf(" -1) || (answer.indexOf(" -1))) { + return false; + } else { + return StringUtils.isBlank(WebUtil.removeHTMLtags(answer)); + } + } + + /** + * moves to the previous question and modifies the map ActionForward + * + * @param qaLearningForm + * @param request + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + @RequestMapping("/getPreviousQuestion") + public String getPreviousQuestion(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException, ToolException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + qaLearningForm.setHttpSessionID(httpSessionID); + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + QaContent qaContent = qaSession.getQaContent(); + + QaQueUsr qaQueUsr = getCurrentUser(toolSessionID); + //prohibit users from submitting answers after response is finalized but Resubmit button is not pressed (e.g. using 2 browsers) + if (qaQueUsr.isResponseFinalized()) { + String redirectURL = "redirect:learning/learningIndex.jsp"; + redirectURL = WebUtil.appendParameterToURL(redirectURL, AttributeNames.PARAM_TOOL_SESSION_ID, + toolSessionID.toString()); + redirectURL = WebUtil.appendParameterToURL(redirectURL, QaAppConstants.MODE, "learner"); + return redirectURL; + } + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + + storeSequentialAnswer(qaLearningForm, request, generalLearnerFlowDTO, false); + + qaLearningForm.resetAll(); + return "learning/AnswersContent"; + } + + /** + * finishes the user's tool activity + * + * @param request + * @param qaService + * @param response + * @throws IOException + * @throws ToolException + */ + @RequestMapping("/endLearning") + public String endLearning(QaLearningForm qaLearningForm, HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException, ToolException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionID); + + String userID = request.getParameter("userID"); + qaLearningForm.setUserID(userID); + + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaQueUsr qaQueUsr = qaService.getUserByIdAndSession(new Long(userID), qaSession.getQaSessionId()); + qaQueUsr.setLearnerFinished(true); + qaService.updateUser(qaQueUsr); + + /* + * The learner is done with the tool session. The tool needs to clean-up. + */ + HttpSession ss = SessionManager.getSession(); + /* get back login user DTO */ + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + + qaSession.setSession_end_date(new Date(System.currentTimeMillis())); + qaSession.setSession_status(QaAppConstants.COMPLETED); + qaService.updateSession(qaSession); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + // request.getSession().removeAttribute(httpSessionID); + qaLearningForm.setHttpSessionID(httpSessionID); + + qaLearningForm.resetAll(); + + String nextActivityUrl = qaService.leaveToolSession(new Long(toolSessionID), + new Long(user.getUserID().longValue())); + response.sendRedirect(nextActivityUrl); + + return null; + } + + /** + * + * @param qaLearningForm + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + @RequestMapping("/submitReflection") + public String submitReflection(QaLearningForm qaLearningForm, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ToolException { + + LearningUtil.saveFormRequestData(request, qaLearningForm); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + qaLearningForm.setHttpSessionID(httpSessionID); + + String toolSessionIDString = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + qaLearningForm.setToolSessionID(toolSessionIDString); + Long toolSessionID = new Long(toolSessionIDString); + + String userIDString = request.getParameter("userID"); + qaLearningForm.setUserID(userIDString); + Integer userID = new Integer(userIDString); + + String reflectionEntry = request.getParameter(QaAppConstants.ENTRY_TEXT); + + // check for existing notebook entry + NotebookEntry entry = qaService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL, MY_SIGNATURE, + userID); + + if (entry == null) { + // create new entry + qaService.createNotebookEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL, + QaAppConstants.MY_SIGNATURE, userID, reflectionEntry); + + } else { + // update existing entry + entry.setEntry(reflectionEntry); + entry.setLastModified(new Date()); + qaService.updateEntry(entry); + } + + qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + return endLearning(qaLearningForm, request, response); + } + + /** + * + * @param qaLearningForm + * @param request + * @return + * @throws IOException + * @throws ServletException + * @throws ToolException + */ + @RequestMapping("/forwardtoReflection") + public String forwardtoReflection(QaLearningForm qaLearningForm, HttpServletRequest request) + throws IOException, ServletException, ToolException { + + String httpSessionID = qaLearningForm.getHttpSessionID(); + + qaLearningForm.setHttpSessionID(httpSessionID); + + String toolSessionID = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + + QaContent qaContent = qaSession.getQaContent(); + + String userID = request.getParameter("userID"); + qaLearningForm.setUserID(userID); + + return forwardtoReflection(request, qaContent, toolSessionID, userID, qaLearningForm); + } + + @RequestMapping("/forwardtoReflection") + private String forwardtoReflection(HttpServletRequest request, QaContent qaContent, String toolSessionID, + String userID, QaLearningForm qaLearningForm) { + + GeneralLearnerFlowDTO generalLearnerFlowDTO = new GeneralLearnerFlowDTO(); + generalLearnerFlowDTO.setActivityTitle(qaContent.getTitle()); + String reflectionSubject = qaContent.getReflectionSubject(); + // reflectionSubject = QaUtils.replaceNewLines(reflectionSubject); + generalLearnerFlowDTO.setReflectionSubject(reflectionSubject); + + // attempt getting notebookEntry + NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + QaAppConstants.MY_SIGNATURE, new Integer(userID)); + + if (notebookEntry != null) { + // String notebookEntryPresentable=QaUtils.replaceNewLines(notebookEntry.getEntry()); + String notebookEntryPresentable = notebookEntry.getEntry(); + generalLearnerFlowDTO.setNotebookEntry(notebookEntryPresentable); + qaLearningForm.setEntryText(notebookEntryPresentable); + } + + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + qaLearningForm.resetUserActions(); /* resets all except submitAnswersContent */ + + qaLearningForm.resetAll(); + return "learning/Notebook"; + } + + /** + * populates data for summary screen, view all results screen. + * + * User id is needed if isUserNamesVisible is false && learnerRequest is true, as it is required to work out if the + * data being analysed is the current user. + */ + public static void refreshSummaryData(HttpServletRequest request, QaContent qaContent, QaSession qaSession, + IQaService qaService, String httpSessionID, QaQueUsr user, GeneralLearnerFlowDTO generalLearnerFlowDTO) { + + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(httpSessionID); + Long userId = user.getQueUsrId(); + Set questions = qaContent.getQaQueContents(); + generalLearnerFlowDTO.setQuestions(questions); + generalLearnerFlowDTO.setUserNameVisible(new Boolean(qaContent.isUsernameVisible()).toString()); + + // potentially empty list if the user starts the lesson after the time restriction has expired. + List userResponses = qaService.getResponsesByUserUid(user.getUid()); + + //handle rating criterias + int commentsMinWordsLimit = 0; + boolean isCommentsEnabled = false; + int countRatedQuestions = 0; + if (qaContent.isAllowRateAnswers()) { + + if (userResponses.isEmpty()) { + Set criterias = qaContent.getRatingCriterias(); + for (LearnerItemRatingCriteria criteria : criterias) { + if (criteria.isCommentRating()) { + isCommentsEnabled = true; + break; + } + } + + } else { + // create itemIds list + List itemIds = new LinkedList<>(); + for (QaUsrResp responseIter : userResponses) { + itemIds.add(responseIter.getResponseId()); + } + + List itemRatingDtos = qaService.getRatingCriteriaDtos(qaContent.getQaContentId(), + qaSession.getQaSessionId(), itemIds, true, userId); + sessionMap.put(AttributeNames.ATTR_ITEM_RATING_DTOS, itemRatingDtos); + + if (itemRatingDtos.size() > 0) { + commentsMinWordsLimit = itemRatingDtos.get(0).getCommentsMinWordsLimit(); + isCommentsEnabled = itemRatingDtos.get(0).isCommentsEnabled(); + } + + //map itemRatingDto to corresponding response + for (QaUsrResp response : userResponses) { + + //find corresponding itemRatingDto + ItemRatingDTO itemRatingDto = null; + for (ItemRatingDTO itemRatingDtoIter : itemRatingDtos) { + if (itemRatingDtoIter.getItemId().equals(response.getResponseId())) { + itemRatingDto = itemRatingDtoIter; + break; + } + } + + response.setItemRatingDto(itemRatingDto); + } + + // store how many items are rated + countRatedQuestions = qaService.getCountItemsRatedByUser(qaContent.getQaContentId(), userId.intValue()); + } + } + + request.setAttribute(TOOL_SESSION_ID, qaSession.getQaSessionId()); + + sessionMap.put("commentsMinWordsLimit", commentsMinWordsLimit); + sessionMap.put("isCommentsEnabled", isCommentsEnabled); + sessionMap.put(AttributeNames.ATTR_COUNT_RATED_ITEMS, countRatedQuestions); + + generalLearnerFlowDTO.setUserResponses(userResponses); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); + } + + /** + * Refreshes user list. + */ + @RequestMapping("/getResponses") + public String getResponses(HttpServletRequest request, HttpServletResponse res) + throws IOException, ServletException { + + // teacher timezone + HttpSession ss = SessionManager.getSession(); + UserDTO userDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone userTimeZone = userDto.getTimeZone(); + + boolean isAllowRateAnswers = WebUtil.readBooleanParam(request, "isAllowRateAnswers"); + boolean isAllowRichEditor = WebUtil.readBooleanParam(request, "isAllowRichEditor"); + boolean isOnlyLeadersIncluded = WebUtil.readBooleanParam(request, "isOnlyLeadersIncluded", false); + Long qaContentId = WebUtil.readLongParam(request, "qaContentId"); + + Long questionUid = WebUtil.readLongParam(request, "questionUid"); + Long qaSessionId = WebUtil.readLongParam(request, "qaSessionId"); + + //in case of monitoring we show all results. in case of learning - don't show results from the current user + boolean isMonitoring = WebUtil.readBooleanParam(request, "isMonitoring", false); + Long userId = isMonitoring ? -1 : WebUtil.readLongParam(request, "userId"); + + //paging parameters of tablesorter + int size = WebUtil.readIntParam(request, "size"); + int page = WebUtil.readIntParam(request, "page"); + Integer sortByCol1 = WebUtil.readIntParam(request, "column[0]", true); + Integer sortByCol2 = WebUtil.readIntParam(request, "column[1]", true); + String searchString = request.getParameter("fcol[0]"); + + int sorting = QaAppConstants.SORT_BY_NO; + if (sortByCol1 != null) { + if (isMonitoring) { + sorting = sortByCol1.equals(0) ? QaAppConstants.SORT_BY_USERNAME_ASC + : QaAppConstants.SORT_BY_USERNAME_DESC; + } else { + sorting = sortByCol1.equals(0) ? QaAppConstants.SORT_BY_ANSWER_ASC : QaAppConstants.SORT_BY_ANSWER_DESC; + } + + } else if (sortByCol2 != null) { + sorting = sortByCol2.equals(0) ? QaAppConstants.SORT_BY_RATING_ASC : QaAppConstants.SORT_BY_RATING_DESC; + + } else if (!isMonitoring) { + // Is it learner and comment only? If so sort by number of comments. + QaSession qaSession = qaService.getSessionById(qaSessionId); + Set criterias = qaSession.getQaContent().getRatingCriterias(); + boolean hasComment = false; + boolean hasRating = false; + for (LearnerItemRatingCriteria criteria : criterias) { + if (criteria.isCommentRating()) { + hasComment = true; + } else { + hasRating = true; + } + } + if (hasComment && !hasRating) { + sorting = QaAppConstants.SORT_BY_COMMENT_COUNT; + } + } + + List responses = qaService.getResponsesForTablesorter(qaContentId, qaSessionId, questionUid, userId, + isOnlyLeadersIncluded, page, size, sorting, searchString); + + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + + responcedata.put("total_rows", qaService.getCountResponsesBySessionAndQuestion(qaSessionId, questionUid, userId, + isOnlyLeadersIncluded, searchString)); + + // handle rating criterias - even though we may have searched on ratings earlier we can't use the average ratings + // calculated as they may have been averages over more than one criteria. + List itemRatingDtos = null; + if (isAllowRateAnswers && !responses.isEmpty()) { + //create itemIds list + List itemIds = new LinkedList<>(); + for (QaUsrResp response : responses) { + itemIds.add(response.getResponseId()); + } + + //all comments required only for monitoring + boolean isCommentsByOtherUsersRequired = isMonitoring; + itemRatingDtos = qaService.getRatingCriteriaDtos(qaContentId, qaSessionId, itemIds, + isCommentsByOtherUsersRequired, userId); + + // store how many items are rated + int countRatedQuestions = qaService.getCountItemsRatedByUser(qaContentId, userId.intValue()); + responcedata.put(AttributeNames.ATTR_COUNT_RATED_ITEMS, countRatedQuestions); + } + + for (QaUsrResp response : responses) { + QaQueUsr user = response.getQaQueUser(); + + /* + * LDEV-3891: This code has been commented out, as the escapeCsv puts double quotes in the string, which + * goes through to the + * client and wrecks img src entries. It appears the browser cannot process the string with all the double + * quotes. + * This is the second time it is being fixed - the escapeCsv was removed in LDEV-3448 and then added back in + * when Peer Review was added (LDEV-3480). If escapeCsv needs to be added in again, make sure it does not + * break + * learner added images being seen in monitoring. + * //remove leading and trailing quotes + * String answer = StringEscapeUtils.escapeCsv(response.getAnswer()); + * if (isAllowRichEditor && answer.startsWith("\"") && answer.length() >= 3) { + * answer = answer.substring(1, answer.length() - 1); + * } + */ + + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); + responseRow.put("responseUid", response.getResponseId().toString()); + responseRow.put("answer", response.getAnswer()); + responseRow.put("userName", StringEscapeUtils.escapeCsv(user.getFullname())); + responseRow.put("visible", new Boolean(response.isVisible()).toString()); + responseRow.put("userID", user.getQueUsrId()); + responseRow.put("portraitId", response.getPortraitId()); + + // format attemptTime - got straight from server time to other timezones in formatter + // as trying to convert dates runs into tz issues - any Date object created is still + // in the server time zone. + Date attemptTime = response.getAttemptTime(); + responseRow.put("attemptTime", DateUtil.convertToStringForJSON(attemptTime, request.getLocale())); + responseRow.put("timeAgo", DateUtil.convertToStringForTimeagoJSON(attemptTime)); + + if (isAllowRateAnswers) { + + //find corresponding itemRatingDto + ItemRatingDTO itemRatingDto = null; + for (ItemRatingDTO itemRatingDtoIter : itemRatingDtos) { + if (response.getResponseId().equals(itemRatingDtoIter.getItemId())) { + itemRatingDto = itemRatingDtoIter; + break; + } + } + + boolean isItemAuthoredByUser = response.getQaQueUser().getQueUsrId().equals(userId); + responseRow.put("isItemAuthoredByUser", isItemAuthoredByUser); + + ArrayNode criteriasRows = JsonNodeFactory.instance.arrayNode(); + for (ItemRatingCriteriaDTO criteriaDto : itemRatingDto.getCriteriaDtos()) { + ObjectNode criteriasRow = JsonNodeFactory.instance.objectNode(); + criteriasRow.put("ratingCriteriaId", criteriaDto.getRatingCriteria().getRatingCriteriaId()); + criteriasRow.put("title", criteriaDto.getRatingCriteria().getTitle()); + criteriasRow.put("averageRating", criteriaDto.getAverageRating()); + criteriasRow.put("numberOfVotes", criteriaDto.getNumberOfVotes()); + criteriasRow.put("userRating", criteriaDto.getUserRating()); + + criteriasRows.add(criteriasRow); + } + responseRow.set("criteriaDtos", criteriasRows); + + //handle comments + responseRow.put("commentsCriteriaId", itemRatingDto.getCommentsCriteriaId()); + String commentPostedByUser = itemRatingDto.getCommentPostedByUser() == null ? "" + : itemRatingDto.getCommentPostedByUser().getComment(); + responseRow.put("commentPostedByUser", commentPostedByUser); + if (itemRatingDto.getCommentDtos() != null) { + + ArrayNode comments = JsonNodeFactory.instance.arrayNode(); + for (RatingCommentDTO commentDto : itemRatingDto.getCommentDtos()) { + ObjectNode comment = JsonNodeFactory.instance.objectNode(); + comment.put("comment", StringEscapeUtils.escapeCsv(commentDto.getComment())); + + if (isMonitoring) { + // format attemptTime + Date postedDate = commentDto.getPostedDate(); + postedDate = DateUtil.convertToTimeZoneFromDefault(userTimeZone, postedDate); + comment.put("postedDate", DateUtil.convertToStringForJSON(postedDate, request.getLocale())); + + comment.put("userFullName", StringEscapeUtils.escapeCsv(commentDto.getUserFullName())); + } + + comments.add(comment); + } + responseRow.set("comments", comments); + } + } + + rows.add(responseRow); + } + responcedata.set("rows", rows); + + res.setContentType("application/json;charset=utf-8"); + res.getWriter().print(new String(responcedata.toString())); + return null; + } + + private static Map removeNewLinesMap(Map map) { + Map newMap = new TreeMap(new QaStringComparator()); + + Iterator itMap = map.entrySet().iterator(); + while (itMap.hasNext()) { + Map.Entry pairs = (Map.Entry) itMap.next(); + String newText = ""; + if (pairs.getValue().toString() != null) { + newText = pairs.getValue().toString().replaceAll("\n", "
"); + } + newMap.put(pairs.getKey(), newText); + } + return newMap; + } + + private QaQueUsr getCurrentUser(String toolSessionID) { + + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Long userId = new Long(toolUser.getUserID().longValue()); + + return qaService.getUserByIdAndSession(userId, new Long(toolSessionID)); + } + +} Index: lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaLearningStarterController.java =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaLearningStarterController.java (.../QaLearningStarterController.java) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_laqa/src/java/org/lamsfoundation/lams/tool/qa/web/controller/QaLearningStarterController.java (.../QaLearningStarterController.java) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -1,457 +1,458 @@ -///**************************************************************** -// * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) -// * ============================================================= -// * License Information: http://lamsfoundation.org/licensing/lams/2.0/ -// * -// * This program is free software; you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program; if not, write to the Free Software -// * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -// * USA -// * -// * http://www.gnu.org/licenses/gpl.txt -// * **************************************************************** -// */ -// -// -//package org.lamsfoundation.lams.tool.qa.web.controller; -// -//import java.io.IOException; -//import java.util.Date; -//import java.util.HashMap; -//import java.util.Iterator; -//import java.util.List; -//import java.util.Map; -//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.log4j.Logger; -//import org.apache.struts.Globals; -//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.apache.struts.action.ActionMessages; -//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.qa.QaAppConstants; -//import org.lamsfoundation.lams.tool.qa.QaContent; -//import org.lamsfoundation.lams.tool.qa.QaQueContent; -//import org.lamsfoundation.lams.tool.qa.QaQueUsr; -//import org.lamsfoundation.lams.tool.qa.QaSession; -//import org.lamsfoundation.lams.tool.qa.dto.GeneralLearnerFlowDTO; -//import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; -//import org.lamsfoundation.lams.tool.qa.service.IQaService; -//import org.lamsfoundation.lams.tool.qa.service.QaServiceProxy; -//import org.lamsfoundation.lams.tool.qa.util.LearningUtil; -//import org.lamsfoundation.lams.tool.qa.util.QaApplicationException; -//import org.lamsfoundation.lams.tool.qa.util.QaComparator; -//import org.lamsfoundation.lams.tool.qa.util.QaUtils; -//import org.lamsfoundation.lams.tool.qa.web.form.QaLearningForm; -//import org.lamsfoundation.lams.usermanagement.dto.UserDTO; -//import org.lamsfoundation.lams.util.DateUtil; -//import org.lamsfoundation.lams.util.MessageService; -//import org.lamsfoundation.lams.util.WebUtil; -//import org.lamsfoundation.lams.web.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.web.bind.annotation.RequestMapping; -// -///** -// * This class is used to load the default content and initialize the presentation Map for Learner mode. -// * It is important that ALL the session attributes created in this action gets removed by: -// * QaUtils.cleanupSession(request) -// * -// * @author Ozgur Demirtas -// * -// */ -//@Controller -//@RequestMapping("/learningStarter") -//public class QaLearningStarterController implements QaAppConstants { -// private static Logger logger = Logger.getLogger(QaLearningStarterController.class.getName()); -// -// @Autowired -// private IQaService qaService; -// -// @Autowired -// @Qualifier("qaMessageService") -// private MessageService messageService; -// -// @Override -// public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, -// HttpServletResponse response) throws IOException, ServletException, QaApplicationException { -// -// QaUtils.cleanUpSessionAbsolute(request); -// if (qaService == null) { -// qaService = QaServiceProxy.getQaService(getServlet().getServletContext()); -// } -// -// QaLearningForm qaLearningForm = (QaLearningForm) form; -// /* validate learning mode parameters */ -// validateParameters(request, mapping, qaLearningForm); -// String mode = qaLearningForm.getMode(); -// String toolSessionID = qaLearningForm.getToolSessionID(); -// -// /* -// * By now, the passed tool session id MUST exist in the db by calling: -// * public void createToolSession(Long toolSessionId, Long toolContentId) by the core. -// * -// * make sure this session exists in tool's session table by now. -// */ -// QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); -// if (qaSession == null) { -// QaUtils.cleanUpSessionAbsolute(request); -// throw new ServletException("No session found"); -// } -// -// QaContent qaContent = qaSession.getQaContent(); -// if (qaContent == null) { -// QaUtils.cleanUpSessionAbsolute(request); -// throw new ServletException("No QA content found"); -// } -// -// QaQueUsr user = null; -// if ((mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())) { -// // monitoring mode - user is specified in URL -// // assessmentUser may be null if the user was force completed. -// user = getSpecifiedUser(toolSessionID, WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID, false)); -// } else { -// user = getCurrentUser(toolSessionID); -// } -// Long userId = user.getQueUsrId(); -// qaLearningForm.setUserID(user.getQueUsrId().toString()); -// -// QaQueUsr groupLeader = null; -// if (qaContent.isUseSelectLeaderToolOuput()) { -// groupLeader = qaService.checkLeaderSelectToolForSessionLeader(user, new Long(toolSessionID).longValue()); -// -// // forwards to the leaderSelection page -// if (groupLeader == null && !mode.equals(ToolAccessMode.TEACHER.toString())) { -// -// List groupUsers = qaService.getUsersBySessionId(new Long(toolSessionID).longValue()); -// request.setAttribute(ATTR_GROUP_USERS, groupUsers); -// request.setAttribute(TOOL_SESSION_ID, toolSessionID); -// request.setAttribute(ATTR_CONTENT, qaContent); -// -// return mapping.findForward(WAIT_FOR_LEADER); -// } -// -// // check if leader has submitted all answers -// if (groupLeader.isResponseFinalized() && !mode.equals(ToolAccessMode.TEACHER.toString())) { -// -// // in case user joins the lesson after leader has answers some answers already - we need to make sure -// // he has the same scratches as leader -// qaService.copyAnswersFromLeader(user, groupLeader); -// -// user.setResponseFinalized(true); -// qaService.updateUser(user); -// } -// } -// -// /* holds the question contents for a given tool session and relevant content */ -// Map mapQuestionStrings = new TreeMap(new QaComparator()); -// Map mapQuestions = new TreeMap(); -// -// String httpSessionID = qaLearningForm.getHttpSessionID(); -// SessionMap sessionMap = httpSessionID == null ? null -// : (SessionMap) request.getSession().getAttribute(httpSessionID); -// if (sessionMap == null) { -// sessionMap = new SessionMap(); -// Map mapSequentialAnswers = new HashMap(); -// sessionMap.put(MAP_SEQUENTIAL_ANSWERS_KEY, mapSequentialAnswers); -// request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); -// qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); -// -// sessionMap.put(AttributeNames.ATTR_LEARNER_CONTENT_FOLDER, -// qaService.getLearnerContentFolder(new Long(toolSessionID), user.getQueUsrId())); -// } -// String sessionMapId = sessionMap.getSessionID(); -// sessionMap.put(IS_DISABLED, qaContent.isLockWhenFinished() && user.isLearnerFinished() -// || (mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())); -// -// sessionMap.put(ATTR_GROUP_LEADER, groupLeader); -// boolean isUserLeader = qaService.isUserGroupLeader(user, new Long(toolSessionID)); -// boolean lockWhenFinished = qaContent.isLockWhenFinished(); -// sessionMap.put(ATTR_IS_USER_LEADER, isUserLeader); -// sessionMap.put(AttributeNames.ATTR_MODE, mode); -// sessionMap.put(ATTR_CONTENT, qaContent); -// sessionMap.put(AttributeNames.USER, user); -// -// GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); -// generalLearnerFlowDTO.setUserUid(user.getQueUsrId().toString()); -// generalLearnerFlowDTO.setHttpSessionID(sessionMapId); -// generalLearnerFlowDTO.setToolSessionID(toolSessionID); -// generalLearnerFlowDTO.setToolContentID(qaContent.getQaContentId().toString()); -// generalLearnerFlowDTO.setReportTitleLearner(qaContent.getReportTitle()); -// -// generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); -// generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); -// generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); -// generalLearnerFlowDTO.setReflectionSubject(qaContent.getReflectionSubject()); -// -// NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, -// MY_SIGNATURE, userId.intValue()); -// if (notebookEntry != null) { -// //String notebookEntryPresentable = QaUtils.replaceNewLines(notebookEntry.getEntry()); -// qaLearningForm.setEntryText(notebookEntry.getEntry()); -// generalLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); -// } -// -// /* -// * Is the tool activity been checked as Define Later in the property inspector? -// */ -// if (qaContent.isDefineLater()) { -// QaUtils.cleanUpSessionAbsolute(request); -// return (mapping.findForward(DEFINE_LATER)); -// } -// -// ActivityPositionDTO activityPosition = LearningWebUtil.putActivityPositionInRequestByToolSessionId( -// new Long(toolSessionID), request, getServlet().getServletContext()); -// sessionMap.put(AttributeNames.ATTR_ACTIVITY_POSITION, activityPosition); -// -// /* -// * fetch question content from content -// */ -// Iterator contentIterator = qaContent.getQaQueContents().iterator(); -// while (contentIterator.hasNext()) { -// QaQueContent qaQuestion = (QaQueContent) contentIterator.next(); -// if (qaQuestion != null) { -// int displayOrder = qaQuestion.getDisplayOrder(); -// -// if (displayOrder != 0) { -// /* -// * add the question to the questions Map in the displayOrder -// */ -// QaQuestionDTO questionDTO = new QaQuestionDTO(qaQuestion); -// mapQuestions.put(displayOrder, questionDTO); -// -// mapQuestionStrings.put(new Integer(displayOrder).toString(), qaQuestion.getQuestion()); -// -// } -// } -// } -// generalLearnerFlowDTO.setMapQuestions(mapQuestionStrings); -// generalLearnerFlowDTO.setMapQuestionContentLearner(mapQuestions); -// generalLearnerFlowDTO.setTotalQuestionCount(new Integer(mapQuestions.size())); -// qaLearningForm.setTotalQuestionCount(new Integer(mapQuestions.size()).toString()); -// -// String feedBackType = ""; -// if (qaContent.isQuestionsSequenced()) { -// feedBackType = FEEDBACK_TYPE_SEQUENTIAL; -// } else { -// feedBackType = FEEDBACK_TYPE_COMBINED; -// } -// String userFeedback = feedBackType + generalLearnerFlowDTO.getTotalQuestionCount() + QUESTIONS; -// generalLearnerFlowDTO.setUserFeedback(userFeedback); -// -// generalLearnerFlowDTO.setRemainingQuestionCount(generalLearnerFlowDTO.getTotalQuestionCount().toString()); -// generalLearnerFlowDTO.setInitialScreen(new Boolean(true).toString()); -// -// request.setAttribute(GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// -// /* -// * by now, we know that the mode is either teacher or learner -// * check if the mode is teacher and request is for Learner Progress -// */ -// if (mode.equals("teacher")) { -// //start generating learner progress report for toolSessionID -// -// /* -// * the report should have the all entries for the users in this tool session, -// * and display under the "my answers" section the answers for the user id in the url -// */ -//// Long learnerProgressUserId = WebUtil.readLongParam(request, AttributeNames.PARAM_USER_ID, false); -// generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); -// generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); -// generalLearnerFlowDTO.setTeacherViewOnly(new Boolean(true).toString()); -// -// QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, -// generalLearnerFlowDTO); -// request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); -// -// return (mapping.findForward(LEARNER_REP)); -// } -// -// //check if there is submission deadline -// Date submissionDeadline = qaContent.getSubmissionDeadline(); -// if (submissionDeadline != null) { -// // store submission deadline to sessionMap -// sessionMap.put(QaAppConstants.ATTR_SUBMISSION_DEADLINE, submissionDeadline); -// -// HttpSession ss = SessionManager.getSession(); -// UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); -// TimeZone learnerTimeZone = learnerDto.getTimeZone(); -// Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); -// Date currentLearnerDate = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, new Date()); -// -// // calculate whether submission deadline has passed, and if so forward to "submissionDeadline" -// if (currentLearnerDate.after(tzSubmissionDeadline)) { -// -// //if ShowOtherAnswersAfterDeadline is enabled - show others answers -// if (qaContent.isShowOtherAnswersAfterDeadline()) { -// generalLearnerFlowDTO.setLockWhenFinished(Boolean.TRUE.toString()); -// generalLearnerFlowDTO.setNoReeditAllowed(true); -// //only for ActionForward refreshAllResults(..) method -// sessionMap.put("noRefresh", true); -// /* -// * the report should have all the users' entries OR the report should have only the current -// * session's entries -// */ -// generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); -// -// QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, -// generalLearnerFlowDTO); -// -// if (user.isLearnerFinished()) { -// generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(true).toString()); -// return (mapping.findForward(REVISITED_LEARNER_REP)); -// } else { -// generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(false).toString()); -// return (mapping.findForward(LEARNER_REP)); -// } -// -// // show submissionDeadline page otherwise -// } else { -// return mapping.findForward("submissionDeadline"); -// } -// } -// } -// -// /* -// * Verify that userId does not already exist in the db. -// * If it does exist and the passed tool session id exists in the db, that means the user already responded to -// * the content and -// * his answers must be displayed read-only -// * -// * if the user's tool session id AND user id exists in the tool tables go to learner's report. -// */ -// /* -// * if the 'All Responses' has been clicked no more user entry is accepted, and isResponseFinalized() returns -// * true -// */ -// Long currentToolSessionID = new Long(qaLearningForm.getToolSessionID()); -// -// //if Response is Finalized -// if (user.isResponseFinalized()) { -// QaSession checkSession = user.getQaSession(); -// -// if (checkSession != null) { -// Long checkQaSessionId = checkSession.getQaSessionId(); -// -// if (checkQaSessionId.toString().equals(currentToolSessionID.toString())) { -// -// // the learner is in the same session and has already responsed to this content -// -// generalLearnerFlowDTO.setLockWhenFinished(new Boolean(qaContent.isLockWhenFinished()).toString()); -// generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); -// /* -// * the report should have all the users' entries OR the report should have only the current -// * session's entries -// */ -// generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); -// -// QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, -// generalLearnerFlowDTO); -// -// if (user.isLearnerFinished()) { -// generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(true).toString()); -// return (mapping.findForward(REVISITED_LEARNER_REP)); -// } else { -// generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(false).toString()); -// return (mapping.findForward(LEARNER_REP)); -// } -// } -// } -// } -// -// //**---- showing AnswersContent.jsp ----** -// LearningUtil.populateAnswers(sessionMap, qaContent, user, mapQuestions, generalLearnerFlowDTO, qaService); -// -// return (mapping.findForward(LOAD_LEARNER)); -// } -// -// /** -// * validates the learning mode parameters -// * -// * @param request -// * @param mapping -// * @return ActionForward -// */ -// protected void validateParameters(HttpServletRequest request, ActionMapping mapping, -// QaLearningForm qaLearningForm) { -// /* -// * process incoming tool session id and later derive toolContentId from it. -// */ -// String strToolSessionId = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); -// long toolSessionId = 0; -// if ((strToolSessionId == null) || (strToolSessionId.length() == 0)) { -// ActionMessages errors = new ActionMessages(); -// errors.add(Globals.ERROR_KEY, new ActionMessage("error.toolSessionId.required")); -// logger.error("error.toolSessionId.required"); -// saveErrors(request, errors); -// return; -// } else { -// try { -// toolSessionId = new Long(strToolSessionId).longValue(); -// qaLearningForm.setToolSessionID(new Long(toolSessionId).toString()); -// } catch (NumberFormatException e) { -// logger.error("add error.sessionId.numberFormatException to ActionMessages."); -// return; -// } -// } -// -// /* mode can be learner, teacher or author */ -// String mode = request.getParameter(MODE); -// if ((mode == null) || (mode.length() == 0)) { -// logger.error("Mode is empty"); -// return; -// } -// if ((!mode.equals("learner")) && (!mode.equals("teacher")) && (!mode.equals("author"))) { -// logger.error("Wrong mode"); -// return; -// } -// qaLearningForm.setMode(mode); -// } -// -// private QaQueUsr getCurrentUser(String toolSessionId) { -// // get back login user DTO -// HttpSession ss = SessionManager.getSession(); -// UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); -// Integer userId = toolUser.getUserID(); -// -// QaQueUsr qaUser = qaService.getUserByIdAndSession(userId.longValue(), new Long(toolSessionId)); -// if (qaUser == null) { -// qaUser = qaService.createUser(new Long(toolSessionId), userId); -// } -// -// return qaUser; -// } -// -// private QaQueUsr getSpecifiedUser(String toolSessionId, Integer userId) { -// QaQueUsr qaUser = qaService.getUserByIdAndSession(userId.longValue(), new Long(toolSessionId)); -// if (qaUser == null) { -// qaUser = qaService.createUser(new Long(toolSessionId), userId); -// } -// return qaUser; -// } -//} \ No newline at end of file +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + + +package org.lamsfoundation.lams.tool.qa.web.controller; + +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +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.log4j.Logger; +import org.apache.struts.Globals; +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.apache.struts.action.ActionMessages; +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.qa.QaAppConstants; +import org.lamsfoundation.lams.tool.qa.QaContent; +import org.lamsfoundation.lams.tool.qa.QaQueContent; +import org.lamsfoundation.lams.tool.qa.QaQueUsr; +import org.lamsfoundation.lams.tool.qa.QaSession; +import org.lamsfoundation.lams.tool.qa.dto.GeneralLearnerFlowDTO; +import org.lamsfoundation.lams.tool.qa.dto.QaQuestionDTO; +import org.lamsfoundation.lams.tool.qa.service.IQaService; +import org.lamsfoundation.lams.tool.qa.service.QaServiceProxy; +import org.lamsfoundation.lams.tool.qa.util.LearningUtil; +import org.lamsfoundation.lams.tool.qa.util.QaApplicationException; +import org.lamsfoundation.lams.tool.qa.util.QaComparator; +import org.lamsfoundation.lams.tool.qa.util.QaUtils; +import org.lamsfoundation.lams.tool.qa.web.form.QaLearningForm; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.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.web.bind.annotation.RequestMapping; + +/** + * This class is used to load the default content and initialize the presentation Map for Learner mode. + * It is important that ALL the session attributes created in this action gets removed by: + * QaUtils.cleanupSession(request) + * + * @author Ozgur Demirtas + * + */ +@Controller +@RequestMapping("/learningStarter") +public class QaLearningStarterController implements QaAppConstants { + private static Logger logger = Logger.getLogger(QaLearningStarterController.class.getName()); + + @Autowired + private IQaService qaService; + + @Autowired + @Qualifier("qaMessageService") + private MessageService messageService; + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, QaApplicationException { + + QaUtils.cleanUpSessionAbsolute(request); + if (qaService == null) { + qaService = QaServiceProxy.getQaService(getServlet().getServletContext()); + } + + QaLearningForm qaLearningForm = (QaLearningForm) form; + /* validate learning mode parameters */ + validateParameters(request, mapping, qaLearningForm); + String mode = qaLearningForm.getMode(); + String toolSessionID = qaLearningForm.getToolSessionID(); + + /* + * By now, the passed tool session id MUST exist in the db by calling: + * public void createToolSession(Long toolSessionId, Long toolContentId) by the core. + * + * make sure this session exists in tool's session table by now. + */ + QaSession qaSession = qaService.getSessionById(new Long(toolSessionID).longValue()); + if (qaSession == null) { + QaUtils.cleanUpSessionAbsolute(request); + throw new ServletException("No session found"); + } + + QaContent qaContent = qaSession.getQaContent(); + if (qaContent == null) { + QaUtils.cleanUpSessionAbsolute(request); + throw new ServletException("No QA content found"); + } + + QaQueUsr user = null; + if ((mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())) { + // monitoring mode - user is specified in URL + // assessmentUser may be null if the user was force completed. + user = getSpecifiedUser(toolSessionID, WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID, false)); + } else { + user = getCurrentUser(toolSessionID); + } + Long userId = user.getQueUsrId(); + qaLearningForm.setUserID(user.getQueUsrId().toString()); + + QaQueUsr groupLeader = null; + if (qaContent.isUseSelectLeaderToolOuput()) { + groupLeader = qaService.checkLeaderSelectToolForSessionLeader(user, new Long(toolSessionID).longValue()); + + // forwards to the leaderSelection page + if (groupLeader == null && !mode.equals(ToolAccessMode.TEACHER.toString())) { + + List groupUsers = qaService.getUsersBySessionId(new Long(toolSessionID).longValue()); + request.setAttribute(ATTR_GROUP_USERS, groupUsers); + request.setAttribute(TOOL_SESSION_ID, toolSessionID); + request.setAttribute(ATTR_CONTENT, qaContent); + + return mapping.findForward(WAIT_FOR_LEADER); + } + + // check if leader has submitted all answers + if (groupLeader.isResponseFinalized() && !mode.equals(ToolAccessMode.TEACHER.toString())) { + + // in case user joins the lesson after leader has answers some answers already - we need to make sure + // he has the same scratches as leader + qaService.copyAnswersFromLeader(user, groupLeader); + + user.setResponseFinalized(true); + qaService.updateUser(user); + } + } + + /* holds the question contents for a given tool session and relevant content */ + Map mapQuestionStrings = new TreeMap(new QaComparator()); + Map mapQuestions = new TreeMap(); + + String httpSessionID = qaLearningForm.getHttpSessionID(); + SessionMap sessionMap = httpSessionID == null ? null + : (SessionMap) request.getSession().getAttribute(httpSessionID); + if (sessionMap == null) { + sessionMap = new SessionMap(); + Map mapSequentialAnswers = new HashMap(); + sessionMap.put(MAP_SEQUENTIAL_ANSWERS_KEY, mapSequentialAnswers); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + qaLearningForm.setHttpSessionID(sessionMap.getSessionID()); + + sessionMap.put(AttributeNames.ATTR_LEARNER_CONTENT_FOLDER, + qaService.getLearnerContentFolder(new Long(toolSessionID), user.getQueUsrId())); + } + String sessionMapId = sessionMap.getSessionID(); + sessionMap.put(IS_DISABLED, qaContent.isLockWhenFinished() && user.isLearnerFinished() + || (mode != null) && mode.equals(ToolAccessMode.TEACHER.toString())); + + sessionMap.put(ATTR_GROUP_LEADER, groupLeader); + boolean isUserLeader = qaService.isUserGroupLeader(user, new Long(toolSessionID)); + boolean lockWhenFinished = qaContent.isLockWhenFinished(); + sessionMap.put(ATTR_IS_USER_LEADER, isUserLeader); + sessionMap.put(AttributeNames.ATTR_MODE, mode); + sessionMap.put(ATTR_CONTENT, qaContent); + sessionMap.put(AttributeNames.USER, user); + + GeneralLearnerFlowDTO generalLearnerFlowDTO = LearningUtil.buildGeneralLearnerFlowDTO(qaService, qaContent); + generalLearnerFlowDTO.setUserUid(user.getQueUsrId().toString()); + generalLearnerFlowDTO.setHttpSessionID(sessionMapId); + generalLearnerFlowDTO.setToolSessionID(toolSessionID); + generalLearnerFlowDTO.setToolContentID(qaContent.getQaContentId().toString()); + generalLearnerFlowDTO.setReportTitleLearner(qaContent.getReportTitle()); + + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(lockWhenFinished).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + generalLearnerFlowDTO.setReflection(new Boolean(qaContent.isReflect()).toString()); + generalLearnerFlowDTO.setReflectionSubject(qaContent.getReflectionSubject()); + + NotebookEntry notebookEntry = qaService.getEntry(new Long(toolSessionID), CoreNotebookConstants.NOTEBOOK_TOOL, + MY_SIGNATURE, userId.intValue()); + if (notebookEntry != null) { + //String notebookEntryPresentable = QaUtils.replaceNewLines(notebookEntry.getEntry()); + qaLearningForm.setEntryText(notebookEntry.getEntry()); + generalLearnerFlowDTO.setNotebookEntry(notebookEntry.getEntry()); + } + + /* + * Is the tool activity been checked as Define Later in the property inspector? + */ + if (qaContent.isDefineLater()) { + QaUtils.cleanUpSessionAbsolute(request); + return (mapping.findForward(DEFINE_LATER)); + } + + ActivityPositionDTO activityPosition = LearningWebUtil.putActivityPositionInRequestByToolSessionId( + new Long(toolSessionID), request, getServlet().getServletContext()); + sessionMap.put(AttributeNames.ATTR_ACTIVITY_POSITION, activityPosition); + + /* + * fetch question content from content + */ + Iterator contentIterator = qaContent.getQaQueContents().iterator(); + while (contentIterator.hasNext()) { + QaQueContent qaQuestion = (QaQueContent) contentIterator.next(); + if (qaQuestion != null) { + int displayOrder = qaQuestion.getDisplayOrder(); + + if (displayOrder != 0) { + /* + * add the question to the questions Map in the displayOrder + */ + QaQuestionDTO questionDTO = new QaQuestionDTO(qaQuestion); + mapQuestions.put(displayOrder, questionDTO); + + mapQuestionStrings.put(new Integer(displayOrder).toString(), qaQuestion.getQuestion()); + + } + } + } + generalLearnerFlowDTO.setMapQuestions(mapQuestionStrings); + generalLearnerFlowDTO.setMapQuestionContentLearner(mapQuestions); + generalLearnerFlowDTO.setTotalQuestionCount(new Integer(mapQuestions.size())); + qaLearningForm.setTotalQuestionCount(new Integer(mapQuestions.size()).toString()); + + String feedBackType = ""; + if (qaContent.isQuestionsSequenced()) { + feedBackType = FEEDBACK_TYPE_SEQUENTIAL; + } else { + feedBackType = FEEDBACK_TYPE_COMBINED; + } + String userFeedback = feedBackType + generalLearnerFlowDTO.getTotalQuestionCount() + QUESTIONS; + generalLearnerFlowDTO.setUserFeedback(userFeedback); + + generalLearnerFlowDTO.setRemainingQuestionCount(generalLearnerFlowDTO.getTotalQuestionCount().toString()); + generalLearnerFlowDTO.setInitialScreen(new Boolean(true).toString()); + + request.setAttribute(GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + /* + * by now, we know that the mode is either teacher or learner + * check if the mode is teacher and request is for Learner Progress + */ + if (mode.equals("teacher")) { + //start generating learner progress report for toolSessionID + + /* + * the report should have the all entries for the users in this tool session, + * and display under the "my answers" section the answers for the user id in the url + */ +// Long learnerProgressUserId = WebUtil.readLongParam(request, AttributeNames.PARAM_USER_ID, false); + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + generalLearnerFlowDTO.setRequestLearningReportProgress(new Boolean(true).toString()); + generalLearnerFlowDTO.setTeacherViewOnly(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, + generalLearnerFlowDTO); + request.setAttribute(QaAppConstants.GENERAL_LEARNER_FLOW_DTO, generalLearnerFlowDTO); + + return (mapping.findForward(LEARNER_REP)); + } + + //check if there is submission deadline + Date submissionDeadline = qaContent.getSubmissionDeadline(); + if (submissionDeadline != null) { + // store submission deadline to sessionMap + sessionMap.put(QaAppConstants.ATTR_SUBMISSION_DEADLINE, submissionDeadline); + + HttpSession ss = SessionManager.getSession(); + UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER); + TimeZone learnerTimeZone = learnerDto.getTimeZone(); + Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); + Date currentLearnerDate = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, new Date()); + + // calculate whether submission deadline has passed, and if so forward to "submissionDeadline" + if (currentLearnerDate.after(tzSubmissionDeadline)) { + + //if ShowOtherAnswersAfterDeadline is enabled - show others answers + if (qaContent.isShowOtherAnswersAfterDeadline()) { + generalLearnerFlowDTO.setLockWhenFinished(Boolean.TRUE.toString()); + generalLearnerFlowDTO.setNoReeditAllowed(true); + //only for ActionForward refreshAllResults(..) method + sessionMap.put("noRefresh", true); + /* + * the report should have all the users' entries OR the report should have only the current + * session's entries + */ + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, + generalLearnerFlowDTO); + + if (user.isLearnerFinished()) { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(true).toString()); + return (mapping.findForward(REVISITED_LEARNER_REP)); + } else { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(false).toString()); + return (mapping.findForward(LEARNER_REP)); + } + + // show submissionDeadline page otherwise + } else { + return mapping.findForward("submissionDeadline"); + } + } + } + + /* + * Verify that userId does not already exist in the db. + * If it does exist and the passed tool session id exists in the db, that means the user already responded to + * the content and + * his answers must be displayed read-only + * + * if the user's tool session id AND user id exists in the tool tables go to learner's report. + */ + /* + * if the 'All Responses' has been clicked no more user entry is accepted, and isResponseFinalized() returns + * true + */ + Long currentToolSessionID = new Long(qaLearningForm.getToolSessionID()); + + //if Response is Finalized + if (user.isResponseFinalized()) { + QaSession checkSession = user.getQaSession(); + + if (checkSession != null) { + Long checkQaSessionId = checkSession.getQaSessionId(); + + if (checkQaSessionId.toString().equals(currentToolSessionID.toString())) { + + // the learner is in the same session and has already responsed to this content + + generalLearnerFlowDTO.setLockWhenFinished(new Boolean(qaContent.isLockWhenFinished()).toString()); + generalLearnerFlowDTO.setNoReeditAllowed(qaContent.isNoReeditAllowed()); + /* + * the report should have all the users' entries OR the report should have only the current + * session's entries + */ + generalLearnerFlowDTO.setRequestLearningReport(new Boolean(true).toString()); + + QaLearningAction.refreshSummaryData(request, qaContent, qaSession, qaService, sessionMapId, user, + generalLearnerFlowDTO); + + if (user.isLearnerFinished()) { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(true).toString()); + return (mapping.findForward(REVISITED_LEARNER_REP)); + } else { + generalLearnerFlowDTO.setRequestLearningReportViewOnly(new Boolean(false).toString()); + return (mapping.findForward(LEARNER_REP)); + } + } + } + } + + //**---- showing AnswersContent.jsp ----** + LearningUtil.populateAnswers(sessionMap, qaContent, user, mapQuestions, generalLearnerFlowDTO, qaService); + + return (mapping.findForward(LOAD_LEARNER)); + } + + /** + * validates the learning mode parameters + * + * @param request + * @param mapping + * @return ActionForward + */ + protected void validateParameters(HttpServletRequest request, ActionMapping mapping, + QaLearningForm qaLearningForm) { + /* + * process incoming tool session id and later derive toolContentId from it. + */ + String strToolSessionId = request.getParameter(AttributeNames.PARAM_TOOL_SESSION_ID); + long toolSessionId = 0; + if ((strToolSessionId == null) || (strToolSessionId.length() == 0)) { + ActionMessages errors = new ActionMessages(); + errors.add(Globals.ERROR_KEY, new ActionMessage("error.toolSessionId.required")); + logger.error("error.toolSessionId.required"); + saveErrors(request, errors); + return; + } else { + try { + toolSessionId = new Long(strToolSessionId).longValue(); + qaLearningForm.setToolSessionID(new Long(toolSessionId).toString()); + } catch (NumberFormatException e) { + logger.error("add error.sessionId.numberFormatException to ActionMessages."); + return; + } + } + + /* mode can be learner, teacher or author */ + String mode = request.getParameter(MODE); + if ((mode == null) || (mode.length() == 0)) { + logger.error("Mode is empty"); + return; + } + if ((!mode.equals("learner")) && (!mode.equals("teacher")) && (!mode.equals("author"))) { + logger.error("Wrong mode"); + return; + } + qaLearningForm.setMode(mode); + } + + private QaQueUsr getCurrentUser(String toolSessionId) { + // get back login user DTO + HttpSession ss = SessionManager.getSession(); + UserDTO toolUser = (UserDTO) ss.getAttribute(AttributeNames.USER); + Integer userId = toolUser.getUserID(); + + QaQueUsr qaUser = qaService.getUserByIdAndSession(userId.longValue(), new Long(toolSessionId)); + if (qaUser == null) { + qaUser = qaService.createUser(new Long(toolSessionId), userId); + } + + return qaUser; + } + + private QaQueUsr getSpecifiedUser(String toolSessionId, Integer userId) { + QaQueUsr qaUser = qaService.getUserByIdAndSession(userId.longValue(), new Long(toolSessionId)); + if (qaUser == null) { + qaUser = qaService.createUser(new Long(toolSessionId), userId); + } + return qaUser; + } +// END OF STARTER +} \ No newline at end of file Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/web/controller/AuthoringController.java =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -126,7 +126,7 @@ * @return */ @RequestMapping("/removeItem") - private String removeItem(HttpServletRequest request) { + private String removeItem(ResourceItemForm resourceItemForm, HttpServletRequest request) { // get back sessionMAP String sessionMapID = WebUtil.readStrParam(request, ResourceConstants.ATTR_SESSION_MAP_ID); @@ -145,6 +145,7 @@ delList.add(item); } + request.setAttribute("resourceItemForm", resourceItemForm); request.setAttribute(ResourceConstants.ATTR_SESSION_MAP_ID, sessionMapID); return "pages/authoring/parts/itemlist"; } @@ -174,6 +175,7 @@ populateItemToForm(itemIdx, item, resourceItemForm, request); } } + request.setAttribute("resourceItemForm", resourceItemForm); switch (item.getType()) { case 1: return "pages/authoring/parts/addurl"; @@ -206,6 +208,7 @@ instructionList.add(""); } request.setAttribute("instructionList", instructionList); + request.setAttribute("resourceItemForm", resourceItemForm); switch (type) { case 1: return "pages/authoring/parts/addurl"; @@ -234,7 +237,7 @@ * @return * @throws ServletException */ - @RequestMapping(value = "/saveOrUpdateItem", method = RequestMethod.POST) + @RequestMapping(value = "/saveOrUpdateItem") private String saveOrUpdateItem(@ModelAttribute ResourceItemForm resourceItemForm, HttpServletRequest request) { // get instructions: List instructionList = getInstructionsFromRequest(request); @@ -244,6 +247,7 @@ if (!errorMap.isEmpty()) { request.setAttribute("errorMap", errorMap); request.setAttribute(ResourceConstants.ATTR_INSTRUCTION_LIST, instructionList); + request.setAttribute("resourceItemForm", resourceItemForm); switch (resourceItemForm.getItemType()) { case 1: return "pages/authoring/parts/addurl"; Index: lams_tool_larsrc/web/pages/authoring/parts/addfile.jsp =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_larsrc/web/pages/authoring/parts/addfile.jsp (.../addfile.jsp) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_larsrc/web/pages/authoring/parts/addfile.jsp (.../addfile.jsp) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -58,7 +58,7 @@ }); - + Index: lams_tool_larsrc/web/pages/authoring/parts/addheader.jsp =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_larsrc/web/pages/authoring/parts/addheader.jsp (.../addheader.jsp) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_larsrc/web/pages/authoring/parts/addheader.jsp (.../addheader.jsp) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -13,7 +13,7 @@ - + - + Index: lams_tool_larsrc/web/pages/authoring/parts/addurl.jsp =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_larsrc/web/pages/authoring/parts/addurl.jsp (.../addurl.jsp) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_larsrc/web/pages/authoring/parts/addurl.jsp (.../addurl.jsp) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -32,7 +32,7 @@ }); - + Index: lams_tool_larsrc/web/pages/authoring/parts/addwebsite.jsp =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_larsrc/web/pages/authoring/parts/addwebsite.jsp (.../addwebsite.jsp) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_larsrc/web/pages/authoring/parts/addwebsite.jsp (.../addwebsite.jsp) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -57,7 +57,7 @@ } }); - + Index: lams_tool_larsrc/web/pages/authoring/parts/instructions.jsp =================================================================== diff -u -r2f53601ac19db5f846eb50d31a111e12ff136a0a -r3c389c340a295760f8bec306638ad270a32a0a0e --- lams_tool_larsrc/web/pages/authoring/parts/instructions.jsp (.../instructions.jsp) (revision 2f53601ac19db5f846eb50d31a111e12ff136a0a) +++ lams_tool_larsrc/web/pages/authoring/parts/instructions.jsp (.../instructions.jsp) (revision 3c389c340a295760f8bec306638ad270a32a0a0e) @@ -16,7 +16,7 @@ @@ -40,7 +40,7 @@