Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/QbStatsController.java =================================================================== diff -u -re51bab38bdf978a85dccdcd423dccd9001d7b2f0 -re00ee97b803f195e523abcd3f765513a58a03d32 --- lams_central/src/java/org/lamsfoundation/lams/web/qb/QbStatsController.java (.../QbStatsController.java) (revision e51bab38bdf978a85dccdcd423dccd9001d7b2f0) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/QbStatsController.java (.../QbStatsController.java) (revision e00ee97b803f195e523abcd3f765513a58a03d32) @@ -23,6 +23,7 @@ package org.lamsfoundation.lams.web.qb; import java.util.Collection; +import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; @@ -34,6 +35,7 @@ import org.lamsfoundation.lams.outcome.service.OutcomeService; import org.lamsfoundation.lams.qb.dto.QbStatsDTO; import org.lamsfoundation.lams.qb.model.QbCollection; +import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.qb.service.IQbService; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.Configuration; @@ -101,6 +103,41 @@ return "qb/stats"; } + @RequestMapping("/merge") + public String mergeQuestions(@RequestParam long sourceQbQuestionUid, @RequestParam long targetQbQuestionUid, + Model model) throws Exception { + QbQuestion sourceQuestion = qbService.getQuestionByUid(sourceQbQuestionUid); + QbQuestion targetQuestion = qbService.getQuestionByUid(targetQbQuestionUid); + List mergeErrors = new LinkedList<>(); + + if (sourceQuestion == null) { + // TODO rewrite it to i18n keys + mergeErrors.add("Source question does not exist"); + } + if (targetQuestion == null) { + mergeErrors.add("Target question does not exist"); + } + + if (mergeErrors.isEmpty()) { + if (!sourceQuestion.getType().equals(targetQuestion.getType())) { + mergeErrors.add("Source question type is different to target question type"); + } + + if (sourceQuestion.getQbOptions().size() != targetQuestion.getQbOptions().size()) { + mergeErrors.add("Number of options in source and target questions does not match"); + } + } + if (mergeErrors.isEmpty()) { + int answersChanged = qbService.mergeQuestions(sourceQbQuestionUid, targetQbQuestionUid); + model.addAttribute("mergeSourceQbQuestionUid", sourceQbQuestionUid); + model.addAttribute("mergeResult", answersChanged); + return showStats(targetQbQuestionUid, model); + } + + model.addAttribute("mergeErrors", mergeErrors); + return showStats(sourceQbQuestionUid, model); + } + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); Index: lams_central/web/qb/stats.jsp =================================================================== diff -u -r269c13324c6bb998631af858dc8091ad3102ef78 -re00ee97b803f195e523abcd3f765513a58a03d32 --- lams_central/web/qb/stats.jsp (.../stats.jsp) (revision 269c13324c6bb998631af858dc8091ad3102ef78) +++ lams_central/web/qb/stats.jsp (.../stats.jsp) (revision e00ee97b803f195e523abcd3f765513a58a03d32) @@ -54,6 +54,10 @@ a { cursor: pointer; } + + .alert ul { + margin-left: 10px; + } @@ -91,7 +95,7 @@ }, 'cache' : false }).done(function(){ - document.location.reload(); + document.location.href = 'qb/stats/show.do?qbQuestionUid=${question.uid}'; }); } @@ -118,7 +122,7 @@ if (permanentRemove) { document.location.href = 'qb/collection/show.do'; } else { - document.location.reload(); + document.location.href = 'qb/stats/show.do?qbQuestionUid=${question.uid}'; } }); } @@ -140,6 +144,12 @@
+ +
+ Question with UID ${mergeSourceQbQuestionUid} was merged with this question.
+ Number of migrated learner answers: ${mergeResult} +
+
@@ -157,6 +167,14 @@
+ UID: +
+
+ +
+
+
+
:
@@ -366,7 +384,6 @@ - @@ -478,7 +495,7 @@ - +
@@ -517,6 +534,53 @@
+ + +
+
+ Merge this question with... +
+
+ +
+
+
+
    + +
  • +
    +
+
+
+
+
+ +
+
+ +
+ Question UID +
+
+ +
+
+ +
+
+
+ +
+
+
+ This will merge this question with the question UID you entered above. + Before you do this, make sure you know what are you doing as once merging is performed this cannot be undone. +
+
+
+
+
+
Index: lams_common/src/java/org/lamsfoundation/lams/qb/dao/IQbDAO.java =================================================================== diff -u -ra2b41bfd7ae2b33847ddbc9d9c46e18b30272905 -re00ee97b803f195e523abcd3f765513a58a03d32 --- lams_common/src/java/org/lamsfoundation/lams/qb/dao/IQbDAO.java (.../IQbDAO.java) (revision a2b41bfd7ae2b33847ddbc9d9c46e18b30272905) +++ lams_common/src/java/org/lamsfoundation/lams/qb/dao/IQbDAO.java (.../IQbDAO.java) (revision e00ee97b803f195e523abcd3f765513a58a03d32) @@ -72,4 +72,6 @@ Set getCollectionQuestionIdsExcluded(long collectionUid, Collection qbQuestionIds); boolean isQuestionInUserCollection(int userId, int qbQuestionId); + + int mergeQuestions(long sourceQbQUestionUid, long targetQbQuestionUid); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java =================================================================== diff -u -r4de125b4eb4a3059669e7808bf4b6a85f06c9077 -re00ee97b803f195e523abcd3f765513a58a03d32 --- lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java (.../QbDAO.java) (revision 4de125b4eb4a3059669e7808bf4b6a85f06c9077) +++ lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java (.../QbDAO.java) (revision e00ee97b803f195e523abcd3f765513a58a03d32) @@ -100,6 +100,14 @@ private static final String GENERATE_QUESTION_ID = "INSERT INTO lams_sequence_generator(lams_qb_question_question_id) VALUES (:qbQuestionId)"; + private static final String MERGE_TOOL_QUESTIONS = "UPDATE QbToolQuestion SET qbQuestion.uid = :targetQbQuestionUid WHERE qbQuestion.uid = :sourceQbQuestionUid"; + + private static final String MERGE_QUESTION_ANSWERS = "UPDATE lams_qb_tool_answer AS tas " + + "JOIN lams_qb_option AS os ON os.qb_question_uid = :sourceQbQuestionUid AND tas.qb_option_uid = os.uid " + + "JOIN lams_qb_option AS ot ON ot.qb_question_uid = :targetQbQuestionUid AND os.display_order = ot.display_order " + + "LEFT JOIN tl_laasse10_option_answer AS aa ON aa.question_option_uid = os.uid " + + "SET tas.qb_option_uid = ot.uid, " + " aa.question_option_uid = ot.uid"; + @Override public QbQuestion getQuestionByUid(Long qbQuestionUid) { return this.find(QbQuestion.class, qbQuestionUid); @@ -404,6 +412,18 @@ .setParameter("qbQuestionId", qbQuestionId).getResultList().isEmpty(); } + @Override + public int mergeQuestions(long sourceQbQUestionUid, long targetQbQuestionUid) { + int result = getSession().createNativeQuery(MERGE_QUESTION_ANSWERS) + .setParameter("sourceQbQuestionUid", sourceQbQUestionUid) + .setParameter("targetQbQuestionUid", targetQbQuestionUid).executeUpdate(); + + getSession().createQuery(MERGE_TOOL_QUESTIONS).setParameter("sourceQbQuestionUid", sourceQbQUestionUid) + .setParameter("targetQbQuestionUid", targetQbQuestionUid).executeUpdate(); + + return result; + } + private Query prepareCollectionQuestionsQuery(long collectionUid, String orderBy, String orderDirection, String search, boolean isCount) { StringBuilder queryBuilder = new StringBuilder(FIND_COLLECTION_QUESTIONS); Index: lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java =================================================================== diff -u -ref86b1a497acdbc249c66c78e59d542ded3044c0 -re00ee97b803f195e523abcd3f765513a58a03d32 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java (.../IQbService.java) (revision ef86b1a497acdbc249c66c78e59d542ded3044c0) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java (.../IQbService.java) (revision e00ee97b803f195e523abcd3f765513a58a03d32) @@ -138,6 +138,8 @@ boolean isQuestionInUserCollection(int qbQuestionId, int userId); void insertQuestion(QbQuestion qbQuestion); - + void prepareQuestionForExport(QbQuestion qbQuestion); + + int mergeQuestions(long sourceQbQuestionUid, long targetQbQuestionUid); } Index: lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java =================================================================== diff -u -ra2a36ce7bc346fb2775998134f5f5ea3a9391698 -re00ee97b803f195e523abcd3f765513a58a03d32 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision a2a36ce7bc346fb2775998134f5f5ea3a9391698) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision e00ee97b803f195e523abcd3f765513a58a03d32) @@ -578,6 +578,7 @@ * Cascades in QbToolQuestion, QbQuestion and QbOptions do not seem to work on insert. * New QbQuestions need to be saved step by step. */ + @Override public void insertQuestion(QbQuestion qbQuestion) { if (qbQuestion.getQuestionId() == null) { qbQuestion.setQuestionId(generateNextQuestionId()); @@ -616,7 +617,7 @@ } } } - + /** * When exporting a LD, QbQuestion's server-specific detail need not be exported */ @@ -630,7 +631,32 @@ qbQuestion.setQbOptions(new ArrayList<>(qbQuestion.getQbOptions())); qbQuestion.setUnits(new ArrayList<>(qbQuestion.getUnits())); } - + + @Override + public int mergeQuestions(long sourceQbQuestionUid, long targetQbQuestionUid) { + QbQuestion sourceQuestion = getQuestionByUid(sourceQbQuestionUid); + QbQuestion targetQuestion = getQuestionByUid(targetQbQuestionUid); + + if (sourceQuestion == null) { + throw new InvalidParameterException("Source question does not exist"); + } + if (targetQuestion == null) { + throw new InvalidParameterException("Target question does not exist"); + } + + if (!sourceQuestion.getType().equals(targetQuestion.getType())) { + throw new InvalidParameterException("Source question type is different to target question type"); + } + + if (sourceQuestion.getQbOptions().size() != targetQuestion.getQbOptions().size()) { + throw new InvalidParameterException("Number of options in source and target questions does not match"); + } + + int answersChanged = qbDAO.mergeQuestions(sourceQbQuestionUid, targetQbQuestionUid); + qbDAO.deleteById(QbQuestion.class, sourceQbQuestionUid); + return answersChanged; + } + public void setQbDAO(IQbDAO qbDAO) { this.qbDAO = qbDAO; }