import json from typing import List from flask_restful import Resource, abort from flask_restful.reqparse import RequestParser from mcserver.app.models import Language, Exercise, ExerciseType, Solution from mcserver.app.services import TextService, NetworkService class H5pAPI(Resource): """The H5P API resource. It gives users access to interactive exercise layouts.""" def __init__(self): """Initialize possible arguments for calls to the H5P REST API.""" self.reqparse: RequestParser = NetworkService.base_request_parser.copy() self.reqparse.add_argument("eid", type=str, required=True, default="", help="No exercise ID provided") self.reqparse.add_argument("lang", type=str, required=True, default="en", help="No language code provided") self.reqparse.add_argument("solution_indices", type=str, required=False, help="No solution IDs provided") self.feedback_template: str = "{0}: @score {1} @total." self.json_template_drag_text: dict = { "taskDescription": "
{0}
\n", "checkAnswer": "Prüfen", "tryAgain": "Nochmal", "showSolution": "Lösung", "behaviour": { "enableRetry": True, "enableSolutionsButton": True, "instantFeedback": False, "enableCheckButton": True }, "textField": "Blueberries are *blue:Check the name of the berry!*.\nStrawberries are *red*.", "overallFeedback": [{"from": 0, "to": 100, "feedback": "Punkte: @score von @total."}], "dropZoneIndex": "Drop Zone @index.", "empty": "Drop Zone @index is empty.", "contains": "Drop Zone @index contains draggable @draggable.", "draggableIndex": "Draggable @text. @index of @count draggables.", "tipLabel": "Show tip", "correctText": "Correct!", "incorrectText": "Incorrect!", "resetDropTitle": "Reset drop", "resetDropDescription": "Are you sure you want to reset this drop zone?", "grabbed": "Draggable is grabbed.", "cancelledDragging": "Cancelled dragging.", "correctAnswer": "Correct answer:", "feedbackHeader": "Feedback", "scoreBarLabel": "You got :num out of :total points" } self.json_template_mark_words: dict = { "checkAnswerButton": "Check", "tryAgainButton": "Retry", "showSolutionButton": "Show solution", "behaviour": { "enableRetry": True, "enableSolutionsButton": True }, "taskDescription": "Click the various types of berries mentioned in the text below!<\/p>\n",
"textField": "*Bilberries*, also known as *blueberries* are edible, nearly black berries found in nutrient-poor soils.
*Cloudberries* are edible orange berries similar to *raspberries* or *blackberries* found in alpine and arctic tundra.
*Redcurrants* are red translucent berries with a diameter of 8\u201310 mm, and are closely related to *blackcurrants*.",
"overallFeedback": [{"from": 0, "to": 100, "feedback": "You got @score of @total points."}]
}
super(H5pAPI, self).__init__()
def get(self):
""" The GET method for the H5P REST API. It provides json templates for client-side H5P exercise layouts. """
args = self.reqparse.parse_args()
eid: str = args["eid"]
solution_indices: List[int] = json.loads(args["solution_indices"] if args["solution_indices"] else "null")
lang: Language
try:
lang = Language(args["lang"])
except ValueError:
lang = Language.English
exercise: Exercise = Exercise.query.filter_by(eid=eid).first()
if exercise is None:
abort(404)
text_field_content: str = ""
if exercise.exercise_type in [ExerciseType.cloze.value, ExerciseType.markWords.value]:
text_field_content = TextService.get_h5p_text_with_solutions(exercise, solution_indices)
elif exercise.exercise_type == ExerciseType.matching.value:
solutions: List[Solution] = TextService.get_solutions_by_index(exercise, solution_indices)
for solution in solutions:
text_field_content += "{0} *{1}*\n".format(solution.target.content, solution.value.content)
else:
abort(422)
response_dict: dict = self.json_template_mark_words
response_dict = get_response(response_dict, lang, self.json_template_drag_text, exercise, text_field_content,
self.feedback_template)
return NetworkService.make_json_response(response_dict)
def get_response(response_dict: dict, lang: Language, json_template_drag_text: dict, exercise: Exercise,
text_field_content: str, feedback_template: str):
# default values for buttons and response
button_dict: dict = {"check": ["checkAnswerButton", "Prüfen" if lang == Language.German else "Check"],
"again": ["tryAgainButton", "Nochmal" if lang == Language.German else "Retry"],
"solution": ["showSolutionButton", "Lösung" if lang == Language.German else "Solution"]}
if exercise.exercise_type != ExerciseType.markWords.value:
button_dict["check"][0] = "checkAnswer"
button_dict["again"][0] = "tryAgain"
button_dict["solution"][0] = "showSolution"
response_dict = json_template_drag_text
for button in button_dict:
response_dict[button_dict[button][0]] = button_dict[button][1]
response_dict["taskDescription"] = "
{0}: {1}
\n".format(exercise.exercise_type_translation, exercise.instructions) response_dict["textField"] = text_field_content feedback: str = feedback_template.format("Punkte", "von") if lang != Language.German: feedback = feedback_template.format("Score", "of") response_dict["overallFeedback"][0]["feedback"] = feedback return response_dict