Index: lams_central/src/java/org/lamsfoundation/lams/web/controller/SearchQBController.java =================================================================== diff -u -r72c9800d4076fa450caff0943dd4de41399c83e0 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_central/src/java/org/lamsfoundation/lams/web/controller/SearchQBController.java (.../SearchQBController.java) (revision 72c9800d4076fa450caff0943dd4de41399c83e0) +++ lams_central/src/java/org/lamsfoundation/lams/web/controller/SearchQBController.java (.../SearchQBController.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -88,17 +88,17 @@ //empty questionTypesAvailable means no other questionTypes available for this tool StringBuilder questionTypesAvailable = new StringBuilder(); //by default show MCQ type of questions (except for Q&A tool) - int questionTypeDefault = QbQuestion.TYPE_MULTIPLE_CHOICE_SINGLE_ANSWER; + int questionTypeDefault = QbQuestion.TYPE_MULTIPLE_CHOICE; if (CommonConstants.TOOL_SIGNATURE_SCRATCHIE.equals(toolSignature) || CommonConstants.TOOL_SIGNATURE_MCQ.equals(toolSignature)) { //CommonConstants.TOOL_SIGNATURE_SURVEY } else if ("lasurv11".equals(toolSignature)) { - questionTypesAvailable.append(QbQuestion.TYPE_MULTIPLE_CHOICE_SINGLE_ANSWER); + questionTypesAvailable.append(QbQuestion.TYPE_MULTIPLE_CHOICE); questionTypesAvailable.append(","); questionTypesAvailable.append(QbQuestion.TYPE_ESSAY); } else if (CommonConstants.TOOL_SIGNATURE_ASSESSMENT.equals(toolSignature)) { - questionTypesAvailable.append(QbQuestion.TYPE_MULTIPLE_CHOICE_SINGLE_ANSWER); + questionTypesAvailable.append(QbQuestion.TYPE_MULTIPLE_CHOICE); questionTypesAvailable.append(","); questionTypesAvailable.append(QbQuestion.TYPE_MATCHING_PAIRS); questionTypesAvailable.append(","); Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20190110.sql =================================================================== diff -u -ra78b24b81609f5ee56f8ac4501e573739f86fabf -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20190110.sql (.../patch20190110.sql) (revision a78b24b81609f5ee56f8ac4501e573739f86fabf) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20190110.sql (.../patch20190110.sql) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -13,8 +13,23 @@ `create_date` DATETIME NOT NULL DEFAULT NOW(), `name` TEXT NOT NULL, `description` TEXT, - `mark` INT, + `max_mark` INT, `feedback` TEXT, + `penalty_factor` float DEFAULT 0, + `answer_required` TINYINT(1) DEFAULT 0, + `multiple_answers_allowed` TINYINT(1) DEFAULT 0, + `incorrect_answer_nullifies_mark` TINYINT(1) DEFAULT 0, + `feedback_on_correct` TEXT, + `feedback_on_partially_correct` TEXT, + `feedback_on_incorrect` TEXT, + `shuffle` TINYINT(1) DEFAULT 0, + `prefix_answers_with_letters` TINYINT(1) DEFAULT 0, + `case_sensitive` TINYINT(1) DEFAULT 0, + `correct_answer` TINYINT(1) DEFAULT 0, + `allow_rich_editor` TINYINT(1) DEFAULT 0, + `max_words_limit` int(11) DEFAULT 0, + `min_words_limit` int(11) DEFAULT 0, + `hedging_justification_enabled` TINYINT(1) DEFAULT 0, `tmp_question_id` BIGINT, PRIMARY KEY (uid), INDEX (tmp_question_id), @@ -35,14 +50,28 @@ `display_order` TINYINT NOT NULL DEFAULT 1, `name` TEXT NOT NULL, `correct` TINYINT(1) NOT NULL DEFAULT 0, + `matching_pair` TEXT, + `numerical_option` float, + `max_mark` float, + `accepted_error` float, + `feedback` TEXT, PRIMARY KEY (uid), INDEX (display_order), CONSTRAINT FK_lams_qb_option_1 FOREIGN KEY (qb_question_uid) REFERENCES lams_qb_question (uid) ON DELETE CASCADE ON UPDATE CASCADE); --- create an answer table from tools' answers will inherit +-- create Question Bank question unit (used by numerical type of questions only) +CREATE TABLE lams_qb_question_unit (`uid` BIGINT AUTO_INCREMENT, + `qb_question_uid` BIGINT NOT NULL, + `display_order` TINYINT NOT NULL DEFAULT 1, + `multiplier` float DEFAULT 0, + `unit` varchar(255), + PRIMARY KEY (uid), + CONSTRAINT FK_lams_qb_question_unit_1 FOREIGN KEY (qb_question_uid) REFERENCES lams_qb_question (uid) ON DELETE CASCADE ON UPDATE CASCADE); + +-- create an answer table from which tools' answers will inherit CREATE TABLE lams_qb_tool_answer (`answer_uid` BIGINT AUTO_INCREMENT, `tool_question_uid` BIGINT NOT NULL, - `qb_option_uid` BIGINT NOT NULL, + `qb_option_uid` BIGINT DEFAULT NULL, PRIMARY KEY (answer_uid), CONSTRAINT FK_lams_qb_tool_answer_1 FOREIGN KEY (tool_question_uid) REFERENCES lams_qb_tool_question (tool_question_uid) ON DELETE CASCADE ON UPDATE CASCADE, @@ -86,12 +115,13 @@ -- fill Question Bank question table with unique questions, with manually incremented question ID SET @question_id = (SELECT IF(MAX(question_id) IS NULL, 0, MAX(question_id)) FROM lams_qb_question); - -INSERT INTO lams_qb_question SELECT NULL, 1, 1, @question_id:=@question_id + 1, 1, IFNULL(c.creation_date, NOW()), - mcq.question, NULL, IFNULL(mcq.mark, 1), mcq.feedback, q.target_uid + +INSERT INTO lams_qb_question (uid, `local`, `type`, question_id, version, create_date, name, description, max_mark, feedback, tmp_question_id) + SELECT NULL, 1, 1, @question_id:=@question_id + 1, 1, IFNULL(c.creation_date, NOW()), + mcq.question, NULL, IFNULL(mcq.max_mark, 1), mcq.feedback, q.target_uid FROM (SELECT uid, TRIM(question) AS question, - mark, + mark AS max_mark, IF(TRIM(feedback) = '', NULL, TRIM(feedback)) AS feedback, mc_content_id FROM tl_lamc11_que_content) AS mcq @@ -194,8 +224,9 @@ UPDATE lams_qb_question SET tmp_question_id = -1; -- fill Question Bank question table with unique questions, with manually incremented question ID -INSERT INTO lams_qb_question SELECT NULL, 1, 1, @question_id:=@question_id + 1, 1, sq.create_date, - sq.question, sq.description, NULL, NULL, q.target_uid +INSERT INTO lams_qb_question (uid, `local`, `type`, question_id, version, create_date, name, description, max_mark, feedback, tmp_question_id) + SELECT NULL, 1, 1, @question_id:=@question_id + 1, 1, sq.create_date, + sq.question, sq.description, NULL, NULL, q.target_uid FROM (SELECT uid, TRIM(title) AS question, TRIM(description) AS description, @@ -285,14 +316,217 @@ -- cleanup -ALTER TABLE lams_qb_question DROP COLUMN tmp_question_id; ALTER TABLE tl_lascrt11_answer_log DROP COLUMN scratchie_item_uid, DROP COLUMN scratchie_answer_uid; -DROP TABLE tl_lascrt11_scratchie_answer, +DROP TABLE tl_lascrt11_scratchie_answer; + +-- prepare for next tool migration +DELETE FROM tmp_question; +DELETE FROM tmp_question_match; +DELETE FROM tmp_qb_question; + + +-- ASSESSMENT + + +-- shift Assessment question UIDs by offset equal to existing UIDs of MCQ adn Scratchie in lams_qb_tool_question +SET @max_tool_question_id = (SELECT MAX(tool_question_uid) FROM lams_qb_tool_question); +UPDATE tl_laasse10_assessment_question SET uid = uid + @max_tool_question_id ORDER BY uid DESC; + +-- first, process questions with question_type=1 (as MCQ and Scratchie have only this type of questions) + +-- create a mapping of Assessment question UID -> its question text + all answers in a single column +-- if this column is not *exactly* as in an other row, it means it should be a separate question in QB +INSERT INTO tmp_question + SELECT q.uid, + GROUP_CONCAT(TRIM(q.title), TRIM(o.option_string) ORDER BY o.sequence_id) + FROM tl_laasse10_assessment_question AS q + JOIN tl_laasse10_question_option AS o + ON q.uid = o.question_uid + WHERE q.question_type = 1 + GROUP BY q.uid; + +-- create a similar mapping for existing questions in QB +INSERT INTO tmp_qb_question + SELECT q.uid AS question_uid, + GROUP_CONCAT(TRIM(q.name), TRIM(o.name) ORDER BY o.display_order) AS content + FROM lams_qb_question AS q + JOIN lams_qb_option AS o + ON q.uid = o.qb_question_uid + WHERE q.type = 1 + GROUP BY q.uid; + +-- create a mapping of Assessment question UID -> UID of one of Assessment questions which holds the same content +INSERT INTO tmp_question_match + SELECT q.question_uid, merged.question_uid + FROM (SELECT * FROM tmp_question GROUP BY content) AS merged + JOIN tmp_question AS q + USING (content) + LEFT JOIN tmp_qb_question AS qb + USING (content) + WHERE qb.question_uid IS NULL; + + +-- second, process questions with all other question_type + +DELETE FROM tmp_question; + +INSERT INTO tmp_question + SELECT q.uid, + GROUP_CONCAT(q.question_type, TRIM(q.title), q.correct_answer, COALESCE(CONCAT(IFNULL(TRIM(o.question), ''),IFNULL(TRIM(o.option_string), ''), o.option_float, o.correct), '') ORDER BY o.sequence_id) + FROM tl_laasse10_assessment_question AS q + JOIN tl_laasse10_question_option AS o + ON q.uid = o.question_uid + WHERE q.question_type != 1 + GROUP BY q.uid; + +INSERT INTO tmp_question_match + SELECT q.question_uid, merged.question_uid + FROM (SELECT * FROM tmp_question GROUP BY content) AS merged + JOIN tmp_question AS q + USING (content); + +-- reset column for matching QB questions with Assessment questions +UPDATE lams_qb_question SET tmp_question_id = -1; + + +-- fill Question Bank question table with unique questions, with manually incremented question ID +INSERT INTO lams_qb_question SELECT NULL, aq.question_type, 1, @question_id:=@question_id + 1, 1, IFNULL(assessment.create_date, NOW()), + aq.question, aq.description, IFNULL(aq.max_mark, 1), aq.feedback, aq.penalty_factor, aq.answer_required, + aq.multiple_answers_allowed, aq.incorrect_answer_nullifies_mark, aq.feedback_on_correct, aq.feedback_on_partially_correct, + aq.feedback_on_incorrect, aq.shuffle, aq.prefix_answers_with_letters, aq.case_sensitive, aq.correct_answer, + aq.allow_rich_editor, aq.max_words_limit, aq.min_words_limit, aq.hedging_justification_enabled, q.target_uid + FROM (SELECT uid, + TRIM(title) AS question, + TRIM(question) AS description, + default_grade AS max_mark, + question_type, + IF(TRIM(general_feedback) = '', NULL, TRIM(general_feedback)) AS feedback, + penalty_factor, + answer_required, + multiple_answers_allowed, + incorrect_answer_nullifies_mark, + TRIM(feedback_on_correct) AS feedback_on_correct, + TRIM(feedback_on_partially_correct) AS feedback_on_partially_correct, + TRIM(feedback_on_incorrect) AS feedback_on_incorrect, + shuffle, + prefix_answers_with_letters, + case_sensitive, + correct_answer, + allow_rich_editor, + max_words_limit, + min_words_limit, + hedging_justification_enabled, + assessment_uid + FROM tl_laasse10_assessment_question) AS aq + JOIN (SELECT DISTINCT target_uid FROM tmp_question_match) AS q + ON aq.uid = q.target_uid + JOIN tl_laasse10_assessment AS assessment + ON aq.assessment_uid = assessment.uid; + +-- set up references to QB question UIDs created above +INSERT INTO lams_qb_tool_question + SELECT q.question_uid, qb.uid, assess.content_id, aq.sequence_id + FROM lams_qb_question AS qb + JOIN tmp_question_match AS q + ON qb.tmp_question_id = q.target_uid + JOIN tl_laasse10_assessment_question AS aq + ON q.question_uid = aq.uid + JOIN tl_laasse10_assessment AS assess + ON aq.assessment_uid = assess.uid; + +-- set up references to QB question UIDs for existing questions +INSERT INTO lams_qb_tool_question + SELECT q.question_uid, qb.question_uid, assess.content_id, aq.sequence_id + FROM tmp_question AS q + JOIN tmp_qb_question qb + USING (content) + JOIN tl_laasse10_assessment_question AS aq + ON q.question_uid = aq.uid + JOIN tl_laasse10_assessment AS assess + ON aq.assessment_uid = assess.uid; + +-- delete obsolete columns +ALTER TABLE tl_laasse10_assessment_question DROP FOREIGN KEY FK_NEW_1720029621_F52D1F93EC0D3147, + DROP COLUMN title, + DROP COLUMN question, + DROP COLUMN question_type, + DROP COLUMN default_grade, + DROP COLUMN feedback, + DROP COLUMN general_feedback, + DROP COLUMN penalty_factor, + DROP COLUMN answer_required, + DROP COLUMN multiple_answers_allowed, + DROP COLUMN incorrect_answer_nullifies_mark, + DROP COLUMN feedback_on_correct, + DROP COLUMN feedback_on_partially_correct, + DROP COLUMN feedback_on_incorrect, + DROP COLUMN shuffle, + DROP COLUMN prefix_answers_with_letters, + DROP COLUMN case_sensitive, + DROP COLUMN correct_answer, + DROP COLUMN allow_rich_editor, + DROP COLUMN max_words_limit, + DROP COLUMN min_words_limit, + DROP COLUMN hedging_justification_enabled, + DROP COLUMN session_uid, + DROP COLUMN sequence_id; + + +-- fill table with options matching unique QB questions inserted above +INSERT INTO lams_qb_option (qb_question_uid, display_order, name, correct, matching_pair, numerical_option, max_mark, accepted_error, feedback) + SELECT q.uid, o.sequence_id, TRIM(o.option_string), o.correct, o.question, o.option_float, o.grade, o.accepted_error, o.feedback + FROM tl_laasse10_question_option AS o + JOIN lams_qb_question AS q + ON o.question_uid = q.tmp_question_id + WHERE o.question_uid IS NOT NULL + ORDER BY o.question_uid, o.sequence_id; + + +-- fill table with units matching unique QB questions inserted above +INSERT INTO lams_qb_question_unit (qb_question_uid, display_order, multiplier, unit) + SELECT q.uid, u.sequence_id, u.multiplier, u.unit + FROM tl_laasse10_assessment_unit AS u + JOIN lams_qb_question AS q + ON u.question_uid = q.tmp_question_id + WHERE u.question_uid IS NOT NULL + ORDER BY u.question_uid, u.sequence_id; + + +-- shift Assessment answer UIDs by offset equal to existing UIDs of MCQ and Assessment answers in lams_qb_tool_answer +SET @max_answer_uid = (SELECT MAX(answer_uid) FROM lams_qb_tool_answer); +UPDATE tl_laasse10_question_result SET uid = uid + @max_answer_uid ORDER BY uid DESC; + +ALTER TABLE tl_laasse10_question_result DROP FOREIGN KEY FK_NEW_1720029621_693580A438BF8DFE; + +-- rewrite references from Assessment options to QB options +UPDATE tl_laasse10_question_result AS sl, tl_laasse10_question_option AS o, lams_qb_tool_question AS tq, lams_qb_option AS qo + SET sl.submitted_option_uid = qo.uid, + sl.assessment_question_uid = tq.tool_question_uid + WHERE o.sequence_id = qo.display_order + AND sl.submitted_option_uid = o.uid + AND qo.qb_question_uid = tq.qb_question_uid + AND o.question_uid = tq.tool_question_uid + AND o.question_uid IS NOT NULL; + +-- prepare for answer inheritance +INSERT INTO lams_qb_tool_answer + SELECT uid, assessment_question_uid, submitted_option_uid FROM tl_laasse10_question_result; + + +-- cleanup +ALTER TABLE lams_qb_question DROP COLUMN tmp_question_id; +ALTER TABLE tl_laasse10_question_result DROP COLUMN assessment_question_uid, + DROP COLUMN submitted_option_uid; + +DROP TABLE tl_laasse10_question_option, + tl_laasse10_assessment_unit, tmp_question, tmp_question_match, tmp_qb_question; + + ----------------------Put all sql statements above here------------------------- -- If there were no errors, commit and restore autocommit to on Index: lams_common/src/java/org/lamsfoundation/lams/qb/model/QbOption.java =================================================================== diff -u -rc87bb47eb670934f10192c08922f83367bc36230 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_common/src/java/org/lamsfoundation/lams/qb/model/QbOption.java (.../QbOption.java) (revision c87bb47eb670934f10192c08922f83367bc36230) +++ lams_common/src/java/org/lamsfoundation/lams/qb/model/QbOption.java (.../QbOption.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -41,7 +41,26 @@ @ManyToOne(optional = false) @JoinColumn(name = "qb_question_uid") private QbQuestion qbQuestion; + + // ********************************************************** + // Properties used only in Assessment + // ********************************************************** + @Column(name = "matching_pair") + private String matchingPair; + + @Column(name = "numerical_option") + private float numericalOption; + + @Column(name = "max_mark") + private float maxMark; + + @Column(name = "accepted_error") + private float acceptedError; + + @Column + private String feedback; + @Override public QbOption clone() { QbOption clone = null; @@ -75,6 +94,10 @@ public Long getUid() { return uid; } + + public void setUid(Long uid) { + this.uid = uid; + } public String getName() { return name; @@ -107,4 +130,44 @@ public void setQbQuestion(QbQuestion question) { this.qbQuestion = question; } + + public String getMatchingPair() { + return matchingPair; + } + + public void setMatchingPair(String matchingPair) { + this.matchingPair = matchingPair; + } + + public float getNumericalOption() { + return numericalOption; + } + + public void setNumericalOption(float numericalOption) { + this.numericalOption = numericalOption; + } + + public float getAcceptedError() { + return acceptedError; + } + + public void setAcceptedError(float acceptedError) { + this.acceptedError = acceptedError; + } + + public float getMaxMark() { + return maxMark; + } + + public void setMaxMark(float maxMark) { + this.maxMark = maxMark; + } + + public String getFeedback() { + return feedback; + } + + public void setFeedback(String feedback) { + this.feedback = feedback; + } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestion.java =================================================================== diff -u -r72c9800d4076fa450caff0943dd4de41399c83e0 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestion.java (.../QbQuestion.java) (revision 72c9800d4076fa450caff0943dd4de41399c83e0) +++ lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestion.java (.../QbQuestion.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -31,7 +31,7 @@ // questions can be of different type // not all tools can produce/consume all question types - public static final int TYPE_MULTIPLE_CHOICE_SINGLE_ANSWER = 1; + public static final int TYPE_MULTIPLE_CHOICE = 1; public static final int TYPE_MATCHING_PAIRS = 2; public static final int TYPE_SHORT_ANSWER = 3; public static final int TYPE_NUMERICAL = 4; @@ -41,7 +41,7 @@ public static final int TYPE_MARK_HEDGING = 8; // primary key - // another candidate is questionId + version, but single uid can fe searched faster + // another candidate is questionId + version, but single uid can be searched faster @Id @Column @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -75,14 +75,66 @@ @Column private String description; - @Column - private Integer mark; + @Column(name = "max_mark") + private Integer maxMark; @Column private String feedback; + @Column(name = "penalty_factor") + private float penaltyFactor; + + @Column(name = "answer_required") + private boolean answerRequired; + + @Column(name = "multiple_answers_allowed") + private boolean multipleAnswersAllowed; + + @Column(name = "incorrect_answer_nullifies_mark") + private boolean incorrectAnswerNullifiesMark; + + @Column(name = "feedback_on_correct") + private String feedbackOnCorrect; + + @Column(name = "feedback_on_partially_correct") + private String feedbackOnPartiallyCorrect; + + @Column(name = "feedback_on_incorrect") + private String feedbackOnIncorrect; + + // only one of shuffle and prefixAnswersWithLetters should be on. Both may be off + @Column + private boolean shuffle; + + @Column(name = "prefix_answers_with_letters") + private boolean prefixAnswersWithLetters; + + @Column(name = "case_sensitive") + private boolean caseSensitive; + + @Column(name = "correct_answer") + private boolean correctAnswer; + + @Column(name = "allow_rich_editor") + private boolean allowRichEditor; + + // only for essay type of question + @Column(name = "max_words_limit") + private int maxWordsLimit; + + // only for essay type of question + @Column(name = "min_words_limit") + private int minWordsLimit; + + // only for hedging maxMark type of question + @Column(name = "hedging_justification_enabled") + private boolean hedgingJustificationEnabled; + @OneToMany(mappedBy = "qbQuestion", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) private List qbOptions = new ArrayList<>(); + + @OneToMany(mappedBy = "qbQuestion", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) + private List units = new ArrayList<>(); // compares if current question data and the other one (probably modified with new data) are the same // it detects if question is the same or should another question/version be created @@ -96,13 +148,14 @@ QbQuestion other = (QbQuestion) o; // options are also checked if they are equal return new EqualsBuilder().append(name, other.name).append(description, other.description) - .append(feedback, other.feedback).append(mark, other.mark) - .append(qbOptions.toArray(), other.getQbOptions().toArray()).isEquals(); + .append(feedback, other.feedback).append(maxMark, other.maxMark) + .append(qbOptions.toArray(), other.getQbOptions().toArray()) + .append(units.toArray(), other.getUnits().toArray()).isEquals(); } @Override public int hashCode() { - return new HashCodeBuilder().append(name).append(description).append(feedback).append(mark).toHashCode(); + return new HashCodeBuilder().append(name).append(description).append(feedback).append(maxMark).toHashCode(); } @Override @@ -122,6 +175,14 @@ optionClone.setQbQuestion(clone); optionsClone.add(optionClone); } + // make a deep copy of units + List unitsClone = new ArrayList<>(units.size()); + clone.setUnits(unitsClone); + for (QbQuestionUnit unit : units) { + QbQuestionUnit unitClone = unit.clone(); + unitClone.setQbQuestion(clone); + unitsClone.add(unitClone); + } return clone; } @@ -130,6 +191,9 @@ for (QbOption option : qbOptions) { option.uid = null; } + for (QbQuestionUnit unit : units) { + unit.uid = null; + } } public Long getUid() { @@ -192,12 +256,12 @@ this.description = description; } - public Integer getMark() { - return mark; + public Integer getMaxMark() { + return maxMark; } - public void setMark(Integer mark) { - this.mark = mark; + public void setMaxMark(Integer maxMark) { + this.maxMark = maxMark; } public String getFeedback() { @@ -207,12 +271,155 @@ public void setFeedback(String feedback) { this.feedback = StringUtils.isBlank(feedback) ? null : feedback.trim(); } + + public float getPenaltyFactor() { + return penaltyFactor; + } + + public void setPenaltyFactor(float penaltyFactor) { + this.penaltyFactor = penaltyFactor; + } + + public boolean isAnswerRequired() { + return answerRequired; + } + + public void setAnswerRequired(boolean answerRequired) { + this.answerRequired = answerRequired; + } + + public boolean isMultipleAnswersAllowed() { + return multipleAnswersAllowed; + } + + public void setMultipleAnswersAllowed(boolean multipleAnswersAllowed) { + this.multipleAnswersAllowed = multipleAnswersAllowed; + } + + public boolean isIncorrectAnswerNullifiesMark() { + return incorrectAnswerNullifiesMark; + } + + public void setIncorrectAnswerNullifiesMark(boolean incorrectAnswerNullifiesMark) { + this.incorrectAnswerNullifiesMark = incorrectAnswerNullifiesMark; + } + + public String getFeedbackOnCorrect() { + return feedbackOnCorrect; + } + + public void setFeedbackOnCorrect(String feedbackOnCorrect) { + this.feedbackOnCorrect = feedbackOnCorrect; + } + + public String getFeedbackOnPartiallyCorrect() { + return feedbackOnPartiallyCorrect; + } + + public void setFeedbackOnPartiallyCorrect(String feedbackOnPartiallyCorrect) { + this.feedbackOnPartiallyCorrect = feedbackOnPartiallyCorrect; + } + + public String getFeedbackOnIncorrect() { + return feedbackOnIncorrect; + } + + public void setFeedbackOnIncorrect(String feedbackOnIncorrect) { + this.feedbackOnIncorrect = feedbackOnIncorrect; + } + + public boolean isShuffle() { + return shuffle; + } + + public void setShuffle(boolean shuffle) { + this.shuffle = shuffle; + } + + public boolean isCaseSensitive() { + return caseSensitive; + } + + public void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + + public boolean getCorrectAnswer() { + return correctAnswer; + } + + public void setCorrectAnswer(boolean correctAnswer) { + this.correctAnswer = correctAnswer; + } + + public boolean isAllowRichEditor() { + return allowRichEditor; + } + + public void setAllowRichEditor(boolean allowRichEditor) { + this.allowRichEditor = allowRichEditor; + } + + /** + * maxWordsLimit set in author. Used only for essay type of questions + */ + public int getMaxWordsLimit() { + return maxWordsLimit; + } + + /** + * @param maxWordsLimit + * set in author. Used only for essay type of questions + */ + public void setMaxWordsLimit(int maxWordsLimit) { + this.maxWordsLimit = maxWordsLimit; + } + + /** + * minWordsLimit set in author. Used only for essay type of questions + */ + public int getMinWordsLimit() { + return minWordsLimit; + } + + /** + * @param minWordsLimit + * set in author. Used only for essay type of questions + */ + public void setMinWordsLimit(int minWordsLimit) { + this.minWordsLimit = minWordsLimit; + } + + public boolean isHedgingJustificationEnabled() { + return hedgingJustificationEnabled; + } + + public void setHedgingJustificationEnabled(boolean hedgingJustificationEnabled) { + this.hedgingJustificationEnabled = hedgingJustificationEnabled; + } + + public boolean isPrefixAnswersWithLetters() { + return prefixAnswersWithLetters; + } + + public void setPrefixAnswersWithLetters(boolean prefixAnswersWithLetters) { + this.prefixAnswersWithLetters = prefixAnswersWithLetters; + } + public List getQbOptions() { return qbOptions; } public void setQbOptions(List options) { this.qbOptions = options; } + + public List getUnits() { + return units; + } + + public void setUnits(List units) { + this.units = units; + } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestionUnit.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestionUnit.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestionUnit.java (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -0,0 +1,111 @@ +package org.lamsfoundation.lams.qb.model; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; + +/** + * Unit for a numerical type of questions in Question Bank. + * + * @author Andrey Balan + */ +@Entity +@Table(name = "lams_qb_question_unit") +public class QbQuestionUnit implements Serializable, Cloneable, Comparable { + private static final long serialVersionUID = -6772525485898794744L; + + @Id + @Column + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long uid; + + @Column + private String name; + + @Column + private float multiplier = 0; + + @Column(name = "display_order") + private int displayOrder = 1; + + @ManyToOne(optional = false) + @JoinColumn(name = "qb_question_uid") + private QbQuestion qbQuestion; + + @Override + public QbQuestionUnit clone() { + QbQuestionUnit clone = null; + try { + clone = (QbQuestionUnit) super.clone(); + clone.qbQuestion = null; + } catch (CloneNotSupportedException e) { + // it should never happen + e.printStackTrace(); + } + return clone; + } + + @Override + public boolean equals(Object o) { + QbQuestionUnit other = (QbQuestionUnit) o; + return new EqualsBuilder().append(this.name, other.name).append(this.multiplier, other.multiplier) + .append(this.displayOrder, other.displayOrder).isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder().append(this.name).append(this.multiplier).toHashCode(); + } + + @Override + public int compareTo(QbQuestionUnit o) { + return Integer.compare(this.displayOrder, o.displayOrder); + } + + public Long getUid() { + return uid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public float getMultiplier() { + return multiplier; + } + + public void setMultiplier(float multiplier) { + this.multiplier = multiplier; + } + + public int getDisplayOrder() { + return displayOrder; + } + + public void setDisplayOrder(int displayOrder) { + this.displayOrder = displayOrder; + } + + public QbQuestion getQbQuestion() { + return qbQuestion; + } + + public void setQbQuestion(QbQuestion question) { + this.qbQuestion = question; + } + +} \ No newline at end of file Index: lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -ra0aa698e675b0a2eb89e51cf645156ade0f93d64 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision a0aa698e675b0a2eb89e51cf645156ade0f93d64) +++ lams_tool_assessment/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -348,5 +348,8 @@ label.do.you.want.to.delete.answer =Are you sure you want to delete? label.settings =Settings label.required.field =Required field +message.qb.modified.update =The question in Question Bank will be updated +message.qb.modified.version =A new version of the question will be created in Question Bank +message.qb.modified.new =A new question will be created in Question Bank #======= End labels: Exported 337 labels for en AU ===== Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== diff -u -r67d7232f087b9f5c72ff41f7bbebe29cff81e099 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 67d7232f087b9f5c72ff41f7bbebe29cff81e099) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -38,23 +38,6 @@ public static final String EXPORT_QUESTIONS_FILENAME = "questions.xml"; - // question type; - public static final short QUESTION_TYPE_MULTIPLE_CHOICE = 1; - - public static final short QUESTION_TYPE_MATCHING_PAIRS = 2; - - public static final short QUESTION_TYPE_SHORT_ANSWER = 3; - - public static final short QUESTION_TYPE_NUMERICAL = 4; - - public static final short QUESTION_TYPE_TRUE_FALSE = 5; - - public static final short QUESTION_TYPE_ESSAY = 6; - - public static final short QUESTION_TYPE_ORDERING = 7; - - public static final short QUESTION_TYPE_MARK_HEDGING = 8; - // for parameters' name public static final String PARAM_WAITING_MESSAGE_KEY = "waitingMessageKey"; @@ -69,7 +52,7 @@ public static final String PARAM_QUESTION_INDEX = "questionIndex"; - public static final String PARAM_QUESTION_SEQUENCE_ID = "questionSequenceId"; + public static final String PARAM_QUESTION_DISPLAY_ORDER = "questionDisplayOrder"; public static final String PARAM_QUESTION_REFERENCE_INDEX = "questionReferenceIndex"; @@ -82,6 +65,8 @@ 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_SESSION_ID = "sessionId"; @@ -108,23 +93,23 @@ public static final String ATTR_OPTION_COUNT = "optionCount"; - public static final String ATTR_OPTION_STRING_PREFIX = "optionString"; + public static final String ATTR_OPTION_NAME_PREFIX = "optionName"; - public static final String ATTR_OPTION_GRADE_PREFIX = "optionGrade"; + public static final String ATTR_OPTION_MAX_MARK_PREFIX = "optionMaxMark"; public static final String ATTR_OPTION_CORRECT = "optionCorrect"; - public static final String ATTR_OPTION_FLOAT_PREFIX = "optionFloat"; + public static final String ATTR_NUMERICAL_OPTION_PREFIX = "numericalOption"; public static final String ATTR_OPTION_ACCEPTED_ERROR_PREFIX = "optionAcceptedError"; public static final String ATTR_OPTION_FEEDBACK_PREFIX = "optionFeedback"; public static final String ATTR_OPTION_UID_PREFIX = "optionUid"; - public static final String ATTR_OPTION_SEQUENCE_ID_PREFIX = "optionSequenceId"; + public static final String ATTR_OPTION_DISPLAY_ORDER_PREFIX = "optionDisplayOrder"; - public static final String ATTR_OPTION_QUESTION_PREFIX = "optionQuestion"; + public static final String ATTR_MATCHING_PAIR_PREFIX = "matchingPair"; public static final String ATTR_QUESTION_PREFIX = "question"; @@ -144,7 +129,7 @@ public static final String ATTR_UNIT_LIST = "unitList"; - public static final String ATTR_QUESTION_REFERENCES_GRADES = "referenceGrades"; + public static final String ATTR_QUESTION_REFERENCES_MAX_MARKS = "referenceMaxMarks"; public static final String ATTR_HAS_EDIT_RIGHT = "hasEditRight"; @@ -153,12 +138,14 @@ public static final String ATTR_SECONDS_LEFT = "secondsLeft"; public static final String ATTR_UNIT_COUNT = "unitCount"; + + public static final String ATTR_UNIT_UID_PREFIX = "unitUid"; - public static final String ATTR_UNIT_UNIT_PREFIX = "unitUnit"; + public static final String ATTR_UNIT_NAME_PREFIX = "unitName"; public static final String ATTR_UNIT_MULTIPLIER_PREFIX = "unitMultiplier"; - public static final String ATTR_UNIT_SEQUENCE_ID_PREFIX = "unitSequenceId"; + public static final String ATTR_UNIT_DISPLAY_ORDER_PREFIX = "unitDisplayOrder"; public static final String ATTR_OVERALL_FEEDBACK_LIST = "overallFeedbackList"; @@ -251,15 +238,6 @@ public static final String OUTPUT_NAME_FIRST_SCORE = "first.score"; public static final String OUTPUT_NAME_AVERAGE_SCORE = "average.score"; - // error message keys - public static final String ERROR_MSG_QUESTION_NAME_BLANK = "error.question.name.blank"; - - public static final String ERROR_MSG_QUESTION_TEXT_BLANK = "error.question.text.blank"; - - public static final String ERROR_MSG_DEFAULT_GRADE_WRONG_FORMAT = "error.default.grade.wrong.format"; - - public static final String ERROR_MSG_PENALTY_FACTOR_WRONG_FORMAT = "error.penalty.factor.wrong.format"; - public static final String ATTR_USER_UID = "userUid"; public static final String DEFUALT_PROTOCOL_REFIX = "http://"; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentQuestionResultDAO.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentQuestionResultDAO.java (.../AssessmentQuestionResultDAO.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentQuestionResultDAO.java (.../AssessmentQuestionResultDAO.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -43,9 +43,9 @@ * * @param assessmentUid * @param userId - * @param questionSequenceId + * @param questionDisplayOrder * @return */ - Float getQuestionResultMark(Long assessmentUid, Long userId, int questionSequenceId); + Float getQuestionResultMark(Long assessmentUid, Long userId, int questionDisplayOrder); } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentQuestionResultDAOHibernate.java =================================================================== diff -u -rdcdc1487609bd4f00afaa93c09272d84ab0cd325 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentQuestionResultDAOHibernate.java (.../AssessmentQuestionResultDAOHibernate.java) (revision dcdc1487609bd4f00afaa93c09272d84ab0cd325) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentQuestionResultDAOHibernate.java (.../AssessmentQuestionResultDAOHibernate.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -48,7 +48,7 @@ private static final String GET_ANSWER_MARK = "SELECT q.mark FROM " + AssessmentQuestionResult.class.getName() + " AS q, " + AssessmentResult.class.getName() + " AS r " - + " WHERE q.assessmentResult.uid = r.uid AND r.assessment.uid = :assessmentUid AND (r.finishDate != null) AND r.user.userId =:userId AND q.assessmentQuestion.sequenceId =:questionSequenceId ORDER BY r.startDate DESC"; + + " WHERE q.assessmentResult.uid = r.uid AND r.assessment.uid = :assessmentUid AND (r.finishDate != null) AND r.user.userId =:userId AND q.assessmentQuestion.displayOrder =:questionDisplayOrder ORDER BY r.startDate DESC"; @Override public int getNumberWrongAnswersDoneBefore(Long assessmentUid, Long userId, Long questionUid) { @@ -77,11 +77,11 @@ } @Override - public Float getQuestionResultMark(final Long assessmentUid, final Long userId, final int questionSequenceId) { + public Float getQuestionResultMark(final Long assessmentUid, final Long userId, final int questionDisplayOrder) { Query q = getSession().createQuery(GET_ANSWER_MARK, Number.class); q.setParameter("assessmentUid", assessmentUid); q.setParameter("userId", userId); - q.setParameter("questionSequenceId", questionSequenceId); + q.setParameter("questionDisplayOrder", questionDisplayOrder); q.setMaxResults(1); Number result = q.uniqueResult(); return result != null ? result.floatValue() : null; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentSessionDAOHibernate.java =================================================================== diff -u -rdcdc1487609bd4f00afaa93c09272d84ab0cd325 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentSessionDAOHibernate.java (.../AssessmentSessionDAOHibernate.java) (revision dcdc1487609bd4f00afaa93c09272d84ab0cd325) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentSessionDAOHibernate.java (.../AssessmentSessionDAOHibernate.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -26,7 +26,6 @@ import java.util.List; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; -import org.lamsfoundation.lams.gradebook.GradebookUserActivity; import org.lamsfoundation.lams.tool.assessment.dao.AssessmentSessionDAO; import org.lamsfoundation.lams.tool.assessment.model.AssessmentSession; import org.springframework.stereotype.Repository; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/OptionDTO.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/OptionDTO.java (.../OptionDTO.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/OptionDTO.java (.../OptionDTO.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -1,25 +1,24 @@ package org.lamsfoundation.lams.tool.assessment.dto; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; -import org.lamsfoundation.lams.tool.assessment.model.Sequencable; +import org.lamsfoundation.lams.qb.model.QbOption; -public class OptionDTO implements Sequencable{ +public class OptionDTO implements Comparable { - // ============= immutable properties copied from AssessmentQuestion question ============= + // ============= immutable properties copied from AssessmentQuestion ============= private Long uid; - private Integer sequenceId; + private Integer displayOrder; - private String question; + private String matchingPair; - private String optionString; + private String name; - private float optionFloat; + private float numericalOption; private float acceptedError; - private float grade; + private float maxMark; private boolean correct; @@ -31,53 +30,62 @@ private boolean answerBoolean; - public OptionDTO(AssessmentQuestionOption option) { - this.uid = option.getUid(); - this.sequenceId = option.getSequenceId(); - this.question = option.getQuestion(); - this.optionString = option.getOptionString(); - this.optionFloat = option.getOptionFloat(); - this.acceptedError = option.getAcceptedError(); - this.grade = option.getGrade(); - this.correct = option.isCorrect(); - this.feedback = option.getFeedback(); + private float percentage; + + private String matchingPairEscaped; + + private String nameEscaped; + + public OptionDTO(QbOption qbOption) { + this.uid = qbOption.getUid(); + this.displayOrder = qbOption.getDisplayOrder(); + this.matchingPair = qbOption.getMatchingPair(); + this.name = qbOption.getName(); + this.numericalOption = qbOption.getNumericalOption(); + this.acceptedError = qbOption.getAcceptedError(); + this.maxMark = qbOption.getMaxMark(); + this.correct = qbOption.isCorrect(); + this.feedback = qbOption.getFeedback(); } + @Override + public int compareTo(OptionDTO o) { + return Integer.compare(this.displayOrder, o.displayOrder); + } + public Long getUid() { return uid; } public void setUid(Long uuid) { uid = uuid; } - @Override - public int getSequenceId() { - return sequenceId; + public int getDisplayOrder() { + return displayOrder; } - @Override - public void setSequenceId(int sequenceId) { - this.sequenceId = sequenceId; + public void setDisplayOrder(int displayOrder) { + this.displayOrder = displayOrder; } - public String getQuestion() { - return question; + public String getMatchingPair() { + return matchingPair; } - public void setQuestion(String question) { - this.question = question; + public void setMatchingPair(String matchingPair) { + this.matchingPair = matchingPair; } - public String getOptionString() { - return optionString; + public String getName() { + return name; } - public void setOptionString(String optionString) { - this.optionString = optionString; + public void setName(String name) { + this.name = name; } - public float getOptionFloat() { - return optionFloat; + public float getNumericalOption() { + return numericalOption; } - public void setOptionFloat(float optionFloat) { - this.optionFloat = optionFloat; + public void setNumericalOption(float numericalOption) { + this.numericalOption = numericalOption; } public float getAcceptedError() { @@ -87,11 +95,11 @@ this.acceptedError = acceptedError; } - public float getGrade() { - return grade; + public float getMaxMark() { + return maxMark; } - public void setGrade(float grade) { - this.grade = grade; + public void setMaxMark(float maxMark) { + this.maxMark = maxMark; } public boolean isCorrect() { @@ -129,4 +137,28 @@ public String formatPrefixLetter(int index) { return new String(Character.toChars(97 + index)) + ")"; } + + public float getPercentage() { + return percentage; + } + + public void setPercentage(float percentage) { + this.percentage = percentage; + } + + public String getMatchingPairEscaped() { + return matchingPairEscaped; + } + + public void setMatchingPairEscaped(String matchingPairEscaped) { + this.matchingPairEscaped = matchingPairEscaped; + } + + public String getNameEscaped() { + return nameEscaped; + } + + public void setNameEscaped(String nameEscaped) { + this.nameEscaped = nameEscaped; + } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionDTO.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionDTO.java (.../QuestionDTO.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionDTO.java (.../QuestionDTO.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -4,33 +4,32 @@ import java.util.Set; import java.util.TreeSet; +import org.lamsfoundation.lams.qb.model.QbOption; +import org.lamsfoundation.lams.qb.model.QbQuestionUnit; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentUnit; -import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; -public class QuestionDTO { +public class QuestionDTO implements Comparable{ // ============= immutable properties copied from AssessmentQuestion question ============= private Long uid; + + private Long qbQuestionUid; - private short type; + private Integer type; private String title; private String question; - private int sequenceId; + private int displayOrder; - private int defaultGrade; + private int maxMark; private float penaltyFactor; private boolean answerRequired; - private String generalFeedback; - private String feedback; private boolean multipleAnswersAllowed; @@ -53,7 +52,7 @@ private boolean allowRichEditor; - private Set units; + private List units; private int maxWordsLimit; @@ -66,6 +65,8 @@ private boolean groupsAnswersDisclosed; // ============= variable properties ============= + + private String titleEscaped; private String answerString; @@ -77,13 +78,11 @@ private boolean responseSubmitted; - private int grade; - private float mark; private float penalty; - private float answerTotalGrade; + private float optionMaxMark; private Set optionDtos; @@ -95,37 +94,41 @@ public QuestionDTO(AssessmentQuestion question) { this.uid = question.getUid(); - this.type = question.getType(); - this.title = question.getTitle(); - this.question = question.getQuestion(); - this.sequenceId = question.getSequenceId(); - this.defaultGrade = question.getDefaultGrade(); - this.penaltyFactor = question.getPenaltyFactor(); - this.answerRequired = question.isAnswerRequired(); - this.generalFeedback = question.getGeneralFeedback(); - this.feedback = question.getFeedback(); - this.multipleAnswersAllowed = question.isMultipleAnswersAllowed(); - this.incorrectAnswerNullifiesMark = question.isIncorrectAnswerNullifiesMark(); - this.feedbackOnCorrect = question.getFeedbackOnCorrect(); - this.feedbackOnPartiallyCorrect = question.getFeedbackOnPartiallyCorrect(); - this.feedbackOnIncorrect = question.getFeedbackOnIncorrect(); - this.shuffle = question.isShuffle(); - this.prefixAnswersWithLetters = question.isPrefixAnswersWithLetters(); - this.caseSensitive = question.isCaseSensitive(); - this.correctAnswer = question.getCorrectAnswer(); - this.allowRichEditor = question.isAllowRichEditor(); - this.units = question.getUnits(); - this.maxWordsLimit = question.getMaxWordsLimit(); - this.minWordsLimit = question.getMinWordsLimit(); - this.hedgingJustificationEnabled = question.isHedgingJustificationEnabled(); + this.type = question.getQbQuestion().getType(); + this.title = question.getQbQuestion().getName(); + this.question = question.getQbQuestion().getDescription(); + this.displayOrder = question.getDisplayOrder(); + this.maxMark = question.getQbQuestion().getMaxMark(); + this.penaltyFactor = question.getQbQuestion().getPenaltyFactor(); + this.answerRequired = question.getQbQuestion().isAnswerRequired(); + this.feedback = question.getQbQuestion().getFeedback(); + this.multipleAnswersAllowed = question.getQbQuestion().isMultipleAnswersAllowed(); + this.incorrectAnswerNullifiesMark = question.getQbQuestion().isIncorrectAnswerNullifiesMark(); + this.feedbackOnCorrect = question.getQbQuestion().getFeedbackOnCorrect(); + this.feedbackOnPartiallyCorrect = question.getQbQuestion().getFeedbackOnPartiallyCorrect(); + this.feedbackOnIncorrect = question.getQbQuestion().getFeedbackOnIncorrect(); + this.shuffle = question.getQbQuestion().isShuffle(); + this.prefixAnswersWithLetters = question.getQbQuestion().isPrefixAnswersWithLetters(); + this.caseSensitive = question.getQbQuestion().isCaseSensitive(); + this.correctAnswer = question.getQbQuestion().getCorrectAnswer(); + this.allowRichEditor = question.getQbQuestion().isAllowRichEditor(); + this.units = question.getQbQuestion().getUnits(); + this.maxWordsLimit = question.getQbQuestion().getMaxWordsLimit(); + this.minWordsLimit = question.getQbQuestion().getMinWordsLimit(); + this.hedgingJustificationEnabled = question.getQbQuestion().isHedgingJustificationEnabled(); this.correctAnswersDisclosed = question.isCorrectAnswersDisclosed(); this.groupsAnswersDisclosed = question.isGroupsAnswersDisclosed(); - optionDtos = new TreeSet(new SequencableComparator()); - for (AssessmentQuestionOption option : question.getOptions()) { + optionDtos = new TreeSet<>(); + for (QbOption option : question.getQbQuestion().getQbOptions()) { optionDtos.add(new OptionDTO(option)); } } + + @Override + public int compareTo(QuestionDTO anotherQuestion) { + return displayOrder - anotherQuestion.getDisplayOrder(); + } public Long getUid() { return uid; @@ -134,12 +137,20 @@ public void setUid(Long userID) { this.uid = userID; } + + public Long getQbQuestionUid() { + return qbQuestionUid; + } - public short getType() { + public void setQbQuestionUid(Long qaQuestionId) { + this.qbQuestionUid = qaQuestionId; + } + + public Integer getType() { return type; } - public void setType(short type) { + public void setType(Integer type) { this.type = type; } @@ -159,20 +170,20 @@ this.question = question; } - public int getSequenceId() { - return sequenceId; + public int getDisplayOrder() { + return displayOrder; } - public void setSequenceId(int sequenceId) { - this.sequenceId = sequenceId; + public void setDisplayOrder(int displayOrder) { + this.displayOrder = displayOrder; } - public int getDefaultGrade() { - return defaultGrade; + public int getMaxMark() { + return maxMark; } - public void setDefaultGrade(int defaultGrade) { - this.defaultGrade = defaultGrade; + public void setMaxMark(int maxMark) { + this.maxMark = maxMark; } public float getPenaltyFactor() { @@ -191,14 +202,6 @@ this.answerRequired = answerRequired; } - public String getGeneralFeedback() { - return generalFeedback; - } - - public void setGeneralFeedback(String generalFeedback) { - this.generalFeedback = generalFeedback; - } - public String getFeedback() { return feedback; } @@ -279,11 +282,11 @@ this.allowRichEditor = allowRichEditor; } - public Set getUnits() { + public List getUnits() { return units; } - public void setUnits(Set units) { + public void setUnits(List units) { this.units = units; } @@ -352,14 +355,6 @@ return questionFeedback; } - public int getGrade() { - return grade; - } - - public void setGrade(int grade) { - this.grade = grade; - } - public Float getMark() { return mark; } @@ -408,12 +403,12 @@ this.responseSubmitted = responseSubmitted; } - public float getAnswerTotalGrade() { - return answerTotalGrade; + public float getOptionMaxMark() { + return optionMaxMark; } - public void setAnswerTotalGrade(float answerTotalGrade) { - this.answerTotalGrade = answerTotalGrade; + public void setOptionMaxMark(float optionMaxMark) { + this.optionMaxMark = optionMaxMark; } public Set getOptionDtos() { @@ -431,4 +426,12 @@ public void setPrefixAnswersWithLetters(boolean prefixAnswersWithLetters) { this.prefixAnswersWithLetters = prefixAnswersWithLetters; } + + public String getTitleEscaped() { + return titleEscaped; + } + + public void setTitleEscaped(String titleEscaped) { + this.titleEscaped = titleEscaped; + } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionSummary.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionSummary.java (.../QuestionSummary.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionSummary.java (.../QuestionSummary.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -47,17 +47,21 @@ */ public class QuestionSummary { - private AssessmentQuestion question; + private QuestionDTO questionDto; private float averageMark; private List> questionResultsPerSession; + + public QuestionSummary(AssessmentQuestion question) { + this.questionDto = new QuestionDTO(question); + } - public AssessmentQuestion getQuestion() { - return question; + public QuestionDTO getQuestionDto() { + return questionDto; } - public void setQuestion(AssessmentQuestion question) { - this.question = question; + public void setQuestionDto(QuestionDTO question) { + this.questionDto = question; } public float getAverageMark() { Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/TblAssessmentQuestionDTO.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/TblAssessmentQuestionDTO.java (.../TblAssessmentQuestionDTO.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/TblAssessmentQuestionDTO.java (.../TblAssessmentQuestionDTO.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -2,26 +2,14 @@ import java.util.List; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; - /** * TBL modification of Assessment tool's QuestionSummary. */ public class TblAssessmentQuestionDTO { - private AssessmentQuestion question; private List sessionQuestionResults; - private String questionTypeLabel; private String correctAnswer; - public AssessmentQuestion getQuestion() { - return question; - } - - public void setQuestion(AssessmentQuestion question) { - this.question = question; - } - public List getSessionQuestionResults() { return sessionQuestionResults; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/UserSummaryItem.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/UserSummaryItem.java (.../UserSummaryItem.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/UserSummaryItem.java (.../UserSummaryItem.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -47,19 +47,19 @@ */ public class UserSummaryItem { - private AssessmentQuestion question; + private QuestionDTO questionDto; private List questionResults; public UserSummaryItem(AssessmentQuestion question) { - this.question = question; + this.questionDto = new QuestionDTO(question); } - public AssessmentQuestion getQuestion() { - return question; + public QuestionDTO getQuestionDto() { + return questionDto; } - public void setQuestion(AssessmentQuestion question) { - this.question = question; + public void setQuestionDto(QuestionDTO question) { + this.questionDto = question; } public List getQuestionResults() { Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java =================================================================== diff -u -r1ee503e3d0e0228ea8a45025fddf15d9623c0377 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java (.../Assessment.java) (revision 1ee503e3d0e0228ea8a45025fddf15d9623c0377) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java (.../Assessment.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -150,10 +150,9 @@ private AssessmentUser createdBy; // Question bank questions - @OneToMany(cascade = CascadeType.ALL) @JoinColumn(name = "assessment_uid") @OrderBy("sequence_id ASC") - private Set questions = new TreeSet<>(new SequencableComparator()); + private Set questions = new TreeSet<>(); // assessment questions references that form question list @OneToMany(cascade = CascadeType.ALL) @@ -192,7 +191,7 @@ // clone questions if (questions != null) { Iterator iter = questions.iterator(); - TreeSet set = new TreeSet<>(new SequencableComparator()); + TreeSet set = new TreeSet<>(); while (iter.hasNext()) { AssessmentQuestion question = iter.next(); AssessmentQuestion newQuestion = (AssessmentQuestion) question.clone(); @@ -213,7 +212,7 @@ // update questionReferences with new cloned question if (newQuestionReference.getQuestion() != null) { for (AssessmentQuestion newQuestion : assessment.questions) { - if (newQuestion.getSequenceId() == newQuestionReference.getQuestion().getSequenceId()) { + if (newQuestion.getDisplayOrder() == newQuestionReference.getQuestion().getDisplayOrder()) { newQuestionReference.setQuestion(newQuestion); break; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestion.java =================================================================== diff -u -rdcdc1487609bd4f00afaa93c09272d84ab0cd325 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestion.java (.../AssessmentQuestion.java) (revision dcdc1487609bd4f00afaa93c09272d84ab0cd325) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestion.java (.../AssessmentQuestion.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -23,29 +23,21 @@ package org.lamsfoundation.lams.tool.assessment.model; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; +import java.io.Serializable; -import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; +import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.qb.model.QbToolQuestion; +import org.lamsfoundation.lams.qb.service.IQbService; import org.lamsfoundation.lams.tool.assessment.dto.QuestionDTO; -import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; /** * Assessment Question @@ -54,144 +46,35 @@ */ @Entity @Table(name = "tl_laasse10_assessment_question") -public class AssessmentQuestion implements Cloneable, Sequencable, Comparable { +//in this entity's table primary key is "uid", but it references "tool_question_uid" in lams_qb_tool_question +@PrimaryKeyJoinColumn(name = "uid") +public class AssessmentQuestion extends QbToolQuestion + implements Serializable, Cloneable, Comparable { + private static final long serialVersionUID = -7767327140430305575L; private static final Logger log = Logger.getLogger(AssessmentQuestion.class); - @Id - @Column - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long uid; - - @Column(name = "question_type") - private short type; - - @Column - private String title; - - @Column - private String question; - /** * It stores sha1(question) value that allows us to search for the AssessmentQuestions with the same question */ @Column(name = "question_hash") private String questionHash; - @Column(name = "sequence_id") - private int sequenceId; - - /** - * Default grade set in author. - */ - @Column(name = "default_grade") - private int defaultGrade; - - @Column(name = "penalty_factor") - private float penaltyFactor; - - @Column(name = "answer_required") - private boolean answerRequired; - - @Column(name = "general_feedback") - private String generalFeedback; - - @Column - private String feedback; - - @Column(name = "multiple_answers_allowed") - private boolean multipleAnswersAllowed; - - @Column(name = "incorrect_answer_nullifies_mark") - private boolean incorrectAnswerNullifiesMark; - - @Column(name = "feedback_on_correct") - private String feedbackOnCorrect; - - @Column(name = "feedback_on_partially_correct") - private String feedbackOnPartiallyCorrect; - - @Column(name = "feedback_on_incorrect") - private String feedbackOnIncorrect; - - // only one of shuffle and prefixAnswersWithLetters should be on. Both may be off - @Column - private boolean shuffle; - - @Column(name = "prefix_answers_with_letters") - private boolean prefixAnswersWithLetters; - - @Column(name = "case_sensitive") - private boolean caseSensitive; - - @Column(name = "correct_answer") - private boolean correctAnswer; - - @Column(name = "allow_rich_editor") - private boolean allowRichEditor; - - // only for essay type of question - @Column(name = "max_words_limit") - private int maxWordsLimit; - - // only for essay type of question - @Column(name = "min_words_limit") - private int minWordsLimit; - - // only for hedging mark type of question - @Column(name = "hedging_justification_enabled") - private boolean hedgingJustificationEnabled; - @Column(name = "correct_answers_disclosed") private boolean correctAnswersDisclosed; @Column(name = "groups_answers_disclosed") private boolean groupsAnswersDisclosed; - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinColumn(name = "question_uid") - @OrderBy("sequence_id ASC") - private Set options = new TreeSet<>(new SequencableComparator()); - - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinColumn(name = "question_uid") - @OrderBy("sequence_id ASC") - private Set units = new TreeSet<>(new SequencableComparator()); - - // *************** NON Persist Fields used in monitoring ******************** + // *************** NON Persistent Fields ******************** @Transient - private String titleEscaped; + private int qbQuestionModified = IQbService.QUESTION_MODIFIED_NONE; @Override public Object clone() { AssessmentQuestion obj = null; try { obj = (AssessmentQuestion) super.clone(); obj.setUid(null); - - // clone options - if (options != null) { - Iterator iter = options.iterator(); - Set set = new TreeSet<>(new SequencableComparator()); - while (iter.hasNext()) { - AssessmentQuestionOption answerOption = iter.next(); - AssessmentQuestionOption newAnswerOption = (AssessmentQuestionOption) answerOption.clone(); - set.add(newAnswerOption); - } - obj.options = set; - } - - // clone units - if (units != null) { - Iterator iter = units.iterator(); - Set set = new TreeSet<>(new SequencableComparator()); - while (iter.hasNext()) { - AssessmentUnit unit = iter.next(); - AssessmentUnit newUnit = (AssessmentUnit) unit.clone(); - set.add(newUnit); - } - obj.units = set; - } - } catch (CloneNotSupportedException e) { log.error("When clone " + AssessmentQuestion.class + " failed"); } @@ -211,12 +94,12 @@ final AssessmentQuestion genericEntity = (AssessmentQuestion) o; return new EqualsBuilder().append(this.getUid(), genericEntity.getUid()) - .append(this.getSequenceId(), genericEntity.getSequenceId()).isEquals(); + .append(this.getDisplayOrder(), genericEntity.getDisplayOrder()).isEquals(); } @Override public int compareTo(AssessmentQuestion anotherQuestion) { - return sequenceId - anotherQuestion.getSequenceId(); + return displayOrder - anotherQuestion.getDisplayOrder(); } @Override @@ -226,7 +109,7 @@ @Override public int hashCode() { - return new HashCodeBuilder().append(getUid()).append(getSequenceId()).toHashCode(); + return new HashCodeBuilder().append(getUid()).append(getDisplayOrder()).toHashCode(); } public QuestionDTO getQuestionDTO() { @@ -235,6 +118,10 @@ return questionDTO; } + public Integer getType() { + return getQbQuestion().getType(); + } + // ********************************************************** // Get/Set methods // ********************************************************** @@ -246,30 +133,6 @@ this.uid = userID; } - public short getType() { - return type; - } - - public void setType(short type) { - this.type = type; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getQuestion() { - return question; - } - - public void setQuestion(String question) { - this.question = question; - } - /** * Returns sha1(question) value that allows us to search for the AssessmentQuestions with the same question */ @@ -281,214 +144,6 @@ this.questionHash = questionHash; } - /** - * Returns image sequence number. - * - * @return image sequence number - */ - @Override - public int getSequenceId() { - return sequenceId; - } - - /** - * Sets image sequence number. - * - * @param sequenceId - * image sequence number - */ - @Override - public void setSequenceId(int sequenceId) { - this.sequenceId = sequenceId; - } - - /** - * Default grade set in author. To be used only in author - */ - public int getDefaultGrade() { - return defaultGrade; - } - - /** - * @param defaultGrade - * Default grade set in author. To be used only in author - */ - public void setDefaultGrade(int defaultGrade) { - this.defaultGrade = defaultGrade; - } - - public float getPenaltyFactor() { - return penaltyFactor; - } - - public void setPenaltyFactor(float penaltyFactor) { - this.penaltyFactor = penaltyFactor; - } - - public boolean isAnswerRequired() { - return answerRequired; - } - - public void setAnswerRequired(boolean answerRequired) { - this.answerRequired = answerRequired; - } - - public String getGeneralFeedback() { - return generalFeedback; - } - - public void setGeneralFeedback(String generalFeedback) { - this.generalFeedback = generalFeedback; - } - - public String getFeedback() { - return feedback; - } - - public void setFeedback(String feedback) { - this.feedback = feedback; - } - - public boolean isMultipleAnswersAllowed() { - return multipleAnswersAllowed; - } - - public void setMultipleAnswersAllowed(boolean multipleAnswersAllowed) { - this.multipleAnswersAllowed = multipleAnswersAllowed; - } - - public boolean isIncorrectAnswerNullifiesMark() { - return incorrectAnswerNullifiesMark; - } - - public void setIncorrectAnswerNullifiesMark(boolean incorrectAnswerNullifiesMark) { - this.incorrectAnswerNullifiesMark = incorrectAnswerNullifiesMark; - } - - public String getFeedbackOnCorrect() { - return feedbackOnCorrect; - } - - public void setFeedbackOnCorrect(String feedbackOnCorrect) { - this.feedbackOnCorrect = feedbackOnCorrect; - } - - public String getFeedbackOnPartiallyCorrect() { - return feedbackOnPartiallyCorrect; - } - - public void setFeedbackOnPartiallyCorrect(String feedbackOnPartiallyCorrect) { - this.feedbackOnPartiallyCorrect = feedbackOnPartiallyCorrect; - } - - public String getFeedbackOnIncorrect() { - return feedbackOnIncorrect; - } - - public void setFeedbackOnIncorrect(String feedbackOnIncorrect) { - this.feedbackOnIncorrect = feedbackOnIncorrect; - } - - public boolean isShuffle() { - return shuffle; - } - - public void setShuffle(boolean shuffle) { - this.shuffle = shuffle; - } - - public boolean isCaseSensitive() { - return caseSensitive; - } - - public void setCaseSensitive(boolean caseSensitive) { - this.caseSensitive = caseSensitive; - } - - public boolean getCorrectAnswer() { - return correctAnswer; - } - - public void setCorrectAnswer(boolean correctAnswer) { - this.correctAnswer = correctAnswer; - } - - public boolean isAllowRichEditor() { - return allowRichEditor; - } - - public void setAllowRichEditor(boolean allowRichEditor) { - this.allowRichEditor = allowRichEditor; - } - - /** - * @return a set of options to this AssessmentQuestion. - */ - public Set getOptions() { - return options; - } - - /** - * @param options - * options to set. - */ - public void setOptions(Set options) { - this.options = options; - } - - /** - * @return a set of units to this AssessmentQuestion. - */ - public Set getUnits() { - return units; - } - - /** - * @param options - * units to set. - */ - public void setUnits(Set units) { - this.units = units; - } - - /** - * maxWordsLimit set in author. Used only for essay type of questions - */ - public int getMaxWordsLimit() { - return maxWordsLimit; - } - - /** - * @param maxWordsLimit - * set in author. Used only for essay type of questions - */ - public void setMaxWordsLimit(int maxWordsLimit) { - this.maxWordsLimit = maxWordsLimit; - } - - /** - * minWordsLimit set in author. Used only for essay type of questions - */ - public int getMinWordsLimit() { - return minWordsLimit; - } - - /** - * @param minWordsLimit - * set in author. Used only for essay type of questions - */ - public void setMinWordsLimit(int minWordsLimit) { - this.minWordsLimit = minWordsLimit; - } - - public boolean isHedgingJustificationEnabled() { - return hedgingJustificationEnabled; - } - - public void setHedgingJustificationEnabled(boolean hedgingJustificationEnabled) { - this.hedgingJustificationEnabled = hedgingJustificationEnabled; - } - public boolean isCorrectAnswersDisclosed() { return correctAnswersDisclosed; } @@ -505,21 +160,13 @@ this.groupsAnswersDisclosed = groupsAnswersDisclosed; } - public boolean isPrefixAnswersWithLetters() { - return prefixAnswersWithLetters; - } - - public void setPrefixAnswersWithLetters(boolean prefixAnswersWithLetters) { - this.prefixAnswersWithLetters = prefixAnswersWithLetters; - } - // *************** NON Persist Fields used in monitoring ******************** - - public String getTitleEscaped() { - return titleEscaped; + + public int getQbQuestionModified() { + return qbQuestionModified; } - public void setTitleEscaped(String titleEscaped) { - this.titleEscaped = titleEscaped; + public void setQbQuestionModified(int qbQuestionModified) { + this.qbQuestionModified = qbQuestionModified; } } Fisheye: Tag 9c3a64b840753192b333afb73c8fe7bdb54be638 refers to a dead (removed) revision in file `lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestionOption.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestionResult.java =================================================================== diff -u -r1ee503e3d0e0228ea8a45025fddf15d9623c0377 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestionResult.java (.../AssessmentQuestionResult.java) (revision 1ee503e3d0e0228ea8a45025fddf15d9623c0377) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentQuestionResult.java (.../AssessmentQuestionResult.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -38,11 +38,15 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; +import org.lamsfoundation.lams.qb.model.QbQuestion; +import org.lamsfoundation.lams.qb.model.QbToolAnswer; +import org.lamsfoundation.lams.tool.assessment.dto.QuestionDTO; /** * Assessment Question Result @@ -51,12 +55,9 @@ */ @Entity @Table(name = "tl_laasse10_question_result") -public class AssessmentQuestionResult { - - @Id - @Column - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long uid; +//in this entity's table primary key is "uid", but it references "answer_uid" in lams_qb_tool_answer +@PrimaryKeyJoinColumn(name = "uid") +public class AssessmentQuestionResult extends QbToolAnswer implements Comparable { @Column(name = "answer_string") private String answerString; @@ -67,8 +68,8 @@ @Column(name = "answer_boolean") private boolean answerBoolean; - @Column(name = "submitted_option_uid") - private Long submittedOptionUid; +// @Column(name = "submitted_option_uid") +// private Long submittedOptionUid; @Column private float mark; @@ -85,9 +86,9 @@ @Column(name = "confidence_level") private int confidenceLevel; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "assessment_question_uid") - private AssessmentQuestion assessmentQuestion; +// @ManyToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "assessment_question_uid") +// private AssessmentQuestion assessmentQuestion; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "result_uid") @@ -103,6 +104,8 @@ private AssessmentUser user; @Transient private String answerStringEscaped; + @Transient + private QuestionDTO questionDto; @Override public int hashCode() { @@ -122,20 +125,18 @@ return new EqualsBuilder().append(this.getUid(), genericEntity.getUid()).isEquals(); } - public Long getUid() { - return uid; + public QbQuestion getQbQuestion() { + return qbToolQuestion.getQbQuestion(); } - - public void setUid(Long uid) { - this.uid = uid; - } - + + //TODO remove public AssessmentQuestion getAssessmentQuestion() { - return assessmentQuestion; + return null; } + //TODO remove public void setAssessmentQuestion(AssessmentQuestion question) { - this.assessmentQuestion = question; +// this.assessmentQuestion = question; } public AssessmentResult getAssessmentResult() { @@ -178,13 +179,15 @@ public void setAnswerBoolean(boolean answerBoolean) { this.answerBoolean = answerBoolean; } - + + //TODO REMOVE public Long getSubmittedOptionUid() { - return submittedOptionUid; + return qbOption.getUid(); } + //TODO REMOVE public void setSubmittedOptionUid(Long submittedOptionUid) { - this.submittedOptionUid = submittedOptionUid; + this.qbOption.setUid(submittedOptionUid); } public Float getMark() { @@ -261,6 +264,23 @@ public void setAnswerStringEscaped(String answerStringEscaped) { this.answerStringEscaped = answerStringEscaped; + } + + public QuestionDTO getQuestionDto() { + return questionDto; } + public void setQuestionDto(QuestionDTO questionDto) { + this.questionDto = questionDto; + } + + @Override + public int compareTo(AssessmentQuestionResult o) { + if (o != null) { + return qbToolQuestion.getDisplayOrder() - o.qbToolQuestion.getDisplayOrder(); + } else { + return 1; + } + } + } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentResult.java =================================================================== diff -u -r1ee503e3d0e0228ea8a45025fddf15d9623c0377 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentResult.java (.../AssessmentResult.java) (revision 1ee503e3d0e0228ea8a45025fddf15d9623c0377) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentResult.java (.../AssessmentResult.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -40,8 +40,6 @@ import javax.persistence.Table; import javax.persistence.Transient; -import org.lamsfoundation.lams.tool.assessment.util.AssessmentQuestionResultComparator; - /** * Assessment Result * @@ -89,7 +87,7 @@ @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name = "result_uid") - private Set questionResults = new TreeSet<>(new AssessmentQuestionResultComparator()); + private Set questionResults = new TreeSet<>(); // *************** NON Persist Fields ******************** @Transient Fisheye: Tag 9c3a64b840753192b333afb73c8fe7bdb54be638 refers to a dead (removed) revision in file `lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/AssessmentUnit.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/QuestionReference.java =================================================================== diff -u -r1ee503e3d0e0228ea8a45025fddf15d9623c0377 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/QuestionReference.java (.../QuestionReference.java) (revision 1ee503e3d0e0228ea8a45025fddf15d9623c0377) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/QuestionReference.java (.../QuestionReference.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -59,7 +59,7 @@ private int sequenceId; @Column(name = "default_grade") - private int defaultGrade; + private int maxMark; @Column(name = "random_question") private boolean randomQuestion; @@ -146,12 +146,12 @@ this.sequenceId = sequenceId; } - public int getDefaultGrade() { - return defaultGrade; + public int getMaxMark() { + return maxMark; } - public void setDefaultGrade(int defaultGrade) { - this.defaultGrade = defaultGrade; + public void setMaxMark(int maxMark) { + this.maxMark = maxMark; } public boolean isRandomQuestion() { Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentImportContentVersionFilter.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentImportContentVersionFilter.java (.../AssessmentImportContentVersionFilter.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentImportContentVersionFilter.java (.../AssessmentImportContentVersionFilter.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -26,7 +26,7 @@ import org.lamsfoundation.lams.learningdesign.service.ToolContentVersionFilter; import org.lamsfoundation.lams.tool.assessment.model.Assessment; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; +import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; /** * Import filter class for different version of Assessment content. @@ -74,7 +74,15 @@ this.removeField(AssessmentQuestion.class, "penalty"); this.removeField(AssessmentQuestion.class, "answerTotalGrade"); - this.removeField(AssessmentQuestionOption.class, "answerInt"); - this.removeField(AssessmentQuestionOption.class, "answerBoolean"); +// this.removeField(AssessmentQuestionOption.class, "answerInt"); +// this.removeField(AssessmentQuestionOption.class, "answerBoolean"); } + + /** + * Import 20140428 version content to 20140707 version tool server. + */ + public void up20170315To20190110() { + this.renameField(QuestionReference.class, "defaultGrade", "maxMark"); + this.renameField(QuestionReference.class, "sequenceId", "displayOrder"); + } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentOutputFactory.java =================================================================== diff -u -rdcdc1487609bd4f00afaa93c09272d84ab0cd325 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentOutputFactory.java (.../AssessmentOutputFactory.java) (revision dcdc1487609bd4f00afaa93c09272d84ab0cd325) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentOutputFactory.java (.../AssessmentOutputFactory.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -65,7 +65,7 @@ Long totalMarksPossible = 0L; for (QuestionReference questionReference : questionReferences) { - totalMarksPossible += questionReference.getDefaultGrade(); + totalMarksPossible += questionReference.getMaxMark(); } definition = buildRangeDefinition(AssessmentConstants.OUTPUT_NAME_LEARNER_TOTAL_SCORE, 0L, totalMarksPossible, true); @@ -90,16 +90,16 @@ int randomQuestionsCount = 1; for (QuestionReference questionReference : questionReferences) { Long markAvailable = null; - if (questionReference.getDefaultGrade() != 0) { - markAvailable = Long.valueOf(questionReference.getDefaultGrade()); + if (questionReference.getMaxMark() != 0) { + markAvailable = Long.valueOf(questionReference.getMaxMark()); } String description = getI18NText("output.user.score.for.question", false); if (questionReference.isRandomQuestion()) { description += getI18NText("label.authoring.basic.type.random.question", false) + " " + randomQuestionsCount++; } else { - description += questionReference.getQuestion().getTitle(); + description += questionReference.getQuestion().getQbQuestion().getName(); } definition = buildRangeDefinition(String.valueOf(questionReference.getSequenceId()), 0L, markAvailable); @@ -147,9 +147,9 @@ } Set questions = assessment.getQuestions(); for (AssessmentQuestion question : questions) { - if (names == null || names.contains(String.valueOf(question.getSequenceId()))) { + if (names == null || names.contains(String.valueOf(question.getDisplayOrder()))) { output.put(AssessmentConstants.OUTPUT_NAME_LEARNER_NUMBER_ATTEMPTS, - getQuestionScore(assessmentService, learnerId, assessment, question.getSequenceId())); + getQuestionScore(assessmentService, learnerId, assessment, question.getDisplayOrder())); } } } @@ -186,8 +186,8 @@ } else { Set questions = assessment.getQuestions(); for (AssessmentQuestion question : questions) { - if (name.equals(String.valueOf(question.getSequenceId()))) { - return getQuestionScore(assessmentService, learnerId, assessment, question.getSequenceId()); + if (name.equals(String.valueOf(question.getDisplayOrder()))) { + return getQuestionScore(assessmentService, learnerId, assessment, question.getDisplayOrder()); } } } @@ -225,7 +225,7 @@ Assessment assessment = assessmentService.getAssessmentByContentId(toolContentId); Set questions = assessment.getQuestions(); for (AssessmentQuestion question : questions) { - if (name.equals(String.valueOf(question.getSequenceId()))) { + if (name.equals(String.valueOf(question.getDisplayOrder()))) { return null; } } @@ -326,12 +326,12 @@ * Get user's score for the question. Will always return a ToolOutput object. */ private ToolOutput getQuestionScore(IAssessmentService assessmentService, Long learnerId, Assessment assessment, - int questionSequenceId) { + int questionDisplayOrder) { Float questionResultMarkDB = assessmentService.getQuestionResultMark(assessment.getUid(), learnerId, - questionSequenceId); + questionDisplayOrder); float questionResultMark = (questionResultMarkDB == null) ? 0 : questionResultMarkDB; - return new ToolOutput(String.valueOf(questionSequenceId), "description", questionResultMark); + return new ToolOutput(String.valueOf(questionDisplayOrder), "description", questionResultMark); } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -r3bb7e0141ae1cc15ccd737c95d90b5762a34ad61 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 3bb7e0141ae1cc15ccd737c95d90b5762a34ad61) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -32,7 +32,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -60,8 +59,10 @@ import org.lamsfoundation.lams.notebook.model.NotebookEntry; import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; -import org.lamsfoundation.lams.questions.Answer; -import org.lamsfoundation.lams.questions.Question; +import org.lamsfoundation.lams.qb.model.QbOption; +import org.lamsfoundation.lams.qb.model.QbQuestion; +import org.lamsfoundation.lams.qb.model.QbQuestionUnit; +import org.lamsfoundation.lams.qb.service.IQbService; import org.lamsfoundation.lams.rest.RestTags; import org.lamsfoundation.lams.rest.ToolRestManager; import org.lamsfoundation.lams.tool.ToolCompletionStatus; @@ -90,16 +91,13 @@ import org.lamsfoundation.lams.tool.assessment.model.Assessment; import org.lamsfoundation.lams.tool.assessment.model.AssessmentOptionAnswer; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionResult; import org.lamsfoundation.lams.tool.assessment.model.AssessmentResult; import org.lamsfoundation.lams.tool.assessment.model.AssessmentSession; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentUnit; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; import org.lamsfoundation.lams.tool.assessment.util.AnswerIntComparator; import org.lamsfoundation.lams.tool.assessment.util.AssessmentEscapeUtils; -import org.lamsfoundation.lams.tool.assessment.util.AssessmentQuestionResultComparator; import org.lamsfoundation.lams.tool.assessment.util.AssessmentSessionComparator; import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; import org.lamsfoundation.lams.tool.exception.DataMissingException; @@ -255,8 +253,8 @@ Set userQuestionResults = userResult.getQuestionResults(); for (AssessmentQuestionResult leaderQuestionResult : leaderQuestionResults) { for (AssessmentQuestionResult userQuestionResult : userQuestionResults) { - if (userQuestionResult.getAssessmentQuestion().getUid() - .equals(leaderQuestionResult.getAssessmentQuestion().getUid())) { + if (userQuestionResult.getQbQuestion().getUid() + .equals(leaderQuestionResult.getQbQuestion().getUid())) { userQuestionResult.setAnswerString(leaderQuestionResult.getAnswerString()); userQuestionResult.setAnswerFloat(leaderQuestionResult.getAnswerFloat()); @@ -419,7 +417,8 @@ public void saveOrUpdateAssessment(Assessment assessment) { //update questions' hashes in case questions' titles or descriptions got changed for (AssessmentQuestion question : (Set) assessment.getQuestions()) { - String newHash = question.getQuestion() == null ? null : HashUtil.sha1(question.getQuestion()); + String newHash = question.getQbQuestion().getDescription() == null ? null + : HashUtil.sha1(question.getQbQuestion().getDescription()); question.setQuestionHash(newHash); } @@ -430,7 +429,8 @@ @Override public void updateAssessmentQuestion(AssessmentQuestion question) { //update question's hash in case question's title or description got changed - String newHash = question.getQuestion() == null ? null : HashUtil.sha1(question.getQuestion()); + String newHash = question.getQbQuestion().getDescription() == null ? null + : HashUtil.sha1(question.getQbQuestion().getDescription()); question.setQuestionHash(newHash); //store object in DB @@ -443,10 +443,10 @@ if (object instanceof AssessmentQuestion) { AssessmentQuestion question = (AssessmentQuestion) object; - for (AssessmentQuestionOption option : question.getOptions()) { + for (QbOption option : question.getQbQuestion().getQbOptions()) { assessmentDao.releaseFromCache(option); } - for (AssessmentUnit unit : question.getUnits()) { + for (QbQuestionUnit unit : question.getQbQuestion().getUnits()) { assessmentDao.releaseFromCache(unit); } } @@ -506,14 +506,13 @@ //check all required questionResults exist, it can be missing in case of random question - create new one then Set questionResults = lastResult.getQuestionResults(); - Set updatedQuestionResults = new TreeSet<>( - new AssessmentQuestionResultComparator()); + Set updatedQuestionResults = new TreeSet<>(); for (AssessmentQuestion question : questions) { // get questionResult from DB instance of AssessmentResult AssessmentQuestionResult questionResult = null; for (AssessmentQuestionResult questionResultIter : questionResults) { - if (question.getUid().equals(questionResultIter.getAssessmentQuestion().getUid())) { + if (question.getUid().equals(questionResultIter.getQbQuestion().getUid())) { questionResult = questionResultIter; } } @@ -561,7 +560,7 @@ // create optionAnswer for each option Set optionAnswers = questionResult.getOptionAnswers(); - for (AssessmentQuestionOption option : question.getOptions()) { + for (QbOption option : question.getQbQuestion().getQbOptions()) { AssessmentOptionAnswer optionAnswer = new AssessmentOptionAnswer(); optionAnswer.setOptionUid(option.getUid()); optionAnswers.add(optionAnswer); @@ -606,7 +605,7 @@ } } questionResult.setMark(mark); - questionResult.setMaxMark((float) questionDto.getGrade()); + questionResult.setMaxMark((float) questionDto.getMaxMark()); assessmentResultDao.saveObject(questionResult); //for displaying purposes calculate mark and set it to questionDto @@ -631,13 +630,13 @@ } } - // store grades and finished date only on user hitting submit all answers button (and not submit mark hedging + // store marks and finished date only on user hitting submit all answers button (and not submit mark hedging // question) if (!isAutosave) { - int maximumGrade = 0; - float grade = 0; + int maximumMark = 0; + float mark = 0; - //sum up user grade and max grade for all questions + //sum up user mark and max mark for all questions for (Set questionsForOnePage : pagedQuestions) { for (QuestionDTO questionDto : questionsForOnePage) { // get questionResult from DB instance of AssessmentResult @@ -650,13 +649,13 @@ calculateAnswerMark(assessment.getUid(), userId, questionResult, questionDto); questionResult.setFinishDate(new Date()); - grade += questionResult.getMark(); - maximumGrade += questionDto.getGrade(); + mark += questionResult.getMark(); + maximumMark += questionDto.getMaxMark(); } } - result.setMaximumGrade(maximumGrade); - result.setGrade(grade); + result.setMaximumGrade(maximumMark); + result.setGrade(mark); result.setFinishDate(new Timestamp(new Date().getTime())); assessmentResultDao.update(result); } @@ -705,7 +704,7 @@ // store option answer values optionAnswer.setAnswerBoolean(optionDto.getAnswerBoolean()); optionAnswer.setAnswerInt(optionDto.getAnswerInt()); - if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING) { + if (questionDto.getType() == QbQuestion.TYPE_ORDERING) { optionAnswer.setAnswerInt(j++); } } @@ -726,52 +725,52 @@ QuestionDTO questionDto) { //calculate both mark and maxMark float mark = 0; - float maxMark = questionDto.getGrade(); - if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + float maxMark = questionDto.getMaxMark(); + if (questionDto.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE) { boolean isMarkNullified = false; - float totalGrade = 0; + float optionMaxMark = 0; for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.getAnswerBoolean()) { - totalGrade += optionDto.getGrade(); - mark += optionDto.getGrade() * maxMark; + optionMaxMark += optionDto.getMaxMark(); + mark += optionDto.getMaxMark() * maxMark; // if option of "incorrect answer nullifies mark" is ON check if selected answer has a zero grade // and if so nullify question's mark - if (questionDto.isIncorrectAnswerNullifiesMark() && (optionDto.getGrade() == 0)) { + if (questionDto.isIncorrectAnswerNullifiesMark() && (optionDto.getMaxMark() == 0)) { isMarkNullified = true; } } } - // set answerTotalGrade to let jsp know whether the question was answered correctly/partly/incorrectly even if mark=0 - questionDto.setAnswerTotalGrade(totalGrade); + // set optionMaxMark to let jsp know whether the question was answered correctly/partly/incorrectly even if mark=0 + questionDto.setOptionMaxMark(optionMaxMark); if (isMarkNullified) { mark = 0; } - } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { + } else if (questionDto.getType() == QbQuestion.TYPE_MATCHING_PAIRS) { float maxMarkForCorrectAnswer = maxMark / questionDto.getOptionDtos().size(); for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.getAnswerInt() == optionDto.getUid()) { mark += maxMarkForCorrectAnswer; } } - } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) { + } else if (questionDto.getType() == QbQuestion.TYPE_SHORT_ANSWER) { //clear previous answer questionResult.setSubmittedOptionUid(null); for (OptionDTO optionDto : questionDto.getOptionDtos()) { //prepare regex which takes into account only * special character String regexWithOnlyAsteriskSymbolActive = "\\Q"; - String optionString = optionDto.getOptionString().trim(); - for (int i = 0; i < optionString.length(); i++) { + String name = optionDto.getName().trim(); + for (int i = 0; i < name.length(); i++) { //everything in between \\Q and \\E are taken literally no matter which characters it contains - if (optionString.charAt(i) == '*') { + if (name.charAt(i) == '*') { regexWithOnlyAsteriskSymbolActive += "\\E.*\\Q"; } else { - regexWithOnlyAsteriskSymbolActive += optionString.charAt(i); + regexWithOnlyAsteriskSymbolActive += name.charAt(i); } } regexWithOnlyAsteriskSymbolActive += "\\E"; @@ -789,39 +788,39 @@ : false; if (isAnswerMatchedCurrentOption) { - mark = optionDto.getGrade() * maxMark; + mark = optionDto.getMaxMark() * maxMark; questionResult.setSubmittedOptionUid(optionDto.getUid()); break; } } - } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + } else if (questionDto.getType() == QbQuestion.TYPE_NUMERICAL) { String answerString = questionDto.getAnswerString(); if (answerString != null) { for (OptionDTO optionDto : questionDto.getOptionDtos()) { boolean isAnswerMatchedCurrentOption = false; try { float answerFloat = Float.valueOf(questionDto.getAnswerString()); - isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getOptionFloat() + isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getNumericalOption() - optionDto.getAcceptedError())) - && (answerFloat <= (optionDto.getOptionFloat() + optionDto.getAcceptedError()))); + && (answerFloat <= (optionDto.getNumericalOption() + optionDto.getAcceptedError()))); } catch (Exception e) { } if (!isAnswerMatchedCurrentOption) { - for (AssessmentUnit unit : questionDto.getUnits()) { - String regex = ".*" + unit.getUnit() + "$"; + for (QbQuestionUnit unit : questionDto.getUnits()) { + String regex = ".*" + unit.getName() + "$"; Pattern pattern = Pattern.compile(regex, java.util.regex.Pattern.CASE_INSENSITIVE | java.util.regex.Pattern.UNICODE_CASE); if (pattern.matcher(answerString).matches()) { String answerFloatStr = answerString.substring(0, - answerString.length() - unit.getUnit().length()); + answerString.length() - unit.getName().length()); try { float answerFloat = Float.valueOf(answerFloatStr); answerFloat = answerFloat / unit.getMultiplier(); - isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getOptionFloat() + isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getNumericalOption() - optionDto.getAcceptedError())) - && (answerFloat <= (optionDto.getOptionFloat() + && (answerFloat <= (optionDto.getNumericalOption() + optionDto.getAcceptedError()))); if (isAnswerMatchedCurrentOption) { break; @@ -832,32 +831,30 @@ } } if (isAnswerMatchedCurrentOption) { - mark = optionDto.getGrade() * maxMark; + mark = optionDto.getMaxMark() * maxMark; questionResult.setSubmittedOptionUid(optionDto.getUid()); break; } } } - } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE) { + } else if (questionDto.getType() == QbQuestion.TYPE_TRUE_FALSE) { if ((questionDto.getAnswerBoolean() == questionDto.getCorrectAnswer()) && (questionDto.getAnswerString() != null)) { mark = maxMark; } - } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING) { + } else if (questionDto.getType() == QbQuestion.TYPE_ORDERING) { float maxMarkForCorrectAnswer = maxMark / questionDto.getOptionDtos().size(); - TreeSet correctOptionSet = new TreeSet<>(new SequencableComparator()); - correctOptionSet.addAll(questionDto.getOptionDtos()); - ArrayList correctOptionList = new ArrayList<>(correctOptionSet); + ArrayList correctOptionList = new ArrayList<>(questionDto.getOptionDtos()); int i = 0; for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.getUid() == correctOptionList.get(i++).getUid()) { mark += maxMarkForCorrectAnswer; } } - } else if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + } else if (questionDto.getType() == QbQuestion.TYPE_MARK_HEDGING) { for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.isCorrect()) { //if hedgingMark is a default '-1', change it to '0' @@ -872,7 +869,7 @@ if (mark > maxMark) { mark = maxMark; - // in case options have negative grades (<0), their total mark can't be less than -maxMark + // in case options have negative marks (<0), their total mark can't be less than -maxMark } else if (mark < -maxMark) { mark = -maxMark; } @@ -921,7 +918,7 @@ //load last finished results for hedging type of questions (in order to prevent retry) Set questionResults = lastResult.getQuestionResults(); - if ((questionDto.getType() == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) + if ((questionDto.getType() == QbQuestion.TYPE_MARK_HEDGING) && (lastResult.getFinishDate() == null) && (lastFinishedResult != null)) { questionResults = lastFinishedResult.getQuestionResults(); } @@ -960,7 +957,7 @@ } //sort ordering type of question in order to show how learner has sorted them - if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING) { + if (questionDto.getType() == QbQuestion.TYPE_ORDERING) { //don't sort ordering type of questions that haven't been submitted to not break their shuffled order boolean isOptionAnswersNeverSubmitted = true; @@ -977,15 +974,15 @@ } } - // set answerTotalGrade to let jsp know whether the question was answered correctly/partly/incorrectly even if mark=0 - if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { - float totalGrade = 0; + // set optionMaxMark to let jsp know whether the question was answered correctly/partly/incorrectly even if mark=0 + if (questionDto.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE) { + float optionMaxMark = 0; for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.getAnswerBoolean()) { - totalGrade += optionDto.getGrade(); + optionMaxMark += optionDto.getMaxMark(); } } - questionDto.setAnswerTotalGrade(totalGrade); + questionDto.setOptionMaxMark(optionMaxMark); } } @@ -1092,8 +1089,8 @@ } @Override - public Float getQuestionResultMark(Long assessmentUid, Long userId, int questionSequenceId) { - return assessmentQuestionResultDao.getQuestionResultMark(assessmentUid, userId, questionSequenceId); + public Float getQuestionResultMark(Long assessmentUid, Long userId, int questionDisplayOrder) { + return assessmentQuestionResultDao.getQuestionResultMark(assessmentUid, userId, questionDisplayOrder); } @Override @@ -1234,8 +1231,7 @@ Set questionResults = lastFinishedResult.getQuestionResults(); //prepare list of the questions to display in user master detail table, filtering out questions that aren't supposed to be answered - SortedSet questionResultsToDisplay = new TreeSet<>( - new AssessmentQuestionResultComparator()); + SortedSet questionResultsToDisplay = new TreeSet<>(); //in case there is at least one random question - we need to show all questions if (assessment.hasRandomQuestion()) { questionResultsToDisplay.addAll(questionResults); @@ -1244,7 +1240,7 @@ } else { for (QuestionReference reference : questionReferences) { for (AssessmentQuestionResult questionResult : questionResults) { - if (reference.getQuestion().getUid().equals(questionResult.getAssessmentQuestion().getUid())) { + if (reference.getQuestion().getUid().equals(questionResult.getQbQuestion().getUid())) { questionResultsToDisplay.add(questionResult); } } @@ -1303,7 +1299,7 @@ List questionResults = new ArrayList<>(); for (AssessmentResult result : results) { for (AssessmentQuestionResult questionResult : result.getQuestionResults()) { - if (question.getUid().equals(questionResult.getAssessmentQuestion().getUid())) { + if (question.getUid().equals(questionResult.getQbQuestion().getUid())) { // for displaying purposes only (no saving occurs) questionResult.setFinishDate(result.getFinishDate()); @@ -1326,11 +1322,9 @@ @Override public QuestionSummary getQuestionSummary(Long contentId, Long questionUid) { - QuestionSummary questionSummary = new QuestionSummary(); AssessmentQuestion question = assessmentQuestionDao.getByUid(questionUid); - questionSummary.setQuestion(question); - - return questionSummary; + + return new QuestionSummary(question); } @Override @@ -1372,8 +1366,7 @@ for (AssessmentQuestion question : (Set) assessment.getQuestions()) { Long questionUid = question.getUid(); - QuestionSummary questionSummary = new QuestionSummary(); - questionSummary.setQuestion(question); + QuestionSummary questionSummary = new QuestionSummary(question); List> questionResults = new ArrayList<>(); @@ -1391,7 +1384,7 @@ questionResult.setAssessmentQuestion(question); } else { for (AssessmentQuestionResult dbQuestionResult : assessmentResult.getQuestionResults()) { - if (dbQuestionResult.getAssessmentQuestion().getUid().equals(questionUid)) { + if (dbQuestionResult.getQbQuestion().getUid().equals(questionUid)) { questionResult = dbQuestionResult; break; } @@ -1613,10 +1606,10 @@ questionSummaryTab.add(questionTitle); // set up the summary table data for the top of the question area. - boolean doSummaryTable = question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE - || question.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER - || question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL - || question.getType() == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE; + boolean doSummaryTable = question.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE + || question.getType() == QbQuestion.TYPE_SHORT_ANSWER + || question.getType() == QbQuestion.TYPE_NUMERICAL + || question.getType() == QbQuestion.TYPE_TRUE_FALSE; // For MC, Numeric & Short Answer Key is optionUid, Value is number of answers // For True/False Key 0 is false and Key 1 is true Map summaryOfAnswers = new HashMap<>(); @@ -1630,9 +1623,9 @@ ArrayList questionSummaryTabTemp = new ArrayList<>(); //add question title row - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + if (question.getType() == QbQuestion.TYPE_MARK_HEDGING) { count = 0; - Set options = question.getOptions(); + List options = question.getQbQuestion().getQbOptions(); colsNum += options.size() - 1; // question row title ExcelCell[] hedgeQuestionTitleRow = new ExcelCell[colsNum]; @@ -1650,9 +1643,9 @@ getMessage("label.monitoring.user.summary.user.name"), true); } hedgeQuestionTitleRow[count++] = new ExcelCell(getMessage("label.export.date.attempted"), true); - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { hedgeQuestionTitleRow[count++] = new ExcelCell( - option.getOptionString().replaceAll("\\<.*?\\>", ""), true); + option.getName().replaceAll("\\<.*?\\>", ""), true); if (option.isCorrect()) { hedgeQuestionTitleRow[count - 1].setColor(IndexedColors.GREEN); } @@ -1678,12 +1671,12 @@ ExcelCell[] userResultRow = new ExcelCell[colsNum]; count = 0; - userResultRow[count++] = new ExcelCell(questionResult.getAssessmentQuestion().getTitle(), + userResultRow[count++] = new ExcelCell(questionResult.getQbQuestion().getName(), false); + userResultRow[count++] = new ExcelCell(AssessmentServiceImpl + .getQuestionTypeLabel(questionResult.getQbQuestion().getType()), false); userResultRow[count++] = new ExcelCell( - getQuestionTypeLanguageLabel(questionResult.getAssessmentQuestion().getType()), false); - userResultRow[count++] = new ExcelCell( - Float.valueOf(questionResult.getAssessmentQuestion().getPenaltyFactor()), false); + Float.valueOf(questionResult.getQbQuestion().getPenaltyFactor()), false); Float maxMark = (questionResult.getMaxMark() == null) ? 0 : Float.valueOf(questionResult.getMaxMark()); userResultRow[count++] = new ExcelCell(maxMark, false); @@ -1695,10 +1688,10 @@ } userResultRow[count++] = new ExcelCell(questionResult.getFinishDate(), false); //answer - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + if (question.getType() == QbQuestion.TYPE_MARK_HEDGING) { Set optionAnswers = questionResult.getOptionAnswers(); - for (AssessmentQuestionOption option : question.getOptions()) { + for (QbOption option : question.getQbQuestion().getQbOptions()) { for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (option.getUid().equals(optionAnswer.getOptionUid())) { userResultRow[count++] = new ExcelCell(optionAnswer.getAnswerInt(), false); @@ -1831,9 +1824,9 @@ } else { AssessmentQuestion question = questionReference.getQuestion(); - title = question.getTitle(); - questionType = getQuestionTypeLanguageLabel(question.getType()); - penaltyFactor = question.getPenaltyFactor(); + title = question.getQbQuestion().getName(); + questionType = AssessmentServiceImpl.getQuestionTypeLabel(question.getType()); + penaltyFactor = question.getQbQuestion().getPenaltyFactor(); QuestionSummary questionSummary = questionSummaries.get(question.getUid()); if (questionSummary != null) { @@ -1842,7 +1835,7 @@ } } - int maxGrade = questionReference.getDefaultGrade(); + int maxGrade = questionReference.getMaxMark(); totalGradesPossible += maxGrade; ExcelCell[] questCell = new ExcelCell[5]; @@ -1926,7 +1919,7 @@ userResultRow[1] = new ExcelCell(assessmentUser.getFullName(), false); userResultRow[2] = new ExcelCell(assessmentResult.getStartDate(), false); userResultRow[3] = new ExcelCell( - questionResult.getAssessmentQuestion().getTitle(), false); + questionResult.getQbQuestion().getName(), false); userResultRow[4] = new ExcelCell( AssessmentEscapeUtils.printResponsesForExcelExport(questionResult), false); @@ -1937,7 +1930,7 @@ userResultRow[0] = new ExcelCell(assessmentUser.getUserId(), false); userResultRow[1] = new ExcelCell(assessmentResult.getStartDate(), false); userResultRow[2] = new ExcelCell( - questionResult.getAssessmentQuestion().getTitle(), false); + questionResult.getQbQuestion().getName(), false); userResultRow[3] = new ExcelCell( AssessmentEscapeUtils.printResponsesForExcelExport(questionResult), false); @@ -1974,23 +1967,24 @@ Long trueKey, Long falseKey) { ExcelCell[] summaryTable; int i = 0; - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE - || question.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER - || question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { - summaryTable = new ExcelCell[question.getOptions().size() + 1]; - for (AssessmentQuestionOption option : question.getOptions()) { + if (question.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE + || question.getType() == QbQuestion.TYPE_SHORT_ANSWER + || question.getType() == QbQuestion.TYPE_NUMERICAL) { + List options = question.getQbQuestion().getQbOptions(); + summaryTable = new ExcelCell[options.size() + 1]; + for (QbOption option : options) { summaryOfAnswers.put(option.getUid(), 0); StringBuilder bldr = new StringBuilder(getMessage("label.authoring.basic.option.answer")).append(" ") .append(i + 1).append(" - "); - if (question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { - bldr.append(option.getOptionFloat()).append(" +- ").append(option.getAcceptedError()); + if (question.getType() == QbQuestion.TYPE_NUMERICAL) { + bldr.append(option.getNumericalOption()).append(" +- ").append(option.getAcceptedError()); } else { - bldr.append(option.getOptionString().replaceAll("\\<.*?\\>", "")); + bldr.append(option.getName().replaceAll("\\<.*?\\>", "")); } summaryTable[i] = new ExcelCell(bldr.toString(), false); i++; } - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + if (question.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE) { summaryTable[i++] = new ExcelCell(getMessage("label.not.answered"), false); } else { summaryTable[i++] = new ExcelCell(getMessage("label.other"), false); @@ -2008,7 +2002,7 @@ private Integer updateSummaryCounts(AssessmentQuestion question, AssessmentQuestionResult questionResult, Map summaryOfAnswers, Integer summaryNACount) { - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + if (question.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE) { boolean foundOption = false; Set optionAnswers = questionResult.getOptionAnswers(); if (optionAnswers != null) { @@ -2030,8 +2024,8 @@ if (!foundOption) { summaryNACount++; } - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER - || question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + } else if (question.getType() == QbQuestion.TYPE_SHORT_ANSWER + || question.getType() == QbQuestion.TYPE_NUMERICAL) { Long submittedUid = questionResult.getSubmittedOptionUid(); if (submittedUid != null) { Integer currentCount = summaryOfAnswers.get(submittedUid); @@ -2046,7 +2040,7 @@ } else { summaryNACount++; } - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE) { + } else if (question.getType() == QbQuestion.TYPE_TRUE_FALSE) { if (questionResult.getAnswerString() == null) { summaryNACount++; } else { @@ -2071,12 +2065,12 @@ total += value; } int i = 0; - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE - || question.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER - || question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { - for (AssessmentQuestionOption option : question.getOptions()) { + if (question.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE + || question.getType() == QbQuestion.TYPE_SHORT_ANSWER + || question.getType() == QbQuestion.TYPE_NUMERICAL) { + for (QbOption option : question.getQbQuestion().getQbOptions()) { summaryTable[i] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(option.getUid()), total), false); - if (option.getGrade() > 0) { + if (option.getMaxMark() > 0) { summaryTable[i].setColor(IndexedColors.GREEN); } i++; @@ -2087,31 +2081,31 @@ summaryTable[0] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(trueKey), total), false); summaryTable[1] = new ExcelCell(valueAsPercentage(summaryOfAnswers.get(falseKey), total), false); summaryTable[2] = new ExcelCell(valueAsPercentage(summaryNACount, total), false); - summaryTable[question.getCorrectAnswer() ? 0 : 1].setColor(IndexedColors.GREEN); + summaryTable[question.getQbQuestion().getCorrectAnswer() ? 0 : 1].setColor(IndexedColors.GREEN); } return summaryTable; } /** * Used only for excell export (for getUserSummaryData() method). */ - private String getQuestionTypeLanguageLabel(short type) { + public static String getQuestionTypeLabel(Integer type) { switch (type) { - case AssessmentConstants.QUESTION_TYPE_ESSAY: + case QbQuestion.TYPE_ESSAY: return "Essay"; - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: + case QbQuestion.TYPE_MATCHING_PAIRS: return "Matching Pairs"; - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: + case QbQuestion.TYPE_MULTIPLE_CHOICE: return "Multiple Choice"; - case AssessmentConstants.QUESTION_TYPE_NUMERICAL: + case QbQuestion.TYPE_NUMERICAL: return "Numerical"; - case AssessmentConstants.QUESTION_TYPE_ORDERING: + case QbQuestion.TYPE_ORDERING: return "Ordering"; - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: + case QbQuestion.TYPE_SHORT_ANSWER: return "Short Answer"; - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: + case QbQuestion.TYPE_TRUE_FALSE: return "True/False"; - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: + case QbQuestion.TYPE_MARK_HEDGING: return "Mark Hedging"; default: return null; @@ -2120,15 +2114,15 @@ @Override public void changeQuestionResultMark(Long questionResultUid, float newMark) { - AssessmentQuestionResult questionAnswer = assessmentQuestionResultDao + AssessmentQuestionResult questionResult = assessmentQuestionResultDao .getAssessmentQuestionResultByUid(questionResultUid); - float oldMark = questionAnswer.getMark(); - AssessmentResult assessmentResult = questionAnswer.getAssessmentResult(); - float totalMark = (assessmentResult.getGrade() - oldMark) + newMark; + float oldMark = questionResult.getMark(); + AssessmentResult assessmentResult = questionResult.getAssessmentResult(); + float assessmentMark = (assessmentResult.getGrade() - oldMark) + newMark; Long toolSessionId = assessmentResult.getSessionId(); Assessment assessment = assessmentResult.getAssessment(); - Long questionUid = questionAnswer.getAssessmentQuestion().getUid(); + Long questionUid = questionResult.getQbQuestion().getUid(); // When changing a mark for user and isUseSelectLeaderToolOuput is true, the mark should be propagated to all // students within the group @@ -2160,15 +2154,15 @@ assessmentQuestionResultDao.saveObject(lastAssessmentQuestionResult); AssessmentResult result = lastAssessmentQuestionResult.getAssessmentResult(); - result.setGrade(totalMark); + result.setGrade(assessmentMark); assessmentResultDao.saveObject(result); // propagade changes to Gradebook - toolService.updateActivityMark(Double.valueOf(totalMark), null, userId.intValue(), toolSessionId, false); + toolService.updateActivityMark(Double.valueOf(assessmentMark), null, userId.intValue(), toolSessionId, false); // records mark change with audit service logEventService.logMarkChange(userId, user.getLoginName(), assessment.getContentId(), "" + oldMark, - "" + totalMark); + "" + assessmentMark); } } @@ -2183,8 +2177,8 @@ List modifiedQuestions = new ArrayList<>(); for (AssessmentQuestion oldQuestion : oldQuestions) { - if (AssessmentConstants.QUESTION_TYPE_ESSAY == oldQuestion.getType() - || AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS == oldQuestion.getType()) { + if (QbQuestion.TYPE_ESSAY == oldQuestion.getType() + || QbQuestion.TYPE_MATCHING_PAIRS == oldQuestion.getType()) { continue; } @@ -2195,30 +2189,30 @@ // title or question is different - do nothing. Also question grade can't be changed - //AssessmentConstants.QUESTION_TYPE_TRUE_FALSE - if (oldQuestion.getCorrectAnswer() != newQuestion.getCorrectAnswer()) { + //QbQuestion.TYPE_TRUE_FALSE + if (oldQuestion.getQbQuestion().getCorrectAnswer() != newQuestion.getQbQuestion().getCorrectAnswer()) { isQuestionModified = true; } // options are different - Set oldOptions = oldQuestion.getOptions(); - Set newOptions = newQuestion.getOptions(); - for (AssessmentQuestionOption oldOption : oldOptions) { - for (AssessmentQuestionOption newOption : newOptions) { + List oldOptions = oldQuestion.getQbQuestion().getQbOptions(); + List newOptions = newQuestion.getQbQuestion().getQbOptions(); + for (QbOption oldOption : oldOptions) { + for (QbOption newOption : newOptions) { if (oldOption.getUid().equals(newOption.getUid())) { //ordering - if (((oldQuestion.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING) - && (oldOption.getSequenceId() != newOption.getSequenceId())) + if (((oldQuestion.getType() == QbQuestion.TYPE_ORDERING) + && (oldOption.getDisplayOrder() != newOption.getDisplayOrder())) //short answer - || ((oldQuestion.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) - && !StringUtils.equals(oldOption.getOptionString(), - newOption.getOptionString())) + || ((oldQuestion.getType() == QbQuestion.TYPE_SHORT_ANSWER) + && !StringUtils.equals(oldOption.getName(), + newOption.getName())) //numbering - || (oldOption.getOptionFloat() != newOption.getOptionFloat()) + || (oldOption.getNumericalOption() != newOption.getNumericalOption()) || (oldOption.getAcceptedError() != newOption.getAcceptedError()) //option grade - || (oldOption.getGrade() != newOption.getGrade()) + || (oldOption.getMaxMark() != newOption.getMaxMark()) //changed correct option || (oldOption.isCorrect() != newOption.isCorrect())) { isQuestionModified = true; @@ -2238,13 +2232,13 @@ } // create list of references with modified grades. - // modifiedReferences holds pairs newReference -> oldReference.getDefaultGrade() + // modifiedReferences holds pairs newReference -> oldReference.getMaxMark() Map modifiedReferences = new HashMap<>(); for (QuestionReference oldReference : oldReferences) { for (QuestionReference newReference : newReferences) { if (oldReference.getUid().equals(newReference.getUid()) - && (oldReference.getDefaultGrade() != newReference.getDefaultGrade())) { - modifiedReferences.put(newReference, oldReference.getDefaultGrade()); + && (oldReference.getMaxMark() != newReference.getMaxMark())) { + modifiedReferences.put(newReference, oldReference.getMaxMark()); } } } @@ -2285,7 +2279,7 @@ //actually recalculate marks QuestionDTO questionDto = question.getQuestionDTO(); - questionDto.setGrade(questionResult.getMaxMark().intValue()); + questionDto.setMaxMark(questionResult.getMaxMark().intValue()); loadupQuestionResultIntoQuestionDto(questionDto, questionResult); calculateAnswerMark(assessmentUid, user.getUserId(), questionResult, questionDto); assessmentQuestionResultDao.saveObject(questionResult); @@ -2299,24 +2293,24 @@ // [+] if the question reference mark is modified for (AssessmentQuestionResult questionResult:questionResults) { - Long questionUid = questionResult.getAssessmentQuestion().getUid(); + Long questionUid = questionResult.getQbQuestion().getUid(); for (QuestionReference modifiedReference : modifiedReferences.keySet()) { if (!modifiedReference.isRandomQuestion() && questionUid.equals(modifiedReference.getQuestion().getUid())) { - int newReferenceGrade = modifiedReference.getDefaultGrade(); - int oldReferenceGrade = modifiedReferences.get(modifiedReference); + int newReferenceMaxMark = modifiedReference.getMaxMark(); + int oldReferenceMaxMark = modifiedReferences.get(modifiedReference); // update question answer's mark Float oldQuestionAnswerMark = questionResult.getMark(); - float newQuestionAnswerMark = (oldQuestionAnswerMark * newReferenceGrade) - / oldReferenceGrade; + float newQuestionAnswerMark = (oldQuestionAnswerMark * newReferenceMaxMark) + / oldReferenceMaxMark; questionResult.setMark(newQuestionAnswerMark); - questionResult.setMaxMark((float) newReferenceGrade); + questionResult.setMaxMark((float) newReferenceMaxMark); assessmentQuestionResultDao.saveObject(questionResult); assessmentMark += newQuestionAnswerMark - oldQuestionAnswerMark; - assessmentMaxMark += newReferenceGrade - oldReferenceGrade; + assessmentMaxMark += newReferenceMaxMark - oldReferenceMaxMark; break; } } @@ -2326,7 +2320,7 @@ ArrayList nonRandomQuestionResults = new ArrayList<>(); for (AssessmentQuestionResult questionResult : questionResults) { for (QuestionReference reference : newReferences) { - if (!reference.isRandomQuestion() && questionResult.getAssessmentQuestion().getUid() + if (!reference.isRandomQuestion() && questionResult.getQbQuestion().getUid() .equals(reference.getQuestion().getUid())) { nonRandomQuestionResults.add(questionResult); } @@ -2338,27 +2332,27 @@ // [+] if the question reference mark is modified (in case of random question references) for (QuestionReference modifiedReference : modifiedReferences.keySet()) { - // in case of random question reference - search for the answer with the same maxmark (it does not matter to which random reference this question belong originally as the only thing that differentiate those references is defaultGrade) + // in case of random question reference - search for the answer with the same maxmark (it does not matter to which random reference this question belong originally as the only thing that differentiate those references is maxMark) if (modifiedReference.isRandomQuestion()) { for (AssessmentQuestionResult randomQuestionResult : randomQuestionResults) { - int newReferenceGrade = modifiedReference.getDefaultGrade(); - int oldReferenceGrade = modifiedReferences.get(modifiedReference); + int newReferenceMaxMark = modifiedReference.getMaxMark(); + int oldReferenceMaxMark = modifiedReferences.get(modifiedReference); - if (randomQuestionResult.getMaxMark().intValue() == oldReferenceGrade) { + if (randomQuestionResult.getMaxMark().intValue() == oldReferenceMaxMark) { // update question answer's mark Float oldQuestionResultMark = randomQuestionResult.getMark(); - float newQuestionResultMark = (oldQuestionResultMark * newReferenceGrade) - / oldReferenceGrade; + float newQuestionResultMark = (oldQuestionResultMark * newReferenceMaxMark) + / oldReferenceMaxMark; randomQuestionResult.setMark(newQuestionResultMark); - randomQuestionResult.setMaxMark((float) newReferenceGrade); + randomQuestionResult.setMaxMark((float) newReferenceMaxMark); assessmentQuestionResultDao.saveObject(randomQuestionResult); nonRandomQuestionResults.add(randomQuestionResult); assessmentMark += newQuestionResultMark - oldQuestionResultMark; - assessmentMaxMark += newReferenceGrade - oldReferenceGrade; + assessmentMaxMark += newReferenceMaxMark - oldReferenceMaxMark; break; } } @@ -2826,40 +2820,40 @@ //fill in question's and user answer's hashes for (AssessmentQuestionResult questionResult : assessmentResult.getQuestionResults()) { - AssessmentQuestion question = questionResult.getAssessmentQuestion(); + QbQuestion qbQuestion = questionResult.getQbQuestion(); List answers = new LinkedList(); - if (question.getType() == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + if (qbQuestion.getType() == QbQuestion.TYPE_MULTIPLE_CHOICE) { - for (AssessmentQuestionOption option : question.getOptions()) { + for (QbOption option : qbQuestion.getQbOptions()) { for (AssessmentOptionAnswer optionAnswer : questionResult.getOptionAnswers()) { if (optionAnswer.getAnswerBoolean() && (optionAnswer.getOptionUid().equals(option.getUid()))) { - answers.add(option.getOptionString()); + answers.add(option.getName()); } } } - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_MATCHING_PAIRS) { - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_SHORT_ANSWER) { answers.add(questionResult.getAnswerString()); - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_NUMERICAL) { answers.add(questionResult.getAnswerString()); - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_TRUE_FALSE) { if (questionResult.getAnswerString() != null) { answers.add("" + questionResult.getAnswerBoolean()); } - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_ESSAY) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_ESSAY) { answers.add(questionResult.getAnswerString()); - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_ORDERING) { - } else if (question.getType() == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + } else if (qbQuestion.getType() == QbQuestion.TYPE_MARK_HEDGING) { } @@ -2868,7 +2862,7 @@ confidenceLevelDto.setUserId(userId.intValue()); confidenceLevelDto.setPortraitUuid(portraitUuid); confidenceLevelDto.setLevel(questionResult.getConfidenceLevel()); - confidenceLevelDto.setQuestion(question.getQuestion()); + confidenceLevelDto.setQuestion(qbQuestion.getDescription()); confidenceLevelDto.setAnswer(answer); confidenceLevelDtos.add(confidenceLevelDto); @@ -3019,7 +3013,7 @@ * "answerFloat", "displayOrder" (Integer), "grade" (Integer). * * The references entry should be a ArrayNode containing JSON objects, which in turn must contain "displayOrder" - * (Integer), "questionDisplayOrder" (Integer - to match to the question). It may also have "defaultGrade" (Integer) + * (Integer), "questionDisplayOrder" (Integer - to match to the question). It may also have "maxMark" (Integer) * and "randomQuestion" (Boolean) * * @throws IOException @@ -3086,57 +3080,62 @@ Set newQuestionSet = assessment.getQuestions(); // the Assessment constructor will set up the collection for (JsonNode questionJSONData : questions) { AssessmentQuestion question = new AssessmentQuestion(); - short type = JsonUtil.optInt(questionJSONData, "type").shortValue(); - question.setType(type); - question.setTitle(questionJSONData.get(RestTags.QUESTION_TITLE).asText()); - question.setQuestion(questionJSONData.get(RestTags.QUESTION_TEXT).asText()); - question.setSequenceId(JsonUtil.optInt(questionJSONData, RestTags.DISPLAY_ORDER)); + Integer type = JsonUtil.optInt(questionJSONData, "type"); + question.getQbQuestion().setType(type); + question.getQbQuestion().setName(questionJSONData.get(RestTags.QUESTION_TITLE).asText()); + question.getQbQuestion().setDescription(questionJSONData.get(RestTags.QUESTION_TEXT).asText()); + question.setDisplayOrder(JsonUtil.optInt(questionJSONData, RestTags.DISPLAY_ORDER)); - question.setAllowRichEditor( + question.getQbQuestion().setAllowRichEditor( JsonUtil.optBoolean(questionJSONData, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); - question.setAnswerRequired(JsonUtil.optBoolean(questionJSONData, "answerRequired", Boolean.FALSE)); - question.setCaseSensitive(JsonUtil.optBoolean(questionJSONData, "caseSensitive", Boolean.FALSE)); - question.setCorrectAnswer(JsonUtil.optBoolean(questionJSONData, "correctAnswer", Boolean.FALSE)); - question.setDefaultGrade(JsonUtil.optInt(questionJSONData, "defaultGrade", 1)); - question.setFeedback(JsonUtil.optString(questionJSONData, "feedback")); - question.setFeedbackOnCorrect(JsonUtil.optString(questionJSONData, "feedbackOnCorrect")); - question.setFeedbackOnIncorrect(JsonUtil.optString(questionJSONData, "feedbackOnIncorrect")); - question.setFeedbackOnPartiallyCorrect(JsonUtil.optString(questionJSONData, "feedbackOnPartiallyCorrect")); - question.setGeneralFeedback(JsonUtil.optString(questionJSONData, "generalFeedback", "")); - question.setMaxWordsLimit(JsonUtil.optInt(questionJSONData, "maxWordsLimit", 0)); - question.setMinWordsLimit(JsonUtil.optInt(questionJSONData, "minWordsLimit", 0)); - question.setMultipleAnswersAllowed( + question.getQbQuestion() + .setAnswerRequired(JsonUtil.optBoolean(questionJSONData, "answerRequired", Boolean.FALSE)); + question.getQbQuestion() + .setCaseSensitive(JsonUtil.optBoolean(questionJSONData, "caseSensitive", Boolean.FALSE)); + question.getQbQuestion() + .setCorrectAnswer(JsonUtil.optBoolean(questionJSONData, "correctAnswer", Boolean.FALSE)); + question.getQbQuestion().setMaxMark(JsonUtil.optInt(questionJSONData, "maxMark", 1)); + question.getQbQuestion().setFeedback(JsonUtil.optString(questionJSONData, "feedback")); + question.getQbQuestion().setFeedbackOnCorrect(JsonUtil.optString(questionJSONData, "feedbackOnCorrect")); + question.getQbQuestion() + .setFeedbackOnIncorrect(JsonUtil.optString(questionJSONData, "feedbackOnIncorrect")); + question.getQbQuestion() + .setFeedbackOnPartiallyCorrect(JsonUtil.optString(questionJSONData, "feedbackOnPartiallyCorrect")); + question.getQbQuestion().setMaxWordsLimit(JsonUtil.optInt(questionJSONData, "maxWordsLimit", 0)); + question.getQbQuestion().setMinWordsLimit(JsonUtil.optInt(questionJSONData, "minWordsLimit", 0)); + question.getQbQuestion().setMultipleAnswersAllowed( JsonUtil.optBoolean(questionJSONData, "multipleAnswersAllowed", Boolean.FALSE)); - question.setIncorrectAnswerNullifiesMark( + question.getQbQuestion().setIncorrectAnswerNullifiesMark( JsonUtil.optBoolean(questionJSONData, "incorrectAnswerNullifiesMark", Boolean.FALSE)); - question.setPenaltyFactor(JsonUtil.optDouble(questionJSONData, "penaltyFactor", 0.0).floatValue()); + question.getQbQuestion() + .setPenaltyFactor(JsonUtil.optDouble(questionJSONData, "penaltyFactor", 0.0).floatValue()); // question.setUnits(units); Needed for numerical type question - if ((type == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) - || (type == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) - || (type == AssessmentConstants.QUESTION_TYPE_NUMERICAL) - || (type == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING)) { + if ((type == QbQuestion.TYPE_MATCHING_PAIRS) + || (type == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (type == QbQuestion.TYPE_NUMERICAL) + || (type == QbQuestion.TYPE_MARK_HEDGING)) { if (!questionJSONData.has(RestTags.ANSWERS)) { throw new IOException("REST Authoring is missing answers for a question of type " + type + ". Data:" + toolContentJSON); } - Set optionList = new LinkedHashSet<>(); + List optionList = new ArrayList<>(); ArrayNode optionsData = JsonUtil.optArray(questionJSONData, RestTags.ANSWERS); for (JsonNode answerData : optionsData) { - AssessmentQuestionOption option = new AssessmentQuestionOption(); - option.setSequenceId(JsonUtil.optInt(answerData, RestTags.DISPLAY_ORDER)); - option.setGrade(answerData.get("grade").floatValue()); + QbOption option = new QbOption(); + option.setDisplayOrder(JsonUtil.optInt(answerData, RestTags.DISPLAY_ORDER)); + option.setMaxMark(answerData.get("maxMark").floatValue()); option.setCorrect(JsonUtil.optBoolean(answerData, "correct", false)); option.setAcceptedError(JsonUtil.optDouble(answerData, "acceptedError", 0.0).floatValue()); option.setFeedback(JsonUtil.optString(answerData, "feedback")); - option.setOptionString(JsonUtil.optString(answerData, RestTags.ANSWER_TEXT)); - option.setOptionFloat(JsonUtil.optDouble(answerData, "answerFloat", 0.0).floatValue()); + option.setName(JsonUtil.optString(answerData, RestTags.ANSWER_TEXT)); + option.setNumericalOption(JsonUtil.optDouble(answerData, "answerFloat", 0.0).floatValue()); // option.setQuestion(question); can't find the use for this field yet! optionList.add(option); } - question.setOptions(optionList); + question.getQbQuestion().setQbOptions(optionList); } checkType(question.getType()); @@ -3151,7 +3150,7 @@ for (JsonNode referenceJSONData : references) { QuestionReference reference = new QuestionReference(); reference.setType((short) 0); - reference.setDefaultGrade(JsonUtil.optInt(referenceJSONData, "defaultGrade", 1)); + reference.setMaxMark(JsonUtil.optInt(referenceJSONData, "maxMark", 1)); reference.setSequenceId(JsonUtil.optInt(referenceJSONData, RestTags.DISPLAY_ORDER)); AssessmentQuestion matchingQuestion = matchQuestion(newQuestionSet, JsonUtil.optInt(referenceJSONData, "questionDisplayOrder")); @@ -3173,7 +3172,7 @@ AssessmentQuestion matchQuestion(Set newReferenceSet, Integer displayOrder) { if (displayOrder != null) { for (AssessmentQuestion question : newReferenceSet) { - if (displayOrder.equals(question.getSequenceId())) { + if (displayOrder.equals(question.getDisplayOrder())) { return question; } } @@ -3182,9 +3181,9 @@ } // TODO Implement REST support for all types and then remove checkType method - void checkType(short type) throws IOException { - if ((type != AssessmentConstants.QUESTION_TYPE_ESSAY) - && (type != AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE)) { + void checkType(Integer type) throws IOException { + if ((type != QbQuestion.TYPE_ESSAY) + && (type != QbQuestion.TYPE_MULTIPLE_CHOICE)) { throw new IOException( "Assessment Tool does not support REST Authoring for anything but Essay Type and Multiple Choice. Found type " + type); @@ -3215,4 +3214,28 @@ jsonCommand.put("hookTrigger", "assessment-results-refresh-" + toolContentId); learnerService.createCommandForLearners(toolContentId, userIds, jsonCommand.toString()); } + + @Override + public int isQbQuestionModified(QbQuestion baseLine, QbQuestion modifiedQuestion) { + if (baseLine.getUid() == null) { + return IQbService.QUESTION_MODIFIED_ID_BUMP; + } + + return baseLine.isModified(modifiedQuestion) ? IQbService.QUESTION_MODIFIED_VERSION_BUMP + : IQbService.QUESTION_MODIFIED_NONE; + } + + @Override + public QbOption getQbOptionByUid(Long optionUid) { + QbOption option = (QbOption) userManagementService.findById(QbOption.class, optionUid); + releaseFromCache(option); + return option; + } + + @Override + public QbQuestionUnit getQbQuestionUnitByUid(Long unitUid) { + QbQuestionUnit unit = (QbQuestionUnit) userManagementService.findById(QbQuestionUnit.class, unitUid); + releaseFromCache(unit); + return unit; + } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java =================================================================== diff -u -r3bb7e0141ae1cc15ccd737c95d90b5762a34ad61 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java (.../IAssessmentService.java) (revision 3bb7e0141ae1cc15ccd737c95d90b5762a34ad61) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java (.../IAssessmentService.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -31,6 +31,9 @@ import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.qb.model.QbOption; +import org.lamsfoundation.lams.qb.model.QbQuestion; +import org.lamsfoundation.lams.qb.model.QbQuestionUnit; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentResultDTO; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentUserDTO; import org.lamsfoundation.lams.tool.assessment.dto.LeaderResultsDTO; @@ -367,10 +370,10 @@ * * @param assessmentUid * @param userId - * @param questionSequenceId + * @param questionDisplayOrder * @return */ - Float getQuestionResultMark(Long assessmentUid, Long userId, int questionSequenceId); + Float getQuestionResultMark(Long assessmentUid, Long userId, int questionDisplayOrder); Long createNotebookEntry(Long sessionId, Integer userId, String entryText); @@ -529,5 +532,11 @@ * to refresh page because new data is available */ void notifyLearnersOnAnswerDisclose(long toolContentId); + + int isQbQuestionModified(QbQuestion baseLine, QbQuestion modifiedQuestion); + + QbOption getQbOptionByUid(Long optionUid); + + QbQuestionUnit getQbQuestionUnitByUid(Long unitUid); } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/AssessmentEscapeUtils.java =================================================================== diff -u -r7475d08afc280b5e2e5ddf04e8bf35e3166aaf80 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/AssessmentEscapeUtils.java (.../AssessmentEscapeUtils.java) (revision 7475d08afc280b5e2e5ddf04e8bf35e3166aaf80) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/AssessmentEscapeUtils.java (.../AssessmentEscapeUtils.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -27,17 +27,16 @@ import java.util.Set; import org.apache.commons.lang.StringEscapeUtils; -import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; +import org.lamsfoundation.lams.qb.model.QbOption; +import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentResultDTO; +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.SessionDTO; import org.lamsfoundation.lams.tool.assessment.dto.UserSummary; import org.lamsfoundation.lams.tool.assessment.dto.UserSummaryItem; import org.lamsfoundation.lams.tool.assessment.model.AssessmentOptionAnswer; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionResult; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentResult; public class AssessmentEscapeUtils { @@ -81,25 +80,27 @@ String answerStringEscaped = StringEscapeUtils.escapeJavaScript(answerString); questionResult.setAnswerStringEscaped(answerStringEscaped); } + + QuestionDTO questionDto = new QuestionDTO(questionResult.getAssessmentQuestion()); + questionResult.setQuestionDto(questionDto); - AssessmentQuestion question = questionResult.getAssessmentQuestion(); - String title = question.getTitle(); + String title = questionDto.getTitle(); if (title != null) { String titleEscaped = StringEscapeUtils.escapeJavaScript(title); - question.setTitleEscaped(titleEscaped); + questionDto.setTitleEscaped(titleEscaped); } - for (AssessmentQuestionOption option : question.getOptions()) { - String questionStr = option.getQuestion(); - if (questionStr != null) { - String questionEscaped = StringEscapeUtils.escapeJavaScript(questionStr); - option.setQuestionEscaped(questionEscaped); + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + String matchingPair = optionDto.getMatchingPair(); + if (matchingPair != null) { + String matchingPairEscaped = StringEscapeUtils.escapeJavaScript(matchingPair); + optionDto.setMatchingPairEscaped(matchingPairEscaped); } - String optionStr = option.getOptionString(); - if (optionStr != null) { - String optionEscaped = StringEscapeUtils.escapeJavaScript(optionStr); - option.setOptionStringEscaped(optionEscaped); + String name = optionDto.getName(); + if (name != null) { + String nameEscaped = StringEscapeUtils.escapeJavaScript(name); + optionDto.setNameEscaped(nameEscaped); } } } @@ -110,26 +111,26 @@ if (questionResult != null) { - Set options = questionResult.getAssessmentQuestion().getOptions(); + List options = questionResult.getQbQuestion().getQbOptions(); Set optionAnswers = questionResult.getOptionAnswers(); - switch (questionResult.getAssessmentQuestion().getType()) { - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: + switch (questionResult.getQbQuestion().getType()) { + case QbQuestion.TYPE_MATCHING_PAIRS: String str = ""; if (optionAnswers != null) { - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { str += "
"; str += "
"; - str += option.getQuestion(); + str += option.getMatchingPair(); str += "
"; str += "
"; str += " - "; for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (option.getUid().equals(optionAnswer.getOptionUid())) { - for (AssessmentQuestionOption option2 : options) { + for (QbOption option2 : options) { if (option2.getUid() == optionAnswer.getAnswerInt()) { - str += option2.getOptionString(); + str += option2.getName(); } } } @@ -143,35 +144,35 @@ } return str; - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: + case QbQuestion.TYPE_MULTIPLE_CHOICE: if (optionAnswers != null) { for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (optionAnswer.getAnswerBoolean()) { - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { if (option.getUid().equals(optionAnswer.getOptionUid())) { - responseStr.append(option.getOptionString() + DELIMITER); + responseStr.append(option.getName() + DELIMITER); } } } } } break; - case AssessmentConstants.QUESTION_TYPE_NUMERICAL: - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: - case AssessmentConstants.QUESTION_TYPE_ESSAY: + case QbQuestion.TYPE_NUMERICAL: + case QbQuestion.TYPE_SHORT_ANSWER: + case QbQuestion.TYPE_ESSAY: responseStr.append(questionResult.getAnswerString()); break; - case AssessmentConstants.QUESTION_TYPE_ORDERING: + case QbQuestion.TYPE_ORDERING: if (optionAnswers != null) { for (int i = 0; i < optionAnswers.size(); i++) { for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (optionAnswer.getAnswerInt() == i) { - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { if (option.getUid().equals(optionAnswer.getOptionUid())) { - responseStr.append(option.getOptionString()); + responseStr.append(option.getName()); } } } @@ -180,19 +181,19 @@ } break; - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: + case QbQuestion.TYPE_TRUE_FALSE: if (questionResult.getAnswerString() != null) { responseStr.append(questionResult.getAnswerBoolean()); } break; - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: + case QbQuestion.TYPE_MARK_HEDGING: if (optionAnswers != null) { - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { responseStr.append("
"); responseStr.append("
"); - responseStr.append(option.getOptionString()); + responseStr.append(option.getName()); responseStr.append("
"); responseStr.append("
"); @@ -209,7 +210,7 @@ } - if (questionResult.getAssessmentQuestion().isHedgingJustificationEnabled()) { + if (questionResult.getQbQuestion().isHedgingJustificationEnabled()) { responseStr.append(questionResult.getAnswerString()); responseStr.append(DELIMITER); } @@ -230,27 +231,27 @@ Object ret = null; if (questionResult != null) { - switch (questionResult.getAssessmentQuestion().getType()) { - case AssessmentConstants.QUESTION_TYPE_ESSAY: + switch (questionResult.getQbQuestion().getType()) { + case QbQuestion.TYPE_ESSAY: String answerString = questionResult.getAnswerString(); return (answerString == null) ? "" : answerString.replaceAll("\\<.*?>", "").replaceAll(" ", " "); - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: + case QbQuestion.TYPE_MATCHING_PAIRS: return AssessmentEscapeUtils.getOptionResponse(questionResult, - AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS); - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: + QbQuestion.TYPE_MATCHING_PAIRS); + case QbQuestion.TYPE_MULTIPLE_CHOICE: return AssessmentEscapeUtils.getOptionResponse(questionResult, - AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE); - case AssessmentConstants.QUESTION_TYPE_NUMERICAL: + QbQuestion.TYPE_MULTIPLE_CHOICE); + case QbQuestion.TYPE_NUMERICAL: return questionResult.getAnswerString(); - case AssessmentConstants.QUESTION_TYPE_ORDERING: + case QbQuestion.TYPE_ORDERING: return AssessmentEscapeUtils.getOptionResponse(questionResult, - AssessmentConstants.QUESTION_TYPE_ORDERING); - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: + QbQuestion.TYPE_ORDERING); + case QbQuestion.TYPE_SHORT_ANSWER: return questionResult.getAnswerString(); - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: + case QbQuestion.TYPE_TRUE_FALSE: return questionResult.getAnswerBoolean(); - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: + case QbQuestion.TYPE_MARK_HEDGING: //taken care beforehand default: return null; @@ -262,60 +263,60 @@ /** * Used only for excell export (for getUserSummaryData() method). */ - private static String getOptionResponse(AssessmentQuestionResult questionResult, short type) { + private static String getOptionResponse(AssessmentQuestionResult questionResult, int type) { StringBuilder sb = new StringBuilder(); //whether there is a need to remove last comma boolean trimLastComma = false; - Set options = questionResult.getAssessmentQuestion().getOptions(); + List options = questionResult.getQbQuestion().getQbOptions(); Set optionAnswers = questionResult.getOptionAnswers(); if (optionAnswers != null) { - if (type == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + if (type == QbQuestion.TYPE_MULTIPLE_CHOICE) { for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (optionAnswer.getAnswerBoolean()) { - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { if (option.getUid().equals(optionAnswer.getOptionUid())) { - sb.append(option.getOptionString() + ", "); + sb.append(option.getName() + ", "); trimLastComma = true; } } } } - } else if (type == AssessmentConstants.QUESTION_TYPE_ORDERING) { + } else if (type == QbQuestion.TYPE_ORDERING) { for (int i = 0; i < optionAnswers.size(); i++) { for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (optionAnswer.getAnswerInt() == i) { - for (AssessmentQuestionOption option : options) { + for (QbOption option : options) { if (option.getUid().equals(optionAnswer.getOptionUid())) { - sb.append(option.getOptionString() + ", "); + sb.append(option.getName() + ", "); trimLastComma = true; } } } } } - } else if (type == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { + } else if (type == QbQuestion.TYPE_MATCHING_PAIRS) { - for (AssessmentQuestionOption option : options) { - sb.append("[" + option.getOptionString() + ", "); + for (QbOption option : options) { + sb.append("[" + option.getName() + ", "); for (AssessmentOptionAnswer optionAnswer : optionAnswers) { if (option.getUid().equals(optionAnswer.getOptionUid())) { - for (AssessmentQuestionOption option2 : options) { + for (QbOption option2 : options) { if (option2.getUid() == optionAnswer.getAnswerInt()) { - sb.append(option2.getOptionString() + "] "); + sb.append(option2.getName() + "] "); } } } } } - } else if (type == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + } else if (type == QbQuestion.TYPE_MARK_HEDGING) { //taken care beforehand } Fisheye: Tag 9c3a64b840753192b333afb73c8fe7bdb54be638 refers to a dead (removed) revision in file `lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/AssessmentQuestionResultComparator.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/QTIUtil.java =================================================================== diff -u -r67d7232f087b9f5c72ff41f7bbebe29cff81e099 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/QTIUtil.java (.../QTIUtil.java) (revision 67d7232f087b9f5c72ff41f7bbebe29cff81e099) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/util/QTIUtil.java (.../QTIUtil.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -12,12 +12,12 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.qb.model.QbOption; +import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.questions.Answer; import org.lamsfoundation.lams.questions.Question; import org.lamsfoundation.lams.questions.QuestionParser; -import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; public class QTIUtil { private static Logger log = Logger.getLogger(QTIUtil.class); @@ -30,149 +30,149 @@ switch (assessmentQuestion.getType()) { - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: + case QbQuestion.TYPE_MULTIPLE_CHOICE: - if (assessmentQuestion.isMultipleAnswersAllowed()) { + if (assessmentQuestion.getQbQuestion().isMultipleAnswersAllowed()) { question.setType(Question.QUESTION_TYPE_MULTIPLE_RESPONSE); int correctAnswerCount = 0; - for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getOptions()) { - if (assessmentAnswer.getGrade() > 0) { + for (QbOption assessmentAnswer : assessmentQuestion.getQbQuestion().getQbOptions()) { + if (assessmentAnswer.getMaxMark() > 0) { correctAnswerCount++; } } Float correctAnswerScore = correctAnswerCount > 0 ? Integer.valueOf(100 / correctAnswerCount).floatValue() : null; - int incorrectAnswerCount = assessmentQuestion.getOptions().size() - correctAnswerCount; + int incorrectAnswerCount = assessmentQuestion.getQbQuestion().getQbOptions().size() - correctAnswerCount; Float incorrectAnswerScore = incorrectAnswerCount > 0 ? Integer.valueOf(-100 / incorrectAnswerCount).floatValue() : null; - for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getOptions()) { + for (QbOption assessmentAnswer : assessmentQuestion.getQbQuestion().getQbOptions()) { Answer answer = new Answer(); - boolean isCorrectAnswer = assessmentAnswer.getGrade() > 0; + boolean isCorrectAnswer = assessmentAnswer.getMaxMark() > 0; - answer.setText(assessmentAnswer.getOptionString()); + answer.setText(assessmentAnswer.getName()); answer.setScore(isCorrectAnswer ? correctAnswerScore : incorrectAnswerScore); - answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getFeedbackOnCorrect() - : assessmentQuestion.getFeedbackOnIncorrect()); + answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getQbQuestion().getFeedbackOnCorrect() + : assessmentQuestion.getQbQuestion().getFeedbackOnIncorrect()); - answers.add(assessmentAnswer.getSequenceId(), answer); + answers.add(assessmentAnswer.getDisplayOrder(), answer); } } else { question.setType(Question.QUESTION_TYPE_MULTIPLE_CHOICE); - for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getOptions()) { + for (QbOption assessmentAnswer : assessmentQuestion.getQbQuestion().getQbOptions()) { Answer answer = new Answer(); - boolean isCorrectAnswer = assessmentAnswer.getGrade() == 1F; + boolean isCorrectAnswer = assessmentAnswer.getMaxMark() == 1F; - answer.setText(assessmentAnswer.getOptionString()); + answer.setText(assessmentAnswer.getName()); answer.setScore( - isCorrectAnswer ? Integer.valueOf(assessmentQuestion.getDefaultGrade()).floatValue() + isCorrectAnswer ? Integer.valueOf(assessmentQuestion.getQbQuestion().getMaxMark()).floatValue() : 0); - answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getFeedbackOnCorrect() - : assessmentQuestion.getFeedbackOnIncorrect()); + answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getQbQuestion().getFeedbackOnCorrect() + : assessmentQuestion.getQbQuestion().getFeedbackOnIncorrect()); - answers.add(assessmentAnswer.getSequenceId(), answer); + answers.add(assessmentAnswer.getDisplayOrder(), answer); } } break; - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: + case QbQuestion.TYPE_SHORT_ANSWER: question.setType(Question.QUESTION_TYPE_FILL_IN_BLANK); - for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getOptions()) { + for (QbOption assessmentAnswer : assessmentQuestion.getQbQuestion().getQbOptions()) { // only answer which has more than 0% is considered a correct one - if (assessmentAnswer.getGrade() > 0) { + if (assessmentAnswer.getMaxMark() > 0) { Answer answer = new Answer(); - answer.setText(assessmentAnswer.getOptionString()); - answer.setScore(Integer.valueOf(assessmentQuestion.getDefaultGrade()).floatValue()); + answer.setText(assessmentAnswer.getName()); + answer.setScore(Integer.valueOf(assessmentQuestion.getQbQuestion().getMaxMark()).floatValue()); answers.add(answer); } } break; - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: + case QbQuestion.TYPE_TRUE_FALSE: question.setType(Question.QUESTION_TYPE_TRUE_FALSE); - boolean isTrueCorrect = assessmentQuestion.getCorrectAnswer(); + boolean isTrueCorrect = assessmentQuestion.getQbQuestion().getCorrectAnswer(); // true/false question is basically the same for QTI, just with special answers Answer trueAnswer = new Answer(); trueAnswer.setText("True"); trueAnswer.setScore( - isTrueCorrect ? Integer.valueOf(assessmentQuestion.getDefaultGrade()).floatValue() : 0); - trueAnswer.setFeedback(isTrueCorrect ? assessmentQuestion.getFeedbackOnCorrect() - : assessmentQuestion.getFeedbackOnIncorrect()); + isTrueCorrect ? Integer.valueOf(assessmentQuestion.getQbQuestion().getMaxMark()).floatValue() : 0); + trueAnswer.setFeedback(isTrueCorrect ? assessmentQuestion.getQbQuestion().getFeedbackOnCorrect() + : assessmentQuestion.getQbQuestion().getFeedbackOnIncorrect()); answers.add(trueAnswer); Answer falseAnswer = new Answer(); falseAnswer.setText("False"); falseAnswer.setScore( - !isTrueCorrect ? Integer.valueOf(assessmentQuestion.getDefaultGrade()).floatValue() : 0); - falseAnswer.setFeedback(!isTrueCorrect ? assessmentQuestion.getFeedbackOnCorrect() - : assessmentQuestion.getFeedbackOnIncorrect()); + !isTrueCorrect ? Integer.valueOf(assessmentQuestion.getQbQuestion().getMaxMark()).floatValue() : 0); + falseAnswer.setFeedback(!isTrueCorrect ? assessmentQuestion.getQbQuestion().getFeedbackOnCorrect() + : assessmentQuestion.getQbQuestion().getFeedbackOnIncorrect()); answers.add(falseAnswer); break; - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: + case QbQuestion.TYPE_MATCHING_PAIRS: question.setType(Question.QUESTION_TYPE_MATCHING); int answerIndex = 0; - float score = assessmentQuestion.getDefaultGrade() / assessmentQuestion.getOptions().size(); - question.setMatchAnswers(new ArrayList(assessmentQuestion.getOptions().size())); + float score = assessmentQuestion.getQbQuestion().getMaxMark() / assessmentQuestion.getQbQuestion().getQbOptions().size(); + question.setMatchAnswers(new ArrayList(assessmentQuestion.getQbQuestion().getQbOptions().size())); question.setMatchMap(new TreeMap()); - for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getOptions()) { + for (QbOption assessmentAnswer : assessmentQuestion.getQbQuestion().getQbOptions()) { Answer answer = new Answer(); - answer.setText(assessmentAnswer.getQuestion()); + answer.setText(assessmentAnswer.getMatchingPair()); answer.setScore(score); answer.setFeedback(assessmentAnswer.getFeedback()); answers.add(answer); Answer matchingAnswer = new Answer(); - matchingAnswer.setText(assessmentAnswer.getOptionString()); + matchingAnswer.setText(assessmentAnswer.getName()); question.getMatchAnswers().add(matchingAnswer); question.getMatchMap().put(answerIndex, answerIndex); answerIndex++; } break; - case AssessmentConstants.QUESTION_TYPE_ESSAY: + case QbQuestion.TYPE_ESSAY: // not much to do with essay question.setType(Question.QUESTION_TYPE_ESSAY); answers = null; break; - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: + case QbQuestion.TYPE_MARK_HEDGING: question.setType(Question.QUESTION_TYPE_MARK_HEDGING); - for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getOptions()) { + for (QbOption assessmentAnswer : assessmentQuestion.getQbQuestion().getQbOptions()) { Answer answer = new Answer(); boolean isCorrectAnswer = assessmentAnswer.isCorrect(); - answer.setText(assessmentAnswer.getOptionString()); + answer.setText(assessmentAnswer.getName()); answer.setScore( - isCorrectAnswer ? Integer.valueOf(assessmentQuestion.getDefaultGrade()).floatValue() : 0); - answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getFeedbackOnCorrect() - : assessmentQuestion.getFeedbackOnIncorrect()); + isCorrectAnswer ? Integer.valueOf(assessmentQuestion.getQbQuestion().getMaxMark()).floatValue() : 0); + answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getQbQuestion().getFeedbackOnCorrect() + : assessmentQuestion.getQbQuestion().getFeedbackOnIncorrect()); - answers.add(assessmentAnswer.getSequenceId(), answer); + answers.add(assessmentAnswer.getDisplayOrder(), answer); } break; default: continue; } - question.setTitle(assessmentQuestion.getTitle()); - question.setText(assessmentQuestion.getQuestion()); - question.setFeedback(assessmentQuestion.getGeneralFeedback()); + question.setTitle(assessmentQuestion.getQbQuestion().getName()); + question.setText(assessmentQuestion.getQbQuestion().getDescription()); + question.setFeedback(assessmentQuestion.getQbQuestion().getFeedback()); question.setAnswers(answers); questions.add(question); @@ -186,20 +186,20 @@ Question[] questions = QuestionParser.parseQuestionChoiceForm(request); for (Question question : questions) { AssessmentQuestion assessmentQuestion = new AssessmentQuestion(); - int maxSeq = 0; + int maxDisplayOrder = 0; if ((questionList != null) && (questionList.size() > 0)) { AssessmentQuestion last = questionList.last(); - maxSeq = last.getSequenceId() + 1; + maxDisplayOrder = last.getDisplayOrder() + 1; } - assessmentQuestion.setSequenceId(maxSeq); - assessmentQuestion.setTitle(question.getTitle()); - assessmentQuestion.setQuestion(QuestionParser.processHTMLField(question.getText(), false, contentFolderID, + assessmentQuestion.setDisplayOrder(maxDisplayOrder); + assessmentQuestion.getQbQuestion().setName(question.getTitle()); + assessmentQuestion.getQbQuestion().setDescription(QuestionParser.processHTMLField(question.getText(), false, contentFolderID, question.getResourcesFolderPath())); - assessmentQuestion.setGeneralFeedback(QuestionParser.processHTMLField(question.getFeedback(), false, + assessmentQuestion.getQbQuestion().setFeedback(QuestionParser.processHTMLField(question.getFeedback(), false, contentFolderID, question.getResourcesFolderPath())); - assessmentQuestion.setPenaltyFactor(0); + assessmentQuestion.getQbQuestion().setPenaltyFactor(0); - int questionGrade = 1; + int questionMark = 1; // options are different depending on the type if (Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getType()) @@ -210,22 +210,22 @@ // setting answers is very similar in both types, so they were put together here if (isMarkHedgingType) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_MARK_HEDGING); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_MARK_HEDGING); } else if (isMultipleChoice) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE); - assessmentQuestion.setMultipleAnswersAllowed(false); - assessmentQuestion.setShuffle(false); - assessmentQuestion.setPrefixAnswersWithLetters(false); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_MULTIPLE_CHOICE); + assessmentQuestion.getQbQuestion().setMultipleAnswersAllowed(false); + assessmentQuestion.getQbQuestion().setShuffle(false); + assessmentQuestion.getQbQuestion().setPrefixAnswersWithLetters(false); } else { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER); - assessmentQuestion.setCaseSensitive(false); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_SHORT_ANSWER); + assessmentQuestion.getQbQuestion().setCaseSensitive(false); } String correctAnswer = null; if (question.getAnswers() != null) { - TreeSet optionList = new TreeSet<>(new SequencableComparator()); + TreeSet optionList = new TreeSet<>(); int orderId = 0; for (Answer answer : question.getAnswers()) { String answerText = QuestionParser.processHTMLField(answer.getText(), false, contentFolderID, @@ -234,32 +234,32 @@ log.warn("Skipping an answer with same text as the correct answer: " + answerText); continue; } - AssessmentQuestionOption assessmentAnswer = new AssessmentQuestionOption(); - assessmentAnswer.setOptionString(answerText); - assessmentAnswer.setSequenceId(orderId++); - assessmentAnswer.setFeedback(answer.getFeedback()); + QbOption option = new QbOption(); + option.setName(answerText); + option.setDisplayOrder(orderId++); + option.setFeedback(answer.getFeedback()); if ((answer.getScore() != null) && (answer.getScore() > 0)) { - // for fill in blanks question all answers are correct and get full grade + // for fill in blanks question all answers are correct and get full mark if (!isMultipleChoice && !isMarkHedgingType || correctAnswer == null) { // whatever the correct answer holds, it becomes the question score - questionGrade = Double.valueOf(Math.ceil(answer.getScore())).intValue(); + questionMark = Double.valueOf(Math.ceil(answer.getScore())).intValue(); // 100% goes to the correct answer - assessmentAnswer.setGrade(1); + option.setMaxMark(1); correctAnswer = answerText; } else { log.warn("Choosing only first correct answer, despite another one was found: " + answerText); - assessmentAnswer.setGrade(0); + option.setMaxMark(0); } } else { - assessmentAnswer.setGrade(0); + option.setMaxMark(0); } - optionList.add(assessmentAnswer); + optionList.add(option); } - assessmentQuestion.setOptions(optionList); + assessmentQuestion.getQbQuestion().setQbOptions(new ArrayList<>(optionList)); } if (correctAnswer == null) { @@ -268,10 +268,10 @@ } } else if (Question.QUESTION_TYPE_MULTIPLE_RESPONSE.equals(question.getType())) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE); - assessmentQuestion.setMultipleAnswersAllowed(true); - assessmentQuestion.setShuffle(false); - assessmentQuestion.setPrefixAnswersWithLetters(false); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_MULTIPLE_CHOICE); + assessmentQuestion.getQbQuestion().setMultipleAnswersAllowed(true); + assessmentQuestion.getQbQuestion().setShuffle(false); + assessmentQuestion.getQbQuestion().setPrefixAnswersWithLetters(false); if (question.getAnswers() != null) { float totalScore = 0; @@ -281,55 +281,55 @@ totalScore += answer.getScore(); } } - questionGrade = Double.valueOf(Math.round(totalScore)).intValue(); + questionMark = Double.valueOf(Math.round(totalScore)).intValue(); - TreeSet optionList = new TreeSet<>(new SequencableComparator()); + TreeSet optionList = new TreeSet<>(); int orderId = 1; for (Answer answer : question.getAnswers()) { String answerText = answer.getText(); - AssessmentQuestionOption assessmentAnswer = new AssessmentQuestionOption(); - assessmentAnswer.setOptionString(answerText); - assessmentAnswer.setSequenceId(orderId++); + QbOption assessmentAnswer = new QbOption(); + assessmentAnswer.setName(answerText); + assessmentAnswer.setDisplayOrder(orderId++); assessmentAnswer.setFeedback(answer.getFeedback()); if ((answer.getScore() != null) && (answer.getScore() > 0)) { // set the factor of score for correct answers - assessmentAnswer.setGrade(answer.getScore() / totalScore); + assessmentAnswer.setMaxMark(answer.getScore() / totalScore); } else { - assessmentAnswer.setGrade(0); + assessmentAnswer.setMaxMark(0); } optionList.add(assessmentAnswer); } - assessmentQuestion.setOptions(optionList); + assessmentQuestion.getQbQuestion().setQbOptions(new ArrayList<>(optionList)); } } else if (Question.QUESTION_TYPE_TRUE_FALSE.equals(question.getType())) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_TRUE_FALSE); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_TRUE_FALSE); if (question.getAnswers() == null) { log.warn("Answers missing from true-false question: " + question.getText()); continue; } else { for (Answer answer : question.getAnswers()) { if ((answer.getScore() != null) && (answer.getScore() > 0)) { - assessmentQuestion.setCorrectAnswer(Boolean.parseBoolean(answer.getText())); - questionGrade = Double.valueOf(Math.ceil(answer.getScore())).intValue(); + assessmentQuestion.getQbQuestion().setCorrectAnswer(Boolean.parseBoolean(answer.getText())); + questionMark = Double.valueOf(Math.ceil(answer.getScore())).intValue(); } if (!StringUtils.isBlank(answer.getFeedback())) { // set feedback for true/false answers if (Boolean.parseBoolean(answer.getText())) { - assessmentQuestion.setFeedbackOnCorrect(answer.getFeedback()); + assessmentQuestion.getQbQuestion().setFeedbackOnCorrect(answer.getFeedback()); } else { - assessmentQuestion.setFeedbackOnIncorrect(answer.getFeedback()); + assessmentQuestion.getQbQuestion().setFeedbackOnIncorrect(answer.getFeedback()); } } } } } else if (Question.QUESTION_TYPE_MATCHING.equals(question.getType())) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS); - assessmentQuestion.setShuffle(true); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_MATCHING_PAIRS); + assessmentQuestion.getQbQuestion().setShuffle(true); if (question.getAnswers() != null) { // the question score information is stored as sum of answer scores @@ -339,9 +339,9 @@ totalScore += answer.getScore(); } } - questionGrade = Double.valueOf(Math.round(totalScore)).intValue(); + questionMark = Double.valueOf(Math.round(totalScore)).intValue(); - TreeSet optionList = new TreeSet<>(new SequencableComparator()); + TreeSet optionList = new TreeSet<>(); int orderId = 1; for (int answerIndex = 0; answerIndex < question.getAnswers().size(); answerIndex++) { // QTI allows answers without a match, but LAMS assessment tool does not @@ -352,30 +352,30 @@ if (matchAnswer != null) { Answer answer = question.getAnswers().get(answerIndex); String answerText = answer.getText(); - AssessmentQuestionOption assessmentAnswer = new AssessmentQuestionOption(); - assessmentAnswer.setQuestion(answerText); - assessmentAnswer.setOptionString(matchAnswer.getText()); - assessmentAnswer.setSequenceId(orderId++); + QbOption assessmentAnswer = new QbOption(); + assessmentAnswer.setMatchingPair(answerText); + assessmentAnswer.setName(matchAnswer.getText()); + assessmentAnswer.setDisplayOrder(orderId++); assessmentAnswer.setFeedback(answer.getFeedback()); optionList.add(assessmentAnswer); } } - assessmentQuestion.setOptions(optionList); + assessmentQuestion.getQbQuestion().setQbOptions(new ArrayList<>(optionList)); } } else if (Question.QUESTION_TYPE_ESSAY.equals(question.getType())) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_ESSAY); - assessmentQuestion.setAllowRichEditor(false); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_ESSAY); + assessmentQuestion.getQbQuestion().setAllowRichEditor(false); } else if (Question.QUESTION_TYPE_ESSAY.equals(question.getType())) { - assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE); - assessmentQuestion.setShuffle(false); - assessmentQuestion.setPrefixAnswersWithLetters(false); + assessmentQuestion.getQbQuestion().setType(QbQuestion.TYPE_MULTIPLE_CHOICE); + assessmentQuestion.getQbQuestion().setShuffle(false); + assessmentQuestion.getQbQuestion().setPrefixAnswersWithLetters(false); String correctAnswer = null; if (question.getAnswers() != null) { - TreeSet optionList = new TreeSet<>(new SequencableComparator()); + TreeSet optionList = new TreeSet<>(); int orderId = 1; for (Answer answer : question.getAnswers()) { String answerText = QuestionParser.processHTMLField(answer.getText(), false, contentFolderID, @@ -384,32 +384,32 @@ log.warn("Skipping an answer with same text as the correct answer: " + answerText); continue; } - AssessmentQuestionOption assessmentAnswer = new AssessmentQuestionOption(); - assessmentAnswer.setOptionString(answerText); - assessmentAnswer.setSequenceId(orderId++); - assessmentAnswer.setFeedback(answer.getFeedback()); + QbOption option = new QbOption(); + option.setName(answerText); + option.setDisplayOrder(orderId++); + option.setFeedback(answer.getFeedback()); if ((answer.getScore() != null) && (answer.getScore() > 0)) { - // for fill in blanks question all answers are correct and get full grade + // for fill in blanks question all answers are correct and get full mark if (correctAnswer == null) { // whatever the correct answer holds, it becomes the question score - questionGrade = Double.valueOf(Math.ceil(answer.getScore())).intValue(); + questionMark = Double.valueOf(Math.ceil(answer.getScore())).intValue(); // 100% goes to the correct answer - assessmentAnswer.setGrade(1); + option.setMaxMark(1); correctAnswer = answerText; } else { log.warn("Choosing only first correct answer, despite another one was found: " + answerText); - assessmentAnswer.setGrade(0); + option.setMaxMark(0); } } else { - assessmentAnswer.setGrade(0); + option.setMaxMark(0); } - optionList.add(assessmentAnswer); + optionList.add(option); } - assessmentQuestion.setOptions(optionList); + assessmentQuestion.getQbQuestion().setQbOptions(new ArrayList<>(optionList)); } if (correctAnswer == null) { @@ -422,11 +422,11 @@ continue; } - assessmentQuestion.setDefaultGrade(questionGrade); + assessmentQuestion.getQbQuestion().setMaxMark(questionMark); questionList.add(assessmentQuestion); if (log.isDebugEnabled()) { - log.debug("Added question: " + assessmentQuestion.getTitle()); + log.debug("Added question: " + assessmentQuestion.getQbQuestion().getName()); } } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/AuthoringController.java =================================================================== diff -u -r72af36328cce2e7260d7466f9276fc2982ce3195 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 72af36328cce2e7260d7466f9276fc2982ce3195) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/AuthoringController.java (.../AuthoringController.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -31,17 +31,16 @@ import java.net.URLDecoder; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; -import java.util.TreeMap; import java.util.TreeSet; import javax.servlet.ServletException; @@ -55,19 +54,17 @@ import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.qb.model.QbOption; import org.lamsfoundation.lams.qb.model.QbQuestion; +import org.lamsfoundation.lams.qb.model.QbQuestionUnit; import org.lamsfoundation.lams.qb.service.IQbService; -import org.lamsfoundation.lams.questions.Answer; import org.lamsfoundation.lams.questions.Question; import org.lamsfoundation.lams.questions.QuestionExporter; -import org.lamsfoundation.lams.questions.QuestionParser; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.model.Assessment; import org.lamsfoundation.lams.tool.assessment.model.AssessmentOverallFeedback; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentUnit; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; import org.lamsfoundation.lams.tool.assessment.service.IAssessmentService; @@ -239,15 +236,16 @@ Set oldReferences = (assessmentPO == null) ? new HashSet<>() : assessmentPO.getQuestionReferences(); - //allow using old and modified questions and references altogether - if (mode.isTeacher()) { - for (AssessmentQuestion question : oldQuestions) { - service.releaseFromCache(question); - } - for (QuestionReference reference : oldReferences) { - service.releaseFromCache(reference); - } - } + //TODO remove +// //allow using old and modified questions and references altogether +// if (mode.isTeacher()) { +// for (AssessmentQuestion question : oldQuestions) { +// service.releaseFromCache(question); +// } +// for (QuestionReference reference : oldReferences) { +// service.releaseFromCache(reference); +// } +// } AssessmentUser assessmentUser = null; @@ -257,6 +255,17 @@ assessmentPO.setCreated(new Timestamp(new Date().getTime())); } else { + // copyProperties() below sets assessmentPO items to empty collection + // but the items still exist in Hibernate cache, so we need to evict them now + for (AssessmentQuestion question : oldQuestions) { + service.releaseFromCache(question); + service.releaseFromCache(question.getQbQuestion()); + } + for (QuestionReference reference : oldReferences) { + service.releaseFromCache(reference); + } + assessmentPO.getQuestions().clear(); + Long uid = assessmentPO.getUid(); assessmentUser = assessmentPO.getCreatedBy(); PropertyUtils.copyProperties(assessmentPO, assessment); @@ -292,11 +301,34 @@ // ************************* Handle assessment questions ******************* Set newQuestions = getQuestionList(sessionMap); for (AssessmentQuestion question : newQuestions) { + question.setToolContentId(assessmentPO.getContentId()); removeNewLineCharacters(question); + // modification status was already set in AuthoringController#saveItem() + switch (question.getQbQuestionModified()) { + case IQbService.QUESTION_MODIFIED_VERSION_BUMP: { + // new version of the old question gets created + QbQuestion qbQuestion = question.getQbQuestion().clone(); + question.setQbQuestion(qbQuestion); + qbQuestion.clearID(); + qbQuestion.setVersion(qbService.getMaxQuestionVersion(qbQuestion.getQuestionId())); + qbQuestion.setCreateDate(new Date()); + } + break; + case IQbService.QUESTION_MODIFIED_ID_BUMP: { + // new question gets created + QbQuestion qbQuestion = question.getQbQuestion().clone(); + question.setQbQuestion(qbQuestion); + qbQuestion.clearID(); + qbQuestion.setVersion(1); + qbQuestion.setQuestionId(qbService.getMaxQuestionId()); + qbQuestion.setCreateDate(new Date()); + } + break; + } } assessmentPO.setQuestions(newQuestions); - Set newReferences = updateQuestionReferencesGrades(request, sessionMap, true); + Set newReferences = updateQuestionReferencesMaxMarks(request, sessionMap, true); //recalculate results in case content is edited from monitoring and it's been already attempted by a student boolean isAuthoringRestricted = (boolean) sessionMap.get(AssessmentConstants.ATTR_IS_AUTHORING_RESTRICTED); @@ -353,38 +385,37 @@ HttpServletRequest request) { String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesGrades(request, sessionMap, false); + updateQuestionReferencesMaxMarks(request, sessionMap, false); String contentFolderID = (String) sessionMap.get(AttributeNames.PARAM_CONTENT_FOLDER_ID); questionForm.setSessionMapID(sessionMapID); - questionForm.setSequenceId(-1);//which signifies it's a new question + questionForm.setDisplayOrder(-1);//which signifies it's a new question questionForm.setContentFolderID(contentFolderID); - questionForm.setDefaultGrade("1"); + questionForm.setMaxMark("1"); questionForm.setPenaltyFactor("0"); questionForm.setAnswerRequired(true); - List optionList = new ArrayList<>(); + List optionList = new ArrayList<>(); for (int i = 0; i < AssessmentConstants.INITIAL_OPTIONS_NUMBER; i++) { - AssessmentQuestionOption option = new AssessmentQuestionOption(); - option.setSequenceId(i + 1); - option.setGrade(0); + QbOption option = new QbOption(); + option.setDisplayOrder(i + 1); optionList.add(option); } request.setAttribute(AssessmentConstants.ATTR_OPTION_LIST, optionList); - List unitList = new ArrayList<>(); - AssessmentUnit unit = new AssessmentUnit(); - unit.setSequenceId(1); + List unitList = new ArrayList<>(); + QbQuestionUnit unit = new QbQuestionUnit(); + unit.setDisplayOrder(1); unit.setMultiplier(1); unitList.add(unit); for (int i = 1; i < AssessmentConstants.INITIAL_UNITS_NUMBER; i++) { - unit = new AssessmentUnit(); - unit.setSequenceId(i + 1); + unit = new QbQuestionUnit(); + unit.setDisplayOrder(i + 1); unit.setMultiplier(0); unitList.add(unit); } request.setAttribute(AssessmentConstants.ATTR_UNIT_LIST, unitList); - short type = (short) NumberUtils.toInt(request.getParameter(AssessmentConstants.ATTR_QUESTION_TYPE)); + Integer type = NumberUtils.toInt(request.getParameter(AssessmentConstants.ATTR_QUESTION_TYPE)); sessionMap.put(AssessmentConstants.ATTR_QUESTION_TYPE, type); request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, contentFolderID); return findForward(type); @@ -397,19 +428,19 @@ public String editQuestion(@ModelAttribute("assessmentQuestionForm") AssessmentQuestionForm questionForm, HttpServletRequest request) { SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesGrades(request, sessionMap, false); + updateQuestionReferencesMaxMarks(request, sessionMap, false); SortedSet questionList = getQuestionList(sessionMap); - int questionSequenceId = WebUtil.readIntParam(request, AssessmentConstants.PARAM_QUESTION_SEQUENCE_ID); + int questionDisplayOrder = WebUtil.readIntParam(request, AssessmentConstants.PARAM_QUESTION_DISPLAY_ORDER); AssessmentQuestion question = null; for (AssessmentQuestion questionIter : questionList) { - if (questionIter.getSequenceId() == questionSequenceId) { + if (questionIter.getDisplayOrder() == questionDisplayOrder) { question = questionIter; break; } } if (question == null) { - throw new RuntimeException("Question with sequenceId:" + questionSequenceId + " was not found!"); + throw new RuntimeException("Question with displayOrder:" + questionDisplayOrder + " was not found!"); } populateQuestionToForm(question, questionForm, request); @@ -548,15 +579,15 @@ @RequestMapping("/removeQuestion") public String removeQuestion(HttpServletRequest request) { SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesGrades(request, sessionMap, false); + updateQuestionReferencesMaxMarks(request, sessionMap, false); - int deletedQuestionSequenceId = NumberUtils.toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_SEQUENCE_ID), -1); + int deletedQuestionDisplayOrder = NumberUtils.toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_DISPLAY_ORDER), -1); SortedSet questionList = getQuestionList(sessionMap); Iterator iterator = questionList.iterator(); AssessmentQuestion deletedQuestion = null; while (iterator.hasNext()) { AssessmentQuestion questionIter = iterator.next(); - if (questionIter.getSequenceId() == deletedQuestionSequenceId) { + if (questionIter.getDisplayOrder() == deletedQuestionDisplayOrder) { deletedQuestion = questionIter; iterator.remove(); } @@ -571,7 +602,7 @@ QuestionReference questionReferenceToDelete = null; for (QuestionReference questionReference : questionReferences) { if ((questionReference.getQuestion() != null) - && (questionReference.getQuestion().getSequenceId() == deletedQuestionSequenceId)) { + && (questionReference.getQuestion().getDisplayOrder() == deletedQuestionDisplayOrder)) { questionReferenceToDelete = questionReference; } } @@ -603,7 +634,7 @@ @RequestMapping("/addQuestionReference") public String addQuestionReference(HttpServletRequest request) { SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesGrades(request, sessionMap, false); + updateQuestionReferencesMaxMarks(request, sessionMap, false); SortedSet references = getQuestionReferences(sessionMap); int questionIdx = NumberUtils.toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_INDEX), -1); @@ -622,19 +653,19 @@ reference.setRandomQuestion(isRandomQuestion); if (isRandomQuestion) { - reference.setDefaultGrade(1); + reference.setMaxMark(1); } else { SortedSet questionList = getQuestionList(sessionMap); AssessmentQuestion question = null; for (AssessmentQuestion questionFromList : questionList) { - if (questionFromList.getSequenceId() == questionIdx) { + if (questionFromList.getDisplayOrder() == questionIdx) { question = questionFromList; break; } } reference.setQuestion(question); - reference.setDefaultGrade(question.getDefaultGrade()); + reference.setMaxMark(question.getQbQuestion().getMaxMark()); } references.add(reference); @@ -650,7 +681,7 @@ @RequestMapping("/removeQuestionReference") public String removeQuestionReference(HttpServletRequest request) { SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesGrades(request, sessionMap, false); + updateQuestionReferencesMaxMarks(request, sessionMap, false); int questionReferenceIdx = NumberUtils .toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_REFERENCE_INDEX), -1); @@ -688,7 +719,7 @@ private String switchQuestionReferences(HttpServletRequest request, boolean up) { SessionMap sessionMap = getSessionMap(request); - updateQuestionReferencesGrades(request, sessionMap, false); + updateQuestionReferencesMaxMarks(request, sessionMap, false); int questionReferenceIdx = NumberUtils .toInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_REFERENCE_INDEX), -1); @@ -766,9 +797,9 @@ int maxSeq = 1; if ((oldQuestions != null) && (oldQuestions.size() > 0)) { AssessmentQuestion last = oldQuestions.last(); - maxSeq = last.getSequenceId() + 1; + maxSeq = last.getDisplayOrder() + 1; } - question.setSequenceId(maxSeq); + question.setDisplayOrder(maxSeq); oldQuestions.add(question); } } @@ -858,15 +889,14 @@ */ @RequestMapping("/addOption") public String addOption(HttpServletRequest request) { - TreeSet optionList = getOptionsFromRequest(request, false); - AssessmentQuestionOption option = new AssessmentQuestionOption(); + TreeSet optionList = getOptionsFromRequest(request, false); + QbOption option = new QbOption(); int maxSeq = 1; if ((optionList != null) && (optionList.size() > 0)) { - AssessmentQuestionOption last = optionList.last(); - maxSeq = last.getSequenceId() + 1; + QbOption last = optionList.last(); + maxSeq = last.getDisplayOrder() + 1; } - option.setSequenceId(maxSeq); - option.setGrade(0); + option.setDisplayOrder(maxSeq); optionList.add(option); request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, @@ -882,14 +912,14 @@ */ @RequestMapping("/newUnit") public String newUnit(HttpServletRequest request) { - TreeSet unitList = getUnitsFromRequest(request, false); - AssessmentUnit unit = new AssessmentUnit(); + TreeSet unitList = getUnitsFromRequest(request, false); + QbQuestionUnit unit = new QbQuestionUnit(); int maxSeq = 1; if ((unitList != null) && (unitList.size() > 0)) { - AssessmentUnit last = unitList.last(); - maxSeq = last.getSequenceId() + 1; + QbQuestionUnit last = unitList.last(); + maxSeq = last.getDisplayOrder() + 1; } - unit.setSequenceId(maxSeq); + unit.setDisplayOrder(maxSeq); unitList.add(unit); request.setAttribute(AssessmentConstants.ATTR_UNIT_LIST, unitList); @@ -959,7 +989,7 @@ questionsFromList.add(reference.getQuestion()); } - Set availableQuestions = new TreeSet<>(new SequencableComparator()); + Set availableQuestions = new TreeSet<>(); availableQuestions.addAll(CollectionUtils.subtract(bankQuestions, questionsFromList)); sessionMap.put(AssessmentConstants.ATTR_AVAILABLE_QUESTIONS, availableQuestions); @@ -973,7 +1003,7 @@ SortedSet list = (SortedSet) sessionMap .get(AssessmentConstants.ATTR_QUESTION_LIST); if (list == null) { - list = new TreeSet<>(new SequencableComparator()); + list = new TreeSet<>(); sessionMap.put(AssessmentConstants.ATTR_QUESTION_LIST, list); } return list; @@ -1024,31 +1054,31 @@ /** * Get back jsp name. */ - private String findForward(short type) { + private String findForward(Integer type) { String forward; switch (type) { - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: + case QbQuestion.TYPE_MULTIPLE_CHOICE: forward = "pages/authoring/parts/addmultiplechoice"; break; - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: + case QbQuestion.TYPE_MATCHING_PAIRS: forward = "pages/authoring/parts/addmatchingpairs"; break; - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: + case QbQuestion.TYPE_SHORT_ANSWER: forward = "pages/authoring/parts/addshortanswer"; break; - case AssessmentConstants.QUESTION_TYPE_NUMERICAL: + case QbQuestion.TYPE_NUMERICAL: forward = "pages/authoring/parts/addnumerical"; break; - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: + case QbQuestion.TYPE_TRUE_FALSE: forward = "pages/authoring/parts/addtruefalse"; break; - case AssessmentConstants.QUESTION_TYPE_ESSAY: + case QbQuestion.TYPE_ESSAY: forward = "pages/authoring/parts/addessay"; break; - case AssessmentConstants.QUESTION_TYPE_ORDERING: + case QbQuestion.TYPE_ORDERING: forward = "pages/authoring/parts/addordering"; break; - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: + case QbQuestion.TYPE_MARK_HEDGING: forward = "pages/authoring/parts/addmarkhedging"; break; default: @@ -1063,40 +1093,39 @@ */ private void populateQuestionToForm(AssessmentQuestion question, AssessmentQuestionForm form, HttpServletRequest request) { - form.setTitle(question.getTitle()); - form.setQuestion(question.getQuestion()); - form.setDefaultGrade(String.valueOf(question.getDefaultGrade())); - form.setPenaltyFactor(String.valueOf(question.getPenaltyFactor())); - form.setAnswerRequired(question.isAnswerRequired()); - form.setGeneralFeedback(question.getGeneralFeedback()); - form.setFeedback(question.getFeedback()); - form.setMultipleAnswersAllowed(question.isMultipleAnswersAllowed()); - form.setIncorrectAnswerNullifiesMark(question.isIncorrectAnswerNullifiesMark()); - form.setFeedbackOnCorrect(question.getFeedbackOnCorrect()); - form.setFeedbackOnPartiallyCorrect(question.getFeedbackOnPartiallyCorrect()); - form.setFeedbackOnIncorrect(question.getFeedbackOnIncorrect()); - form.setShuffle(question.isShuffle()); - form.setPrefixAnswersWithLetters(question.isPrefixAnswersWithLetters()); - form.setCaseSensitive(question.isCaseSensitive()); - form.setCorrectAnswer(question.getCorrectAnswer()); - form.setAllowRichEditor(question.isAllowRichEditor()); - form.setMaxWordsLimit(question.getMaxWordsLimit()); - form.setMinWordsLimit(question.getMinWordsLimit()); - form.setHedgingJustificationEnabled(question.isHedgingJustificationEnabled()); - form.setSequenceId(question.getSequenceId()); + form.setTitle(question.getQbQuestion().getName()); + form.setQuestion(question.getQbQuestion().getDescription()); + form.setMaxMark(String.valueOf(question.getQbQuestion().getMaxMark())); + form.setPenaltyFactor(String.valueOf(question.getQbQuestion().getPenaltyFactor())); + form.setAnswerRequired(question.getQbQuestion().isAnswerRequired()); + form.setFeedback(question.getQbQuestion().getFeedback()); + form.setMultipleAnswersAllowed(question.getQbQuestion().isMultipleAnswersAllowed()); + form.setIncorrectAnswerNullifiesMark(question.getQbQuestion().isIncorrectAnswerNullifiesMark()); + form.setFeedbackOnCorrect(question.getQbQuestion().getFeedbackOnCorrect()); + form.setFeedbackOnPartiallyCorrect(question.getQbQuestion().getFeedbackOnPartiallyCorrect()); + form.setFeedbackOnIncorrect(question.getQbQuestion().getFeedbackOnIncorrect()); + form.setShuffle(question.getQbQuestion().isShuffle()); + form.setPrefixAnswersWithLetters(question.getQbQuestion().isPrefixAnswersWithLetters()); + form.setCaseSensitive(question.getQbQuestion().isCaseSensitive()); + form.setCorrectAnswer(question.getQbQuestion().getCorrectAnswer()); + form.setAllowRichEditor(question.getQbQuestion().isAllowRichEditor()); + form.setMaxWordsLimit(question.getQbQuestion().getMaxWordsLimit()); + form.setMinWordsLimit(question.getQbQuestion().getMinWordsLimit()); + form.setHedgingJustificationEnabled(question.getQbQuestion().isHedgingJustificationEnabled()); + form.setDisplayOrder(question.getDisplayOrder()); - short questionType = question.getType(); - if ((questionType == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) - || (questionType == AssessmentConstants.QUESTION_TYPE_ORDERING) - || (questionType == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) - || (questionType == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) - || (questionType == AssessmentConstants.QUESTION_TYPE_NUMERICAL) - || (questionType == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING)) { - Set optionList = question.getOptions(); + Integer questionType = question.getType(); + if ((questionType == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (questionType == QbQuestion.TYPE_ORDERING) + || (questionType == QbQuestion.TYPE_MATCHING_PAIRS) + || (questionType == QbQuestion.TYPE_SHORT_ANSWER) + || (questionType == QbQuestion.TYPE_NUMERICAL) + || (questionType == QbQuestion.TYPE_MARK_HEDGING)) { + List optionList = question.getQbQuestion().getQbOptions(); request.setAttribute(AssessmentConstants.ATTR_OPTION_LIST, optionList); } - if (questionType == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { - Set unitList = question.getUnits(); + if (questionType == QbQuestion.TYPE_NUMERICAL) { + List unitList = question.getQbQuestion().getUnits(); request.setAttribute(AssessmentConstants.ATTR_UNIT_LIST, unitList); } } @@ -1114,127 +1143,138 @@ //find according question AssessmentQuestion question = null; // add - if (questionForm.getSequenceId() == -1) { + if (questionForm.getDisplayOrder() == -1) { question = new AssessmentQuestion(); + QbQuestion qbQuestion = new QbQuestion(); + qbQuestion.setType(questionForm.getQuestionType()); + question.setQbQuestion(qbQuestion); int maxSeq = 1; if ((questionList != null) && (questionList.size() > 0)) { AssessmentQuestion last = questionList.last(); - maxSeq = last.getSequenceId() + 1; + maxSeq = last.getDisplayOrder() + 1; } - question.setSequenceId(maxSeq); + question.setDisplayOrder(maxSeq); questionList.add(question); // edit } else { for (AssessmentQuestion questionIter : questionList) { - if (questionIter.getSequenceId() == questionForm.getSequenceId()) { + if (questionIter.getDisplayOrder() == questionForm.getDisplayOrder()) { question = questionIter; break; } } } - short type = questionForm.getQuestionType(); - question.setType(type); + QbQuestion baseLine = question.getQbQuestion().clone(); + // evict everything manually as we do not use DTOs, just real entities + // without eviction changes would be saved immediately into DB + service.releaseFromCache(question); + service.releaseFromCache(baseLine); + service.releaseFromCache(question.getQbQuestion()); - question.setTitle(questionForm.getTitle()); - question.setQuestion(questionForm.getQuestion()); + question.getQbQuestion().setName(questionForm.getTitle()); + question.getQbQuestion().setDescription(questionForm.getQuestion()); if (!isAuthoringRestricted) { - question.setDefaultGrade(Integer.parseInt(questionForm.getDefaultGrade())); + question.getQbQuestion().setMaxMark(Integer.parseInt(questionForm.getMaxMark())); } - question.setGeneralFeedback(questionForm.getGeneralFeedback()); - question.setAnswerRequired(questionForm.isAnswerRequired()); + question.getQbQuestion().setFeedback(questionForm.getFeedback()); + question.getQbQuestion().setAnswerRequired(questionForm.isAnswerRequired()); - if (type == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { - question.setMultipleAnswersAllowed(questionForm.isMultipleAnswersAllowed()); + Integer type = questionForm.getQuestionType(); + if (type == QbQuestion.TYPE_MULTIPLE_CHOICE) { + question.getQbQuestion().setMultipleAnswersAllowed(questionForm.isMultipleAnswersAllowed()); boolean incorrectAnswerNullifiesMark = questionForm.isMultipleAnswersAllowed() ? questionForm.isIncorrectAnswerNullifiesMark() : false; - question.setIncorrectAnswerNullifiesMark(incorrectAnswerNullifiesMark); - question.setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); - question.setShuffle(questionForm.isShuffle()); - question.setPrefixAnswersWithLetters(questionForm.isPrefixAnswersWithLetters()); - question.setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); - question.setFeedbackOnPartiallyCorrect(questionForm.getFeedbackOnPartiallyCorrect()); - question.setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); - } else if ((type == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS)) { - question.setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); - question.setShuffle(questionForm.isShuffle()); - } else if ((type == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER)) { - question.setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); - question.setCaseSensitive(questionForm.isCaseSensitive()); - } else if ((type == AssessmentConstants.QUESTION_TYPE_NUMERICAL)) { - question.setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); - } else if ((type == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE)) { - question.setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); - question.setCorrectAnswer(questionForm.isCorrectAnswer()); - question.setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); - question.setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); - } else if ((type == AssessmentConstants.QUESTION_TYPE_ESSAY)) { - question.setAllowRichEditor(questionForm.isAllowRichEditor()); - question.setMaxWordsLimit(questionForm.getMaxWordsLimit()); - question.setMinWordsLimit(questionForm.getMinWordsLimit()); - } else if (type == AssessmentConstants.QUESTION_TYPE_ORDERING) { - question.setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); - question.setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); - question.setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); - } else if (type == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { - question.setShuffle(questionForm.isShuffle()); - question.setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); - question.setFeedbackOnPartiallyCorrect(questionForm.getFeedbackOnPartiallyCorrect()); - question.setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); - question.setHedgingJustificationEnabled(questionForm.isHedgingJustificationEnabled()); + question.getQbQuestion().setIncorrectAnswerNullifiesMark(incorrectAnswerNullifiesMark); + question.getQbQuestion().setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); + question.getQbQuestion().setShuffle(questionForm.isShuffle()); + question.getQbQuestion().setPrefixAnswersWithLetters(questionForm.isPrefixAnswersWithLetters()); + question.getQbQuestion().setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); + question.getQbQuestion().setFeedbackOnPartiallyCorrect(questionForm.getFeedbackOnPartiallyCorrect()); + question.getQbQuestion().setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); + } else if ((type == QbQuestion.TYPE_MATCHING_PAIRS)) { + question.getQbQuestion().setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); + question.getQbQuestion().setShuffle(questionForm.isShuffle()); + } else if ((type == QbQuestion.TYPE_SHORT_ANSWER)) { + question.getQbQuestion().setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); + question.getQbQuestion().setCaseSensitive(questionForm.isCaseSensitive()); + } else if ((type == QbQuestion.TYPE_NUMERICAL)) { + question.getQbQuestion().setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); + } else if ((type == QbQuestion.TYPE_TRUE_FALSE)) { + question.getQbQuestion().setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); + question.getQbQuestion().setCorrectAnswer(questionForm.isCorrectAnswer()); + question.getQbQuestion().setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); + question.getQbQuestion().setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); + } else if ((type == QbQuestion.TYPE_ESSAY)) { + question.getQbQuestion().setAllowRichEditor(questionForm.isAllowRichEditor()); + question.getQbQuestion().setMaxWordsLimit(questionForm.getMaxWordsLimit()); + question.getQbQuestion().setMinWordsLimit(questionForm.getMinWordsLimit()); + } else if (type == QbQuestion.TYPE_ORDERING) { + question.getQbQuestion().setPenaltyFactor(Float.parseFloat(questionForm.getPenaltyFactor())); + question.getQbQuestion().setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); + question.getQbQuestion().setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); + } else if (type == QbQuestion.TYPE_MARK_HEDGING) { + question.getQbQuestion().setShuffle(questionForm.isShuffle()); + question.getQbQuestion().setFeedbackOnCorrect(questionForm.getFeedbackOnCorrect()); + question.getQbQuestion().setFeedbackOnPartiallyCorrect(questionForm.getFeedbackOnPartiallyCorrect()); + question.getQbQuestion().setFeedbackOnIncorrect(questionForm.getFeedbackOnIncorrect()); + question.getQbQuestion().setHedgingJustificationEnabled(questionForm.isHedgingJustificationEnabled()); } // set options - if ((type == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) - || (type == AssessmentConstants.QUESTION_TYPE_ORDERING) - || (type == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) - || (type == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) - || (type == AssessmentConstants.QUESTION_TYPE_NUMERICAL) - || (type == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING)) { - Set optionList = getOptionsFromRequest(request, true); - Set options = new LinkedHashSet<>(); - int seqId = 0; - for (AssessmentQuestionOption option : optionList) { - option.setSequenceId(seqId++); + if ((type == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (type == QbQuestion.TYPE_ORDERING) + || (type == QbQuestion.TYPE_MATCHING_PAIRS) + || (type == QbQuestion.TYPE_SHORT_ANSWER) + || (type == QbQuestion.TYPE_NUMERICAL) + || (type == QbQuestion.TYPE_MARK_HEDGING)) { + Set optionList = getOptionsFromRequest(request, true); + List options = new ArrayList<>(); + int displayOrder = 0; + for (QbOption option : optionList) { + option.setDisplayOrder(displayOrder++); options.add(option); } - question.setOptions(options); + question.getQbQuestion().setQbOptions(options); } // set units - if (type == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { - Set unitList = getUnitsFromRequest(request, true); - Set units = new LinkedHashSet<>(); - int seqId = 0; - for (AssessmentUnit unit : unitList) { - unit.setSequenceId(seqId++); + if (type == QbQuestion.TYPE_NUMERICAL) { + Set unitList = getUnitsFromRequest(request, true); + List units = new ArrayList<>(); + int displayOrder = 0; + for (QbQuestionUnit unit : unitList) { + unit.setDisplayOrder(displayOrder++); units.add(unit); } - question.setUnits(units); + question.getQbQuestion().setUnits(units); } - + + question.setQbQuestionModified(service.isQbQuestionModified(baseLine, question.getQbQuestion())); + //TODO ????qbQuestionModified + request.setAttribute("qbQuestionModified", question.getQbQuestionModified()); } - private Set updateQuestionReferencesGrades(HttpServletRequest request, + private Set updateQuestionReferencesMaxMarks(HttpServletRequest request, SessionMap sessionMap, boolean isFormSubmit) { Map paramMap = splitRequestParameter(request, - AssessmentConstants.ATTR_QUESTION_REFERENCES_GRADES); + AssessmentConstants.ATTR_QUESTION_REFERENCES_MAX_MARKS); SortedSet questionReferences = getQuestionReferences(sessionMap); for (QuestionReference questionReference : questionReferences) { try { - int grade; + int maxMark; if (isFormSubmit) { - grade = WebUtil.readIntParam(request, - AssessmentConstants.PARAM_GRADE + questionReference.getSequenceId()); + maxMark = WebUtil.readIntParam(request, + AssessmentConstants.PARAM_MAX_MARK + questionReference.getSequenceId()); } else { - String gradeStr = paramMap.get(AssessmentConstants.PARAM_GRADE + questionReference.getSequenceId()); - grade = Integer.valueOf(gradeStr); + String maxMarkStr = paramMap.get(AssessmentConstants.PARAM_MAX_MARK + questionReference.getSequenceId()); + maxMark = Integer.valueOf(maxMarkStr); } - questionReference.setDefaultGrade(grade); + questionReference.setMaxMark(maxMark); } catch (Exception e) { log.debug(e.getMessage()); } @@ -1250,95 +1290,97 @@ * @param isForSaving * whether the blank options will be preserved or not */ - private TreeSet getOptionsFromRequest(HttpServletRequest request, boolean isForSaving) { + private TreeSet getOptionsFromRequest(HttpServletRequest request, boolean isForSaving) { Map paramMap = splitRequestParameter(request, AssessmentConstants.ATTR_OPTION_LIST); int count = NumberUtils.toInt(paramMap.get(AssessmentConstants.ATTR_OPTION_COUNT)); int questionType = WebUtil.readIntParam(request, AssessmentConstants.ATTR_QUESTION_TYPE); Integer correctOptionIndex = (paramMap.get(AssessmentConstants.ATTR_OPTION_CORRECT) == null) ? null : NumberUtils.toInt(paramMap.get(AssessmentConstants.ATTR_OPTION_CORRECT)); - TreeSet optionList = new TreeSet<>(new SequencableComparator()); + TreeSet optionList = new TreeSet<>(); for (int i = 0; i < count; i++) { - AssessmentQuestionOption option = new AssessmentQuestionOption(); - String sequenceId = paramMap.get(AssessmentConstants.ATTR_OPTION_SEQUENCE_ID_PREFIX + i); - //sequenceId is null, in case this item was removed using Remove button - if (sequenceId == null) { + String displayOrder = paramMap.get(AssessmentConstants.ATTR_OPTION_DISPLAY_ORDER_PREFIX + i); + //displayOrder is null, in case this item was removed using Remove button + if (displayOrder == null) { continue; - } else { - option.setSequenceId(NumberUtils.toInt(sequenceId)); } - String uid = paramMap.get(AssessmentConstants.ATTR_OPTION_UID_PREFIX + i); - if (uid != null) { - option.setUid(NumberUtils.toLong(uid)); + QbOption option = null; + String uidStr = paramMap.get(AssessmentConstants.ATTR_OPTION_UID_PREFIX + i); + if (uidStr != null) { + Long uid = NumberUtils.toLong(uidStr); + option = service.getQbOptionByUid(uid); + service.releaseFromCache(option.getQbQuestion()); + + } else { + option = new QbOption(); } + option.setDisplayOrder(NumberUtils.toInt(displayOrder)); - if ((questionType == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) - || (questionType == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER)) { - String optionString = paramMap.get(AssessmentConstants.ATTR_OPTION_STRING_PREFIX + i); - if ((optionString == null) && isForSaving) { + if ((questionType == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (questionType == QbQuestion.TYPE_SHORT_ANSWER)) { + String name = paramMap.get(AssessmentConstants.ATTR_OPTION_NAME_PREFIX + i); + if ((name == null) && isForSaving) { continue; } - option.setOptionString(optionString); - float grade = Float.valueOf(paramMap.get(AssessmentConstants.ATTR_OPTION_GRADE_PREFIX + i)); - option.setGrade(grade); + option.setName(name); + float maxMark = Float.valueOf(paramMap.get(AssessmentConstants.ATTR_OPTION_MAX_MARK_PREFIX + i)); + option.setMaxMark(maxMark); option.setFeedback(paramMap.get(AssessmentConstants.ATTR_OPTION_FEEDBACK_PREFIX + i)); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { - String question = paramMap.get(AssessmentConstants.ATTR_OPTION_QUESTION_PREFIX + i); - if ((question == null) && isForSaving) { + } else if (questionType == QbQuestion.TYPE_MATCHING_PAIRS) { + String matchingPair = paramMap.get(AssessmentConstants.ATTR_MATCHING_PAIR_PREFIX + i); + if ((matchingPair == null) && isForSaving) { continue; } - option.setOptionString(paramMap.get(AssessmentConstants.ATTR_OPTION_STRING_PREFIX + i)); - option.setQuestion(question); + option.setName(paramMap.get(AssessmentConstants.ATTR_OPTION_NAME_PREFIX + i)); + option.setMatchingPair(matchingPair); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { - String optionFloatStr = paramMap.get(AssessmentConstants.ATTR_OPTION_FLOAT_PREFIX + i); + } else if (questionType == QbQuestion.TYPE_NUMERICAL) { + String numericalOptionStr = paramMap.get(AssessmentConstants.ATTR_NUMERICAL_OPTION_PREFIX + i); String acceptedErrorStr = paramMap.get(AssessmentConstants.ATTR_OPTION_ACCEPTED_ERROR_PREFIX + i); - String gradeStr = paramMap.get(AssessmentConstants.ATTR_OPTION_GRADE_PREFIX + i); - if (optionFloatStr.equals("0.0") && optionFloatStr.equals("0.0") && gradeStr.equals("0.0") + String maxMarkStr = paramMap.get(AssessmentConstants.ATTR_OPTION_MAX_MARK_PREFIX + i); + if (numericalOptionStr.equals("0.0") && numericalOptionStr.equals("0.0") && maxMarkStr.equals("0.0") && isForSaving) { continue; } try { - float optionFloat = Float.valueOf(optionFloatStr); - option.setOptionFloat(optionFloat); + float numericalOption = Float.valueOf(numericalOptionStr); + option.setNumericalOption(numericalOption); } catch (Exception e) { - option.setOptionFloat(0); + option.setNumericalOption(0); } try { float acceptedError = Float.valueOf(acceptedErrorStr); option.setAcceptedError(acceptedError); } catch (Exception e) { option.setAcceptedError(0); } - float grade = Float.valueOf(paramMap.get(AssessmentConstants.ATTR_OPTION_GRADE_PREFIX + i)); - option.setGrade(grade); + float maxMark = Float.valueOf(paramMap.get(AssessmentConstants.ATTR_OPTION_MAX_MARK_PREFIX + i)); + option.setMaxMark(maxMark); option.setFeedback(paramMap.get(AssessmentConstants.ATTR_OPTION_FEEDBACK_PREFIX + i)); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_ORDERING) { - String optionString = paramMap.get(AssessmentConstants.ATTR_OPTION_STRING_PREFIX + i); - if ((optionString == null) && isForSaving) { + } else if (questionType == QbQuestion.TYPE_ORDERING) { + String name = paramMap.get(AssessmentConstants.ATTR_OPTION_NAME_PREFIX + i); + if ((name == null) && isForSaving) { continue; } - option.setOptionString(optionString); - //TODO check the following line is not required - //option.setAnswerInt(i); + option.setName(name); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { - String optionString = paramMap.get(AssessmentConstants.ATTR_OPTION_STRING_PREFIX + i); - if ((optionString == null) && isForSaving) { + } else if (questionType == QbQuestion.TYPE_MARK_HEDGING) { + String name = paramMap.get(AssessmentConstants.ATTR_OPTION_NAME_PREFIX + i); + if ((name == null) && isForSaving) { continue; } - option.setOptionString(optionString); - if ((correctOptionIndex != null) && correctOptionIndex.equals(Integer.valueOf(sequenceId))) { + option.setName(name); + if ((correctOptionIndex != null) && correctOptionIndex.equals(Integer.valueOf(displayOrder))) { option.setCorrect(true); } option.setFeedback(paramMap.get(AssessmentConstants.ATTR_OPTION_FEEDBACK_PREFIX + i)); @@ -1354,21 +1396,30 @@ * * @param request */ - private TreeSet getUnitsFromRequest(HttpServletRequest request, boolean isForSaving) { + private TreeSet getUnitsFromRequest(HttpServletRequest request, boolean isForSaving) { Map paramMap = splitRequestParameter(request, AssessmentConstants.ATTR_UNIT_LIST); int count = NumberUtils.toInt(paramMap.get(AssessmentConstants.ATTR_UNIT_COUNT)); - TreeSet unitList = new TreeSet<>(new SequencableComparator()); + TreeSet unitList = new TreeSet<>(); for (int i = 0; i < count; i++) { - String unitStr = paramMap.get(AssessmentConstants.ATTR_UNIT_UNIT_PREFIX + i); - if (StringUtils.isBlank(unitStr) && isForSaving) { + String name = paramMap.get(AssessmentConstants.ATTR_UNIT_NAME_PREFIX + i); + if (StringUtils.isBlank(name) && isForSaving) { continue; } - AssessmentUnit unit = new AssessmentUnit(); - String sequenceId = paramMap.get(AssessmentConstants.ATTR_UNIT_SEQUENCE_ID_PREFIX + i); - unit.setSequenceId(NumberUtils.toInt(sequenceId)); - unit.setUnit(unitStr); + QbQuestionUnit unit = null; + String uidStr = paramMap.get(AssessmentConstants.ATTR_UNIT_UID_PREFIX + i); + if (uidStr != null) { + Long uid = NumberUtils.toLong(uidStr); + unit = service.getQbQuestionUnitByUid(uid); + service.releaseFromCache(unit.getQbQuestion()); + + } else { + unit = new QbQuestionUnit(); + } + String displayOrder = paramMap.get(AssessmentConstants.ATTR_UNIT_DISPLAY_ORDER_PREFIX + i); + unit.setDisplayOrder(NumberUtils.toInt(displayOrder)); + unit.setName(name); float multiplier = Float.valueOf(paramMap.get(AssessmentConstants.ATTR_UNIT_MULTIPLIER_PREFIX + i)); unit.setMultiplier(multiplier); unitList.add(unit); @@ -1477,20 +1528,19 @@ * @param question */ private void removeNewLineCharacters(AssessmentQuestion question) { - Set options = question.getOptions(); + Collection options = question.getQbQuestion().getQbOptions(); if (options != null) { - for (AssessmentQuestionOption option : options) { - String optionString = option.getOptionString(); - if (optionString != null) { - option.setOptionString(optionString.replaceAll("[\n\r\f]", "")); + for (QbOption option : options) { + String name = option.getName(); + if (name != null) { + option.setName(name.replaceAll("[\n\r\f]", "")); } - String questionStr = option.getQuestion(); - if (questionStr != null) { - option.setQuestion(questionStr.replaceAll("[\n\r\f]", "")); + String matchingPair = option.getMatchingPair(); + if (matchingPair != null) { + option.setMatchingPair(matchingPair.replaceAll("[\n\r\f]", "")); } } - } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java =================================================================== diff -u -r3ee06bc1b00b1673399c1871a73cfa1d8ec2c0db -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 3ee06bc1b00b1673399c1871a73cfa1d8ec2c0db) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -51,6 +51,7 @@ import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.dto.OptionDTO; @@ -289,7 +290,7 @@ AssessmentQuestion question = questionToReferenceMap.get(questionReference.getUid()); QuestionDTO questionDto = question.getQuestionDTO(); - questionDto.setGrade(questionReference.getDefaultGrade()); + questionDto.setMaxMark(questionReference.getMaxMark()); questionDtos.add(questionDto); } @@ -301,24 +302,24 @@ questionDtos = new LinkedList<>(shuffledList); } for (QuestionDTO questionDto : questionDtos) { - if (questionDto.isShuffle() || (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_ORDERING)) { + if (questionDto.isShuffle() || (questionDto.getType() == QbQuestion.TYPE_ORDERING)) { ArrayList shuffledList = new ArrayList<>(questionDto.getOptionDtos()); Collections.shuffle(shuffledList); questionDto.setOptionDtos(new LinkedHashSet<>(shuffledList)); } - if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { + if (questionDto.getType() == QbQuestion.TYPE_MATCHING_PAIRS) { //sort answer options alphanumerically (as per LDEV-4326) - ArrayList optionsSortedByOptionString = new ArrayList<>(questionDto.getOptionDtos()); - optionsSortedByOptionString.sort(new Comparator() { + ArrayList optionsSortedByName = new ArrayList<>(questionDto.getOptionDtos()); + optionsSortedByName.sort(new Comparator() { @Override public int compare(OptionDTO o1, OptionDTO o2) { - String optionString1 = o1.getOptionString() != null ? o1.getOptionString() : ""; - String optionString2 = o2.getOptionString() != null ? o2.getOptionString() : ""; + String name1 = o1.getName() != null ? o1.getName() : ""; + String name2 = o2.getName() != null ? o2.getName() : ""; - return AlphanumComparator.compareAlphnumerically(optionString1, optionString2); + return AlphanumComparator.compareAlphnumerically(name1, name2); } }); - questionDto.setMatchingPairOptions(new LinkedHashSet<>(optionsSortedByOptionString)); + questionDto.setMatchingPairOptions(new LinkedHashSet<>(optionsSortedByName)); } } @@ -817,58 +818,58 @@ } int questionType = questionDto.getType(); - if (questionType == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + if (questionType == QbQuestion.TYPE_MULTIPLE_CHOICE) { for (OptionDTO optionDto : questionDto.getOptionDtos()) { boolean answerBoolean = false; if (questionDto.isMultipleAnswersAllowed()) { String answerString = request.getParameter( - AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getSequenceId()); + AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getDisplayOrder()); answerBoolean = !StringUtils.isBlank(answerString); } else { String answerString = request.getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i); if (answerString != null) { - int optionSequenceId = Integer.parseInt(answerString); - answerBoolean = (optionDto.getSequenceId() == optionSequenceId); + int optionDisplayOrder = Integer.parseInt(answerString); + answerBoolean = (optionDto.getDisplayOrder() == optionDisplayOrder); } } optionDto.setAnswerBoolean(answerBoolean); } - } else if (questionType == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { + } else if (questionType == QbQuestion.TYPE_MATCHING_PAIRS) { for (OptionDTO optionDto : questionDto.getOptionDtos()) { int answerInt = WebUtil.readIntParam(request, - AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getSequenceId()); + AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getDisplayOrder()); optionDto.setAnswerInt(answerInt); } - } else if (questionType == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) { + } else if (questionType == QbQuestion.TYPE_SHORT_ANSWER) { String answerString = request.getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i); questionDto.setAnswerString(answerString); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + } else if (questionType == QbQuestion.TYPE_NUMERICAL) { String answerString = request.getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i); questionDto.setAnswerString(answerString); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE) { + } else if (questionType == QbQuestion.TYPE_TRUE_FALSE) { String answerString = request.getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i); if (answerString != null) { questionDto.setAnswerBoolean(Boolean.parseBoolean(answerString)); questionDto.setAnswerString("answered"); } - } else if (questionType == AssessmentConstants.QUESTION_TYPE_ESSAY) { + } else if (questionType == QbQuestion.TYPE_ESSAY) { String answerString = request.getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i); answerString = answerString.replaceAll("[\n\r\f]", ""); questionDto.setAnswerString(answerString); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_ORDERING) { + } else if (questionType == QbQuestion.TYPE_ORDERING) { - } else if (questionType == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + } else if (questionType == QbQuestion.TYPE_MARK_HEDGING) { //store hedging marks for (OptionDTO optionDto : questionDto.getOptionDtos()) { Integer markHedging = WebUtil.readIntParam(request, - AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getSequenceId(), true); + AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getDisplayOrder(), true); if (markHedging != null) { optionDto.setAnswerInt(markHedging); } @@ -918,38 +919,38 @@ //enforce all hedging marks question type to be answered as well if (questionDto.isAnswerRequired() - || (questionType == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING)) { + || (questionType == QbQuestion.TYPE_MARK_HEDGING)) { boolean isAnswered = false; - if (questionType == AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE) { + if (questionType == QbQuestion.TYPE_MULTIPLE_CHOICE) { for (OptionDTO optionDto : questionDto.getOptionDtos()) { isAnswered |= optionDto.getAnswerBoolean(); } - } else if (questionType == AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS) { + } else if (questionType == QbQuestion.TYPE_MATCHING_PAIRS) { for (OptionDTO optionDto : questionDto.getOptionDtos()) { isAnswered |= optionDto.getAnswerInt() != 0; } - } else if ((questionType == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER) - || (questionType == AssessmentConstants.QUESTION_TYPE_NUMERICAL) - || (questionType == AssessmentConstants.QUESTION_TYPE_TRUE_FALSE) - || (questionType == AssessmentConstants.QUESTION_TYPE_ESSAY)) { + } else if ((questionType == QbQuestion.TYPE_SHORT_ANSWER) + || (questionType == QbQuestion.TYPE_NUMERICAL) + || (questionType == QbQuestion.TYPE_TRUE_FALSE) + || (questionType == QbQuestion.TYPE_ESSAY)) { isAnswered |= StringUtils.isNotBlank(questionDto.getAnswerString()); - } else if (questionType == AssessmentConstants.QUESTION_TYPE_ORDERING) { + } else if (questionType == QbQuestion.TYPE_ORDERING) { isAnswered = true; - } else if (questionType == AssessmentConstants.QUESTION_TYPE_MARK_HEDGING) { + } else if (questionType == QbQuestion.TYPE_MARK_HEDGING) { - //verify sum of all hedging marks is equal to question's grade + //verify sum of all hedging marks is equal to question's maxMark int sumMarkHedging = 0; for (OptionDTO optionDto : questionDto.getOptionDtos()) { sumMarkHedging += optionDto.getAnswerInt(); } - isAnswered = sumMarkHedging == questionDto.getGrade(); + isAnswered = sumMarkHedging == questionDto.getMaxMark(); //verify justification of hedging is provided if it was enabled if (questionDto.isHedgingJustificationEnabled()) { @@ -965,7 +966,7 @@ } - if ((questionDto.getType() == AssessmentConstants.QUESTION_TYPE_ESSAY) + if ((questionDto.getType() == QbQuestion.TYPE_ESSAY) && (questionDto.getMinWordsLimit() > 0)) { if (questionDto.getAnswerString() == null) { @@ -1016,7 +1017,7 @@ // find corresponding questionResult for (AssessmentQuestionResult questionResult : result.getQuestionResults()) { - if (questionDto.getUid().equals(questionResult.getAssessmentQuestion().getUid())) { + if (questionDto.getUid().equals(questionResult.getQbQuestion().getUid())) { // copy questionResult's info to the question questionDto.setMark(questionResult.getMark()); @@ -1030,12 +1031,12 @@ } } // required for showing right/wrong answers icons on results page correctly - if (questionDto.getType() == AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER - || questionDto.getType() == AssessmentConstants.QUESTION_TYPE_NUMERICAL) { + if (questionDto.getType() == QbQuestion.TYPE_SHORT_ANSWER + || questionDto.getType() == QbQuestion.TYPE_NUMERICAL) { boolean isAnsweredCorrectly = false; for (OptionDTO optionDto : questionDto.getOptionDtos()) { if (optionDto.getUid().equals(questionResult.getSubmittedOptionUid())) { - isAnsweredCorrectly = optionDto.getGrade() > 0; + isAnsweredCorrectly = optionDto.getMaxMark() > 0; break; } } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java =================================================================== diff -u -rdcdc1487609bd4f00afaa93c09272d84ab0cd325 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision dcdc1487609bd4f00afaa93c09272d84ab0cd325) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -380,7 +380,7 @@ Long questionResultUid = null; if (assessmentResult != null) { for (AssessmentQuestionResult dbQuestionResult : assessmentResult.getQuestionResults()) { - if (dbQuestionResult.getAssessmentQuestion().getUid().equals(questionUid)) { + if (dbQuestionResult.getQbQuestion().getUid().equals(questionUid)) { questionResultUid = dbQuestionResult.getUid(); break; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/TblMonitoringController.java =================================================================== diff -u -rdcdc1487609bd4f00afaa93c09272d84ab0cd325 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/TblMonitoringController.java (.../TblMonitoringController.java) (revision dcdc1487609bd4f00afaa93c09272d84ab0cd325) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/TblMonitoringController.java (.../TblMonitoringController.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -11,23 +11,25 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentResultDTO; +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.TblAssessmentDTO; import org.lamsfoundation.lams.tool.assessment.dto.TblAssessmentQuestionDTO; import org.lamsfoundation.lams.tool.assessment.dto.TblAssessmentQuestionResultDTO; import org.lamsfoundation.lams.tool.assessment.model.Assessment; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestion; -import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionResult; import org.lamsfoundation.lams.tool.assessment.model.AssessmentSession; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; +import org.lamsfoundation.lams.tool.assessment.service.AssessmentServiceImpl; import org.lamsfoundation.lams.tool.assessment.service.IAssessmentService; import org.lamsfoundation.lams.tool.assessment.util.AssessmentEscapeUtils; import org.lamsfoundation.lams.tool.assessment.util.AssessmentSessionComparator; -import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; @@ -69,7 +71,7 @@ Assessment assessment = assessmentService.getAssessmentByContentId(toolContentId); //prepare list of the questions, filtering out questions that aren't supposed to be answered - Set questionList = new TreeSet(); + Set questionList = new TreeSet<>(); //in case there is at least one random question - we need to show all questions in a drop down select if (assessment.hasRandomQuestion()) { questionList.addAll(assessment.getQuestions()); @@ -81,32 +83,32 @@ } } //keep only MCQ type of questions - Set mcqQuestions = new TreeSet(); + Set questionDtos = new TreeSet<>(); int maxOptionsInQuestion = 0; for (AssessmentQuestion question : questionList) { - if (AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE == question.getType()) { - mcqQuestions.add(question); + if (QbQuestion.TYPE_MULTIPLE_CHOICE == question.getType()) { + questionDtos.add(new QuestionDTO(question)); //calculate maxOptionsInQuestion - if (question.getOptions().size() > maxOptionsInQuestion) { - maxOptionsInQuestion = question.getOptions().size(); + if (question.getQbQuestion().getQbOptions().size() > maxOptionsInQuestion) { + maxOptionsInQuestion = question.getQbQuestion().getQbOptions().size(); } } } request.setAttribute("maxOptionsInQuestion", maxOptionsInQuestion); int totalNumberOfUsers = assessmentService.getCountUsersByContentId(toolContentId); - for (AssessmentQuestion question : mcqQuestions) { + for (QuestionDTO questionDto : questionDtos) { // build candidate dtos - for (AssessmentQuestionOption option : question.getOptions()) { - int optionAttemptCount = assessmentService.countAttemptsPerOption(option.getUid()); + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + int optionAttemptCount = assessmentService.countAttemptsPerOption(optionDto.getUid()); float percentage = (float) (optionAttemptCount * 100) / totalNumberOfUsers; - option.setPercentage(percentage); + optionDto.setPercentage(percentage); } } - request.setAttribute("questions", mcqQuestions); + request.setAttribute("questions", questionDtos); request.setAttribute(AttributeNames.PARAM_TOOL_CONTENT_ID, toolContentId); return "pages/tblmonitoring/iraAssessmentStudentChoices"; @@ -141,7 +143,7 @@ private Set prepareQuestionsList(Assessment assessment) { // question list to display - Set questions = new TreeSet(); + Set questions = new TreeSet<>(); boolean hasRandomQuestion = false; for (QuestionReference reference : (Set) assessment.getQuestionReferences()) { hasRandomQuestion |= reference.isRandomQuestion(); @@ -155,7 +157,7 @@ for (QuestionReference reference : (Set) assessment.getQuestionReferences()) { //sort questions the same way references are sorted (as per LKC request) AssessmentQuestion question = reference.getQuestion(); - question.setSequenceId(reference.getSequenceId()); + question.setDisplayOrder(reference.getSequenceId()); questions.add(question); } } @@ -190,12 +192,11 @@ Map questionSummaries = assessmentService.getQuestionSummaryForExport(assessment); List tblQuestionDtos = new ArrayList(); for (QuestionSummary questionSummary : questionSummaries.values()) { - AssessmentQuestion question = questionSummary.getQuestion(); + QuestionDTO questionDto = questionSummary.getQuestionDto(); TblAssessmentQuestionDTO tblQuestionDto = new TblAssessmentQuestionDTO(); - tblQuestionDto.setQuestion(question); - tblQuestionDto.setQuestionTypeLabel(TblMonitoringController.getAssessmentQuestionTypeLabel(question.getType())); - tblQuestionDto.setCorrectAnswer(getAssessmentCorrectAnswer(question)); + tblQuestionDto.setQuestionTypeLabel(AssessmentServiceImpl.getQuestionTypeLabel(questionDto.getType())); + tblQuestionDto.setCorrectAnswer(getAssessmentCorrectAnswer(questionDto)); List sessionQuestionResults = new ArrayList(); for (List questionResultsPerSession : questionSummary @@ -221,7 +222,7 @@ tblQuestionDtos.add(tblQuestionDto); } - SortedSet sessions = new TreeSet(new AssessmentSessionComparator()); + SortedSet sessions = new TreeSet<>(new AssessmentSessionComparator()); sessions.addAll(assessmentService.getSessionsByContentId(assessment.getContentId())); request.setAttribute("sessions", sessions); @@ -233,81 +234,51 @@ /** * Used only for excell export (for getUserSummaryData() method). */ - private static String getAssessmentQuestionTypeLabel(short type) { - switch (type) { - case AssessmentConstants.QUESTION_TYPE_ESSAY: - return "Essay"; - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: - return "Matching Pairs"; - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: - return "Multiple Choice"; - case AssessmentConstants.QUESTION_TYPE_NUMERICAL: - return "Numerical"; - case AssessmentConstants.QUESTION_TYPE_ORDERING: - return "Ordering"; - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: - return "Short Answer"; - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: - return "True/False"; - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: - return "Mark Hedging"; - default: - return null; - } - } - - /** - * Used only for excell export (for getUserSummaryData() method). - */ - private String getAssessmentCorrectAnswer(AssessmentQuestion question) { + private String getAssessmentCorrectAnswer(QuestionDTO questionDto) { StringBuilder sb = new StringBuilder(); - if (question != null) { - switch (question.getType()) { - case AssessmentConstants.QUESTION_TYPE_ESSAY: + if (questionDto != null) { + switch (questionDto.getType()) { + case QbQuestion.TYPE_ESSAY: return "N.A."; - case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: - for (AssessmentQuestionOption option : question.getOptions()) { - sb.append((option.getQuestion() + " - " + option.getOptionString()).replaceAll("\\<.*?\\>", "") + case QbQuestion.TYPE_MATCHING_PAIRS: + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + sb.append((optionDto.getMatchingPair() + " - " + optionDto.getName()).replaceAll("\\<.*?\\>", "") + "
"); } return sb.toString(); - case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: - case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: - for (AssessmentQuestionOption option : question.getOptions()) { - if (option.getGrade() == 1f) { - return option.getOptionString(); + case QbQuestion.TYPE_MULTIPLE_CHOICE: + case QbQuestion.TYPE_SHORT_ANSWER: + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + if (optionDto.getMaxMark() == 1f) { + return optionDto.getName(); } } break; - case AssessmentConstants.QUESTION_TYPE_NUMERICAL: - for (AssessmentQuestionOption option : question.getOptions()) { - if (option.getGrade() == 1f) { - return "" + option.getOptionFloat(); + case QbQuestion.TYPE_NUMERICAL: + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + if (optionDto.getMaxMark() == 1f) { + return "" + optionDto.getNumericalOption(); } } break; - case AssessmentConstants.QUESTION_TYPE_ORDERING: - TreeSet correctOptionSet = new TreeSet( - new SequencableComparator()); - correctOptionSet.addAll(question.getOptions()); - - for (AssessmentQuestionOption option : question.getOptions()) { - sb.append(option.getOptionString() + "\n"); + case QbQuestion.TYPE_ORDERING: + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + sb.append(optionDto.getName() + "\n"); } return sb.toString(); - case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: - return String.valueOf(question.getCorrectAnswer()); + case QbQuestion.TYPE_TRUE_FALSE: + return String.valueOf(questionDto.getCorrectAnswer()); - case AssessmentConstants.QUESTION_TYPE_MARK_HEDGING: - for (AssessmentQuestionOption option : question.getOptions()) { - if (option.isCorrect()) { - return option.getOptionString(); + case QbQuestion.TYPE_MARK_HEDGING: + for (OptionDTO optionDto : questionDto.getOptionDtos()) { + if (optionDto.isCorrect()) { + return optionDto.getName(); } } break; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/form/AssessmentQuestionForm.java =================================================================== diff -u -r67d7232f087b9f5c72ff41f7bbebe29cff81e099 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/form/AssessmentQuestionForm.java (.../AssessmentQuestionForm.java) (revision 67d7232f087b9f5c72ff41f7bbebe29cff81e099) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/form/AssessmentQuestionForm.java (.../AssessmentQuestionForm.java) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -31,20 +31,19 @@ */ public class AssessmentQuestionForm { - private int sequenceId; + private int displayOrder; private String sessionMapID; private String contentFolderID; // tool access mode; private String mode; - private short questionType; + private Integer questionType; private String title; private String question; - private String defaultGrade; + private String maxMark; private String penaltyFactor; private boolean answerRequired; - private String generalFeedback; private String feedback; private boolean multipleAnswersAllowed; private boolean incorrectAnswerNullifiesMark; @@ -101,28 +100,28 @@ this.question = question; } - public int getSequenceId() { - return sequenceId; + public int getDisplayOrder() { + return displayOrder; } - public void setSequenceId(int sequenceId) { - this.sequenceId = sequenceId; + public void setDisplayOrder(int displayOrder) { + this.displayOrder = displayOrder; } - public short getQuestionType() { + public Integer getQuestionType() { return questionType; } - public void setQuestionType(short type) { + public void setQuestionType(Integer type) { this.questionType = type; } - public String getDefaultGrade() { - return defaultGrade; + public String getMaxMark() { + return maxMark; } - public void setDefaultGrade(String defaultGrade) { - this.defaultGrade = defaultGrade; + public void setMaxMark(String maxMark) { + this.maxMark = maxMark; } public String getPenaltyFactor() { @@ -141,14 +140,6 @@ this.answerRequired = answerRequired; } - public String getGeneralFeedback() { - return generalFeedback; - } - - public void setGeneralFeedback(String generalFeedback) { - this.generalFeedback = generalFeedback; - } - public String getFeedback() { return feedback; } Index: lams_tool_assessment/web/includes/javascript/authoring-options.js =================================================================== diff -u -r78ae88b9a7c79f31eb1f795d084be7d283963885 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/includes/javascript/authoring-options.js (.../authoring-options.js) (revision 78ae88b9a7c79f31eb1f795d084be7d283963885) +++ lams_tool_assessment/web/includes/javascript/authoring-options.js (.../authoring-options.js) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -38,12 +38,12 @@ //in order to be able to use option's value, copy it from CKEditor to textarea function prepareOptionEditorsForAjaxSubmit(){ if ((QUESTION_TYPE == 1) || (QUESTION_TYPE == 7) || (QUESTION_TYPE == 8)) { - $("textarea[name^=optionString], textarea[name^=optionFeedback]").each(function() { + $("textarea[name^=optionName], textarea[name^=optionFeedback]").each(function() { prepareOptionEditorForAjaxSubmit(this); }); } else if (QUESTION_TYPE == 2) { - $("[name^=optionQuestion]").each(function() { + $("[name^=matchingPair]").each(function() { prepareOptionEditorForAjaxSubmit(this); }); @@ -122,11 +122,11 @@ }, store: { set: function (sortable) { - //update all sequenceIds in order to later save it as options' order + //update all displayOrders in order to later save it as options' order var order = sortable.toArray(); for (var i = 0; i < order.length; i++) { var optionIndex = order[i]; - $('input[name="optionSequenceId' + optionIndex + '"]').val(i+1); + $('input[name="optionDisplayOrder' + optionIndex + '"]').val(i+1); } } } Index: lams_tool_assessment/web/includes/javascript/authoring-question.js =================================================================== diff -u -r629116ce2b6bac35146c7b90b668dbc5f887eb69 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/includes/javascript/authoring-question.js (.../authoring-question.js) (revision 629116ce2b6bac35146c7b90b668dbc5f887eb69) +++ lams_tool_assessment/web/includes/javascript/authoring-question.js (.../authoring-question.js) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -34,7 +34,7 @@ //show/hide settings tab, if it contains an error var showSettingsTab = true; $.each(validator.errorMap, function(key, value) { - showSettingsTab &= key == "defaultGrade" || key == "penaltyFactor"; + showSettingsTab &= key == "maxMark" || key == "penaltyFactor"; }); if (showSettingsTab) { $("#question-settings-link.btn-default").trigger( "click" ); Index: lams_tool_assessment/web/pages/authoring/basic.jsp =================================================================== diff -u -r67d7232f087b9f5c72ff41f7bbebe29cff81e099 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/pages/authoring/basic.jsp (.../basic.jsp) (revision 67d7232f087b9f5c72ff41f7bbebe29cff81e099) +++ lams_tool_assessment/web/pages/authoring/basic.jsp (.../basic.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -13,17 +13,17 @@ //The panel of assessment list panel var questionListTargetDiv = "#questionListArea"; - function deleteQuestion(questionSequenceId){ + function deleteQuestion(questionDisplayOrder){ var deletionConfirmed = confirm(""); if (deletionConfirmed) { var url = ""; $(questionListTargetDiv).load( url, { - questionSequenceId: questionSequenceId, + questionDisplayOrder: questionDisplayOrder, sessionMapID: "${sessionMapID}", - referenceGrades: serializeReferenceGrades() + referenceMaxMarks: serializeReferenceMaxMarks() }, function(){ reinitializePassingMarkSelect(false); @@ -42,7 +42,7 @@ { questionIndex: idx, sessionMapID: "${sessionMapID}", - referenceGrades: serializeReferenceGrades() + referenceMaxMarks: serializeReferenceMaxMarks() }, function(){ reinitializePassingMarkSelect(false); @@ -57,7 +57,7 @@ { questionReferenceIndex: idx, sessionMapID: "${sessionMapID}", - referenceGrades: serializeReferenceGrades() + referenceMaxMarks: serializeReferenceMaxMarks() }, function(){ reinitializePassingMarkSelect(false); @@ -72,7 +72,7 @@ { questionReferenceIndex: idx, sessionMapID: "${sessionMapID}", - referenceGrades: serializeReferenceGrades() + referenceMaxMarks: serializeReferenceMaxMarks() }, function(){ refreshThickbox(); @@ -86,19 +86,19 @@ { questionReferenceIndex: idx, sessionMapID: "${sessionMapID}", - referenceGrades: serializeReferenceGrades() + referenceMaxMarks: serializeReferenceMaxMarks() }, function(){ refreshThickbox(); } ); } - function serializeReferenceGrades(){ - var serializedGrades = ""; - $("[name^=grade]").each(function() { - serializedGrades += "&" + this.name + "=" + this.value; + function serializeReferenceMaxMarks(){ + var serializedMaxMarks = ""; + $("[name^=maxMark]").each(function() { + serializedMaxMarks += "&" + this.name + "=" + this.value; }); - return serializedGrades; + return serializedMaxMarks; } function exportQuestions(){ @@ -110,7 +110,7 @@ function createNewQuestionInitHref() { var questionTypeDropdown = document.getElementById("questionType"); var questionType = questionTypeDropdown.selectedIndex + 1; - var newQuestionInitHref = "${newQuestionInitUrl}&questionType=" + questionType + "&referenceGrades=" + encodeURIComponent(serializeReferenceGrades()) + "&KeepThis=true&TB_iframe=true&modal=true"; + var newQuestionInitHref = "${newQuestionInitUrl}&questionType=" + questionType + "&referenceMaxMarks=" + encodeURIComponent(serializeReferenceMaxMarks()) + "&KeepThis=true&TB_iframe=true&modal=true"; $("#newQuestionInitHref").attr("href", newQuestionInitHref) }; function refreshThickbox(){ @@ -121,12 +121,12 @@ $('#passingMark').empty(); $('#passingMark').append( new Option("",0) ); - var maxGrade = 0; - $("[name^=grade]").each(function() { - maxGrade += eval(this.value); + var sumMaxMark = 0; + $("[name^=maxMark]").each(function() { + sumMaxMark += eval(this.value); }); - for (var i = 1; i<=maxGrade; i++) { + for (var i = 1; i<=sumMaxMark; i++) { var isSelected = (oldValue == i); $('#passingMark').append( new Option(i, i, isSelected, isSelected) ); } Index: lams_tool_assessment/web/pages/authoring/parts/addessay.jsp =================================================================== diff -u -r629116ce2b6bac35146c7b90b668dbc5f887eb69 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/pages/authoring/parts/addessay.jsp (.../addessay.jsp) (revision 629116ce2b6bac35146c7b90b668dbc5f887eb69) +++ lams_tool_assessment/web/pages/authoring/parts/addessay.jsp (.../addessay.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -21,7 +21,7 @@ ignore: 'hidden', rules: { title: "required", - defaultGrade: { + maxMark: { required: true, digits: true }, @@ -34,14 +34,14 @@ }, messages: { title: "", - defaultGrade: { + maxMark: { required: "", digits: "" } }, submitHandler: function(form) { $("#question").val(CKEDITOR.instances.question.getData()); - $("#generalFeedback").val(CKEDITOR.instances.generalFeedback.getData()); + $("#feedback").val(CKEDITOR.instances.feedback.getData()); var options = { target: parent.jQuery('#questionListArea'), @@ -115,7 +115,7 @@ - +
Index: lams_tool_assessment/web/pages/authoring/parts/addmarkhedging.jsp =================================================================== diff -u -r629116ce2b6bac35146c7b90b668dbc5f887eb69 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/pages/authoring/parts/addmarkhedging.jsp (.../addmarkhedging.jsp) (revision 629116ce2b6bac35146c7b90b668dbc5f887eb69) +++ lams_tool_assessment/web/pages/authoring/parts/addmarkhedging.jsp (.../addmarkhedging.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -14,20 +14,20 @@ ignore: 'hidden', rules: { title: "required", - defaultGrade: { + maxMark: { required: true, digits: true }, hasOptionFilled: { required: function(element) { prepareOptionEditorsForAjaxSubmit(); - return $("textarea[name^=optionString]:filled").length < 1; + return $("textarea[name^=optionName]:filled").length < 1; } } }, messages: { title: "", - defaultGrade: { + maxMark: { required: "", digits: "" }, @@ -39,7 +39,7 @@ prepareOptionEditorsForAjaxSubmit(); $("#optionList").val($("#optionForm").serialize(true)); $("#question").val(CKEDITOR.instances.question.getData()); - $("#generalFeedback").val(CKEDITOR.instances.generalFeedback.getData()); + $("#feedback").val(CKEDITOR.instances.feedback.getData()); $("#feedbackOnCorrect").val(CKEDITOR.instances.feedbackOnCorrect.getData()); $("#feedbackOnPartiallyCorrect").val(CKEDITOR.instances.feedbackOnPartiallyCorrect.getData()); $("#feedbackOnIncorrect").val(CKEDITOR.instances.feedbackOnIncorrect.getData()); @@ -83,7 +83,7 @@ - +
Index: lams_tool_assessment/web/pages/authoring/parts/addmultiplechoice.jsp =================================================================== diff -u -r629116ce2b6bac35146c7b90b668dbc5f887eb69 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/pages/authoring/parts/addmultiplechoice.jsp (.../addmultiplechoice.jsp) (revision 629116ce2b6bac35146c7b90b668dbc5f887eb69) +++ lams_tool_assessment/web/pages/authoring/parts/addmultiplechoice.jsp (.../addmultiplechoice.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -11,7 +11,7 @@ ignore: 'hidden', rules: { title: "required", - defaultGrade: { + maxMark: { required: true, digits: true }, @@ -22,22 +22,22 @@ hasOptionFilled: { required: function(element) { prepareOptionEditorsForAjaxSubmit(); - return $("textarea[name^=optionString]:filled").length < 1; + return $("textarea[name^=optionName]:filled").length < 1; } }, - hasOneHundredGrade: { + hasOneHundredMaxMark: { required: function(element) { - var hasOneHundredGrade = false; - $("input[name^='optionGrade']").each(function() { - hasOneHundredGrade = hasOneHundredGrade || (eval(this.value) == 1); + var hasOneHundredMaxMark = false; + $("input[name^='optionMaxMark']").each(function() { + hasOneHundredMaxMark = hasOneHundredMaxMark || (eval(this.value) == 1); }); - return !hasOneHundredGrade && !eval($("#multipleAnswersAllowed").val()); + return !hasOneHundredMaxMark && !eval($("#multipleAnswersAllowed").val()); } } }, messages: { title: "", - defaultGrade: { + maxMark: { required: "", digits: "" }, @@ -48,15 +48,15 @@ hasOptionFilled: { required: "" }, - hasOneHundredGrade: { + hasOneHundredMaxMark: { required: "" } }, submitHandler: function(form) { prepareOptionEditorsForAjaxSubmit(); $("#optionList").val($("#optionForm").serialize(true)); $("#question").val(CKEDITOR.instances.question.getData()); - $("#generalFeedback").val(CKEDITOR.instances.generalFeedback.getData()); + $("#feedback").val(CKEDITOR.instances.feedback.getData()); $("#feedbackOnCorrect").val(CKEDITOR.instances.feedbackOnCorrect.getData()); $("#feedbackOnPartiallyCorrect").val(CKEDITOR.instances.feedbackOnPartiallyCorrect.getData()); $("#feedbackOnIncorrect").val(CKEDITOR.instances.feedbackOnIncorrect.getData()); @@ -124,7 +124,7 @@ - +
- +
@@ -178,13 +178,13 @@
-
@@ -248,7 +248,7 @@
General Feedback -
Index: lams_tool_assessment/web/pages/authoring/parts/addnumerical.jsp =================================================================== diff -u -r629116ce2b6bac35146c7b90b668dbc5f887eb69 -r9c3a64b840753192b333afb73c8fe7bdb54be638 --- lams_tool_assessment/web/pages/authoring/parts/addnumerical.jsp (.../addnumerical.jsp) (revision 629116ce2b6bac35146c7b90b668dbc5f887eb69) +++ lams_tool_assessment/web/pages/authoring/parts/addnumerical.jsp (.../addnumerical.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) @@ -11,7 +11,7 @@ ignore: 'hidden', rules: { title: "required", - defaultGrade: { + maxMark: { required: true, digits: true }, @@ -21,19 +21,19 @@ }, hasOptionFilled: { required: function(element) { - $("input[name^='optionFloat']").each(function() { + $("input[name^='numericalOption']").each(function() { $(this).attr("value", this.value); }); - return $("input[name^=optionFloat][value!='0.0']").length < 1; + return $("input[name^=numericalOption][value!='0.0']").length < 1; } }, - hasOneHundredGrade: { + hasOneHundredMaxMark: { required: function(element) { - var hasOneHundredGrade = false; - $("input[name^='optionGrade']").each(function() { - hasOneHundredGrade = hasOneHundredGrade || (eval(this.value) == 1); + var hasOneHundredMaxMark = false; + $("input[name^='optionMaxMark']").each(function() { + hasOneHundredMaxMark = hasOneHundredMaxMark || (eval(this.value) == 1); }); - return !hasOneHundredGrade; + return !hasOneHundredMaxMark; } }, allAcceptedErrorsPositive: { @@ -60,7 +60,7 @@ }, messages: { title: "", - defaultGrade: { + maxMark: { required: "", digits: "" }, @@ -71,7 +71,7 @@ hasOptionFilled: { required: "" }, - hasOneHundredGrade: { + hasOneHundredMaxMark: { required: "" }, allAcceptedErrorsPositive: { @@ -89,7 +89,7 @@ $("#optionList").val($("#optionForm").serialize(true)); $("#unitList").val($("#unitForm").serialize(true)); $("#question").val(CKEDITOR.instances.question.getData()); - $("#generalFeedback").val(CKEDITOR.instances.generalFeedback.getData()); + $("#feedback").val(CKEDITOR.instances.feedback.getData()); var options = { target: parent.jQuery('#questionListArea'), @@ -136,7 +136,7 @@ - +