Index: lams_build/3rdParty.userlibraries =================================================================== diff -u -re376b240aecf9b255b8b26fe22c3d33c70f67ddb -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision e376b240aecf9b255b8b26fe22c3d33c70f67ddb) +++ lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -43,5 +43,6 @@ + Index: lams_build/build.xml =================================================================== diff -u -rb6d0779192887979b5d3d244dec3506d12a7e401 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_build/build.xml (.../build.xml) (revision b6d0779192887979b5d3d244dec3506d12a7e401) +++ lams_build/build.xml (.../build.xml) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -63,7 +63,6 @@ - @@ -87,6 +86,7 @@ + @@ -108,7 +108,6 @@ - @@ -259,7 +258,7 @@ - + @@ -389,7 +388,6 @@ - ${ant.project.name}: Deploying libraries as WildFly modules @@ -410,6 +408,14 @@ + + + + + + + @@ -699,7 +705,6 @@ - Index: lams_build/conf/j2ee/jboss-deployment-structure.xml =================================================================== diff -u -rb6d0779192887979b5d3d244dec3506d12a7e401 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_build/conf/j2ee/jboss-deployment-structure.xml (.../jboss-deployment-structure.xml) (revision b6d0779192887979b5d3d244dec3506d12a7e401) +++ lams_build/conf/j2ee/jboss-deployment-structure.xml (.../jboss-deployment-structure.xml) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -19,6 +19,7 @@ + Index: lams_build/liblist.txt =================================================================== diff -u -rc42f68a09110f060149fba432df9ff60ccc84751 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_build/liblist.txt (.../liblist.txt) (revision c42f68a09110f060149fba432df9ff60ccc84751) +++ lams_build/liblist.txt (.../liblist.txt) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -5,8 +5,12 @@ apache-poi poi-4.0.1.jar 4.0.1 Apache License 2.0 Apache the Java API for Microsoft Documents poi-ooxml-4.0.1.jar poi-ooxml-schemas-4.0.1.jar + poi-scratchpad-4.0.1.jar xmlbeans-3.0.2.jar 3.0.2 +apache-tika tika-core-1.24.jar 1.24 Apache License 2.0 Apache a content analysis toolkit that detects and extracts metadata and text from over a thousand different file types + tika-parsers-1.24.jar + autopatch autopatch-1.4.2-lams.jar 1.4.2-lams Apache License Tacit Knowledge automated Java patching system discovery-1.0.5-lams.jar 1.0.5-lams Index: lams_central/conf/security/Owasp.CsrfGuard.properties =================================================================== diff -u -r8df2f2fd1327e415d338658a64cb110cfdd21872 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_central/conf/security/Owasp.CsrfGuard.properties (.../Owasp.CsrfGuard.properties) (revision 8df2f2fd1327e415d338658a64cb110cfdd21872) +++ lams_central/conf/security/Owasp.CsrfGuard.properties (.../Owasp.CsrfGuard.properties) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -111,6 +111,7 @@ org.owasp.csrfguard.protected.monitoringEmailNotificationsDel=/lams/monitoring/emailNotifications/deleteNotification.do org.owasp.csrfguard.protected.monitoringGateOpen=/lams/monitoring/gate/openGate.do org.owasp.csrfguard.protected.monitoringGateOpenForSingleUser=/lams/monitoring/gate/openGateForSingleUser.do +org.owasp.csrfguard.protected.monitoringGateChangePassword=/lams/monitoring/gate/changeGatePassword.do org.owasp.csrfguard.protected.monitoringGateSchedule=/lams/monitoring/gate/scheduleGate.do org.owasp.csrfguard.protected.monitoringGroupingSaveAsCourseGrouping=/lams/monitoring/grouping/saveAsCourseGrouping.do org.owasp.csrfguard.protected.monitoringGroupingAddMembers=/lams/monitoring/grouping/addMembers.do @@ -137,6 +138,7 @@ org.owasp.csrfguard.protected.dokuAuthoringSave=/lams/tool/ladoku11/authoring/update.do org.owasp.csrfguard.protected.dokuAuthoringDefineLater=/lams/tool/ladoku11/authoring/definelater.do +org.owasp.csrfguard.protected.dokuMonitoringUpdateLearnerMark=/lams/tool/ladoku11/monitoring/updateLearnerMark.do org.owasp.csrfguard.protected.forumAuthoringSave=/lams/tool/lafrum11/authoring/update.do org.owasp.csrfguard.protected.forumAuthoringDefineLater=/lams/tool/lafrum11/authoring/definelater.do Index: lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateController.java =================================================================== diff -u -rb5d2a6851ee4797e641081bd5e6a1f28f78c30a6 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateController.java (.../LdTemplateController.java) (revision b5d2a6851ee4797e641081bd5e6a1f28f78c30a6) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateController.java (.../LdTemplateController.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -781,12 +781,13 @@ * to be expanded. */ protected Long createAssessmentToolContent(UserDTO user, String title, String instructions, - String reflectionInstructions, boolean selectLeaderToolOutput, boolean enableNumbering, ArrayNode questions) - throws IOException { + String reflectionInstructions, boolean selectLeaderToolOutput, boolean enableNumbering, + boolean enableConfidenceLevels, ArrayNode questions) throws IOException { ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, null, null, user); toolContentJSON.put(RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, selectLeaderToolOutput); + toolContentJSON.put(RestTags.ENABLE_CONFIDENCE_LEVELS, enableConfidenceLevels); toolContentJSON.put("numbered", enableNumbering); toolContentJSON.put("displaySummary", Boolean.TRUE); toolContentJSON.put("allowDiscloseAnswers", Boolean.TRUE); @@ -796,7 +797,7 @@ for (int i = 0; i < questions.size(); i++) { ObjectNode question = (ObjectNode) questions.get(i); Integer questionDisplayOrder = question.get(RestTags.DISPLAY_ORDER).asInt(); - Integer defaultGrade = question.get("defaultGrade").asInt(); + Integer defaultGrade = JsonUtil.optInt(question, "defaultGrade", 1); references.add(JsonNodeFactory.instance.objectNode().put(RestTags.DISPLAY_ORDER, questionDisplayOrder) .put("questionDisplayOrder", questionDisplayOrder).put("defaultGrade", defaultGrade)); } Index: lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/TBLTemplateController.java =================================================================== diff -u -rb5d2a6851ee4797e641081bd5e6a1f28f78c30a6 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/TBLTemplateController.java (.../TBLTemplateController.java) (revision b5d2a6851ee4797e641081bd5e6a1f28f78c30a6) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/TBLTemplateController.java (.../TBLTemplateController.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -153,11 +153,12 @@ activityTitle = data.getText("boilerplate.ira.title"); ArrayNode testQuestionsArray = JsonUtil.readArray(data.testQuestions.values()); Long iRAToolContentId = createAssessmentToolContent(userDTO, activityTitle, - data.getText("boilerplate.ira.instructions"), "", false, false, testQuestionsArray); + data.getText("boilerplate.ira.instructions"), null, false, false, data.confidenceLevelEnable, + testQuestionsArray); ObjectNode iraActivityJSON = createAssessmentActivity(maxUIID, order++, currentActivityPosition, iRAToolContentId, data.contentFolderID, groupingUIID, null, null, activityTitle); activities.add(iraActivityJSON); - + // Leader Selection firstActivityInRowPosition = calcPositionBelow(firstActivityInRowPosition); currentActivityPosition = firstActivityInRowPosition; @@ -226,7 +227,7 @@ assessmentNumber++; } Long aetoolContentId = createAssessmentToolContent(userDTO, applicationExerciseTitle, - data.getText("boilerplate.ae.instructions"), null, true, false, questionsJSONArray); + data.getText("boilerplate.ae.instructions"), null, true, false, false, questionsJSONArray); activities.add(createAssessmentActivity(maxUIID, order++, currentActivityPosition, aetoolContentId, data.contentFolderID, groupingUIID, null, null, applicationExerciseTitle)); @@ -634,6 +635,7 @@ ObjectNode question = testQuestions.get(questionDisplayOrder); if (question == null) { question = JsonNodeFactory.instance.objectNode(); + question.put("type", Assessment.ASSESSMENT_QUESTION_TYPE_MULTIPLE_CHOICE); question.set(RestTags.ANSWERS, JsonNodeFactory.instance.arrayNode()); question.put(RestTags.DISPLAY_ORDER, questionDisplayOrder); testQuestions.put(questionDisplayOrder, question); Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20200220.sql =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20200220.sql (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20200220.sql (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -0,0 +1,23 @@ +CREATE FUNCTION UUID_V4() + RETURNS CHAR(36) +BEGIN + -- Generate 8 2-byte strings that we will combine into a UUIDv4 + SET @h1 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'); + SET @h2 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'); + SET @h3 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'); + SET @h6 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'); + SET @h7 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'); + SET @h8 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'); + + -- 4th section will start with a 4 indicating the version + SET @h4 = CONCAT('4', LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0')); + + -- 5th section first half-byte can only be 8, 9 A or B + SET @h5 = CONCAT(HEX(FLOOR(RAND() * 4 + 8)), + LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0')); + + -- Build the complete UUID + RETURN LOWER(CONCAT( + @h1, @h2, '-', @h3, '-', @h4, '-', @h5, '-', @h6, @h7, @h8 + )); +END; \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20200221.sql =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20200221.sql (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20200221.sql (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -0,0 +1,19 @@ +SET AUTOCOMMIT = 0; +set FOREIGN_KEY_CHECKS = 0; + +-- LDEV-4962 Use random UUIDs v4 for user portraits + +ALTER TABLE lams_cr_node ADD COLUMN temp BIGINT; + +UPDATE lams_cr_node AS n JOIN lams_user AS u USING (portrait_uuid) +SET n.temp = u.user_id, + n.portrait_uuid = UUID_TO_BIN(UUID_V4()); + +UPDATE lams_cr_node AS n JOIN lams_user AS u ON n.temp = u.user_id +SET u.portrait_uuid = n.portrait_uuid; + +ALTER TABLE lams_cr_node DROP COLUMN temp; + +COMMIT; +SET AUTOCOMMIT = 1; +set FOREIGN_KEY_CHECKS = 1; \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r8df2f2fd1327e415d338658a64cb110cfdd21872 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 8df2f2fd1327e415d338658a64cb110cfdd21872) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -90,6 +90,7 @@ import org.lamsfoundation.lams.learningdesign.McqImportContentVersionFilter; import org.lamsfoundation.lams.learningdesign.OptionsActivity; import org.lamsfoundation.lams.learningdesign.OptionsWithSequencesActivity; +import org.lamsfoundation.lams.learningdesign.PasswordGateActivity; import org.lamsfoundation.lams.learningdesign.PermissionGateActivity; import org.lamsfoundation.lams.learningdesign.RandomGrouping; import org.lamsfoundation.lams.learningdesign.ScheduleGateActivity; @@ -1947,6 +1948,13 @@ ((PermissionGateActivity) act) .setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.PERMISSION_GATE)); break; + case Activity.PASSWORD_GATE_ACTIVITY_TYPE: + ((PasswordGateActivity) act).setGateActivityLevelId(actDto.getGateActivityLevelID()); + ((PasswordGateActivity) act).setGateOpen(false); + + ((PasswordGateActivity) act).setGatePassword(actDto.getGatePassword()); + ((PasswordGateActivity) act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.PASSWORD_GATE)); + break; case Activity.CONDITION_GATE_ACTIVITY_TYPE: ((ConditionGateActivity) act).setGateActivityLevelId(actDto.getGateActivityLevelID()); ((ConditionGateActivity) act).setGateOpen(false); Index: lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java =================================================================== diff -u -rb5d2a6851ee4797e641081bd5e6a1f28f78c30a6 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java (.../QbDAO.java) (revision b5d2a6851ee4797e641081bd5e6a1f28f78c30a6) +++ lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java (.../QbDAO.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -115,6 +115,9 @@ + "JOIN tl_laasse10_option_answer AS aa ON aa.question_option_uid = os.uid " + "SET aa.question_option_uid = ot.uid"; + private static final String REMOVE_ANSWERS_BY_TOOL_CONTENT_ID = "DELETE a FROM lams_qb_tool_answer AS a JOIN lams_qb_tool_question AS tq " + + "USING (tool_question_uid) WHERE tq.tool_content_id = :toolContentId"; + @Override public QbQuestion getQuestionByUid(Long qbQuestionUid) { return this.find(QbQuestion.class, qbQuestionUid); @@ -441,6 +444,12 @@ return result; } + @Override + public void removeAnswersByToolContentId(long toolContentId) { + getSession().createNativeQuery(REMOVE_ANSWERS_BY_TOOL_CONTENT_ID).setParameter("toolContentId", toolContentId) + .executeUpdate(); + } + private Query prepareCollectionQuestionsQuery(long collectionUid, String orderBy, String orderDirection, String search, boolean isCount) { StringBuilder queryBuilder = new StringBuilder(FIND_COLLECTION_QUESTIONS); Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -rb5d2a6851ee4797e641081bd5e6a1f28f78c30a6 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision b5d2a6851ee4797e641081bd5e6a1f28f78c30a6) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -38,6 +38,7 @@ import java.util.Set; import java.util.TreeMap; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.gradebook.service.IGradebookService; import org.lamsfoundation.lams.learning.command.dao.ICommandDAO; @@ -64,6 +65,7 @@ import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouping; import org.lamsfoundation.lams.learningdesign.LearningDesign; import org.lamsfoundation.lams.learningdesign.OptionsActivity; +import org.lamsfoundation.lams.learningdesign.PasswordGateActivity; import org.lamsfoundation.lams.learningdesign.SequenceActivity; import org.lamsfoundation.lams.learningdesign.ToolActivity; import org.lamsfoundation.lams.learningdesign.ToolBranchingActivity; @@ -551,8 +553,8 @@ } if (log.isDebugEnabled()) { - log.debug("CompleteToolSession() for tool session id " + toolSessionId + " learnerId " - + learnerId + " url is " + returnURL); + log.debug("CompleteToolSession() for tool session id " + toolSessionId + " learnerId " + learnerId + + " url is " + returnURL); } return returnURL; @@ -565,12 +567,12 @@ if (currentActivity == null) { progress = joinLesson(learnerId, lesson.getLessonId()); - + } else if (progress.getCompletedActivities().containsKey(currentActivity)) { // recalculate activity mark and pass it to gradebook updateGradebookMark(currentActivity, progress); return actionMappings.getCloseForward(currentActivity, lesson.getLessonId()); - + } else { completeActivity(learnerId, currentActivity, progress.getLearnerProgressId()); } @@ -672,7 +674,7 @@ private void updateGradebookMark(Activity activity, LearnerProgress progress) { User learner = progress.getUser(); Lesson lesson = progress.getLesson(); - + if ((learner == null) || (lesson == null) || (activity == null) || !(activity instanceof ToolActivity) || (((ToolActivity) activity).getEvaluation() == null)) { return; @@ -681,16 +683,16 @@ if (toolSession == null) { return; } - + //in case this is a leader - update marks for all users in the group, otherwise update marks only for the specified user List learnersRequiringMarkUpdate = new ArrayList<>(); if (lamsCoreToolService.isUserLeaderInActivity(toolSession, learner)) { learnersRequiringMarkUpdate.addAll(toolSession.getLearners()); - + } else { learnersRequiringMarkUpdate.add(learner); } - + for (User learnerRequiringMarksUpdate : learnersRequiringMarkUpdate) { gradebookService.updateGradebookUserActivityMark(lesson, activity, learnerRequiringMarksUpdate); } @@ -830,10 +832,10 @@ * org.lamsfoundation.lams.usermanagement.User) */ @Override - public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate) { + public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate, Object key) { GateActivity gate = (GateActivity) activityDAO.getActivityByActivityId(gateActivityId, GateActivity.class); if (gate != null) { - return knockGate(gate, knocker, forceGate); + return knockGate(gate, knocker, forceGate, key); } String error = "Gate activity " + gateActivityId + " does not exist. Cannot knock on gate."; @@ -846,7 +848,7 @@ * org.lamsfoundation.lams.usermanagement.User) */ @Override - public GateActivityDTO knockGate(GateActivity gate, User knocker, boolean forceGate) { + public GateActivityDTO knockGate(GateActivity gate, User knocker, boolean forceGate, Object key) { boolean gateOpen = false; if (forceGate) { @@ -875,8 +877,11 @@ // normal case - knock the gate. gateOpen = gate.shouldOpenGateFor(knocker, expectedLearnerCount, waitingLearnerCount); if (!gateOpen) { - // only for a condition gate - gateOpen = determineConditionGateStatus(gate, knocker); + if (gate instanceof ConditionGateActivity) { + gateOpen = determineConditionGateStatus((ConditionGateActivity) gate, knocker); + } else if (gate instanceof PasswordGateActivity) { + gateOpen = determinePasswordGateStatus((PasswordGateActivity) gate, knocker, (String) key); + } } } @@ -1067,18 +1072,18 @@ // If no conditions match, use the branch that is the "default" branch for this branching activity. if (matchedBranch != null) { if (log.isDebugEnabled()) { - log.debug("Found branch " + matchedBranch.getActivityId() + ":" - + matchedBranch.getTitle() + " for branching activity " + branchingActivity.getActivityId() - + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + log.debug("Found branch " + matchedBranch.getActivityId() + ":" + matchedBranch.getTitle() + + " for branching activity " + branchingActivity.getActivityId() + ":" + + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + learner.getLogin()); } return matchedBranch; } else if (defaultBranch != null) { if (log.isDebugEnabled()) { - log.debug("Using default branch " + defaultBranch.getActivityId() + ":" - + defaultBranch.getTitle() + " for branching activity " + branchingActivity.getActivityId() - + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + log.debug("Using default branch " + defaultBranch.getActivityId() + ":" + defaultBranch.getTitle() + + " for branching activity " + branchingActivity.getActivityId() + ":" + + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + learner.getLogin()); } // have to convert it to a real activity of the correct type, as it could be a cglib value @@ -1119,10 +1124,10 @@ if (sequenceActivity != null) { if (log.isDebugEnabled()) { - log.debug("Found branch " + sequenceActivity.getActivityId() + ":" - + sequenceActivity.getTitle() + " for branching activity " - + branchingActivity.getActivityId() + ":" + branchingActivity.getTitle() + " for learner " - + learner.getUserId() + ":" + learner.getLogin()); + log.debug("Found branch " + sequenceActivity.getActivityId() + ":" + sequenceActivity.getTitle() + + " for branching activity " + branchingActivity.getActivityId() + ":" + + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + + learner.getLogin()); } } @@ -1140,56 +1145,63 @@ * learner who is knocking to the gate * @return true if learner satisfied any of the conditions and is allowed to pass */ - private boolean determineConditionGateStatus(GateActivity gate, User learner) { + private boolean determineConditionGateStatus(ConditionGateActivity conditionGate, User learner) { boolean shouldOpenGate = false; - if (gate instanceof ConditionGateActivity) { - ConditionGateActivity conditionGate = (ConditionGateActivity) gate; - // Work out the tool session appropriate for this user and gate activity. We expect there to be only one at - // this point. - ToolSession toolSession = null; - for (Activity inputActivity : conditionGate.getInputActivities()) { - toolSession = lamsCoreToolService.getToolSessionByLearner(learner, inputActivity); - } + // Work out the tool session appropriate for this user and gate activity. We expect there to be only one at + // this point. + ToolSession toolSession = null; + for (Activity inputActivity : conditionGate.getInputActivities()) { + toolSession = lamsCoreToolService.getToolSessionByLearner(learner, inputActivity); + } - if (toolSession != null) { + if (toolSession != null) { - // Go through each condition until we find one that passes and that opens the gate. - // Cache the tool output so that we aren't calling it over an over again. - Map toolOutputMap = new HashMap<>(); - for (BranchActivityEntry entry : conditionGate.getBranchActivityEntries()) { - BranchCondition condition = entry.getCondition(); - String conditionName = condition.getName(); - ToolOutput toolOutput = toolOutputMap.get(conditionName); + // Go through each condition until we find one that passes and that opens the gate. + // Cache the tool output so that we aren't calling it over an over again. + Map toolOutputMap = new HashMap<>(); + for (BranchActivityEntry entry : conditionGate.getBranchActivityEntries()) { + BranchCondition condition = entry.getCondition(); + String conditionName = condition.getName(); + ToolOutput toolOutput = toolOutputMap.get(conditionName); + if (toolOutput == null) { + toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, learner.getUserId()); if (toolOutput == null) { - toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, - learner.getUserId()); - if (toolOutput == null) { - log.warn("Condition " + condition + " refers to a tool output " - + conditionName - + " but tool doesn't return any tool output for that name. Skipping this condition."); - } else { - toolOutputMap.put(conditionName, toolOutput); - } + log.warn("Condition " + condition + " refers to a tool output " + conditionName + + " but tool doesn't return any tool output for that name. Skipping this condition."); + } else { + toolOutputMap.put(conditionName, toolOutput); } + } - if ((toolOutput != null) && condition.isMet(toolOutput)) { - shouldOpenGate = entry.getGateOpenWhenConditionMet(); - if (shouldOpenGate) { - // save the learner to the "allowed to pass" list so we don't check the conditions over and - // over - // again (maybe we should??) - conditionGate.getAllowedToPassLearners().add(learner); - } - break; + if ((toolOutput != null) && condition.isMet(toolOutput)) { + shouldOpenGate = entry.getGateOpenWhenConditionMet(); + if (shouldOpenGate) { + // save the learner to the "allowed to pass" list so we don't check the conditions over and + // over + // again (maybe we should??) + conditionGate.getAllowedToPassLearners().add(learner); } + break; } } } return shouldOpenGate; } /** + * Checks if learner provided correct password for the gate. + */ + private boolean determinePasswordGateStatus(PasswordGateActivity gate, User learner, + String learnerProvidedPassword) { + if (StringUtils.isNotBlank(learnerProvidedPassword) && learnerProvidedPassword.equals(gate.getGatePassword())) { + gate.getAllowedToPassLearners().add(learner); + return true; + } + return false; + } + + /** * Select a particular branch - we are in preview mode and the author has selected a particular activity. * * @throws LearnerServiceException @@ -1268,9 +1280,9 @@ groupingDAO.update(grouping); if (log.isDebugEnabled()) { - log.debug("Found branch " + selectedBranch.getActivityId() + ":" - + selectedBranch.getTitle() + " for branching activity " + branchingActivity.getActivityId() - + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + log.debug("Found branch " + selectedBranch.getActivityId() + ":" + selectedBranch.getTitle() + + " for branching activity " + branchingActivity.getActivityId() + ":" + + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + learner.getLogin()); } Index: lams_monitoring/web/tblmonitor/teams.jsp =================================================================== diff -u -rb5d2a6851ee4797e641081bd5e6a1f28f78c30a6 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_monitoring/web/tblmonitor/teams.jsp (.../teams.jsp) (revision b5d2a6851ee4797e641081bd5e6a1f28f78c30a6) +++ lams_monitoring/web/tblmonitor/teams.jsp (.../teams.jsp) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -1,440 +1,440 @@ -<%@ include file="/taglibs.jsp"%> - - - - - - - - -
-
-

- -

-
-
- - - -
-
- - -
- - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- font-weight-bold" - data-portrait="${userDto.portraitUuid}" data-fullname="${userDto.lastName}, ${userDto.firstName}"> - ${userDto.lastName}, ${userDto.firstName} - - - - - - - - - ${userDto.iraScore} - - - - 0 - - - - - ${groupDto.traScore} - -
-
- - -
-
- - - - - - - -
-
- - -
- -
-
-
- -
-
- - - - - - - - - - - - - - - - - - +<%@ include file="/taglibs.jsp"%> + + + + + + + + +
+
+

+ +

+
+
+ + + +
+
+ + +
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ font-weight-bold" + data-portrait="${userDto.portraitUuid}" data-fullname="${userDto.lastName}, ${userDto.firstName}"> + ${userDto.lastName}, ${userDto.firstName} + + + + + + + + + ${userDto.iraScore} + + + + 0 + + + + + ${groupDto.traScore} + +
+
+ + +
+
+ + + + + + + +
+
+ + +
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + Index: lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -ra96f86b151cdcdf191654e8596eb2cf599e4e12b -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) +++ lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -377,7 +377,9 @@ label.incorrect =Incorrect label.answer.alternatives =Answer alternatives label.someone.allocated.this.answer =Sorry, someone has allocated this answer already +label.monitoring.user.summary.full.name =Full name + label.export.marks.mcq =Export marks for MCQ questions label.not.available =N/A label.legend =Legend Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== diff -u -ra96f86b151cdcdf191654e8596eb2cf599e4e12b -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -35,9 +35,9 @@ public static final String EXPORT_QUESTIONS_FILENAME = "questions.xml"; // for parameters' name - + public static final String PARAM_WAITING_MESSAGE_KEY = "waitingMessageKey"; - + public static final String PARAM_TOOL_CONTENT_ID = "toolContentID"; public static final String PARAM_TOOL_SESSION_ID = "toolSessionID"; @@ -47,7 +47,7 @@ public static final String PARAM_FILE_UUID = "fileUuid"; public static final String PARAM_QUESTION_INDEX = "questionIndex"; - + public static final String PARAM_QUESTION_DISPLAY_ORDER = "questionDisplayOrder"; public static final String PARAM_QUESTION_UID = "questionUid"; @@ -59,22 +59,22 @@ public static final String PARAM_NOT_A_NUMBER = "nan"; public static final String PARAM_GRADE = "grade"; - + public static final String PARAM_MAX_MARK = "maxMark"; - + public static final String PARAM_SEQUENCE_ID = "sequenceId"; public static final String PARAM_SESSION_ID = "sessionId"; public static final String PARAM_QUESTION_RESULT_UID = "questionResultUid"; // for request attribute name - + /** * used to signify edit in monitor when assessment has been attempted already */ public static final String ATTR_IS_AUTHORING_RESTRICTED = "isAuthoringRestricted"; - + public static final String ATTR_GROUP_USERS = "groupUsers"; public static final String ATTR_IS_USER_LEADER = "isUserLeader"; @@ -86,13 +86,13 @@ public static final String ATTR_TOOL_SESSION_ID = "toolSessionID"; public static final String ATTR_QUESTION_PREFIX = "question"; - + public static final String ATTR_CONFIDENCE_LEVEL_PREFIX = "confidenceLevel"; public static final String ATTR_QUESTION_LIST = "questionList"; - + public static final String ATTR_RANDOM_POOL_QUESTIONS = "randomPoolQuestions"; - + public static final String ATTR_DELETED_RANDOM_POOL_QUESTIONS = "deletedRandomPoolQuestions"; public static final String ATTR_QUESTION_REFERENCES = "questionReferences"; @@ -102,13 +102,13 @@ public static final String ATTR_UNIT_LIST = "unitList"; public static final String ATTR_REFERENCES_MAX_MARKS = "referenceMaxMarks"; - + public static final String ATTR_REFERENCES_SEQUENCE_IDS = "sequenceIds"; - + public static final String ATTR_HAS_EDIT_RIGHT = "hasEditRight"; - + public static final String ATTR_IS_TIME_LIMIT_NOT_LAUNCHED = "isTimeLimitNotLaunched"; - + public static final String ATTR_SECONDS_LEFT = "secondsLeft"; public static final String ATTR_OVERALL_FEEDBACK_LIST = "overallFeedbackList"; @@ -170,7 +170,7 @@ public static final String ATTR_QUESTION_NUMBERING_OFFSET = "questionNumberingOffset"; public static final String ATTR_SUBMISSION_DEADLINE = "submissionDeadline"; - + public static final String ATTR_SUBMISSION_DEADLINE_DATESTRING = "submissionDateString"; public static final String ATTR_IS_SUBMISSION_DEADLINE_PASSED = "isSubmissionDeadlinePassed"; @@ -203,15 +203,19 @@ public static final String OUTPUT_NAME_ORDERED_ANSWERS = "ordered.answers"; public static final String OUTPUT_NAME_CONDITION_ORDERED_ANSWER = "ordered.answer"; - + public static final String ATTR_USER_UID = "userUid"; public static final String DEFUALT_PROTOCOL_REFIX = "http://"; public static final String ALLOW_PROTOCOL_REFIX = new String("[http://|https://|ftp://|nntp://]"); - public static final String EVENT_NAME_NOTIFY_TEACHERS_ON_ASSIGMENT_SUBMIT = "notify_teachers_on_assigment_submit"; - + public static final String EVENT_NAME_NOTIFY_TEACHERS_ON_ASSIGMENT_SUBMIT = "notify_teachers_on_assigment_submit"; + // configuration keys public static final String CONFIG_KEY_HIDE_TITLES = "hideTitles"; + + public static final String ATTR_IS_QUESTION_ETHERPAD_ENABLED = "isQuestionEtherpadEnabled"; + + public static final String ATTR_ALL_GROUP_USERS = "allGroupUsers"; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -r8df2f2fd1327e415d338658a64cb110cfdd21872 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 8df2f2fd1327e415d338658a64cb110cfdd21872) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -1652,7 +1652,7 @@ @Override public List exportSummary(Assessment assessment, List sessionDtos) { - List sheets = new LinkedList(); + List sheets = new LinkedList<>(); // -------------- First tab: Summary ---------------------------------------------------- ExcelSheet summarySheet = new ExcelSheet(getMessage("label.export.summary")); @@ -2042,13 +2042,16 @@ Set assessmentUsers = assessmentSession.getAssessmentUsers(); if (assessmentUsers != null) { for (AssessmentUser assessmentUser : assessmentUsers) { - ExcelRow userTitleRow = userSummarySheet.initRow(); - userTitleRow.addCell(getMessage("label.export.user.id"), true); - userTitleRow.addCell(getMessage("label.learner"), true); - userTitleRow.addCell(getMessage("label.export.date.attempted"), true); - userTitleRow.addCell(getMessage("label.monitoring.question.summary.question"), true); - userTitleRow.addCell(getMessage("label.authoring.basic.option.answer"), true); - userTitleRow.addCell(getMessage("label.export.mark"), true); + ExcelRow userTitleRow = userSummarySheet.initRow(); + userTitleRow.addCell(getMessage("label.export.user.id"), true); + userTitleRow.addCell(getMessage("label.monitoring.user.summary.full.name"), true); + userTitleRow.addCell(getMessage("label.export.date.attempted"), true); + userTitleRow.addCell(getMessage("label.monitoring.question.summary.question"), true); + userTitleRow.addCell(getMessage("label.authoring.basic.option.answer"), true); + if (assessment.isEnableConfidenceLevels()) { + userTitleRow.addCell(getMessage("label.confidence"), true); + } + userTitleRow.addCell(getMessage("label.export.mark"), true); AssessmentResult assessmentResult = userUidToResultMap.get(assessmentUser.getUid()); if (assessmentResult != null) { @@ -2062,12 +2065,34 @@ userResultRow.addCell(questionResult.getQbQuestion().getName()); userResultRow.addCell( AssessmentEscapeUtils.printResponsesForExcelExport(questionResult)); + if (assessment.isEnableConfidenceLevels()) { + String confidenceLevel = null; + + switch (assessment.getConfidenceLevelsType()) { + case 2: + confidenceLevel = new String[] { getMessage("label.not.confident"), + getMessage("label.confident"), + getMessage("label.very.confident") }[questionResult + .getConfidenceLevel() / 5]; + break; + case 3: + confidenceLevel = new String[] { getMessage("label.not.sure"), + getMessage("label.sure"), + getMessage("label.very.sure") }[questionResult + .getConfidenceLevel() / 5]; + break; + default: + confidenceLevel = questionResult.getConfidenceLevel() * 10 + "%"; + } + + userResultRow.addCell(confidenceLevel); + } userResultRow.addCell(questionResult.getMark()); } } ExcelRow userTotalRow = userSummarySheet.initRow(); - userTotalRow.addEmptyCells(4); + userTotalRow.addEmptyCells(assessment.isEnableConfidenceLevels() ? 5 : 4); userTotalRow.addCell(getMessage("label.monitoring.summary.total"), true); userTotalRow.addCell(assessmentResult.getGrade()); userSummarySheet.addEmptyRow(); @@ -2211,7 +2236,7 @@ return summaryTableRow; } - + @Override public byte[] exportMarksMcq(Assessment assessment, Set questions) throws IOException { int maxOptionsInQuestion = 0; @@ -2231,7 +2256,7 @@ SessionDTO sessionDto = new SessionDTO(session.getSessionId(), session.getSessionName()); List userMarkDtos = new LinkedList<>(); - for (AssessmentUser user: session.getAssessmentUsers()) { + for (AssessmentUser user : session.getAssessmentUsers()) { UserMarkDTO userMarkDto = new UserMarkDTO(); userMarkDto.setFullName(user.getLastName() + " " + user.getFirstName()); userMarkDto.setUserGroupLeader(isUserGroupLeader(user.getUserId(), session.getSessionId())); @@ -2251,7 +2276,8 @@ Float[] userMarks = new Float[numQuestions]; String[] answeredOptions = new String[numQuestions]; Date attemptTime = null; - AssessmentResult finalizedUserAttempt = getLastFinishedAssessmentResult(assessment.getUid(), user.getUserId()); + AssessmentResult finalizedUserAttempt = getLastFinishedAssessmentResult(assessment.getUid(), + user.getUserId()); Float totalMark = 0f; if (finalizedUserAttempt != null) { for (AssessmentQuestionResult questionResult : finalizedUserAttempt.getQuestionResults()) { @@ -3757,6 +3783,11 @@ JsonUtil.optBoolean(toolContentJSON, "allowRightAnswersAfterQuestion", Boolean.FALSE)); assessment.setAllowWrongAnswersAfterQuestion( JsonUtil.optBoolean(toolContentJSON, "allowWrongAnswersAfterQuestion", Boolean.FALSE)); + assessment.setEnableConfidenceLevels( + JsonUtil.optBoolean(toolContentJSON, RestTags.ENABLE_CONFIDENCE_LEVELS, Boolean.FALSE)); + if (assessment.isEnableConfidenceLevels()) { + assessment.setConfidenceLevelsType(ConfidenceLevelDTO.CONFIDENCE_LEVELS_TYPE_0_TO_100); + } assessment.setAttemptsAllowed(JsonUtil.optInt(toolContentJSON, "attemptsAllows", 1)); assessment.setDefineLater(false); assessment.setDisplaySummary(JsonUtil.optBoolean(toolContentJSON, "displaySummary", Boolean.FALSE)); @@ -3797,6 +3828,7 @@ ArrayNode questions = JsonUtil.optArray(toolContentJSON, "questions"); Set newQuestionSet = assessment.getQuestions(); // the Assessment constructor will set up the collection for (JsonNode questionJSONData : questions) { + boolean addToCollection = false; AssessmentQuestion question = new AssessmentQuestion(); @@ -3841,8 +3873,19 @@ JsonUtil.optBoolean(questionJSONData, "incorrectAnswerNullifiesMark", Boolean.FALSE)); qbQuestion.setPenaltyFactor(JsonUtil.optDouble(questionJSONData, "penaltyFactor", 0.0).floatValue()); + // UUID normally gets generated in the DB, but we need it immediately, + // so we generate it programatically. + // Re-reading the QbQuestion we just saved does not help as it is read from Hibernate cache, + // not from DB where UUID is filed + qbQuestion.setUuid(UUID.randomUUID()); assessmentDao.insert(qbQuestion); + // Store it back into JSON so Scratchie can read it + // and use the same questions, not create new ones + uuid = qbQuestion.getUuid().toString(); + ObjectNode questionData = (ObjectNode) questionJSONData; + questionData.put(RestTags.QUESTION_UUID, uuid); + if ((type == QbQuestion.TYPE_MATCHING_PAIRS) || (type == QbQuestion.TYPE_MULTIPLE_CHOICE) || (type == QbQuestion.TYPE_NUMERICAL) || (type == QbQuestion.TYPE_MARK_HEDGING)) { @@ -3857,8 +3900,13 @@ QbOption option = new QbOption(); option.setQbQuestion(qbQuestion); option.setDisplayOrder(JsonUtil.optInt(answerData, RestTags.DISPLAY_ORDER)); - Double grade = JsonUtil.optDouble(answerData, "grade"); - option.setMaxMark(grade == null ? 0 : grade.floatValue()); + Boolean correct = JsonUtil.optBoolean(answerData, RestTags.CORRECT, null); + if (correct == null) { + Double grade = JsonUtil.optDouble(answerData, "grade"); + option.setMaxMark(grade == null ? 0 : grade.floatValue()); + } else { + option.setMaxMark(correct ? 1 : 0); + } option.setAcceptedError(JsonUtil.optDouble(answerData, "acceptedError", 0.0).floatValue()); option.setFeedback(JsonUtil.optString(answerData, "feedback")); option.setName(JsonUtil.optString(answerData, RestTags.ANSWER_TEXT)); @@ -3958,4 +4006,9 @@ public String getConfigValue(String key) { return assessmentConfigDao.getConfigValue(key); } + + @Override + public Collection getAllGroupUsers(Long toolSessionId) { + return toolService.getToolSession(toolSessionId).getLearners(); + } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java =================================================================== diff -u -r8df2f2fd1327e415d338658a64cb110cfdd21872 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java (.../IAssessmentService.java) (revision 8df2f2fd1327e415d338658a64cb110cfdd21872) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java (.../IAssessmentService.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -25,6 +25,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -47,6 +48,7 @@ import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; import org.lamsfoundation.lams.tool.service.ICommonToolService; +import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.util.excel.ExcelSheet; /** @@ -428,15 +430,16 @@ /** * Allocate learner's answer into one of the available answer groups. - * + * * @param questionUid * @param targetOptionUid * @param previousOptionUid * @param questionResultUid * @return if present, it contains optionUid of the option group containing duplicate (added there presumably by * another teacher working in parallel) */ - Optional allocateAnswerToOption(Long questionUid, Long targetOptionUid, Long previousOptionUid, Long questionResultUid); + Optional allocateAnswerToOption(Long questionUid, Long targetOptionUid, Long previousOptionUid, + Long questionResultUid); /** * For export purposes @@ -545,4 +548,6 @@ void setConfigValue(String key, String value); String getConfigValue(String key); + + Collection getAllGroupUsers(Long toolSessionId); } \ No newline at end of file Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java =================================================================== diff -u -r8df2f2fd1327e415d338658a64cb110cfdd21872 -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 8df2f2fd1327e415d338658a64cb110cfdd21872) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -50,6 +50,8 @@ import org.lamsfoundation.lams.tool.assessment.dto.AssessmentResultDTO; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentUserDTO; import org.lamsfoundation.lams.tool.assessment.dto.LeaderResultsDTO; +import org.lamsfoundation.lams.tool.assessment.dto.OptionDTO; +import org.lamsfoundation.lams.tool.assessment.dto.QuestionDTO; import org.lamsfoundation.lams.tool.assessment.dto.QuestionSummary; import org.lamsfoundation.lams.tool.assessment.dto.ReflectDTO; import org.lamsfoundation.lams.tool.assessment.dto.SessionDTO; @@ -65,6 +67,8 @@ import org.lamsfoundation.lams.tool.assessment.util.AssessmentEscapeUtils; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.CommonConstants; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.DateUtil; import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.WebUtil; @@ -176,6 +180,44 @@ sessionMap.put(AssessmentConstants.ATTR_TOOL_CONTENT_ID, contentId); sessionMap.put(AttributeNames.PARAM_CONTENT_FOLDER_ID, WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID)); + + // display student choices only if all questions are multiple choice + boolean displayStudentChoices = true; + int maxOptionsInQuestion = 0; + for (AssessmentQuestion question : assessment.getQuestions()) { + if (question.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE) { + int optionsInQuestion = question.getQbQuestion().getQbOptions().size(); + if (optionsInQuestion > maxOptionsInQuestion) { + maxOptionsInQuestion = optionsInQuestion; + } + } else { + displayStudentChoices = false; + break; + } + } + + request.setAttribute("displayStudentChoices", displayStudentChoices); + if (displayStudentChoices) { + request.setAttribute("maxOptionsInQuestion", maxOptionsInQuestion); + + int totalNumberOfUsers = service.getCountUsersByContentId(contentId); + + Set questionDtos = new TreeSet<>(); + for (AssessmentQuestion question : assessment.getQuestions()) { + QuestionDTO questionDto = new QuestionDTO(question); + questionDtos.add(questionDto); + + // build candidate dtos + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + int optionAttemptCount = service.countAttemptsPerOption(contentId, optionDto.getUid()); + + float percentage = (float) (optionAttemptCount * 100) / totalNumberOfUsers; + optionDto.setPercentage(percentage); + } + } + request.setAttribute("questions", questionDtos); + } + return "pages/monitoring/monitoring"; } @@ -228,9 +270,17 @@ Long userId = WebUtil.readLongParam(request, AttributeNames.PARAM_USER_ID); Long sessionId = WebUtil.readLongParam(request, AssessmentConstants.PARAM_SESSION_ID); Long contentId = (Long) sessionMap.get(AssessmentConstants.ATTR_TOOL_CONTENT_ID); - UserSummary userSummary = service.getUserSummary(contentId, userId, sessionId); + UserSummary userSummary = service.getUserSummary(contentId, userId, sessionId); request.setAttribute(AssessmentConstants.ATTR_USER_SUMMARY, userSummary); + + Assessment assessment = service.getAssessmentByContentId(contentId); + boolean questionEtherpadEnabled = assessment.isUseSelectLeaderToolOuput() + && assessment.isQuestionEtherpadEnabled() + && StringUtils.isNotBlank(Configuration.get(ConfigurationKeys.ETHERPAD_API_KEY)); + request.setAttribute(AssessmentConstants.ATTR_IS_QUESTION_ETHERPAD_ENABLED, questionEtherpadEnabled); + request.setAttribute(AssessmentConstants.ATTR_TOOL_SESSION_ID, sessionId); + return "pages/monitoring/parts/usersummary"; } Index: lams_tool_assessment/web/pages/monitoring/summary.jsp =================================================================== diff -u -ra96f86b151cdcdf191654e8596eb2cf599e4e12b -r8bc318f44b193b1d926fcc62211ca1b4b18d9b30 --- lams_tool_assessment/web/pages/monitoring/summary.jsp (.../summary.jsp) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) +++ lams_tool_assessment/web/pages/monitoring/summary.jsp (.../summary.jsp) (revision 8bc318f44b193b1d926fcc62211ca1b4b18d9b30) @@ -330,6 +330,12 @@ + +
+ + <%@ include file="/pages/monitoring/parts/mcqStudentChoices.jsp" %> +
+