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

feat: Allow having multiparagraph question descriptions #14 (#33)

parent b004908e
No related branches found
No related tags found
No related merge requests found
......@@ -23,7 +23,7 @@ Pictures are always added to the end of the text.
Supports only single choice and multiple choice/checkbox questions.
Doesn't support multi paragraph question descriptions.
Supports multi paragraph question descriptions.
Coursera doesn't support default feedback for multi nor single choice questions.
......@@ -32,3 +32,6 @@ By default no shuffle.
When multiple choice question then in MOODLE every correct answer gives 100/nrOfCorrectAnswers and every incorrect answer gives
-100/nrOfCorrectAnswers. In COURSERA it is behaving as "no partial credit".
Answer option need to start with letter or number followed by colon ':' or closing parenthesis ')'
Correct answer should be marked wit '*'. Example: "*A) answer option text". Also multiple symbols will work: " ** * 1: answer option text".
......@@ -3,16 +3,17 @@ package com.quiz.converter.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@NoArgsConstructor
@Getter
public class QuestionDescription {
private String text;
private List<Picture> pictures;
private List<String> texts = new ArrayList<>();
private List<Picture> pictures = new ArrayList<>();
public QuestionDescription(String text, List<Picture> pictures) {
this.text = text;
public QuestionDescription(List<String> texts, List<Picture> pictures) {
this.texts = texts;
this.pictures = pictures;
}
}
......@@ -6,5 +6,6 @@ public enum ParagraphType {
ANSWER_OPTION,
QUESTION_DETAILS,
EMPTY_TEXT,
DEFAULT_FEEDBACK
DEFAULT_FEEDBACK,
UNKNOWN
}
package com.quiz.converter.models.enums;
public enum QuestionWarningType {
CHECK_QUESTION_NAME
CHECK_QUESTION_NAME,
UNKNOWN_PARAGRAPH_TYPE
}
......@@ -36,9 +36,11 @@ public class CourseraDocxCreatorService {
}
private static void addQuestionDescription(Question question, XWPFDocument doc) {
var questionDescription = doc.createParagraph();
var questionDescriptionRun = questionDescription.createRun();
questionDescriptionRun.setText(question.description().getText());
for (var description : question.description().getTexts()) {
var questionDescription = doc.createParagraph();
var questionDescriptionRun = questionDescription.createRun();
questionDescriptionRun.setText(description);
}
question.description().getPictures().forEach(p -> addPictures(p, doc));
}
......
......@@ -5,6 +5,7 @@ import com.quiz.converter.handlers.QuestionHandler;
import com.quiz.converter.handlers.QuestionValidationHandler;
import com.quiz.converter.models.*;
import com.quiz.converter.models.enums.ParagraphType;
import com.quiz.converter.models.enums.QuestionWarningType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.springframework.stereotype.Service;
......@@ -45,7 +46,10 @@ public class FileUploadService {
state.setPreviousParagraphType(paragraphType);
}
case QUESTION_DESCRIPTION -> {
state.setDescription(new QuestionDescription(text, paragraphPictures));
var descriptionTexts = state.getDescription().getTexts();
descriptionTexts.add(text);
var descriptionPictures = state.getDescription().getPictures();
descriptionPictures.addAll(paragraphPictures);
state.setPreviousParagraphType(paragraphType);
}
case FEEDBACK, DEFAULT_FEEDBACK -> {
......@@ -73,12 +77,17 @@ public class FileUploadService {
private ParagraphType getParagraphType(String text, QuestionState state) {
if (text.replaceAll("\t", "").isEmpty() || text.replaceAll("\n", "").isEmpty()) return ParagraphType.EMPTY_TEXT;
var lowerCaseText = text.toLowerCase().strip();
if (lowerCaseText.startsWith("question")) return ParagraphType.QUESTION_DETAILS;
if (lowerCaseText.matches("\s*(question).*")) return ParagraphType.QUESTION_DETAILS;
if (lowerCaseText.matches("\s*(feedback).*")) return ParagraphType.FEEDBACK;
if (lowerCaseText.matches(".*(default)\s*(feedback).*")) return ParagraphType.DEFAULT_FEEDBACK;
if (lowerCaseText.matches("(\\s*\\**\\s*)*[a-zA-Z\\d]\\s*[:)].*")) return ParagraphType.ANSWER_OPTION;
if (state.getPreviousParagraphType().equals(ParagraphType.QUESTION_DETAILS))
return ParagraphType.QUESTION_DESCRIPTION;
if (lowerCaseText.startsWith("feedback")) return ParagraphType.FEEDBACK;
if (lowerCaseText.startsWith("default feedback")) return ParagraphType.DEFAULT_FEEDBACK;
return ParagraphType.ANSWER_OPTION;
if (state.getPreviousParagraphType().equals(ParagraphType.QUESTION_DESCRIPTION)) {
return ParagraphType.QUESTION_DESCRIPTION;
}
state.getWarnings().add(QuestionWarningType.UNKNOWN_PARAGRAPH_TYPE);
return ParagraphType.UNKNOWN;
}
private List<Picture> handleParagraphPictures(XWPFParagraph paragraph) {
......@@ -98,14 +107,8 @@ public class FileUploadService {
}
private Answer createAnswerFromString(String text, List<Picture> paragraphPictures) {
var isCorrectAnswer = text.strip().startsWith("*");
var indexOfColon = !text.contains(":") ? Integer.MAX_VALUE : text.indexOf(":");
var indexOfParenthesis = !text.contains(")") ? Integer.MAX_VALUE : text.indexOf(")");
if (text.contains(")") || text.contains(":")) {
text = text.substring(Math.min(indexOfColon, indexOfParenthesis) + 1);
}
return new Answer(text, null, isCorrectAnswer, paragraphPictures);
var isCorrectAnswer = text.strip().matches("(\\s*\\*+\s*).*");
var answerText = text.strip().replaceAll("(\\s*\\**\\s*)*[a-zA-Z\\d]\\s*[:)]", "");
return new Answer(answerText, null, isCorrectAnswer, paragraphPictures);
}
}
......@@ -83,7 +83,10 @@ public class MoodleXmlCreatorService {
questionElem.appendChild(questionTextElem);
var textElem = doc.createElement("text");
var descriptionContent = new StringBuilder(question.description().getText());
var descriptionContent = new StringBuilder();
for (var description : question.description().getTexts()) {
descriptionContent.append("<br>").append(description);
}
for (var picture : question.description().getPictures()) {
descriptionContent.append(addPicture(doc, picture, questionTextElem));
......
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