h5pAPI.py 6.05 KB
Newer Older
1 2 3
import json
from typing import List

4 5
from flask_restful import Resource, abort
from flask_restful.reqparse import RequestParser
6 7 8 9 10 11 12 13 14 15

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."""
16
        self.reqparse: RequestParser = NetworkService.base_request_parser.copy()
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
        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": "<p>{0}</p>\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": "<p>Click the various types of berries&nbsp;mentioned&nbsp;in the text below!<\/p>\n",
            "textField": "*Bilberries*, also known as *blueberries* are edible, nearly black berries found in nutrient-poor soils.<br><br>*Cloudberries* are edible orange berries similar to *raspberries* or *blackberries* found in alpine and arctic tundra. <br><br>*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"] = "<p>{0}: {1}</p>\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