Skip to content
Snippets Groups Projects
Unverified Commit 19ea8d1e authored by AnneliKlamas's avatar AnneliKlamas Committed by GitHub
Browse files

feature: Add text match/short answer question type #36 (#37)

parent 39b3e880
No related branches found
No related tags found
No related merge requests found
......@@ -21,7 +21,7 @@ Pictures are always added to the end of the text.
\* marks right answers.
Supports only single choice and multiple choice/checkbox questions.
Supports only single choice, multiple choice/checkbox and text match/short answer questions.
Supports multi paragraph question descriptions.
......@@ -38,5 +38,9 @@ By default, Coursera DOCX will have partial credit option.
Answer option need to start with letter or number followed by colon ':' or closing parenthesis ')'
Correct answer should be marked with '*'. Example: "*A) answer option text". Also, multiple symbols will work: " ** * 1: answer option text".
Correct answer should be marked with '*'. Example: "*A) answer option text". Also multiple symbols will work: " ** * 1:
answer option text".
Text match/short answer questions are not case-sensitive. Moodle doesn't support incorrect answers and their feedback,
so incorrect answers will be skipped.
......@@ -14,8 +14,7 @@ public class FeedbackHandler {
public void add(String text, ParagraphType paragraphType) {
switch (paragraphType) {
case DEFAULT_FEEDBACK ->
state.setDefaultFeedback(text.toLowerCase().replace("default feedback:", "").strip());
case DEFAULT_FEEDBACK -> state.setDefaultFeedback(text.toLowerCase().replaceAll("^\s*(default)\s*(feedback)\s*(:)", "").strip());
case FEEDBACK -> {
var feedbackText = text.toLowerCase().replace("feedback", "").strip().replace(":", "").strip();
state.getAnswerOptions().get(state.getAnswerOptions().size() - 1).setFeedback(Optional.of(feedbackText));
......
......@@ -58,6 +58,8 @@ public class QuestionHandler {
state.setType(QuestionType.SINGLE_CHOICE);
} else if (lowerCaseText.matches(".*(multiple)\s*(choice).*") || lowerCaseText.contains("checkbox")) {
state.setType(QuestionType.MULTIPLE_CHOICE);
} else if (lowerCaseText.matches(".*(text)\s*(match).*") || lowerCaseText.matches(".*(short)\s*(answer).*")) {
state.setType(QuestionType.TEXT_MATCH);
} else {
state.setType(QuestionType.UNKNOWN);
}
......
......@@ -8,7 +8,7 @@ import java.util.List;
public record Question(
String name,
String feedback,
String defaultFeedback,
QuestionType type,
QuestionDescription description,
List<Answer> answerOptions,
......
......@@ -3,5 +3,6 @@ package com.quiz.converter.models.enums;
public enum QuestionType {
SINGLE_CHOICE,
MULTIPLE_CHOICE,
TEXT_MATCH,
UNKNOWN
}
......@@ -26,6 +26,8 @@ public class CourseraDocxCreatorService {
for (int i = 0; i < question.answerOptions().size(); i++) {
addAnswerOptions(question, i, doc);
}
addDefaultFeedback(question, doc);
}
var bos = new ByteArrayOutputStream();
......@@ -35,6 +37,14 @@ public class CourseraDocxCreatorService {
return bos.toByteArray();
}
private void addDefaultFeedback(Question question, XWPFDocument doc) {
if (!question.defaultFeedback().isEmpty()) {
var defaultFeedback = doc.createParagraph();
var defaultFeedbackRun = defaultFeedback.createRun();
defaultFeedbackRun.setText("Default Feedback: " + question.defaultFeedback());
}
}
private static void addQuestionDescription(Question question, XWPFDocument doc) {
for (var description : question.description().getTexts()) {
var questionDescription = doc.createParagraph();
......@@ -53,6 +63,8 @@ public class CourseraDocxCreatorService {
questionTypeText = "single correct answer";
} else if (question.type().equals(QuestionType.MULTIPLE_CHOICE)) {
questionTypeText = "checkbox";
} else if (question.type().equals(QuestionType.TEXT_MATCH)) {
questionTypeText = "text match";
}
int questionName;
try {
......
......@@ -108,7 +108,7 @@ public class FileUploadService {
private Answer createAnswerFromString(String text, List<Picture> paragraphPictures) {
var isCorrectAnswer = text.strip().matches("(\\s*\\*+\s*).*");
var answerText = text.strip().replaceAll("(\\s*\\**\\s*)*[a-zA-Z\\d]\\s*[:)]", "");
var answerText = text.strip().replaceAll("^(\\s*\\**\\s*)*[a-zA-Z\\d]\\s*[:)]", "");
return new Answer(answerText, null, isCorrectAnswer, paragraphPictures);
}
}
......@@ -51,14 +51,16 @@ public class MoodleXmlCreatorService {
var correctAnswerCount = (int) question.answerOptions().stream().filter(Answer::isCorrect).count();
for (var answer : question.answerOptions()) {
addAnswer(doc, answer, questionElem, correctAnswerCount);
addAnswer(doc, answer, questionElem, correctAnswerCount, question.type());
}
addQuestionOptions(question, doc, questionElem);
addQuestionType(question, doc, questionElem);
if (question.type().equals(QuestionType.MULTIPLE_CHOICE) || question.type().equals(QuestionType.SINGLE_CHOICE)) {
addQuestionType(question, doc, questionElem);
}
if (!question.feedback().isEmpty()) {
addFeedback(doc, questionElem, question.feedback());
if (!question.defaultFeedback().isEmpty()) {
addFeedback(doc, questionElem, question.defaultFeedback());
}
}
......@@ -108,14 +110,22 @@ public class MoodleXmlCreatorService {
var type = "";
if (question.type().equals(QuestionType.SINGLE_CHOICE) || (question.type().equals(QuestionType.MULTIPLE_CHOICE)))
type = "multichoice";
else if (question.type().equals(QuestionType.TEXT_MATCH)) {
type = "shortanswer";
}
questionElem.setAttribute("type", type);
rootElem.appendChild(questionElem);
}
private static void addAnswer(Document doc, Answer answer, Element questionElem, int correctAnswerCount) {
private static void addAnswer(Document doc, Answer answer, Element questionElem, int correctAnswerCount, QuestionType questionType) {
var answerElem = doc.createElement("answer");
answerElem.setAttribute("fraction", answer.isCorrect() ? String.valueOf(100.0 / correctAnswerCount) : String.valueOf(-100.0 / correctAnswerCount));
var fraction = 0.0;
if (questionType.equals(QuestionType.MULTIPLE_CHOICE)) {
fraction = answer.isCorrect() ? 100.0 / correctAnswerCount : -100.0 / correctAnswerCount;
} else {
fraction = answer.isCorrect() ? 100 : 0;
}
answerElem.setAttribute("fraction", String.valueOf(fraction));
answerElem.setAttribute("format", "html");
questionElem.appendChild(answerElem);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment