Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/EditQbQuestionController.java =================================================================== diff -u -r0b1e74374b821758fdda7835d8d283bf84fa8db0 -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_central/src/java/org/lamsfoundation/lams/web/qb/EditQbQuestionController.java (.../EditQbQuestionController.java) (revision 0b1e74374b821758fdda7835d8d283bf84fa8db0) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/EditQbQuestionController.java (.../EditQbQuestionController.java) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -1,16 +1,23 @@ package org.lamsfoundation.lams.web.qb; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.TreeSet; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.qb.QbConstants; @@ -20,22 +27,24 @@ import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.qb.model.QbQuestionUnit; import org.lamsfoundation.lams.qb.service.IQbService; -import org.lamsfoundation.lams.qb.service.QbUtils; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; -import org.lamsfoundation.lams.util.CommonConstants; import org.lamsfoundation.lams.util.Configuration; import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.FileUtil; 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.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.context.WebApplicationContext; @Controller @@ -56,23 +65,20 @@ /** * Display empty page for new assessment question. */ - @RequestMapping("/newQuestionInit") - public String newQuestionInit(HttpServletRequest request, HttpServletResponse response, - @RequestParam Long collectionUid) throws ServletException, IOException { + @RequestMapping("/initNewQuestion") + public String initNewQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm form, + HttpServletRequest request, HttpServletResponse response, + @RequestParam(required = false) Long collectionUid) throws ServletException, IOException { - //TODO think about where do we need to get ContentFolderID, and whether it's a good idea to generate a new one each time - String contentFolderID = FileUtil.generateUniqueContentFolderID(); + form.setUid(-1L);//which signifies it's a new question + form.setMaxMark(1); + form.setPenaltyFactor("0"); + form.setAnswerRequired(true); + + // generate a new contentFolderID for new question + String contentFolderId = FileUtil.generateUniqueContentFolderID(); + form.setContentFolderID(contentFolderId); - QbQuestionForm questionForm = new QbQuestionForm(); - //we need to set form as a request attribute, as long as we use jsps from another context from the Assessment tool - request.setAttribute("assessmentQuestionForm", questionForm); - questionForm.setDisplayOrder(-1);//which signifies it's a new question - questionForm.setContentFolderID(contentFolderID); - questionForm.setMaxMark("1"); - questionForm.setPenaltyFactor("0"); - questionForm.setAnswerRequired(true); - questionForm.setCollectionUid(collectionUid); - List optionList = new ArrayList<>(); for (int i = 0; i < QbConstants.INITIAL_OPTIONS_NUMBER; i++) { QbOption option = new QbOption(); @@ -93,77 +99,133 @@ unitList.add(unit); } request.setAttribute(QbConstants.ATTR_UNIT_LIST, unitList); + + //prepare data for displaying collections + Integer userId = getUserId(); + Collection userCollections = qbService.getUserCollections(userId); + request.setAttribute("userCollections", userCollections); - Integer type = NumberUtils.toInt(request.getParameter(QbConstants.ATTR_QUESTION_TYPE)); -// sessionMap.put(QbConstants.ATTR_QUESTION_TYPE, type); - request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); + //in case request came from assessment tool - set private collection as default, otherwise collectioUid is already supplied as parameter from collections.jsp + final boolean isRequestCameFromAssessmentTool = StringUtils.isNotBlank(form.getSessionMapID()); + if (isRequestCameFromAssessmentTool) { + for (QbCollection collection : userCollections) { + if (collection.isPersonal()) { + form.setCollectionUid(collection.getUid()); + break; + } + } + } - String jspPageName = EditQbQuestionController.getAuthoringJspByQuestionType(type); - forwardToAssessmentJsp(jspPageName, request, response); - return null; + Integer type = NumberUtils.toInt(request.getParameter(QbConstants.ATTR_QUESTION_TYPE)); + return findForwardByQuestionType(type); } /** - * Display edit page for existed assessment question. + * Display edit page for existing question. */ @RequestMapping("/editQuestion") - public String editQuestion(HttpServletRequest request, HttpServletResponse response, - @RequestParam(defaultValue = "-1") Long collectionUid) throws ServletException, IOException { + public String editQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm form, + HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Long qbQuestionUid = WebUtil.readLongParam(request, "qbQuestionUid"); QbQuestion qbQuestion = qbService.getQuestionByUid(qbQuestionUid); if (qbQuestion == null) { throw new RuntimeException("QbQuestion with uid:" + qbQuestionUid + " was not found!"); } - QbQuestionForm questionForm = new QbQuestionForm(); - questionForm.setCollectionUid(collectionUid); - //we need to set form as a request attribute, as long as we use jsps from another context from the Assessment tool - request.setAttribute("assessmentQuestionForm", questionForm); - QbUtils.fillFormWithQbQuestion(qbQuestion, questionForm, request); + + //populate question information to its form for editing + form.setUid(qbQuestion.getUid()); + //TODO remove hardcoded value, once we transfer contentFolderId from old DB entries + form.setContentFolderID(qbQuestion.getContentFolderId() == null ? "temp" : qbQuestion.getContentFolderId()); + form.setTitle(qbQuestion.getName()); + form.setQuestion(qbQuestion.getDescription()); + form.setMaxMark(qbQuestion.getMaxMark()); + form.setPenaltyFactor(String.valueOf(qbQuestion.getPenaltyFactor())); + form.setAnswerRequired(qbQuestion.isAnswerRequired()); + form.setFeedback(qbQuestion.getFeedback()); + form.setMultipleAnswersAllowed(qbQuestion.isMultipleAnswersAllowed()); + form.setIncorrectAnswerNullifiesMark(qbQuestion.isIncorrectAnswerNullifiesMark()); + form.setFeedbackOnCorrect(qbQuestion.getFeedbackOnCorrect()); + form.setFeedbackOnPartiallyCorrect(qbQuestion.getFeedbackOnPartiallyCorrect()); + form.setFeedbackOnIncorrect(qbQuestion.getFeedbackOnIncorrect()); + form.setShuffle(qbQuestion.isShuffle()); + form.setPrefixAnswersWithLetters(qbQuestion.isPrefixAnswersWithLetters()); + form.setCaseSensitive(qbQuestion.isCaseSensitive()); + form.setCorrectAnswer(qbQuestion.getCorrectAnswer()); + form.setAllowRichEditor(qbQuestion.isAllowRichEditor()); + form.setMaxWordsLimit(qbQuestion.getMaxWordsLimit()); + form.setMinWordsLimit(qbQuestion.getMinWordsLimit()); + form.setHedgingJustificationEnabled(qbQuestion.isHedgingJustificationEnabled()); - //store uid as displayOrder in order to use it later during question saving - questionForm.setDisplayOrder(qbQuestionUid.intValue()); + Integer questionType = qbQuestion.getType(); + if ((questionType == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (questionType == QbQuestion.TYPE_ORDERING) + || (questionType == QbQuestion.TYPE_MATCHING_PAIRS) + || (questionType == QbQuestion.TYPE_SHORT_ANSWER) + || (questionType == QbQuestion.TYPE_NUMERICAL) + || (questionType == QbQuestion.TYPE_MARK_HEDGING)) { + List optionList = qbQuestion.getQbOptions(); + request.setAttribute(QbConstants.ATTR_OPTION_LIST, optionList); + } + if (questionType == QbQuestion.TYPE_NUMERICAL) { + List unitList = qbQuestion.getUnits(); + request.setAttribute(QbConstants.ATTR_UNIT_LIST, unitList); + } + + //prepare data for displaying collections + Integer userId = getUserId(); + Collection userCollections = qbService.getUserCollections(userId); + request.setAttribute("userCollections", userCollections); + //in case request came from assessment tool - set private collection as default, otherwise collectioUid is already supplied as parameter from collections.jsp + final boolean isRequestCameFromAssessmentTool = StringUtils.isNotBlank(form.getSessionMapID()); + if (isRequestCameFromAssessmentTool) { + Collection questionCollections = qbService.getQuestionCollectionsByUid(qbQuestionUid); - //TODO think about where do we need to get ContentFolderID, and whether it's a good idea to generate a new one each time - String contentFolderID = FileUtil.generateUniqueContentFolderID(); - questionForm.setContentFolderID(contentFolderID); - request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); + Long collectionUid = null; + if (questionCollections.isEmpty()) { + for (QbCollection collection : userCollections) { + if (collection.isPersonal()) { + collectionUid = collection.getUid(); + break; + } + } + } else { + collectionUid = questionCollections.iterator().next().getUid(); + } + form.setCollectionUid(collectionUid); + } - String jspPageName = EditQbQuestionController.getAuthoringJspByQuestionType(qbQuestion.getType()); - forwardToAssessmentJsp(jspPageName, request, response); - return null; + return findForwardByQuestionType(qbQuestion.getType()); } /** * This method will get necessary information from assessment question form and save or update into * HttpSession AssessmentQuestionList. 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. - * - * @throws IOException */ @RequestMapping("/saveOrUpdateQuestion") - @ResponseBody - public String saveOrUpdateQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm questionForm, - HttpServletRequest request, HttpServletResponse response) throws IOException { + public String saveOrUpdateQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm form, + HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + //find according question QbQuestion qbQuestion = null; Long oldQuestionUid = null; - + + boolean isAddingQuestion = form.getUid() == -1; // add - if (questionForm.getDisplayOrder() == -1) { + if (isAddingQuestion) { qbQuestion = new QbQuestion(); - qbQuestion.setType(questionForm.getQuestionType()); - - // edit + qbQuestion.setType(form.getQuestionType()); + + // edit } else { - oldQuestionUid = Long.valueOf(questionForm.getDisplayOrder()); + oldQuestionUid = form.getUid(); qbQuestion = qbService.getQuestionByUid(oldQuestionUid); + qbService.releaseFromCache(qbQuestion); } - - boolean IS_AUTHORING_RESTRICTED = false; - int isQbQuestionModified = QbUtils.extractFormToQbQuestion(qbQuestion, questionForm, request, qbService, - IS_AUTHORING_RESTRICTED); - switch (isQbQuestionModified) { + + int questionModificationStatus = extractFormToQbQuestion(qbQuestion, form, request); + switch (questionModificationStatus) { case IQbService.QUESTION_MODIFIED_VERSION_BUMP: { // new version of the old question gets created qbQuestion = qbQuestion.clone(); @@ -179,48 +241,168 @@ qbQuestion.setVersion(1); qbQuestion.setQuestionId(qbService.getMaxQuestionId() + 1); qbQuestion.setCreateDate(new Date()); - } break; } - boolean belongsToNoCollection = qbQuestion.getUid() == null; userManagementService.save(qbQuestion); + + final boolean IS_REQUEST_CAME_FROM_ASSESSMENT_TOOL = StringUtils.isNotBlank(form.getSessionMapID()); + if (IS_REQUEST_CAME_FROM_ASSESSMENT_TOOL) { + + //take care about question's collections + Long collectionUid = form.getCollectionUid(); + qbService.addQuestionToCollection(collectionUid, qbQuestion.getQuestionId(), false); + //remove from the old collection, if needed + if (!isAddingQuestion) { + Collection oldQuestionCollections = qbService.getQuestionCollectionsByUid(oldQuestionUid); + Collection newQuestionCollections = qbService + .getQuestionCollectionsByUid(qbQuestion.getUid()); + oldQuestionCollections.removeAll(newQuestionCollections); + for (QbCollection obsoleteOldQuestionCollection : oldQuestionCollections) { + qbService.removeQuestionFromCollectionByQuestionId(obsoleteOldQuestionCollection.getUid(), + qbQuestion.getQuestionId()); + } + } + + //forward to Assessment controller + String params = "?qbQuestionUid=" + qbQuestion.getUid(); + params += "&questionModificationStatus=" + questionModificationStatus; - //in case of new question - add it to specified collection - if (belongsToNoCollection) { + String serverURLContextPath = Configuration.get(ConfigurationKeys.SERVER_URL_CONTEXT_PATH); + serverURLContextPath = serverURLContextPath.startsWith("/") ? serverURLContextPath + : "/" + serverURLContextPath; + serverURLContextPath += serverURLContextPath.endsWith("/") ? "" : "/"; + applicationcontext.getServletContext().getContext(serverURLContextPath + "tool/laasse10/") + .getRequestDispatcher("/authoring/saveOrUpdateQuestion.do" + params) + .forward(request, response); + return null; - Long collectionUid = questionForm.getCollectionUid(); - //try to get collection from the old question - if (collectionUid != null && collectionUid.equals(-1L)) { - Collection existingCollections = qbService.getQuestionCollectionsByUid(oldQuestionUid); - collectionUid = existingCollections.stream().findFirst().map(collection -> collection.getUid()) - .orElse(null); - } + } else { + + // in case adding new question - return nothing + if (isAddingQuestion) { + return null; - if (collectionUid != null && !collectionUid.equals(-1L)) { - qbService.addQuestionToCollection(collectionUid, qbQuestion.getQuestionId(), false); + // edit question case - return question's uid + } else { + return "forward:returnQuestionUid.do?qbQuestionUid=" + qbQuestion.getUid(); } } + } + + @RequestMapping("/returnQuestionUid") + @ResponseBody + public String returnQuestionUid(HttpServletResponse response, @RequestParam Long qbQuestionUid) { + response.setContentType("text/plain"); + response.setCharacterEncoding("UTF-8"); + return qbQuestionUid.toString(); + } - // add question case - return nothing - if (questionForm.getDisplayOrder() == -1) { - return null; + /** + * Extract web form content to QB question. + * + * BE CAREFUL: This method will copy necessary info from request form to an old or new AssessmentQuestion + * instance. It gets all info EXCEPT AssessmentQuestion.createDate, which need be set when + * persisting this assessment Question. + * + * @return qbQuestionModified + */ + private int extractFormToQbQuestion(QbQuestion qbQuestion, QbQuestionForm form, HttpServletRequest request) { + QbQuestion oldQuestion = qbQuestion.clone(); + // evict everything manually as we do not use DTOs, just real entities + // without eviction changes would be saved immediately into DB + qbService.releaseFromCache(oldQuestion); - // edit question case - return question's uid - } else { - response.setContentType("text/plain"); - response.setCharacterEncoding("UTF-8"); - return qbQuestion.getUid().toString(); + qbQuestion.setName(form.getTitle()); + qbQuestion.setDescription(form.getQuestion()); + + if (!form.isAuthoringRestricted()) { + qbQuestion.setMaxMark(form.getMaxMark()); } + qbQuestion.setFeedback(form.getFeedback()); + qbQuestion.setAnswerRequired(form.isAnswerRequired()); + qbQuestion.setContentFolderId(form.getContentFolderID()); + + Integer type = form.getQuestionType(); + if (type == QbQuestion.TYPE_MULTIPLE_CHOICE) { + qbQuestion.setMultipleAnswersAllowed(form.isMultipleAnswersAllowed()); + boolean incorrectAnswerNullifiesMark = form.isMultipleAnswersAllowed() + ? form.isIncorrectAnswerNullifiesMark() + : false; + qbQuestion.setIncorrectAnswerNullifiesMark(incorrectAnswerNullifiesMark); + qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); + qbQuestion.setShuffle(form.isShuffle()); + qbQuestion.setPrefixAnswersWithLetters(form.isPrefixAnswersWithLetters()); + qbQuestion.setFeedbackOnCorrect(form.getFeedbackOnCorrect()); + qbQuestion.setFeedbackOnPartiallyCorrect(form.getFeedbackOnPartiallyCorrect()); + qbQuestion.setFeedbackOnIncorrect(form.getFeedbackOnIncorrect()); + } else if ((type == QbQuestion.TYPE_MATCHING_PAIRS)) { + qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); + qbQuestion.setShuffle(form.isShuffle()); + } else if ((type == QbQuestion.TYPE_SHORT_ANSWER)) { + qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); + qbQuestion.setCaseSensitive(form.isCaseSensitive()); + } else if ((type == QbQuestion.TYPE_NUMERICAL)) { + qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); + } else if ((type == QbQuestion.TYPE_TRUE_FALSE)) { + qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); + qbQuestion.setCorrectAnswer(form.isCorrectAnswer()); + qbQuestion.setFeedbackOnCorrect(form.getFeedbackOnCorrect()); + qbQuestion.setFeedbackOnIncorrect(form.getFeedbackOnIncorrect()); + } else if ((type == QbQuestion.TYPE_ESSAY)) { + qbQuestion.setAllowRichEditor(form.isAllowRichEditor()); + qbQuestion.setMaxWordsLimit(form.getMaxWordsLimit()); + qbQuestion.setMinWordsLimit(form.getMinWordsLimit()); + } else if (type == QbQuestion.TYPE_ORDERING) { + qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); + qbQuestion.setFeedbackOnCorrect(form.getFeedbackOnCorrect()); + qbQuestion.setFeedbackOnIncorrect(form.getFeedbackOnIncorrect()); + } else if (type == QbQuestion.TYPE_MARK_HEDGING) { + qbQuestion.setShuffle(form.isShuffle()); + qbQuestion.setFeedbackOnCorrect(form.getFeedbackOnCorrect()); + qbQuestion.setFeedbackOnPartiallyCorrect(form.getFeedbackOnPartiallyCorrect()); + qbQuestion.setFeedbackOnIncorrect(form.getFeedbackOnIncorrect()); + qbQuestion.setHedgingJustificationEnabled(form.isHedgingJustificationEnabled()); + } + + // set options + if ((type == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (type == QbQuestion.TYPE_ORDERING) + || (type == QbQuestion.TYPE_MATCHING_PAIRS) + || (type == QbQuestion.TYPE_SHORT_ANSWER) + || (type == QbQuestion.TYPE_NUMERICAL) + || (type == QbQuestion.TYPE_MARK_HEDGING)) { + Set optionList = getOptionsFromRequest(request, true); + List options = new ArrayList<>(); + int displayOrder = 0; + for (QbOption option : optionList) { + option.setDisplayOrder(displayOrder++); + options.add(option); + } + qbQuestion.setQbOptions(options); + } + // set units + if (type == QbQuestion.TYPE_NUMERICAL) { + Set unitList = getUnitsFromRequest(request, true); + List units = new ArrayList<>(); + int displayOrder = 0; + for (QbQuestionUnit unit : unitList) { + unit.setDisplayOrder(displayOrder++); + units.add(unit); + } + qbQuestion.setUnits(units); + } + + return qbQuestion.isQbQuestionModified(oldQuestion); } /** * Ajax call, will add one more input line for new resource item instruction. */ @RequestMapping("/addOption") - public String addOption(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - TreeSet optionList = QbUtils.getOptionsFromRequest(qbService, request, false); + public String addOption(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + TreeSet optionList = getOptionsFromRequest(request, false); + QbOption option = new QbOption(); int maxSeq = 1; if ((optionList != null) && (optionList.size() > 0)) { @@ -235,17 +417,15 @@ request.setAttribute(QbConstants.ATTR_QUESTION_TYPE, WebUtil.readIntParam(request, QbConstants.ATTR_QUESTION_TYPE)); request.setAttribute(QbConstants.ATTR_OPTION_LIST, optionList); - forwardToAssessmentJsp("optionlist.jsp", request, response); - return null; + return "qb/authoring/optionlist"; } /** * Ajax call, will add one more input line for new Unit. */ @RequestMapping("/newUnit") - public String newUnit(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - TreeSet unitList = QbUtils.getUnitsFromRequest(qbService, request, false); + public String newUnit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + TreeSet unitList = getUnitsFromRequest(request, false); QbQuestionUnit unit = new QbQuestionUnit(); int maxSeq = 1; if ((unitList != null) && (unitList.size() > 0)) { @@ -256,58 +436,224 @@ unitList.add(unit); request.setAttribute(QbConstants.ATTR_UNIT_LIST, unitList); - forwardToAssessmentJsp("unitlist.jsp", request, response); - return null; + return "qb/authoring/unitlist"; } + /** + * Get answer options from HttpRequest + * + * @param request + * @param isForSaving + * whether the blank options will be preserved or not + */ + private TreeSet getOptionsFromRequest(HttpServletRequest request, boolean isForSaving) { + Map paramMap = splitRequestParameter(request, QbConstants.ATTR_OPTION_LIST); + + int count = NumberUtils.toInt(paramMap.get(QbConstants.ATTR_OPTION_COUNT)); + int questionType = WebUtil.readIntParam(request, QbConstants.ATTR_QUESTION_TYPE); + Integer correctOptionIndex = (paramMap.get(QbConstants.ATTR_OPTION_CORRECT) == null) ? null + : NumberUtils.toInt(paramMap.get(QbConstants.ATTR_OPTION_CORRECT)); + + TreeSet optionList = new TreeSet<>(); + for (int i = 0; i < count; i++) { + + String displayOrder = paramMap.get(QbConstants.ATTR_OPTION_DISPLAY_ORDER_PREFIX + i); + //displayOrder is null, in case this item was removed using Remove button + if (displayOrder == null) { + continue; + } + + QbOption option = null; + String uidStr = paramMap.get(QbConstants.ATTR_OPTION_UID_PREFIX + i); + if (uidStr != null) { + Long uid = NumberUtils.toLong(uidStr); + option = qbService.getOptionByUid(uid); + + } else { + option = new QbOption(); + } + option.setDisplayOrder(NumberUtils.toInt(displayOrder)); + + if ((questionType == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (questionType == QbQuestion.TYPE_SHORT_ANSWER)) { + String name = paramMap.get(QbConstants.ATTR_OPTION_NAME_PREFIX + i); + if ((name == null) && isForSaving) { + continue; + } + + option.setName(name); + float maxMark = Float.valueOf(paramMap.get(QbConstants.ATTR_OPTION_MAX_MARK_PREFIX + i)); + option.setMaxMark(maxMark); + option.setFeedback(paramMap.get(QbConstants.ATTR_OPTION_FEEDBACK_PREFIX + i)); + + } else if (questionType == QbQuestion.TYPE_MATCHING_PAIRS) { + String matchingPair = paramMap.get(QbConstants.ATTR_MATCHING_PAIR_PREFIX + i); + if ((matchingPair == null) && isForSaving) { + continue; + } + + option.setName(paramMap.get(QbConstants.ATTR_OPTION_NAME_PREFIX + i)); + option.setMatchingPair(matchingPair); + + } else if (questionType == QbQuestion.TYPE_NUMERICAL) { + String numericalOptionStr = paramMap.get(QbConstants.ATTR_NUMERICAL_OPTION_PREFIX + i); + String acceptedErrorStr = paramMap.get(QbConstants.ATTR_OPTION_ACCEPTED_ERROR_PREFIX + i); + String maxMarkStr = paramMap.get(QbConstants.ATTR_OPTION_MAX_MARK_PREFIX + i); + if (numericalOptionStr.equals("0.0") && numericalOptionStr.equals("0.0") && maxMarkStr.equals("0.0") + && isForSaving) { + continue; + } + + try { + float numericalOption = Float.valueOf(numericalOptionStr); + option.setNumericalOption(numericalOption); + } catch (Exception e) { + option.setNumericalOption(0); + } + try { + float acceptedError = Float.valueOf(acceptedErrorStr); + option.setAcceptedError(acceptedError); + } catch (Exception e) { + option.setAcceptedError(0); + } + float maxMark = Float.valueOf(paramMap.get(QbConstants.ATTR_OPTION_MAX_MARK_PREFIX + i)); + option.setMaxMark(maxMark); + option.setFeedback(paramMap.get(QbConstants.ATTR_OPTION_FEEDBACK_PREFIX + i)); + + } else if (questionType == QbQuestion.TYPE_ORDERING) { + String name = paramMap.get(QbConstants.ATTR_OPTION_NAME_PREFIX + i); + if ((name == null) && isForSaving) { + continue; + } + + option.setName(name); + + } else if (questionType == QbQuestion.TYPE_MARK_HEDGING) { + String name = paramMap.get(QbConstants.ATTR_OPTION_NAME_PREFIX + i); + if ((name == null) && isForSaving) { + continue; + } + + option.setName(name); + if ((correctOptionIndex != null) && correctOptionIndex.equals(Integer.valueOf(displayOrder))) { + option.setCorrect(true); + } + option.setFeedback(paramMap.get(QbConstants.ATTR_OPTION_FEEDBACK_PREFIX + i)); + } + + optionList.add(option); + } + return optionList; + } + + /** + * Get units from HttpRequest + * + * @param request + */ + private TreeSet getUnitsFromRequest(HttpServletRequest request, boolean isForSaving) { + Map paramMap = splitRequestParameter(request, QbConstants.ATTR_UNIT_LIST); + + int count = NumberUtils.toInt(paramMap.get(QbConstants.ATTR_UNIT_COUNT)); + TreeSet unitList = new TreeSet<>(); + for (int i = 0; i < count; i++) { + String name = paramMap.get(QbConstants.ATTR_UNIT_NAME_PREFIX + i); + if (StringUtils.isBlank(name) && isForSaving) { + continue; + } + + QbQuestionUnit unit = null; + String uidStr = paramMap.get(QbConstants.ATTR_UNIT_UID_PREFIX + i); + if (uidStr != null) { + Long uid = NumberUtils.toLong(uidStr); + unit = qbService.getQuestionUnitByUid(uid); + + } else { + unit = new QbQuestionUnit(); + } + String displayOrder = paramMap.get(QbConstants.ATTR_UNIT_DISPLAY_ORDER_PREFIX + i); + unit.setDisplayOrder(NumberUtils.toInt(displayOrder)); + unit.setName(name); + float multiplier = Float.valueOf(paramMap.get(QbConstants.ATTR_UNIT_MULTIPLIER_PREFIX + i)); + unit.setMultiplier(multiplier); + unitList.add(unit); + } + + return unitList; + } + + /** + * Split Request Parameter from HttpRequest + * + * @param request + * @param parameterName + * parameterName + */ + private static Map splitRequestParameter(HttpServletRequest request, String parameterName) { + String list = request.getParameter(parameterName); + if (list == null) { + return null; + } + + String[] params = list.split("&"); + Map paramMap = new HashMap<>(); + String[] pair; + for (String item : params) { + pair = item.split("="); + if ((pair == null) || (pair.length != 2)) { + continue; + } + try { + paramMap.put(pair[0], URLDecoder.decode(pair[1], "UTF-8")); + } catch (UnsupportedEncodingException e) { + log.error("Error occurs when decode instruction string:" + e.toString()); + } + } + return paramMap; + } + + /** * Get back jsp name. */ - private static String getAuthoringJspByQuestionType(Integer type) { - String jspName; + private String findForwardByQuestionType(Integer type) { + String forward; switch (type) { case QbQuestion.TYPE_MULTIPLE_CHOICE: - jspName = "addmultiplechoice.jsp"; + forward = "qb/authoring/addmultiplechoice"; break; case QbQuestion.TYPE_MATCHING_PAIRS: - jspName = "addmatchingpairs.jsp"; + forward = "qb/authoring/addmatchingpairs"; break; case QbQuestion.TYPE_SHORT_ANSWER: - jspName = "addshortanswer.jsp"; + forward = "qb/authoring/addshortanswer"; break; case QbQuestion.TYPE_NUMERICAL: - jspName = "addnumerical.jsp"; + forward = "qb/authoring/addnumerical"; break; case QbQuestion.TYPE_TRUE_FALSE: - jspName = "addtruefalse.jsp"; + forward = "qb/authoring/addtruefalse"; break; case QbQuestion.TYPE_ESSAY: - jspName = "addessay.jsp"; + forward = "qb/authoring/addessay"; break; case QbQuestion.TYPE_ORDERING: - jspName = "addordering.jsp"; + forward = "qb/authoring/addordering"; break; case QbQuestion.TYPE_MARK_HEDGING: - jspName = "addmarkhedging.jsp"; + forward = "qb/authoring/addmarkhedging"; break; default: - jspName = null; + forward = null; break; } - return jspName; + return forward; } - - /** - * Forwards to the specified jsp page from Assessment tool. - */ - private void forwardToAssessmentJsp(String jspPageName, HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - String serverURLContextPath = Configuration.get(ConfigurationKeys.SERVER_URL_CONTEXT_PATH); - serverURLContextPath = serverURLContextPath.startsWith("/") ? serverURLContextPath : "/" + serverURLContextPath; - serverURLContextPath += serverURLContextPath.endsWith("/") ? "" : "/"; - applicationcontext.getServletContext() - .getContext(serverURLContextPath + "tool/" + CommonConstants.TOOL_SIGNATURE_ASSESSMENT) - .getRequestDispatcher("/pages/authoring/parts/" + jspPageName + "?lessonID=1") - .forward(request, response); + + private Integer getUserId() { + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + return user != null ? user.getUserID() : null; } + } Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/SearchQBController.java =================================================================== diff -u -r0b1e74374b821758fdda7835d8d283bf84fa8db0 -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_central/src/java/org/lamsfoundation/lams/web/qb/SearchQBController.java (.../SearchQBController.java) (revision 0b1e74374b821758fdda7835d8d283bf84fa8db0) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/SearchQBController.java (.../SearchQBController.java) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -121,7 +121,12 @@ request.setAttribute("questionType", questionTypeDefault); request.setAttribute("questionTypesAvailable", questionTypesAvailable.toString()); - return "qb/search"; + boolean isFullJspRequested = WebUtil.readBooleanParam(request, "isFullJspRequested", true); + if (isFullJspRequested) { + return "qb/search"; + } else { + return "qb/searchWidget"; + } } /** Index: lams_central/web/qb/collection.jsp =================================================================== diff -u -r289d71a2af5137360ca926e9b03ca4bfccc4fe86 -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_central/web/qb/collection.jsp (.../collection.jsp) (revision 289d71a2af5137360ca926e9b03ca4bfccc4fe86) +++ lams_central/web/qb/collection.jsp (.../collection.jsp) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -216,7 +216,7 @@ + "\", \"_blank\")' title='Show stats'>"; cellhtml += "' href='?qbQuestionUid=" - + cellvalue + "&collectionUid=${collection.uid}&KeepThis=true&TB_iframe=true' class='thickbox'>"; + + cellvalue + "&collectionUid=${collection.uid}&KeepThis=true&TB_iframe=true&modal=true' class='thickbox'>"; cellhtml += ""; cellhtml += ""; @@ -354,7 +354,7 @@ function initLinkHref() { var questionType = document.getElementById("question-type").selectedIndex + 1; $("#create-question-href").attr("href", - "?questionType=" + questionType + "?questionType=" + questionType + "&collectionUid=${collection.uid}" + "&KeepThis=true&TB_iframe=true&modal=true"); }; Index: lams_central/web/qb/stats.jsp =================================================================== diff -u -r80ab947256f1314103a88c68432755741615271b -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_central/web/qb/stats.jsp (.../stats.jsp) (revision 80ab947256f1314103a88c68432755741615271b) +++ lams_central/web/qb/stats.jsp (.../stats.jsp) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -136,7 +136,7 @@ Question
- + "> Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20190110.sql =================================================================== diff -u -r1ade6b745b16bb963a1e817dc7fde5b83f1acf5e -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20190110.sql (.../patch20190110.sql) (revision 1ade6b745b16bb963a1e817dc7fde5b83f1acf5e) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20190110.sql (.../patch20190110.sql) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -8,6 +8,7 @@ `question_id` INT NOT NULL, `version` SMALLINT NOT NULL DEFAULT 1, `create_date` DATETIME NOT NULL DEFAULT NOW(), + `content_folder_id` char(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `name` TEXT NOT NULL, `description` TEXT, `max_mark` INT, Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -r0b1e74374b821758fdda7835d8d283bf84fa8db0 -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 0b1e74374b821758fdda7835d8d283bf84fa8db0) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -416,11 +416,14 @@ @Override public void saveOrUpdateAssessment(Assessment assessment) { - for (AssessmentQuestion question : assessment.getQuestions()) { - //update only in case QbQuestion was modified, to prevent updating the same QbQuestions received from SesssionMap - if (question.getQbQuestionModified() != IQbService.QUESTION_MODIFIED_NONE) { - assessmentQuestionDao.saveObject(question.getQbQuestion()); + for (QuestionReference reference : assessment.getQuestionReferences()) { + if (!reference.isRandomQuestion()) { + assessmentQuestionDao.saveObject(reference.getQuestion()); } + assessmentQuestionDao.saveObject(reference); + } + + for (AssessmentQuestion question : assessment.getQuestions()) { assessmentQuestionDao.saveObject(question); } @@ -3151,7 +3154,6 @@ ;// collection for (JsonNode referenceJSONData : references) { QuestionReference reference = new QuestionReference(); - reference.setType((short) 0); reference.setMaxMark(JsonUtil.optInt(referenceJSONData, "maxMark", 1)); reference.setSequenceId(JsonUtil.optInt(referenceJSONData, RestTags.DISPLAY_ORDER)); AssessmentQuestion matchingQuestion = matchQuestion(newQuestionSet, @@ -3162,7 +3164,6 @@ } reference.setQuestion(matchingQuestion); reference.setRandomQuestion(JsonUtil.optBoolean(referenceJSONData, "randomQuestion", Boolean.FALSE)); - reference.setTitle(null); newReferenceSet.add(reference); } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/AuthoringController.java =================================================================== diff -u -r0b1e74374b821758fdda7835d8d283bf84fa8db0 -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 0b1e74374b821758fdda7835d8d283bf84fa8db0) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/AuthoringController.java (.../AuthoringController.java) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -23,20 +23,15 @@ package org.lamsfoundation.lams.tool.assessment.web.controller; -import java.io.File; import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,17 +44,13 @@ import javax.servlet.http.HttpSession; import org.apache.commons.beanutils.PropertyUtils; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; -import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; import org.lamsfoundation.lams.qb.QbConstants; import org.lamsfoundation.lams.qb.form.QbQuestionForm; import org.lamsfoundation.lams.qb.model.QbOption; import org.lamsfoundation.lams.qb.model.QbQuestion; -import org.lamsfoundation.lams.qb.model.QbQuestionUnit; -import org.lamsfoundation.lams.qb.service.QbUtils; import org.lamsfoundation.lams.qb.service.IQbService; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; @@ -72,9 +63,9 @@ import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; import org.lamsfoundation.lams.tool.assessment.web.form.AssessmentForm; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; -import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CommonConstants; -import org.lamsfoundation.lams.util.FileUtil; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; @@ -86,11 +77,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.context.WebApplicationContext; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.xml.StaxDriver; -import com.thoughtworks.xstream.security.AnyTypePermission; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * @author Andrey Balan @@ -104,12 +95,10 @@ @Autowired @Qualifier("laasseAssessmentService") private IAssessmentService service; - @Autowired private IQbService qbService; - @Autowired - private IUserManagementService userManagementService; + WebApplicationContext applicationcontext; /** * Read assessment data from database and put them into HttpSession. It will redirect to init.do directly after this @@ -172,28 +161,26 @@ throw new ServletException(e); } - List questions = null; - if (assessment.getQuestions() != null) { - questions = new ArrayList(assessment.getQuestions()); - } else { - questions = new ArrayList<>(); + // init RandomPoolQuestions + List randomPoolQuestions = getRandomPoolQuestions(sessionMap); + randomPoolQuestions.clear(); + for (AssessmentQuestion question : assessment.getQuestions()) { + if (question.isRandomQuestion()) { + randomPoolQuestions.add(question); + } } - // init assessment question list - SortedSet questionList = getQuestionList(sessionMap); - questionList.clear(); - questionList.addAll(questions); - // init question references SortedSet references = getQuestionReferences(sessionMap); references.clear(); - if (assessment.getQuestionReferences() != null) { - references.addAll(assessment.getQuestionReferences()); + references.addAll(assessment.getQuestionReferences()); + //init references' qbQuestions to avoid no session exception + for (QuestionReference reference : references) { + if (!reference.isRandomQuestion()) { + reference.getQuestion().getQbQuestion(); + } } - // init available questions - reinitializeAvailableQuestions(sessionMap); - boolean isAssessmentAttempted = assessment.getUid() == null ? false : service.isAssessmentAttempted(assessment.getUid()); sessionMap.put(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED, isAssessmentAttempted && mode.isTeacher()); @@ -235,9 +222,10 @@ Assessment assessment = assessmentForm.getAssessment(); Assessment assessmentPO = service.getAssessmentByContentId(assessmentForm.getAssessment().getContentId()); - Set oldQuestions = (assessmentPO == null) ? new HashSet<>() : assessmentPO.getQuestions(); - Set oldReferences = (assessmentPO == null) ? new HashSet<>() - : assessmentPO.getQuestionReferences(); + //TODO **part of markrecalculation** +// Set oldQuestions = (assessmentPO == null) ? new HashSet<>() : assessmentPO.getQuestions(); +// Set oldReferences = (assessmentPO == null) ? new HashSet<>() +// : assessmentPO.getQuestionReferences(); AssessmentUser assessmentUser = null; @@ -247,15 +235,16 @@ assessmentPO.setCreated(new Timestamp(new Date().getTime())); } else { - // copyProperties() below sets assessmentPO items to empty collection - // but the items still exist in Hibernate cache, so we need to evict them now - for (AssessmentQuestion question : oldQuestions) { - service.releaseFromCache(question); -// service.releaseFromCache(question.getQbQuestion()); - } - for (QuestionReference reference : oldReferences) { - service.releaseFromCache(reference); - } + //TODO **part of markrecalculation** +// // copyProperties() below sets assessmentPO items to empty collection +// // but the items still exist in Hibernate cache, so we need to evict them now +// for (AssessmentQuestion question : oldQuestions) { +// service.releaseFromCache(question); +//// service.releaseFromCache(question.getQbQuestion()); +// } +// for (QuestionReference reference : oldReferences) { +// service.releaseFromCache(reference); +// } assessmentPO.getQuestions().clear(); Long uid = assessmentPO.getUid(); @@ -291,45 +280,37 @@ assessmentPO.setCreatedBy(assessmentUser); // ************************* Handle assessment questions ******************* - Set newQuestions = getQuestionList(sessionMap); - int maxQuestionId = qbService.getMaxQuestionId(); - for (AssessmentQuestion question : newQuestions) { + List newRandomQuestions = getRandomPoolQuestions(sessionMap); + TreeSet newQuestions = new TreeSet<>(newRandomQuestions); + + for (AssessmentQuestion question : newRandomQuestions) { question.setToolContentId(assessmentPO.getContentId()); - removeNewLineCharacters(question); - // modification status was already set in AuthoringController#saveItem() - switch (question.getQbQuestionModified()) { - case IQbService.QUESTION_MODIFIED_VERSION_BUMP: { - // new version of the old question gets created - QbQuestion qbQuestion = question.getQbQuestion().clone(); - question.setQbQuestion(qbQuestion); - qbQuestion.clearID(); - qbQuestion.setVersion(qbService.getMaxQuestionVersion(qbQuestion.getQuestionId())); - qbQuestion.setCreateDate(new Date()); - } - break; - case IQbService.QUESTION_MODIFIED_ID_BUMP: { - // new question gets created - QbQuestion qbQuestion = question.getQbQuestion().clone(); - question.setQbQuestion(qbQuestion); - qbQuestion.clearID(); - qbQuestion.setVersion(1); - qbQuestion.setQuestionId(maxQuestionId++); - qbQuestion.setCreateDate(new Date()); - } - break; - } + //TODO check +// removeNewLineCharacters(question); } - assessmentPO.setQuestions(newQuestions); - - Set newReferences = updateQuestionReferencesMaxMarks(request, sessionMap, true); - //recalculate results in case content is edited from monitoring and it's been already attempted by a student - boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); - if (isAuthoringRestricted) { - service.recalculateUserAnswers(assessmentPO.getUid(), assessmentPO.getContentId(), oldQuestions, - newQuestions, oldReferences, newReferences); + Set newReferences = updateQuestionReferencesMaxMarks(request, sessionMap, true); + for (QuestionReference reference : newReferences) { + if (!reference.isRandomQuestion()) { + AssessmentQuestion question = reference.getQuestion(); + question.setToolContentId(assessmentPO.getContentId()); + newQuestions.add(question); + } + //TODO check +// removeNewLineCharacters(question); } + + assessmentPO.setQuestions(newQuestions); + + //TODO **part of markrecalculation** +// // recalculate results in case content is edited from monitoring and it's been already attempted by a student +// boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); +// if (isAuthoringRestricted) { +// service.recalculateUserAnswers(assessmentPO.getUid(), assessmentPO.getContentId(), oldQuestions, +// newQuestions, oldReferences, newReferences); +// } + // Handle question references assessmentPO.setQuestionReferences(newReferences); @@ -350,17 +331,20 @@ iterRef.remove(); if (reference.getUid() != null) { service.deleteQuestionReference(reference.getUid()); + + //TODO maybe check and delete orphaned AssessmentQuestion + //service.deleteAssessmentQuestion(question.getUid()); } } - - // delete Questions from database - List deletedQuestions = getDeletedQuestionList(sessionMap); - Iterator iter = deletedQuestions.iterator(); - while (iter.hasNext()) { - AssessmentQuestion question = iter.next(); - iter.remove(); - if (question.getUid() != null) { - service.deleteAssessmentQuestion(question.getUid()); + + // delete References from database + List deletedRandomPoolQuestions = getDeletedRandomPoolQuestions(sessionMap); + Iterator iterDeletedQuestions = deletedRandomPoolQuestions.iterator(); + while (iterDeletedQuestions.hasNext()) { + AssessmentQuestion delQuestion = iterDeletedQuestions.next(); + iterDeletedQuestions.remove(); + if (delQuestion.getUid() != null) { + service.deleteAssessmentQuestion(delQuestion.getUid()); } } @@ -372,78 +356,98 @@ /** * Display empty page for new assessment question. */ - @RequestMapping("/newQuestionInit") - public String newQuestionInit(@ModelAttribute("assessmentQuestionForm") QbQuestionForm questionForm, - HttpServletRequest request) { - String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); + @RequestMapping("/initNewQuestion") + public String initNewQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm questionForm, + HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { SessionMap sessionMap = getSessionMap(request); updateQuestionReferencesMaxMarks(request, sessionMap, false); - String contentFolderID = (String) sessionMap.get(AttributeNames.PARAM_CONTENT_FOLDER_ID); - questionForm.setSessionMapID(sessionMapID); - questionForm.setDisplayOrder(-1);//which signifies it's a new question - questionForm.setContentFolderID(contentFolderID); - questionForm.setMaxMark("1"); - questionForm.setPenaltyFactor("0"); - questionForm.setAnswerRequired(true); + + +// request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); +// questionForm.setContentFolderID(contentFolderID); + - List optionList = new ArrayList<>(); - for (int i = 0; i < QbConstants.INITIAL_OPTIONS_NUMBER; i++) { - QbOption option = new QbOption(); - option.setDisplayOrder(i + 1); - optionList.add(option); - } - request.setAttribute(QbConstants.ATTR_OPTION_LIST, optionList); +// request.setAttribute("isRequestedByTool", true); +// request.setAttribute("contentFolderID", contentFolderID); + + +// questionForm.setDisplayOrder(-1);//which signifies it's a new question +// +// questionForm.setMaxMark("1"); +// questionForm.setPenaltyFactor("0"); +// questionForm.setAnswerRequired(true); + - List unitList = new ArrayList<>(); - QbQuestionUnit unit = new QbQuestionUnit(); - unit.setDisplayOrder(1); - unit.setMultiplier(1); - unitList.add(unit); - for (int i = 1; i < QbConstants.INITIAL_UNITS_NUMBER; i++) { - unit = new QbQuestionUnit(); - unit.setDisplayOrder(i + 1); - unit.setMultiplier(0); - unitList.add(unit); - } - request.setAttribute(AssessmentConstants.ATTR_UNIT_LIST, unitList); + Integer type = NumberUtils.toInt(request.getParameter(QbConstants.ATTR_QUESTION_TYPE)); + if (type.equals(-1)) {//randomQuestion case + questionForm.setUid(-1L);//which signifies it's a new question + questionForm.setMaxMark(1); + questionForm.setPenaltyFactor("0"); + questionForm.setAnswerRequired(false); + return "pages/authoring/randomQuestion"; + + } else { + //let QB controller know request comes from the tool +// boolean REQUEST_CAME_FROM_ASSESSMENT_TOOL = true; +// questionForm.setRequestCameFromAssessmentTool(REQUEST_CAME_FROM_ASSESSMENT_TOOL); + boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); - Integer type = NumberUtils.toInt(request.getParameter(AssessmentConstants.ATTR_QUESTION_TYPE)); - sessionMap.put(AssessmentConstants.ATTR_QUESTION_TYPE, type); - request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); - return findForward(type); + String params = "?" + AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED + "=" + isAuthoringRestricted; + // sessionMapID and questionType is already supplied as parameters + + forwardToEditQbQuestionController(request, response, "/qb/edit/initNewQuestion.do", params); + return null; + } } /** * Display edit page for existed assessment question. */ - @RequestMapping("/editQuestion") - public String editQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm questionForm, - HttpServletRequest request) { + @RequestMapping("/editQuestionReference") + public String editQuestionReference(HttpServletRequest request, HttpServletResponse response, + @RequestParam int questionReferenceIndex) throws ServletException, IOException { SessionMap sessionMap = getSessionMap(request); updateQuestionReferencesMaxMarks(request, sessionMap, false); + + SortedSet questionReferences = getQuestionReferences(sessionMap); + List rList = new ArrayList<>(questionReferences); + QuestionReference questionReference = rList.get(questionReferenceIndex); + + if (questionReference.isRandomQuestion()) { + return "pages/authoring/randomQuestion"; + + } else { +// QbUtils.fillFormWithQbQuestion(question.getQbQuestion(), questionForm, request); +// questionForm.setDisplayOrder(question.getDisplayOrder()); - SortedSet questionList = getQuestionList(sessionMap); - int questionDisplayOrder = WebUtil.readIntParam(request, AssessmentConstants.PARAM_QUESTION_DISPLAY_ORDER); - AssessmentQuestion question = null; - for (AssessmentQuestion questionIter : questionList) { - if (questionIter.getDisplayOrder() == questionDisplayOrder) { - question = questionIter; - break; - } + //let QB controller know request comes from the tool +// boolean REQUEST_CAME_FROM_ASSESSMENT_TOOL = true; +// questionForm.setRequestCameFromAssessmentTool(REQUEST_CAME_FROM_ASSESSMENT_TOOL); +// questionForm.setContentFolderID(contentFolderID); + boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); +// questionForm.setAuthoringRestricted(isAuthoringRestricted); + AssessmentQuestion question = questionReference.getQuestion(); + + String params = "?" + AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED + "=" + isAuthoringRestricted; + params += "&qbQuestionUid=" + question.getQbQuestion().getUid(); + // sessionMapID and questionType is already supplied as parameters + + forwardToEditQbQuestionController(request, response, "/qb/edit/editQuestion.do", params); + return null; } - if (question == null) { - throw new RuntimeException("Question with displayOrder:" + questionDisplayOrder + " was not found!"); - } - QbUtils.fillFormWithQbQuestion(question.getQbQuestion(), questionForm, request); - questionForm.setDisplayOrder(question.getDisplayOrder()); - - sessionMap.put(AssessmentConstants.ATTR_QUESTION_TYPE, question.getType()); - - String contentFolderID = (String) sessionMap.get(AttributeNames.PARAM_CONTENT_FOLDER_ID); - questionForm.setContentFolderID(contentFolderID); - request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); - return findForward(question.getType()); } + + /** + * Forwards to the specified jsp page from Assessment tool. + */ + private void forwardToEditQbQuestionController(HttpServletRequest request, HttpServletResponse response, String url, + String params) throws ServletException, IOException { + String serverURLContextPath = Configuration.get(ConfigurationKeys.SERVER_URL_CONTEXT_PATH); + serverURLContextPath = serverURLContextPath.startsWith("/") ? serverURLContextPath : "/" + serverURLContextPath; + serverURLContextPath += serverURLContextPath.endsWith("/") ? "" : "/"; + applicationcontext.getServletContext().getContext(serverURLContextPath).getRequestDispatcher(url + params) + .forward(request, response); + } /** * This method will get necessary information from assessment question form and save or update into @@ -454,54 +458,73 @@ @SuppressWarnings("unchecked") @RequestMapping("/saveOrUpdateQuestion") public String saveOrUpdateQuestion(@ModelAttribute("assessmentQuestionForm") QbQuestionForm questionForm, - HttpServletRequest request) { + HttpServletRequest request, @RequestParam Long qbQuestionUid, @RequestParam int questionModificationStatus) { + String sessionMapId = questionForm.getSessionMapID(); SessionMap sessionMap = (SessionMap) request.getSession() - .getAttribute(questionForm.getSessionMapID()); - boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); - SortedSet questionList = getQuestionList(sessionMap); + .getAttribute(sessionMapId); + SortedSet references = getQuestionReferences(sessionMap); + QbQuestion qbQuestion = qbService.getQuestionByUid(qbQuestionUid); - //find according question - AssessmentQuestion question = null; // add - if (questionForm.getDisplayOrder() == -1) { - question = new AssessmentQuestion(); - QbQuestion qbQuestion = new QbQuestion(); - qbQuestion.setType(questionForm.getQuestionType()); - question.setQbQuestion(qbQuestion); - int maxSeq = 1; - if ((questionList != null) && (questionList.size() > 0)) { - AssessmentQuestion last = questionList.last(); - maxSeq = last.getDisplayOrder() + 1; + Long oldQbQuestionUid = questionForm.getUid(); + if (oldQbQuestionUid == -1) { + AssessmentQuestion assessmentQuestion = new AssessmentQuestion(); + assessmentQuestion.setQbQuestion(qbQuestion); + assessmentQuestion.setRandomQuestion(false); + assessmentQuestion.setDisplayOrder(getNextDisplayOrder(sessionMap)); + + //create new QuestionReference + QuestionReference reference = new QuestionReference(); + reference.setQuestion(assessmentQuestion); + reference.setRandomQuestion(false); + // set SequenceId + int maxSeq2 = 1; + if ((references != null) && (references.size() > 0)) { + QuestionReference last = references.last(); + maxSeq2 = last.getSequenceId() + 1; } - question.setDisplayOrder(maxSeq); - questionList.add(question); + reference.setSequenceId(maxSeq2); + //set maxMark + int maxMark = qbQuestion.getMaxMark() == null ? 1 : qbQuestion.getMaxMark(); + reference.setMaxMark(maxMark); + references.add(reference); // edit } else { - for (AssessmentQuestion questionIter : questionList) { - if (questionIter.getDisplayOrder() == questionForm.getDisplayOrder()) { - question = questionIter; - break; + //QbQuestion's uid is kept the same - means it's a minor change, do nothing + if (oldQbQuestionUid.equals(qbQuestion.getUid())) { + + //replace QbQuestion with the new version of it + } else { + for (QuestionReference reference : references) { + if (!reference.isRandomQuestion() + && oldQbQuestionUid.equals(reference.getQuestion().getQbQuestion().getUid())) { + AssessmentQuestion assessmentQuestion = reference.getQuestion(); + assessmentQuestion.setQbQuestion(qbQuestion); + assessmentQuestion.setDisplayOrder(getNextDisplayOrder(sessionMap)); + break; + } } } } - QbQuestion qbQuestion = question.getQbQuestion(); - // evict everything manually as we do not use DTOs, just real entities - // without eviction changes would be saved immediately into DB - service.releaseFromCache(question); - service.releaseFromCache(qbQuestion); +// QbQuestion qbQuestion = assessmentQuestion.getQbQuestion(); +// // evict everything manually as we do not use DTOs, just real entities +// // without eviction changes would be saved immediately into DB +// service.releaseFromCache(assessmentQuestion); +// service.releaseFromCache(qbQuestion); - int isQbQuestionModified = QbUtils.extractFormToQbQuestion(qbQuestion, questionForm, request, qbService, - isAuthoringRestricted); - question.setQbQuestionModified(isQbQuestionModified); - request.setAttribute("qbQuestionModified", isQbQuestionModified); - reinitializeAvailableQuestions(sessionMap); + +// int isQbQuestionModified = QbUtils.extractFormToQbQuestion(qbQuestion, questionForm, request, qbService, +// isAuthoringRestricted); +// assessmentQuestion.setQbQuestionModified(isQbQuestionModified); + request.setAttribute("qbQuestionModified", questionModificationStatus); // set session map ID so that questionlist.jsp can get sessionMAP - request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, questionForm.getSessionMapID()); + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapId); //in case of edit in monitor and at least one attempted user, we show authoring page with restricted options + boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); if (isAuthoringRestricted) { return "pages/authoring/parts/questionlistRestricted"; } else { @@ -514,137 +537,89 @@ */ @SuppressWarnings("unchecked") @RequestMapping(value = "/importQbQuestion", method = RequestMethod.POST) - private String importQbQuestion(HttpServletRequest request) { + private String importQbQuestion(HttpServletRequest request, @RequestParam Long qbQuestionUid) { + //TODO perform updateQuestionReferencesMaxMarks prior to runnning this method + String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); SessionMap sessionMap = (SessionMap) request.getSession() .getAttribute(sessionMapID); - SortedSet questionList = getQuestionList(sessionMap); - - Long qbQuestionUid = WebUtil.readLongParam(request, "qbQuestionUid"); QbQuestion qbQuestion = qbService.getQuestionByUid(qbQuestionUid); //create new ScratchieItem and assign imported qbQuestion to it - AssessmentQuestion question = new AssessmentQuestion(); - question.setQbQuestion(qbQuestion); - int maxSeq = 1; - if (questionList != null && questionList.size() > 0) { - AssessmentQuestion last = questionList.last(); - maxSeq = last.getDisplayOrder() + 1; - } - question.setDisplayOrder(maxSeq); - question.setQbQuestionModified(IQbService.QUESTION_MODIFIED_NONE); - questionList.add(question); + AssessmentQuestion assessmentQuestion = new AssessmentQuestion(); + assessmentQuestion.setQbQuestion(qbQuestion); + assessmentQuestion.setDisplayOrder(getNextDisplayOrder(sessionMap)); + + QuestionReference reference = new QuestionReference(); + reference.setQuestion(assessmentQuestion); + reference.setRandomQuestion(false); - reinitializeAvailableQuestions(sessionMap); - - // set session map ID so that itemlist.jsp can get sessionMAP - request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); - return "pages/authoring/parts/questionlist"; - } - - /** - * Remove assessment question 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. - */ - @RequestMapping("/removeQuestion") - public String removeQuestion(HttpServletRequest request) { - SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesMaxMarks(request, sessionMap, false); - - int deletedQuestionDisplayOrder = NumberUtils.toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_DISPLAY_ORDER), -1); - SortedSet questionList = getQuestionList(sessionMap); - Iterator iterator = questionList.iterator(); - AssessmentQuestion deletedQuestion = null; - while (iterator.hasNext()) { - AssessmentQuestion questionIter = iterator.next(); - if (questionIter.getDisplayOrder() == deletedQuestionDisplayOrder) { - deletedQuestion = questionIter; - iterator.remove(); - } - } - - // add to delList - List delList = getDeletedQuestionList(sessionMap); - delList.add(deletedQuestion); - - // remove according questionReference, if exists - SortedSet questionReferences = getQuestionReferences(sessionMap); - QuestionReference questionReferenceToDelete = null; - for (QuestionReference questionReference : questionReferences) { - if ((questionReference.getQuestion() != null) - && (questionReference.getQuestion().getDisplayOrder() == deletedQuestionDisplayOrder)) { - questionReferenceToDelete = questionReference; - } - } - // check if we need to delete random question reference - if ((questionReferenceToDelete == null) && (questionReferences.size() > questionList.size())) { - // find the first random question - for (QuestionReference questionReference : questionReferences) { - if (questionReference.isRandomQuestion()) { - questionReferenceToDelete = questionReference; - break; - } - } - } - if (questionReferenceToDelete != null) { - questionReferences.remove(questionReferenceToDelete); - // add to delList - List delReferencesList = getDeletedQuestionReferences(sessionMap); - delReferencesList.add(questionReferenceToDelete); - } - - reinitializeAvailableQuestions(sessionMap); - return "pages/authoring/parts/questionlist"; - } - - /** - * Remove assessment question 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. - */ - @RequestMapping("/addQuestionReference") - public String addQuestionReference(HttpServletRequest request) { - SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesMaxMarks(request, sessionMap, false); - - SortedSet references = getQuestionReferences(sessionMap); - int questionIdx = NumberUtils.toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_INDEX), -1); - // set SequenceId - QuestionReference reference = new QuestionReference(); int maxSeq = 1; + SortedSet references = getQuestionReferences(sessionMap); if ((references != null) && (references.size() > 0)) { QuestionReference last = references.last(); maxSeq = last.getSequenceId() + 1; } reference.setSequenceId(maxSeq); - - // set isRandomQuestion - boolean isRandomQuestion = (questionIdx == -1); - reference.setRandomQuestion(isRandomQuestion); - - if (isRandomQuestion) { - reference.setMaxMark(1); - } else { - SortedSet questionList = getQuestionList(sessionMap); - AssessmentQuestion question = null; - for (AssessmentQuestion questionFromList : questionList) { - if (questionFromList.getDisplayOrder() == questionIdx) { - question = questionFromList; - break; - } - } - reference.setQuestion(question); - - int maxMark = question.getQbQuestion().getMaxMark() == null ? 1 : question.getQbQuestion().getMaxMark(); - reference.setMaxMark(maxMark); - } + + //set maxMark + int maxMark = qbQuestion.getMaxMark() == null ? 1 : qbQuestion.getMaxMark(); + reference.setMaxMark(maxMark); + references.add(reference); - reinitializeAvailableQuestions(sessionMap); - + // set session map ID so that itemlist.jsp can get sessionMAP + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); return "pages/authoring/parts/questionlist"; } +// /** +// * Remove assessment question 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. +// */ +// @RequestMapping("/addQuestionReference") +// public String addQuestionReference(HttpServletRequest request, @RequestParam int questionIndex) { +// SessionMap sessionMap = getSessionMap(request); +// updateQuestionReferencesMaxMarks(request, sessionMap, false); +// +// SortedSet references = getQuestionReferences(sessionMap); +// +// // set SequenceId +// QuestionReference reference = new QuestionReference(); +// int maxSeq = 1; +// if ((references != null) && (references.size() > 0)) { +// QuestionReference last = references.last(); +// maxSeq = last.getSequenceId() + 1; +// } +// reference.setSequenceId(maxSeq); +// +// // set isRandomQuestion +// boolean isRandomQuestion = (questionIndex == -1); +// reference.setRandomQuestion(isRandomQuestion); +// +// if (isRandomQuestion) { +// reference.setMaxMark(1); +// +// } else { +// SortedSet questionList = getQuestionList(sessionMap); +// AssessmentQuestion question = null; +// for (AssessmentQuestion questionFromList : questionList) { +// if (questionFromList.getDisplayOrder() == questionIndex) { +// question = questionFromList; +// break; +// } +// } +// reference.setQuestion(question); +// +// int maxMark = question.getQbQuestion().getMaxMark() == null ? 1 : question.getQbQuestion().getMaxMark(); +// reference.setMaxMark(maxMark); +// } +// references.add(reference); +// +// return "pages/authoring/parts/questionlist"; +// } + /** * Remove assessment question 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. @@ -667,8 +642,6 @@ delList.add(questionReference); } - reinitializeAvailableQuestions(sessionMap); - return "pages/authoring/parts/questionlist"; } @@ -722,51 +695,48 @@ return "pages/authoring/parts/questionlist"; } } + + @RequestMapping("/addToRandomPool") + @ResponseBody + public String addToRandomPool(HttpServletRequest request, HttpServletResponse response, + @RequestParam Long qbQuestionUid) { + SessionMap sessionMap = getSessionMap(request); + QbQuestion qbQuestion = qbService.getQuestionByUid(qbQuestionUid); + + AssessmentQuestion assessmentQuestion = new AssessmentQuestion(); + assessmentQuestion.setQbQuestion(qbQuestion); + assessmentQuestion.setRandomQuestion(true); + assessmentQuestion.setDisplayOrder(getNextDisplayOrder(sessionMap)); + + List randomPoolQuestions = getRandomPoolQuestions(sessionMap); + randomPoolQuestions.add(assessmentQuestion); - /** - * Ajax call, will add one more input line for new resource item instruction. - */ - @RequestMapping("/addOption") - public String addOption(HttpServletRequest request) { - TreeSet optionList = QbUtils.getOptionsFromRequest(qbService, request, false); - QbOption option = new QbOption(); - int maxSeq = 1; - if ((optionList != null) && (optionList.size() > 0)) { - QbOption last = optionList.last(); - maxSeq = last.getDisplayOrder() + 1; - } - option.setDisplayOrder(maxSeq); - optionList.add(option); - - request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, - WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID)); - request.setAttribute(AssessmentConstants.ATTR_QUESTION_TYPE, - WebUtil.readIntParam(request, AssessmentConstants.ATTR_QUESTION_TYPE)); - request.setAttribute(QbConstants.ATTR_OPTION_LIST, optionList); - return "pages/authoring/parts/optionlist"; + ObjectNode responseJSON = JsonNodeFactory.instance.objectNode(); + responseJSON.put("isDone", true); + response.setContentType("application/json;charset=utf-8"); + return responseJSON.toString(); } - - /** - * Ajax call, will add one more input line for new Unit. - */ - @RequestMapping("/newUnit") - public String newUnit(HttpServletRequest request) { - TreeSet unitList = QbUtils.getUnitsFromRequest(qbService, request, false); - QbQuestionUnit unit = new QbQuestionUnit(); - int maxSeq = 1; - if ((unitList != null) && (unitList.size() > 0)) { - QbQuestionUnit last = unitList.last(); - maxSeq = last.getDisplayOrder() + 1; + + @RequestMapping("/removeFromRandomPool") + @ResponseBody + public void removeFromRandomPool(HttpServletRequest request, HttpServletResponse response, + @RequestParam Long qbQuestionUid) { + SessionMap sessionMap = getSessionMap(request); + + List randomPoolQuestions = getRandomPoolQuestions(sessionMap); + for (AssessmentQuestion randomPoolQuestion : randomPoolQuestions) { + if (qbQuestionUid.equals(randomPoolQuestion.getQbQuestion().getUid())) { + randomPoolQuestions.remove(randomPoolQuestion); + + // add to delList + List deletedRandomPoolQuestions = getDeletedRandomPoolQuestions(sessionMap); + deletedRandomPoolQuestions.add(randomPoolQuestion); + } } - unit.setDisplayOrder(maxSeq); - unitList.add(unit); - - request.setAttribute(AssessmentConstants.ATTR_UNIT_LIST, unitList); - return "pages/authoring/parts/unitlist"; } /** - * Ajax call, will add one more input line for new resource item instruction. + * Ajax call, will add one more input line for a new OverallFeedback. */ @RequestMapping("/initOverallFeedback") public String initOverallFeedback(HttpServletRequest request) { @@ -817,38 +787,6 @@ // ************************************************************************************* /** - * refreshes set of all available questions for adding to question list - */ - @SuppressWarnings("unchecked") - private void reinitializeAvailableQuestions(SessionMap sessionMap) { - SortedSet bankQuestions = getQuestionList(sessionMap); - SortedSet references = getQuestionReferences(sessionMap); - Set questionsFromList = new LinkedHashSet<>(); - for (QuestionReference reference : references) { - questionsFromList.add(reference.getQuestion()); - } - - Set availableQuestions = new TreeSet<>(); - availableQuestions.addAll(CollectionUtils.subtract(bankQuestions, questionsFromList)); - - sessionMap.put(AssessmentConstants.ATTR_AVAILABLE_QUESTIONS, availableQuestions); - } - - /** - * List save current assessment questions. - */ - @SuppressWarnings("unchecked") - private SortedSet getQuestionList(SessionMap sessionMap) { - SortedSet list = (SortedSet) sessionMap - .get(AssessmentConstants.ATTR_QUESTION_LIST); - if (list == null) { - list = new TreeSet<>(); - sessionMap.put(AssessmentConstants.ATTR_QUESTION_LIST, list); - } - return list; - } - - /** * List save current question references. */ @SuppressWarnings("unchecked") @@ -866,16 +804,24 @@ * List save deleted assessment questions, which could be persisted or non-persisted questions. */ @SuppressWarnings("unchecked") - private List getDeletedQuestionList(SessionMap sessionMap) { - return (List) getListFromSession(sessionMap, AssessmentConstants.ATTR_DELETED_QUESTION_LIST); + private List getDeletedQuestionReferences(SessionMap sessionMap) { + return (List) getListFromSession(sessionMap, AssessmentConstants.ATTR_DELETED_QUESTION_REFERENCES); } + + /** + * List current assessment questions. + */ + @SuppressWarnings("unchecked") + private List getRandomPoolQuestions(SessionMap sessionMap) { + return (List) getListFromSession(sessionMap, AssessmentConstants.ATTR_RANDOM_POOL_QUESTIONS); + } /** - * List save deleted assessment questions, which could be persisted or non-persisted questions. + * List current assessment questions. */ @SuppressWarnings("unchecked") - private List getDeletedQuestionReferences(SessionMap sessionMap) { - return (List) getListFromSession(sessionMap, AssessmentConstants.ATTR_DELETED_QUESTION_REFERENCES); + private List getDeletedRandomPoolQuestions(SessionMap sessionMap) { + return (List) getListFromSession(sessionMap, AssessmentConstants.ATTR_DELETED_RANDOM_POOL_QUESTIONS); } /** @@ -890,43 +836,6 @@ return list; } - /** - * Get back jsp name. - */ - private String findForward(Integer type) { - String forward; - switch (type) { - case QbQuestion.TYPE_MULTIPLE_CHOICE: - forward = "pages/authoring/parts/addmultiplechoice"; - break; - case QbQuestion.TYPE_MATCHING_PAIRS: - forward = "pages/authoring/parts/addmatchingpairs"; - break; - case QbQuestion.TYPE_SHORT_ANSWER: - forward = "pages/authoring/parts/addshortanswer"; - break; - case QbQuestion.TYPE_NUMERICAL: - forward = "pages/authoring/parts/addnumerical"; - break; - case QbQuestion.TYPE_TRUE_FALSE: - forward = "pages/authoring/parts/addtruefalse"; - break; - case QbQuestion.TYPE_ESSAY: - forward = "pages/authoring/parts/addessay"; - break; - case QbQuestion.TYPE_ORDERING: - forward = "pages/authoring/parts/addordering"; - break; - case QbQuestion.TYPE_MARK_HEDGING: - forward = "pages/authoring/parts/addmarkhedging"; - break; - default: - forward = null; - break; - } - return forward; - } - private Set updateQuestionReferencesMaxMarks(HttpServletRequest request, SessionMap sessionMap, boolean isFormSubmit) { Map paramMap = splitRequestParameter(request, @@ -1075,4 +984,25 @@ request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); return (SessionMap) request.getSession().getAttribute(sessionMapID); } + + private int getNextDisplayOrder(SessionMap sessionMap) { + int maxDisplayOrder = 1; + + List randomPoolQuestions = getRandomPoolQuestions(sessionMap); + for (AssessmentQuestion randomPoolQuestion : randomPoolQuestions) { + if (randomPoolQuestion.getDisplayOrder() > maxDisplayOrder) { + maxDisplayOrder = randomPoolQuestion.getDisplayOrder(); + } + } + + Set references = getQuestionReferences(sessionMap); + for (QuestionReference reference : references) { + AssessmentQuestion question = reference.getQuestion(); + if (question != null && question.getDisplayOrder() > maxDisplayOrder) { + maxDisplayOrder = question.getDisplayOrder(); + } + } + + return maxDisplayOrder+1; + } } Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/AuthoringController.java =================================================================== diff -u -r0b1e74374b821758fdda7835d8d283bf84fa8db0 -rd709559abc2186520af2f18c3fc7417a5a598e9e --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 0b1e74374b821758fdda7835d8d283bf84fa8db0) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/AuthoringController.java (.../AuthoringController.java) (revision d709559abc2186520af2f18c3fc7417a5a598e9e) @@ -34,7 +34,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -43,7 +42,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.math.NumberUtils; @@ -52,11 +50,6 @@ import org.lamsfoundation.lams.qb.model.QbOption; import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.qb.service.IQbService; -import org.lamsfoundation.lams.qb.service.QbUtils; -import org.lamsfoundation.lams.questions.Answer; -import org.lamsfoundation.lams.questions.Question; -import org.lamsfoundation.lams.questions.QuestionExporter; -import org.lamsfoundation.lams.questions.QuestionParser; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.scratchie.ScratchieConstants; import org.lamsfoundation.lams.tool.scratchie.model.Scratchie; @@ -496,8 +489,9 @@ } item.getQbQuestion().setQbOptions(options); - item.setQbQuestionModified(QbUtils.isQbQuestionModified(baseLine, item.getQbQuestion())); - request.setAttribute("qbQuestionModified", item.getQbQuestionModified()); + int isQbQuestionModified = item.getQbQuestion().isQbQuestionModified(baseLine); + item.setQbQuestionModified(isQbQuestionModified); + request.setAttribute("qbQuestionModified", isQbQuestionModified); // set session map ID so that itemlist.jsp can get sessionMAP request.setAttribute(ScratchieConstants.ATTR_SESSION_MAP_ID, scratchieItemForm.getSessionMapID());