Index: lams_monitoring/web/error.jsp =================================================================== diff -u -r40de3afab4e8d589660daffb6efd6e568e87f8fa -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_monitoring/web/error.jsp (.../error.jsp) (revision 40de3afab4e8d589660daffb6efd6e568e87f8fa) +++ lams_monitoring/web/error.jsp (.../error.jsp) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -1,4 +1,5 @@ +<%@ page isErrorPage="true"%> <%@ include file="/taglibs.jsp"%> <%@ page import="org.lamsfoundation.lams.util.Configuration" import="org.lamsfoundation.lams.util.ConfigurationKeys" %> Index: lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r731ac9bda6562e241a71eb71b18caeaa49aeefb5 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 731ac9bda6562e241a71eb71b18caeaa49aeefb5) +++ lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -378,4 +378,16 @@ label.answer.alternatives =Answer alternatives label.someone.allocated.this.answer =Sorry, someone has allocated this answer already +label.export.marks.mcq =Export marks for MCQ questions +label.not.available =N/A +label.legend =Legend +label.denotes.correct.answer =*- Denotes the correct answer +label.report.by.student =Report by learner +label.correct.answer =Correct answer +label.class.mean =Class mean mark +label.median =Median mark +label.export.question.mark =Question {0} (mark: {1}) +label.learner =Learner + + #======= End labels: Exported 370 labels for en AU ===== Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== diff -u -r670dd8e248dc4705c92031c79d05a99559e35024 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 670dd8e248dc4705c92031c79d05a99559e35024) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -199,6 +199,7 @@ public static final String OUTPUT_NAME_BEST_SCORE = "best.score"; public static final String OUTPUT_NAME_FIRST_SCORE = "first.score"; public static final String OUTPUT_NAME_AVERAGE_SCORE = "average.score"; + public static final String OUTPUT_NAME_LEARNER_ALL_CORRECT = "learner.all.correct"; public static final String OUTPUT_NAME_ORDERED_ANSWERS = "ordered.answers"; public static final String OUTPUT_NAME_CONDITION_ORDERED_ANSWER = "ordered.answer"; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20200120.sql =================================================================== diff -u --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20200120.sql (revision 0) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20200120.sql (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -0,0 +1,152 @@ +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS = 0; + +-- LDEV-4951 Replace MCQ with Asssessment + +-- transform McContent to Assessment +ALTER TABLE `tl_laasse10_assessment` ADD COLUMN `tmp_mcq_uid` BIGINT; +ALTER TABLE tl_laasse10_assessment ADD INDEX (tmp_mcq_uid); + +INSERT INTO tl_laasse10_assessment (`create_date`, `update_date`, `submission_deadline`,`create_by`,`title`,`time_limit`, + `attempts_allowed`,`passing_mark`,`instructions`,`define_later`,`content_id`,`allow_question_feedback`,`allow_overall_feedback`, + `allow_disclose_answers`,`allow_right_answers`,`allow_wrong_answers`,`allow_grades_after_attempt`,`allow_history_responses`, + `display_summary`,`questions_per_page`,`shuffled`,`attempt_completion_notify`,`reflect_on_activity`,`reflect_instructions`, + `numbered`,`use_select_leader_tool_ouput`,`enable_confidence_levels`,`confidence_levels_type`, `tmp_mcq_uid`) +SELECT `creation_date`,`update_date`,`submission_deadline`,NULL,`title`,0, + !`retries`,`pass_mark`,`instructions`,`define_later`,`content_id`,1,`display_feedback_only`, + 1,0,0,`showMarks`,0, + `displayAnswers`, `questions_sequenced`,`randomize`,0,`reflect`,`reflectionSubject`, + `prefix_answers_with_letters`,`use_select_leader_tool_ouput`,`enable_confidence_levels`,1, uid + FROM tl_lamc11_content; +-- MCQ's `show_report` property was seemingly abandoned by tool itself + +-- transform McSession to AssessmentSession +ALTER TABLE `tl_laasse10_session` ADD COLUMN `tmp_mcq_session_uid` BIGINT; +ALTER TABLE tl_laasse10_session ADD INDEX (tmp_mcq_session_uid); + +INSERT INTO tl_laasse10_session(`session_end_date`,`session_start_date`,`status`,`assessment_uid`,`session_id`,`session_name`,`group_leader_uid`,tmp_mcq_session_uid) +SELECT ses.`session_end_date`,ses.`session_start_date`,ses.`session_status`="COMPLETED",asse.`uid`,ses.`mc_session_id`,ses.`session_name`,ses.`mc_group_leader_uid`,ses.uid + FROM tl_lamc11_session as ses + JOIN tl_laasse10_assessment AS asse ON asse.tmp_mcq_uid = ses.mc_content_id; + + +-- transform McQueUser to AssessmentUser +ALTER TABLE `tl_laasse10_user` ADD COLUMN `tmp_mcq_user_uid` BIGINT; +ALTER TABLE tl_laasse10_user ADD INDEX (tmp_mcq_user_uid); + +INSERT INTO tl_laasse10_user(`user_id`,`last_name`,`first_name`,`login_name`,`session_finished`,`session_uid`,`assessment_uid`,tmp_mcq_user_uid) +SELECT usr.`que_usr_id`,commonUsr.`last_name`,commonUsr.`first_name`,usr.`username`,usr.`responseFinalised`,ses.uid,ses.assessment_uid,usr.uid + FROM tl_lamc11_que_usr as usr + JOIN lams_user AS commonUsr ON usr.que_usr_id = commonUsr.user_id + JOIN tl_laasse10_session AS ses ON usr.mc_session_id = ses.tmp_mcq_session_uid; +-- `viewSummaryRequested` tinyint(1) NOT NULL DEFAULT '0', +-- `last_attempt_total_mark` int(11) DEFAULT NULL, +-- `number_attempts` int(11) DEFAULT '0', + +-- change references from MCQ users to Assessment ones +UPDATE tl_laasse10_session AS ses, tl_laasse10_user AS usr + SET ses.group_leader_uid = usr.uid + WHERE ses.group_leader_uid = usr.tmp_mcq_user_uid AND ses.tmp_mcq_session_uid IS NOT NULL; + +-- transform McQueContent to AssessmentQuestion +INSERT INTO tl_laasse10_assessment_question(`uid`,`assessment_uid`) +SELECT mcQuestion.`uid`,asses.`uid` + FROM tl_lamc11_que_content as mcQuestion + JOIN tl_laasse10_assessment AS asses ON mcQuestion.mc_content_id = asses.tmp_mcq_uid; + +UPDATE lams_qb_tool_question AS qbToolQuestion, tl_lamc11_content AS mcContent, tl_laasse10_assessment as assessment + SET qbToolQuestion.tool_content_id = assessment.content_id + WHERE mcContent.content_id = qbToolQuestion.tool_content_id AND assessment.tmp_mcq_uid=mcContent.uid; + +ALTER TABLE `tl_laasse10_question_reference` ADD COLUMN `tmp_mcq` TINYINT(1); +INSERT INTO tl_laasse10_question_reference(`question_uid`,`sequence_id`,`default_grade`,`random_question`,`assessment_uid`,tmp_mcq) +SELECT mcQuestion.`uid`,qbToolQuestion.display_order,1,0,asses.`uid`,1 + FROM tl_lamc11_que_content as mcQuestion + JOIN tl_laasse10_assessment AS asses ON mcQuestion.mc_content_id = asses.tmp_mcq_uid + JOIN lams_qb_tool_question AS qbToolQuestion ON mcQuestion.uid = qbToolQuestion.tool_question_uid; + + +-- transform McUsrAttempt to AssessmentResult +INSERT INTO tl_laasse10_assessment_result(`assessment_uid`,`start_date`,`finish_date`,`user_uid`,`session_id`,`grade`,`latest`,`time_limit_launched_date`) +SELECT session.`assessment_uid`, mcAttempt.`attempt_time`, IF(mcUser.responseFinalised,mcAttempt.`attempt_time`,NULL), assessmentUser.uid, session.session_id, + IF(mcUser.last_attempt_total_mark IS NULL,0,mcUser.last_attempt_total_mark), 1, NULL + FROM tl_lamc11_usr_attempt as mcAttempt + JOIN tl_laasse10_user as assessmentUser ON mcAttempt.que_usr_id = assessmentUser.tmp_mcq_user_uid + JOIN tl_lamc11_que_usr as mcUser ON mcAttempt.que_usr_id = mcUser.uid + JOIN tl_laasse10_session as session ON assessmentUser.session_uid = session.uid + GROUP BY mcAttempt.que_usr_id; + +-- calculate AssessmentResult'maxMark (it's a different query, as user might have not answered all questions) +UPDATE tl_laasse10_assessment_result AS result + JOIN (SELECT assessment_uid, SUM(default_grade) maxGrade FROM tl_laasse10_question_reference WHERE tmp_mcq=1 GROUP BY assessment_uid) AS maxGrade + ON result.assessment_uid = maxGrade.assessment_uid + SET result.maximum_grade = maxGrade.maxGrade; + +INSERT INTO tl_laasse10_question_result(`uid`,`result_uid`,`answer_float`,`answer_boolean`,`mark`, + `penalty`,`finish_date`,`max_mark`,`confidence_level`) +SELECT mcAttempt.`uid`,assmResult.uid,0,0,mcAttempt.`mark`,0,IF(mcUser.responseFinalised,mcAttempt.`attempt_time`,NULL),qbQuestion.`max_mark`,mcAttempt.`confidence_level` + FROM tl_lamc11_usr_attempt as mcAttempt + JOIN lams_qb_tool_answer AS qbToolAnswer ON mcAttempt.uid = qbToolAnswer.answer_uid + JOIN lams_qb_tool_question AS qbToolQuestion ON qbToolAnswer.tool_question_uid = qbToolQuestion.tool_question_uid + JOIN lams_qb_question AS qbQuestion ON qbToolQuestion.qb_question_uid = qbQuestion.uid + + JOIN tl_laasse10_user as assmUser ON mcAttempt.que_usr_id = assmUser.tmp_mcq_user_uid + JOIN tl_laasse10_assessment_result AS assmResult ON assmUser.uid = assmResult.user_uid + + JOIN tl_lamc11_que_usr as mcUser ON mcAttempt.que_usr_id = mcUser.uid; + +INSERT INTO tl_laasse10_option_answer(`question_result_uid`,`question_option_uid`,`answer_boolean`,`answer_int`) +SELECT mcAttempt.`uid`,qbOption.uid,qbToolAnswer.qb_option_uid=qbOption.uid,-1 + FROM tl_lamc11_usr_attempt as mcAttempt + + JOIN lams_qb_tool_answer AS qbToolAnswer ON mcAttempt.uid = qbToolAnswer.answer_uid + JOIN lams_qb_tool_question AS qbToolQuestion ON qbToolAnswer.tool_question_uid = qbToolQuestion.tool_question_uid + JOIN lams_qb_question AS qbQuestion ON qbToolQuestion.qb_question_uid = qbQuestion.uid + + LEFT JOIN lams_qb_option AS qbOption ON qbQuestion.uid = qbOption.qb_question_uid; + +-- take care about lams_tool_content +UPDATE lams_tool_content AS toolContent +JOIN `lams_tool` as mcqTool ON mcqTool.tool_id=toolContent.tool_id AND mcqTool.`tool_signature` = 'lamc11' +JOIN `lams_tool` as assmTool ON assmTool.`tool_signature` = 'laasse10' +SET toolContent.tool_id = assmTool.tool_id; + +-- take care about ActivityEvaluation +UPDATE lams_activity_evaluation AS evaluation +JOIN lams_learning_activity AS mcqActivity ON mcqActivity.activity_id=evaluation.activity_id +JOIN `lams_tool` as mcqTool ON mcqTool.tool_id=mcqActivity.tool_id AND mcqTool.`tool_signature` = 'lamc11' +SET evaluation.tool_output_definition = 'learner.total.score' +WHERE evaluation.tool_output_definition='learner.mark'; + +-- migrate lams_learning_activity +UPDATE lams_learning_activity AS activity +JOIN `lams_tool` as mcqTool ON mcqTool.tool_id=activity.tool_id AND mcqTool.`tool_signature` = 'lamc11' +JOIN `lams_tool` as assmTool ON assmTool.`tool_signature` = 'laasse10' +SET activity.learning_library_id = assmTool.learning_library_id, + activity.tool_id = assmTool.tool_id, + activity.library_activity_ui_image = 'tool/laasse10/images/icon_assessment.svg'; + +-- migrate notebook entries +UPDATE lams_notebook_entry +SET external_signature = 'laasse10' +WHERE external_signature='lamc11'; + +ALTER TABLE tl_laasse10_assessment DROP COLUMN tmp_mcq_uid; +ALTER TABLE tl_laasse10_session DROP COLUMN tmp_mcq_session_uid; +ALTER TABLE tl_laasse10_user DROP COLUMN tmp_mcq_user_uid; +ALTER TABLE tl_laasse10_question_reference DROP COLUMN tmp_mcq; + +--DROP TABLE tl_lamc11_content, +-- tl_lamc11_session, +-- tl_lamc11_que_usr, +-- tl_lamc11_que_content, +-- tl_lamc11_configuration, +-- tl_lamc11_usr_attempt; + +--DELETE FROM `lams_tool` WHERE (`tool_signature` = 'lamc11'); + +-- 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/dto/SessionDTO.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/SessionDTO.java (.../SessionDTO.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/SessionDTO.java (.../SessionDTO.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -44,6 +44,7 @@ //used for export purposes only private List assessmentResults; + private List userMarkDtos; public SessionDTO() { } @@ -78,14 +79,6 @@ this.sessionName = sessionName; } - public List getAssessmentResults() { - return assessmentResults; - } - - public void setAssessmentResults(List assessmentResults) { - this.assessmentResults = assessmentResults; - } - public int getNumberLearners() { return numberLearners; } @@ -118,4 +111,20 @@ this.maxMark = maxMark; } + public List getAssessmentResults() { + return assessmentResults; + } + + public void setAssessmentResults(List assessmentResults) { + this.assessmentResults = assessmentResults; + } + + public List getUserMarkDtos() { + return userMarkDtos; + } + + public void setUserMarkDtos(List userMarkDtos) { + this.userMarkDtos = userMarkDtos; + } + } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/UserMarkDTO.java =================================================================== diff -u --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/UserMarkDTO.java (revision 0) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/UserMarkDTO.java (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -0,0 +1,170 @@ +package org.lamsfoundation.lams.tool.assessment.dto; + +import java.util.Date; + +import org.apache.commons.lang.builder.ToStringBuilder; + +/** + * DTO that hols user marks. Used only for monitor export MCQ. + * + * @author Ozgur Demirtas + */ +public class UserMarkDTO implements Comparable { + private String queUsrId; // mc user uid + private String userId; // LAMS userId + private String portraitId; + private String userName; + private String fullName; + private boolean isUserLeader; + private Date attemptTime; + private Float[] marks; + private String[] answeredOptions; + private Float totalMark; + + @Override + public String toString() { + return new ToStringBuilder(this).append("Listing UserMarkDTO:").append("queUsrId", queUsrId) + .append("userName", userName).append("fullName", fullName).append("marks", marks) + .append("totalMark", totalMark).append("attemptTime", attemptTime).toString(); + } + + /** + * @return Returns the marks. + */ + public Float[] getMarks() { + return marks; + } + + /** + * @param marks + * The marks to set. + */ + public void setMarks(Float[] marks) { + this.marks = marks; + } + + /** + * @return Returns the answeredOptions - sequencial letter of the option that was chosen. + */ + public String[] getAnsweredOptions() { + return answeredOptions; + } + + /** + * @param answeredOptions + * The answeredOptions to set. + */ + public void setAnsweredOptions(String[] answeredOptions) { + this.answeredOptions = answeredOptions; + } + + /** + * @return Returns the queUsrId. + */ + public String getQueUsrId() { + return queUsrId; + } + + /** + * @param queUsrId + * The queUsrId to set. + */ + public void setQueUsrId(String queUsrId) { + this.queUsrId = queUsrId; + } + + /** + * @return Returns the userName. + */ + public String getUserName() { + return userName; + } + + /** + * @param userName + * The userName to set. + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * @return Returns the userName. + */ + public String getFullName() { + return fullName; + } + + /** + * @param userName + * The userName to set. + */ + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public boolean setUserGroupLeader(boolean isUserLeader) { + return this.isUserLeader = isUserLeader; + } + + public boolean isUserGroupLeader() { + return isUserLeader; + } + + @Override + public int compareTo(Object o) { + UserMarkDTO userMarkDTO = (UserMarkDTO) o; + + if (userMarkDTO == null) { + return 1; + } else { + return (int) (new Long(queUsrId).longValue() - new Long(userMarkDTO.queUsrId).longValue()); + } + } + + /** + * @return Returns the totalMark. + */ + public Float getTotalMark() { + return totalMark; + } + + /** + * @param totalMark + * The totalMark to set. + */ + public void setTotalMark(Float totalMark) { + this.totalMark = totalMark; + } + + /** + * @return Returns the attemptTime. + */ + public Date getAttemptTime() { + return attemptTime; + } + + /** + * @param attemptTime + * The attemptTime to set. + */ + public void setAttemptTime(Date attemptTime) { + this.attemptTime = attemptTime; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getPortraitId() { + return portraitId; + } + + public void setPortraitId(String portraitId) { + this.portraitId = portraitId; + } +} Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentOutputFactory.java =================================================================== diff -u -r394f403c289f0fd7808c228840bead5c4e7d5d32 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentOutputFactory.java (.../AssessmentOutputFactory.java) (revision 394f403c289f0fd7808c228840bead5c4e7d5d32) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentOutputFactory.java (.../AssessmentOutputFactory.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -65,6 +65,9 @@ definition = buildRangeDefinition(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN, 0L, null); definitionMap.put(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN, definition); + + definition = buildBooleanOutputDefinition(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT); + definitionMap.put(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT, definition); if (toolContentObject != null) { Assessment assessment = (Assessment) toolContentObject; @@ -170,6 +173,10 @@ output.put(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN, getTimeTaken(assessmentService, learnerId, assessment)); } + if (names == null || names.contains(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT)) { + output.put(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT, + getLearnerAllCorrect(assessmentService, learnerId, assessment)); + } if (names == null || names.contains(AssessmentConstants.OUTPUT_NAME_LEARNER_NUMBER_ATTEMPTS)) { output.put(AssessmentConstants.OUTPUT_NAME_LEARNER_NUMBER_ATTEMPTS, getNumberAttempts(assessmentService, learnerId, assessment)); @@ -217,6 +224,9 @@ } else if (name.equals(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN)) { return getTimeTaken(assessmentService, learnerId, assessment); + } else if (name.equals(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT)) { + return getLearnerAllCorrect(assessmentService, learnerId, assessment); + } else if (name.equals(AssessmentConstants.OUTPUT_NAME_LEARNER_NUMBER_ATTEMPTS)) { return getNumberAttempts(assessmentService, learnerId, assessment); @@ -257,6 +267,9 @@ if (name.equals(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN)) { return null; } + if (name.equals(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT)) { + return null; + } if (name.equals(AssessmentConstants.OUTPUT_NAME_LEARNER_NUMBER_ATTEMPTS)) { return null; } @@ -352,7 +365,29 @@ return new ToolOutput(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN, getI18NText(AssessmentConstants.OUTPUT_NAME_LEARNER_TIME_TAKEN, true), timeTaken); } + + /** + * Did the user get the questions all correct. This checks the answers associated with the last attempt. Assumes all + * correct if the mark is equal to the maximum possible mark. Will always return a ToolOutput object. + */ + private ToolOutput getLearnerAllCorrect(IAssessmentService assessmentService, Long learnerId, Assessment assessment) { + //exclude essays maxMark from the total mark (as we need maxMark to be available pronto, and not hours later when teacher assigns it, as with essays) + AssessmentResult assessmentResult = assessmentService.getLastFinishedAssessmentResult(assessment.getUid(), learnerId); + int maxScore = assessmentResult.getMaximumGrade(); + for (QuestionReference questionReference: assessment.getQuestionReferences()) { + if (questionReference.getQuestion().getQbQuestion().getType() == QbQuestion.TYPE_ESSAY) { + maxScore -= questionReference.getMaxMark(); + } + }; + + // We know the user didn't get everything wrong, but did they answer enough options correctly? + // This case is used when there is more than one correct option for each answer. Simple way, compare counts! + boolean allCorrect = assessmentResult.getGrade() == maxScore; + return new ToolOutput(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT, + getI18NText(AssessmentConstants.OUTPUT_NAME_LEARNER_ALL_CORRECT, true), allCorrect); + } + /** * Get the number of attempts done by user. Will always return a ToolOutput object. */ Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -r90aaa6a33006ccf9104ff54239cf13b9ef587728 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 90aaa6a33006ccf9104ff54239cf13b9ef587728) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -23,6 +23,7 @@ package org.lamsfoundation.lams.tool.assessment.service; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.sql.Timestamp; @@ -51,7 +52,15 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.util.CellUtil; import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.confidencelevel.VsaAnswerDTO; import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; @@ -94,6 +103,7 @@ import org.lamsfoundation.lams.tool.assessment.dto.QuestionSummary; import org.lamsfoundation.lams.tool.assessment.dto.ReflectDTO; import org.lamsfoundation.lams.tool.assessment.dto.SessionDTO; +import org.lamsfoundation.lams.tool.assessment.dto.UserMarkDTO; import org.lamsfoundation.lams.tool.assessment.dto.UserSummary; import org.lamsfoundation.lams.tool.assessment.dto.UserSummaryItem; import org.lamsfoundation.lams.tool.assessment.model.Assessment; @@ -123,6 +133,7 @@ import org.lamsfoundation.lams.util.excel.ExcelCell; import org.lamsfoundation.lams.util.excel.ExcelRow; import org.lamsfoundation.lams.util.excel.ExcelSheet; +import org.lamsfoundation.lams.util.excel.ExcelUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -1775,7 +1786,7 @@ ExcelCell.BORDER_STYLE_BOTTOM_THIN); questionTitleRow.addCell(getMessage("label.export.user.id"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); if (showUserNames) { - questionTitleRow.addCell(getMessage("label.monitoring.user.summary.user.name"), true, + questionTitleRow.addCell(getMessage("label.learner"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); } questionTitleRow.addCell(getMessage("label.export.date.attempted"), true, @@ -1823,7 +1834,7 @@ hedgeQuestionTitleRow.addCell(getMessage("label.monitoring.question.summary.default.mark"), true); hedgeQuestionTitleRow.addCell(getMessage("label.export.user.id"), true); if (showUserNames) { - hedgeQuestionTitleRow.addCell(getMessage("label.monitoring.user.summary.user.name"), true); + hedgeQuestionTitleRow.addCell(getMessage("label.learner"), true); } hedgeQuestionTitleRow.addCell(getMessage("label.export.date.attempted"), true); hedgeQuestionTitleRow.addCell(getMessage("label.export.time.attempted"), true); @@ -2039,7 +2050,7 @@ if (showUserNames) { ExcelRow userTitleRow = userSummarySheet.initRow(); userTitleRow.addCell(getMessage("label.export.user.id"), true); - userTitleRow.addCell(getMessage("label.monitoring.user.summary.user.name"), 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); @@ -2220,7 +2231,381 @@ return summaryTableRow; } + + @Override + public byte[] exportMarksMcq(Assessment assessment, Set questions) throws IOException { + int maxOptionsInQuestion = 0; + for (AssessmentQuestion question : questions) { + if (question.getQbQuestion().getQbOptions().size() > maxOptionsInQuestion) { + maxOptionsInQuestion = question.getQbQuestion().getQbOptions().size(); + } + } + int totalNumberOfUsers = getCountUsersByContentId(assessment.getContentId()); + int numQuestions = questions.size(); + + //prepareDataForExportMcq + List sessionDtos = new LinkedList<>(); + List sessions = assessmentSessionDao.getByContentId(assessment.getContentId()); + for (AssessmentSession session : sessions) { + SessionDTO sessionDto = new SessionDTO(session.getSessionId(), session.getSessionName()); + + List userMarkDtos = new LinkedList<>(); + for (AssessmentUser user: session.getAssessmentUsers()) { + UserMarkDTO userMarkDto = new UserMarkDTO(); + userMarkDto.setFullName(user.getLastName() + " " + user.getFirstName()); + userMarkDto.setUserGroupLeader(isUserGroupLeader(user.getUserId(), session.getSessionId())); + userMarkDto.setUserName(user.getLoginName()); + userMarkDto.setQueUsrId(user.getUid().toString()); + userMarkDto.setUserId(user.getUserId().toString()); + + // The marks for the user must be listed in the display order of the questionDescription. + // Other parts of the code assume that the questions will be in consecutive display + // order starting 1 (e.g. 1, 2, 3, not 1, 3, 4) so we set up an array and use + // the ( display order - 1) as the index (arrays start at 0, rather than 1 hence -1) + // The user must answer all questions, so we can assume that they will have marks + // for all questions or no questions. + // At present there can only be one answer for each questionDescription but there may be more + // than one in the future and if so, we don't want to count the mark twice hence + // we need to check if we've already processed this questionDescription in the total. + Float[] userMarks = new Float[numQuestions]; + String[] answeredOptions = new String[numQuestions]; + Date attemptTime = null; + AssessmentResult finalizedUserAttempt = getLastFinishedAssessmentResult(assessment.getUid(), user.getUserId()); + Float totalMark = 0f; + if (finalizedUserAttempt != null) { + for (AssessmentQuestionResult questionResult : finalizedUserAttempt.getQuestionResults()) { + Integer displayOrder = questionResult.getQbToolQuestion().getDisplayOrder(); + int arrayIndex = (displayOrder != null) && (displayOrder.intValue() > 0) + ? displayOrder.intValue() - 1 + : 1; + if (userMarks[arrayIndex] == null) { + Float mark = questionResult.getMark(); + userMarks[arrayIndex] = mark; + totalMark += mark; + + // find out the answered option's sequential letter - A,B,C... + String answeredOptionLetter = ""; + int optionCount = 1; + for (QbOption qbOption : questionResult.getQbQuestion().getQbOptions()) { + for (AssessmentOptionAnswer optionAnswer : questionResult.getOptionAnswers()) { + if (optionAnswer.getAnswerBoolean() + && optionAnswer.getOptionUid().equals(qbOption.getUid())) { + answeredOptionLetter = String.valueOf((char) ((optionCount + 'A') - 1)); + break; + } + } + optionCount++; + } + answeredOptions[arrayIndex] = answeredOptionLetter; + } + // get the attempt time, (NB all questions will have the same attempt time) + // Not efficient, since we assign this value for each attempt + attemptTime = questionResult.getFinishDate(); + } + } + + userMarkDto.setMarks(userMarks); + userMarkDto.setAnsweredOptions(answeredOptions); + userMarkDto.setAttemptTime(attemptTime); + userMarkDto.setTotalMark(totalMark); + + userMarkDtos.add(userMarkDto); + } + + sessionDto.setUserMarkDtos(userMarkDtos); + sessionDtos.add(sessionDto); + } + + // create an empty excel file + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFCellStyle greenColor = wb.createCellStyle(); + greenColor.setFillForegroundColor(IndexedColors.LIME.getIndex()); + greenColor.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font whiteFont = wb.createFont(); + whiteFont.setColor(IndexedColors.WHITE.getIndex()); + whiteFont.setFontName(ExcelUtil.DEFAULT_FONT_NAME); + greenColor.setFont(whiteFont); + + short percentageFormat = wb.createDataFormat().getFormat("0%"); + + // ======================================================= Report by questionDescription IRA page + // ======================================= + + HSSFSheet sheet = wb.createSheet(messageService.getMessage("label.monitoring.summary.report.by.question")); + + HSSFRow row; + HSSFCell cell; + int rowCount = 0; + + row = sheet.createRow(rowCount++); + int count = 0; + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.question.summary.question")); + for (int optionCount = 0; optionCount < maxOptionsInQuestion; optionCount++) { + cell = row.createCell(count++); + cell.setCellValue(String.valueOf((char) (optionCount + 'A'))); + } + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.not.available")); + + for (AssessmentQuestion question : questions) { + row = sheet.createRow(rowCount); + count = 0; + + cell = row.createCell(count++); + cell.setCellValue(rowCount); + rowCount++; + + Double totalPercentage = 0d; + for (QbOption option : question.getQbQuestion().getQbOptions()) { + int optionAttemptCount = countAttemptsPerOption(assessment.getContentId(), option.getUid()); + cell = row.createCell(count++); + Double percentage = (totalNumberOfUsers != 0) ? (double) optionAttemptCount / totalNumberOfUsers : 0d; + cell.setCellValue(percentage); + if (option.isCorrect()) { + cell.setCellStyle(greenColor); + } + CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, percentageFormat); + + totalPercentage += percentage; + } + cell = row.createCell(maxOptionsInQuestion + 1); + cell.setCellValue((1 - totalPercentage)); + CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, percentageFormat); + } + + rowCount++; + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.legend")); + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.denotes.correct.answer")); + cell.setCellStyle(greenColor); + cell = row.createCell(1); + cell.setCellStyle(greenColor); + cell = row.createCell(2); + cell.setCellStyle(greenColor); + + // ======================================================= Report by student IRA page + // ======================================= + + sheet = wb.createSheet(messageService.getMessage("label.report.by.student")); + rowCount = 0; + + row = sheet.createRow(rowCount++); + count = 2; + for (int questionCount = 1; questionCount <= questions.size(); questionCount++) { + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.question.summary.question") + questionCount); + } + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.summary.total")); + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.summary.total") + " %"); + + row = sheet.createRow(rowCount++); + count = 1; + ArrayList correctAnswers = new ArrayList<>(); + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.correct.answer")); + for (AssessmentQuestion question : questions) { + + // find out the correct answer's sequential letter - A,B,C... + String correctAnswerLetter = ""; + int answerCount = 1; + for (QbOption option : question.getQbQuestion().getQbOptions()) { + if (option.isCorrect()) { + correctAnswerLetter = String.valueOf((char) ((answerCount + 'A') - 1)); + break; + } + answerCount++; + } + cell = row.createCell(count++); + cell.setCellValue(correctAnswerLetter); + correctAnswers.add(correctAnswerLetter); + } + + row = sheet.createRow(rowCount++); + count = 0; + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("monitoring.label.group")); + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.learner")); + + ArrayList totalPercentList = new ArrayList<>(); + int[] numberOfCorrectAnswersPerQuestion = new int[questions.size()]; + for (SessionDTO sessionDto : sessionDtos) { + for (UserMarkDTO userMarkDto : sessionDto.getUserMarkDtos()) { + row = sheet.createRow(rowCount++); + count = 0; + cell = row.createCell(count++); + cell.setCellValue(sessionDto.getSessionName()); + + cell = row.createCell(count++); + cell.setCellValue(userMarkDto.getFullName()); + + String[] answeredOptions = userMarkDto.getAnsweredOptions(); + int numberOfCorrectlyAnsweredByUser = 0; + for (int i = 0; i < answeredOptions.length; i++) { + String answeredOption = answeredOptions[i]; + cell = row.createCell(count++); + cell.setCellValue(answeredOption); + if (StringUtils.equals(answeredOption, correctAnswers.get(i))) { + cell.setCellStyle(greenColor); + numberOfCorrectlyAnsweredByUser++; + numberOfCorrectAnswersPerQuestion[count - 3]++; + } + } + + cell = row.createCell(count++); + cell.setCellValue(userMarkDto.getTotalMark()); + + Double totalPercents = questions.size() != 0 + ? (double) numberOfCorrectlyAnsweredByUser / questions.size() + : 0d; + totalPercentList.add(totalPercents); + cell = row.createCell(count++); + cell.setCellValue(totalPercents); + CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, percentageFormat); + } + + rowCount++; + } + + // ave + row = sheet.createRow(rowCount++); + count = 1; + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.question.summary.average.mark")); + for (int numberOfCorrectAnswers : numberOfCorrectAnswersPerQuestion) { + cell = row.createCell(count++); + Double average = totalPercentList.size() == 0 ? 0d + : (double) numberOfCorrectAnswers / totalPercentList.size(); + cell.setCellValue(average); + CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, percentageFormat); + } + + // class mean + Double[] totalPercents = totalPercentList.toArray(new Double[0]); + Arrays.sort(totalPercents); + Double sum = 0d; + for (int i = 0; i < totalPercents.length; i++) { + sum += totalPercents[i]; + } + row = sheet.createRow(rowCount++); + cell = row.createCell(1); + cell.setCellValue(messageService.getMessage("label.class.mean")); + if (totalPercents.length != 0) { + Double classMean = totalPercents.length == 0 ? 0d : sum / totalPercents.length; + cell = row.createCell(questions.size() + 3); + cell.setCellValue(classMean); + CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, percentageFormat); + } + + // median + row = sheet.createRow(rowCount++); + cell = row.createCell(1); + cell.setCellValue(messageService.getMessage("label.median")); + if (totalPercents.length != 0) { + Double median; + int middle = totalPercents.length / 2; + if ((totalPercents.length % 2) == 1) { + median = totalPercents[middle]; + } else { + median = ((totalPercents[middle - 1] + totalPercents[middle]) / 2.0); + } + cell = row.createCell(questions.size() + 3); + cell.setCellValue(median); + CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, percentageFormat); + } + + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.legend")); + + row = sheet.createRow(rowCount++); + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("label.denotes.correct.answer")); + cell.setCellStyle(greenColor); + cell = row.createCell(1); + cell.setCellStyle(greenColor); + cell = row.createCell(2); + cell.setCellStyle(greenColor); + + // ======================================================= Marks page + // ======================================= + + sheet = wb.createSheet("Marks"); + + rowCount = 0; + count = 0; + + row = sheet.createRow(rowCount++); + for (AssessmentQuestion question : questions) { + cell = row.createCell(2 + count++); + cell.setCellValue(messageService.getMessage("label.export.question.mark", + new Object[] { count, question.getQbQuestion().getMaxMark() })); + } + + for (SessionDTO sessionDto : sessionDtos) { + String currentSessionName = sessionDto.getSessionName(); + + row = sheet.createRow(rowCount++); + + cell = row.createCell(0); + cell.setCellValue(messageService.getMessage("monitoring.label.group")); + + cell = row.createCell(1); + cell.setCellValue(currentSessionName); + cell.setCellStyle(greenColor); + + rowCount++; + count = 0; + + row = sheet.createRow(rowCount++); + + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.learner")); + + cell = row.createCell(count++); + cell.setCellValue(messageService.getMessage("label.monitoring.user.summary.user.name")); + + cell = row.createCell(questions.size() + 2); + cell.setCellValue(messageService.getMessage("label.monitoring.summary.total")); + + for (UserMarkDTO userMarkDto : sessionDto.getUserMarkDtos()) { + row = sheet.createRow(rowCount++); + count = 0; + + cell = row.createCell(count++); + cell.setCellValue(userMarkDto.getFullName()); + + cell = row.createCell(count++); + cell.setCellValue(userMarkDto.getUserName()); + + Float[] marks = userMarkDto.getMarks(); + for (int i = 0; i < marks.length; i++) { + cell = row.createCell(count++); + Float mark = (marks[i] == null) ? 0 : marks[i]; + cell.setCellValue(mark); + } + + cell = row.createCell(count++); + cell.setCellValue(userMarkDto.getTotalMark()); + } + + rowCount++; + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + wb.write(bos); + + byte[] data = bos.toByteArray(); + return data; + } + /** * Used only for excell export (for getUserSummaryData() method). */ Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java =================================================================== diff -u -r731ac9bda6562e241a71eb71b18caeaa49aeefb5 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java (.../IAssessmentService.java) (revision 731ac9bda6562e241a71eb71b18caeaa49aeefb5) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java (.../IAssessmentService.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -23,6 +23,7 @@ package org.lamsfoundation.lams.tool.assessment.service; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map; @@ -455,6 +456,11 @@ * @return */ List exportSummary(Assessment assessment, List sessionDtos, boolean showUserNames); + + /** + * Alternative Excel export. (Copied from now obsolete MCQ tool.) + */ + byte[] exportMarksMcq(Assessment assessment, Set questions) throws IOException ; /** * Gets the basic statistics for the grades for the Leaders when an Assessment is done using Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java =================================================================== diff -u -r4a2902072e80bc9fcfd6534115751829210e2153 -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 4a2902072e80bc9fcfd6534115751829210e2153) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -24,6 +24,7 @@ package org.lamsfoundation.lams.tool.assessment.web.controller; import java.io.IOException; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; @@ -43,6 +44,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.qb.dto.QbStatsActivityDTO; +import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.qb.service.IQbService; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentResultDTO; @@ -144,6 +146,16 @@ questionList.add(reference.getQuestion()); } } + + //check if all questions are of MCQ question type, then exportMarksMCQ export will be available + boolean isOnlyMcqQuestionsAvailable = true; + for (AssessmentQuestion question : questionList) { + if (question.getQbQuestion().getType() != QbQuestion.TYPE_MULTIPLE_CHOICE) { + isOnlyMcqQuestionsAvailable = false; + break; + } + } + sessionMap.put("isOnlyMcqQuestionsAvailable", isOnlyMcqQuestionsAvailable); //prepare toolOutputDefinitions and activityEvaluation List toolOutputDefinitions = new ArrayList<>(); @@ -570,7 +582,47 @@ ServletOutputStream out = response.getOutputStream(); ExcelUtil.createExcel(out, sheets, service.getMessage("label.export.exported.on"), true); } + + /** + * Export marks for MCQ questions + */ + @RequestMapping(path = "/exportSummaryMCQ", method = RequestMethod.POST) + @ResponseStatus(HttpStatus.OK) + public void exportSummaryMCQ(HttpServletRequest request, HttpServletResponse response) throws IOException { + String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + Assessment assessment = (Assessment) sessionMap.get(AssessmentConstants.ATTR_ASSESSMENT); + Set questions = (Set) sessionMap.get(AssessmentConstants.ATTR_QUESTION_LIST); + + byte[] spreadsheet = service.exportMarksMcq(assessment, questions); + // set cookie that will tell JS script that export has been finished + String downloadTokenValue = WebUtil.readStrParam(request, "downloadTokenValue"); + Cookie fileDownloadTokenCookie = new Cookie("fileDownloadToken", downloadTokenValue); + fileDownloadTokenCookie.setPath("/"); + response.addCookie(fileDownloadTokenCookie); + + // construct download file response header + OutputStream out = response.getOutputStream(); + String fileName = "assessment_marks_" + assessment.getUid() + "_export.xls"; + response.setContentType("application/x-download"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName); + + // write response + try { + out.write(spreadsheet); + out.flush(); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + } + } + } + @RequestMapping("/statistic") public String statistic(HttpServletRequest request, HttpServletResponse response) { SessionMap sessionMap = getSessionMap(request); Index: lams_tool_assessment/web/pages/monitoring/summary.jsp =================================================================== diff -u -re6dc4db4137cfd6b07a4aa79711b9d12b39fb78e -ra96f86b151cdcdf191654e8596eb2cf599e4e12b --- lams_tool_assessment/web/pages/monitoring/summary.jsp (.../summary.jsp) (revision e6dc4db4137cfd6b07a4aa79711b9d12b39fb78e) +++ lams_tool_assessment/web/pages/monitoring/summary.jsp (.../summary.jsp) (revision a96f86b151cdcdf191654e8596eb2cf599e4e12b) @@ -302,6 +302,10 @@ var url = "?&sessionMapID=${sessionMapID}&reqID="+(new Date()).getTime(); return downloadFile(url, 'messageArea_Busy', '', 'messageArea', 'btn-disable-on-submit'); }; + function exportMarksMCQ() { + var url = "?sessionMapID=${sessionMapID}&reqID="+(new Date()).getTime(); + return downloadFile(url, 'messageArea_Busy', '', 'messageArea', 'btn-disable-on-submit'); + };
@@ -330,6 +334,13 @@ + + + +