Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/QbStatsController.java =================================================================== diff -u -r0f2b554d8e5dca78a8e936730490d03ecd0357ba -r21606f18aac597a4f64d761bd0e33e904e35a997 --- lams_central/src/java/org/lamsfoundation/lams/web/qb/QbStatsController.java (.../QbStatsController.java) (revision 0f2b554d8e5dca78a8e936730490d03ecd0357ba) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/QbStatsController.java (.../QbStatsController.java) (revision 21606f18aac597a4f64d761bd0e33e904e35a997) @@ -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; @@ -100,6 +102,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 -r03a003d5613ffaac6f9b96bef5170e9743642808 -r21606f18aac597a4f64d761bd0e33e904e35a997 --- lams_central/web/qb/stats.jsp (.../stats.jsp) (revision 03a003d5613ffaac6f9b96bef5170e9743642808) +++ lams_central/web/qb/stats.jsp (.../stats.jsp) (revision 21606f18aac597a4f64d761bd0e33e904e35a997) @@ -53,6 +53,10 @@ a { cursor: pointer; } + + .alert ul { + margin-left: 10px; + } @@ -90,7 +94,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}'; } }); } @@ -139,6 +143,13 @@
+ +
+ Question with UID ${mergeSourceQbQuestionUid} was merged with this question.
+ Number of migrated learner answers: ${mergeResult} +
+
+
Question @@ -156,6 +167,14 @@
+ UID: +
+
+ +
+
+
+
Version:
@@ -358,7 +377,6 @@ - @@ -464,7 +482,7 @@ - +
@@ -503,6 +521,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 -r21606f18aac597a4f64d761bd0e33e904e35a997 --- 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 21606f18aac597a4f64d761bd0e33e904e35a997) @@ -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 -r21606f18aac597a4f64d761bd0e33e904e35a997 --- 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 21606f18aac597a4f64d761bd0e33e904e35a997) @@ -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 -ra2b41bfd7ae2b33847ddbc9d9c46e18b30272905 -r21606f18aac597a4f64d761bd0e33e904e35a997 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java (.../IQbService.java) (revision a2b41bfd7ae2b33847ddbc9d9c46e18b30272905) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java (.../IQbService.java) (revision 21606f18aac597a4f64d761bd0e33e904e35a997) @@ -65,9 +65,9 @@ QbStatsActivityDTO getActivityStats(Long activityId, Long qbQuestionUid, Collection correctOptionUids); - List getPagedQuestions(String questionTypes, String collectionUids, int page, int size, String sortBy, String sortOrder, - String searchString); - + List getPagedQuestions(String questionTypes, String collectionUids, int page, int size, String sortBy, + String sortOrder, String searchString); + List getAllQuestionUids(String collectionUids, String sortBy, String sortOrder, String searchString); int getCountQuestions(String questionTypes, String collectionUids, String searchString); @@ -133,4 +133,6 @@ void releaseFromCache(Object object); boolean isQuestionInUserCollection(int qbQuestionId, int userId); + + int mergeQuestions(long sourceQbQuestionUid, long targetQbQuestionUid); } Index: lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java =================================================================== diff -u -r4de125b4eb4a3059669e7808bf4b6a85f06c9077 -r21606f18aac597a4f64d761bd0e33e904e35a997 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision 4de125b4eb4a3059669e7808bf4b6a85f06c9077) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision 21606f18aac597a4f64d761bd0e33e904e35a997) @@ -234,8 +234,8 @@ // sort grades by highest mark Collections.sort(userLessonGrades, Comparator.comparing(GradebookUserLesson::getMark).reversed()); // see how many learners should be in top/bottom 27% of the group - int groupCount = (int) Math.ceil( - Configuration.getAsInt(ConfigurationKeys.QB_STATS_GROUP_SIZE) / 100.0 * participantCount); + int groupCount = (int) Math + .ceil(Configuration.getAsInt(ConfigurationKeys.QB_STATS_GROUP_SIZE) / 100.0 * participantCount); // go through each grade and gather data for indexes for (int userIndex = 0; userIndex < participantCount; userIndex++) { @@ -564,6 +564,31 @@ return qbDAO.isQuestionInUserCollection(userId, qbQuestionId); } + @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; }