Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20190809.sql =================================================================== diff -u --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20190809.sql (revision 0) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20190809.sql (revision 846fd5c0307ebedc923d937f6dbe9a614b746e2e) @@ -0,0 +1,15 @@ +-- Turn off autocommit, so nothing is committed if there is an error +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS=0; +----------------------Put all sql statements below here------------------------- + +--LDEV-4845 Bump version so content version filter kicks in + +UPDATE lams_tool SET tool_version='20190809' WHERE tool_signature='laasse10'; + +----------------------Put all sql statements above here------------------------- + +-- If there were no errors, commit and restore autocommit to on +COMMIT; +SET AUTOCOMMIT = 1; +SET FOREIGN_KEY_CHECKS=1; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentImportContentVersionFilter.java =================================================================== diff -u -r6cbd849584c40532c6be292f9f009c88cde9439c -r846fd5c0307ebedc923d937f6dbe9a614b746e2e --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentImportContentVersionFilter.java (.../AssessmentImportContentVersionFilter.java) (revision 6cbd849584c40532c6be292f9f009c88cde9439c) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentImportContentVersionFilter.java (.../AssessmentImportContentVersionFilter.java) (revision 846fd5c0307ebedc923d937f6dbe9a614b746e2e) @@ -20,13 +20,20 @@ * **************************************************************** */ - package org.lamsfoundation.lams.tool.assessment.service; +import java.io.IOException; +import java.util.List; + import org.lamsfoundation.lams.learningdesign.service.ToolContentVersionFilter; +import org.lamsfoundation.lams.qb.QbUtils; import org.lamsfoundation.lams.tool.assessment.model.Assessment; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; +import org.lamsfoundation.lams.util.XMLUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; /** * Import filter class for different version of Assessment content. @@ -57,7 +64,7 @@ this.renameField(AssessmentQuestion.class, "questionOptions", "options"); this.addField(AssessmentQuestion.class, "answerRequired", "true"); } - + /** * Import 20140428 version content to 20140707 version tool server. */ @@ -73,28 +80,155 @@ this.removeField(AssessmentQuestion.class, "mark"); this.removeField(AssessmentQuestion.class, "penalty"); this.removeField(AssessmentQuestion.class, "answerTotalGrade"); - + // this.removeField(AssessmentQuestionOption.class, "answerInt"); // this.removeField(AssessmentQuestionOption.class, "answerBoolean"); } - + /** * Import 20140428 version content to 20140707 version tool server. */ public void up20170315To20190110() { this.renameField(QuestionReference.class, "defaultGrade", "maxMark"); this.renameField(QuestionReference.class, "sequenceId", "displayOrder"); } - + /** * Import 20190110 version content to 20190517 version tool server. */ public void up20190110To20190517() { this.removeField(AssessmentQuestion.class, "questionHash"); } - + public void up20190517To20190704() { this.removeField(QuestionReference.class, "title"); this.removeField(QuestionReference.class, "type"); } + + public void up20190704To20190809(String toolFilePath) throws IOException { + // tell which file to process and what to do with its root element + transformXML(toolFilePath, root -> { + Document document = root.getOwnerDocument(); + + // first find questions + NodeList assessmentQuestions = root + .getElementsByTagName("org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion"); + if (assessmentQuestions.getLength() == 0) { + return; + } + + // go through each question + for (int assessmentQuestionIndex = 0; assessmentQuestionIndex < assessmentQuestions + .getLength(); assessmentQuestionIndex++) { + Element assessmentQuestion = (Element) assessmentQuestions.item(assessmentQuestionIndex); + // create an element for QbQuestion + Element qbQuestion = document.createElement("qbQuestion"); + assessmentQuestion.appendChild(qbQuestion); + + // transform Assessment data into QB structure + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "type", "type", null, false, true); + // Question ID will be filled later as it requires QbService + XMLUtil.addTextElement(qbQuestion, "version", "1"); + XMLUtil.rewriteTextElement(root, qbQuestion, "created", "createDate", null, true, false); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "title", "name", null, false, true, + QbUtils.QB_MIGRATION_CKEDITOR_CLEANER, QbUtils.QB_MIGRATION_TAG_CLEANER); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "question", "description", null, false, true, + QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "defaultGrade", "maxMark", "1", false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "generalFeedback", "feedback", null, false, + true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); + XMLUtil.rewriteTextElement(assessmentQuestion, assessmentQuestion, "sequenceId", "displayOrder", null, + false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "penaltyFactor", "penaltyFactor", "0", false, + true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "answerRequired", "answerRequired", "false", + false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "multipleAnswersAllowed", + "multipleAnswersAllowed", "false", false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "incorrectAnswerNullifiesMark", + "incorrectAnswerNullifiesMark", "false", false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "feedbackOnCorrect", "feedbackOnCorrect", + null, false, true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "feedbackOnPartiallyCorrect", + "feedbackOnPartiallyCorrect", null, false, true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "feedbackOnIncorrect", "feedbackOnIncorrect", + null, false, true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "shuffle", "shuffle", "false", false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "prefixAnswersWithLetters", + "prefixAnswersWithLetters", "false", false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "caseSensitive", "caseSensitive", "false", + false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "correctAnswer", "correctAnswer", "false", + false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "allowRichEditor", "allowRichEditor", + "false", false, true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "maxWordsLimit", "maxWordsLimit", "0", false, + true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "minWordsLimit", "minWordsLimit", "0", false, + true); + XMLUtil.rewriteTextElement(assessmentQuestion, qbQuestion, "hedgingJustificationEnabled", + "hedgingJustificationEnabled", "false", false, true); + + // now it's time for options + NodeList assessmentOptions = assessmentQuestion + .getElementsByTagName("org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption"); + if (assessmentOptions.getLength() == 0) { + continue; + } + + boolean shiftOptionsDisplayOrder = false; + List assessmentOptionsSequenceIds = XMLUtil + .findChildren((Element) assessmentOptions.item(0).getParentNode(), "sequenceId"); + for (Element sequenceIdElement : assessmentOptionsSequenceIds) { + int sequenceId = Integer.parseInt(sequenceIdElement.getTextContent()); + if (sequenceId == 0) { + shiftOptionsDisplayOrder = true; + break; + } + } + + Element qbOptions = document.createElement("qbOptions"); + qbQuestion.appendChild(qbOptions); + int maxDisplayOrder = 0; + for (int assessmentOptionIndex = 0; assessmentOptionIndex < assessmentOptions + .getLength(); assessmentOptionIndex++) { + Element assessmentOption = (Element) assessmentOptions.item(assessmentOptionIndex); + Element qbOption = document.createElement("org.lamsfoundation.lams.qb.model.QbOption"); + qbOptions.appendChild(qbOption); + + String sequenceIdString = XMLUtil.getChildElementValue(assessmentOption, "sequenceId", null); + Integer sequenceId = sequenceIdString == null ? null : Integer.valueOf(sequenceIdString); + if (sequenceId == null) { + sequenceId = ++maxDisplayOrder; + } + if (shiftOptionsDisplayOrder) { + sequenceId++; + } + XMLUtil.rewriteTextElement(assessmentOption, qbOption, "sequenceId", "displayOrder", + String.valueOf(sequenceId), false, true); + XMLUtil.rewriteTextElement(assessmentOption, qbOption, "grade", "maxMark", "1", false, true); + XMLUtil.rewriteTextElement(assessmentOption, qbOption, "optionString", "name", null, false, true, + QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); + } + + // get rid of junk + assessmentQuestion.removeChild(assessmentOptions.item(0).getParentNode()); + XMLUtil.removeElement(assessmentQuestion, "questionHash"); + } + + // now rewrite question references + NodeList questionReferences = root + .getElementsByTagName("org.lamsfoundation.lams.tool.assessment.model.QuestionReference"); + if (questionReferences.getLength() == 0) { + return; + } + + for (int questionReferenceIndex = 0; questionReferenceIndex < questionReferences + .getLength(); questionReferenceIndex++) { + Element questionReference = (Element) questionReferences.item(questionReferenceIndex); + XMLUtil.rewriteTextElement(questionReference, questionReference, "defaultGrade", "maxMark", "1", false, + true); + } + }); + } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -rec62f6f6a9e56cd545c527d2fd530614b3a7e744 -r846fd5c0307ebedc923d937f6dbe9a614b746e2e --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision ec62f6f6a9e56cd545c527d2fd530614b3a7e744) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 846fd5c0307ebedc923d937f6dbe9a614b746e2e) @@ -2260,10 +2260,10 @@ //check whether according question was modified for (AssessmentQuestion modifiedQuestion : modifiedQuestions) { if (oldQuestion.getDisplayOrder() == modifiedQuestion.getDisplayOrder()) { - - //update questionResult's qbQuestion with the new one + + //update questionResult's qbQuestion with the new one questionResult.setQbToolQuestion(modifiedQuestion); - //update questionResult's qbOption + //update questionResult's qbOption // for (QbOption newOption : modifiedQuestion.getQbQuestion().getQbOptions()) { // if (questionResult.getQbOption().getDisplayOrder() == newOption.getDisplayOrder()) { // questionResult.setQbOption(newOption); @@ -2272,29 +2272,30 @@ // } //update questionResult's optionAnswers for (AssessmentOptionAnswer oldOptionAnswer : questionResult.getOptionAnswers()) { - + //find according old qbOption QbOption oldOption = null; - for (QbOption oldOptionIter: oldQuestion.getQbQuestion().getQbOptions()) { + for (QbOption oldOptionIter : oldQuestion.getQbQuestion().getQbOptions()) { if (oldOptionIter.getUid().equals(oldOptionAnswer.getOptionUid())) { oldOption = oldOptionIter; } } - + //update for (QbOption newOption : modifiedQuestion.getQbQuestion().getQbOptions()) { if (oldOption.getDisplayOrder() == newOption.getDisplayOrder()) { oldOptionAnswer.setOptionUid(newOption.getUid()); break; } } - } - + } + //actually recalculate marks QuestionDTO modifiedQuestionDto = new QuestionDTO(modifiedQuestion); modifiedQuestionDto.setMaxMark(oldResultMaxMark); loadupQuestionResultIntoQuestionDto(modifiedQuestionDto, questionResult); - calculateAnswerMark(assessmentUid, user.getUserId(), questionResult, modifiedQuestionDto); + calculateAnswerMark(assessmentUid, user.getUserId(), questionResult, + modifiedQuestionDto); assessmentQuestionResultDao.saveObject(questionResult); float newQuestionAnswerMark = questionResult.getMark(); @@ -2643,6 +2644,26 @@ } toolContentObj.setCreatedBy(user); + // we need to save QB questions and options first + for (AssessmentQuestion assessmentQuestion : toolContentObj.getQuestions()) { + QbQuestion qbQuestion = assessmentQuestion.getQbQuestion(); + qbQuestion.setQuestionId(qbService.generateNextQuestionId()); + + Collection qbOptions = new ArrayList<>(qbQuestion.getQbOptions()); + qbQuestion.getQbOptions().clear(); + + assessmentDao.insert(qbQuestion); + + qbQuestion.getQbOptions().addAll(qbOptions); + for (QbOption qbOption : qbOptions) { + qbOption.setQbQuestion(qbQuestion); + assessmentDao.insert(qbOption); + } + qbOptions.clear(); + + assessmentDao.insert(assessmentQuestion); + } + saveOrUpdateAssessment(toolContentObj); } catch (ImportToolContentException e) { throw new ToolException(e); Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieImportContentVersionFilter.java =================================================================== diff -u -rb765f567ba3ca9ca048b434d243d94d865ef363c -r846fd5c0307ebedc923d937f6dbe9a614b746e2e --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieImportContentVersionFilter.java (.../ScratchieImportContentVersionFilter.java) (revision b765f567ba3ca9ca048b434d243d94d865ef363c) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieImportContentVersionFilter.java (.../ScratchieImportContentVersionFilter.java) (revision 846fd5c0307ebedc923d937f6dbe9a614b746e2e) @@ -124,7 +124,7 @@ XMLUtil.rewriteTextElement(scratchieQuestion, qbQuestion, "title", "name", null, false, true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER, QbUtils.QB_MIGRATION_TAG_CLEANER); XMLUtil.rewriteTextElement(scratchieQuestion, qbQuestion, "description", "description", null, false, - true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER, QbUtils.QB_MIGRATION_TRIMMER); + true, QbUtils.QB_MIGRATION_CKEDITOR_CLEANER); XMLUtil.rewriteTextElement(scratchieQuestion, scratchieQuestion, "orderId", "displayOrder", null, false, true);