Beispiel #1
0
def normalize_flow_desc(flow_desc):
    if hasattr(flow_desc, "pages"):
        pages = flow_desc.pages
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(flow_desc)
        del d["pages"]
        d["groups"] = [Struct({"id": "main", "pages": pages})]
        return Struct(d)

    if hasattr(flow_desc, "rules"):
        rules = flow_desc.rules
        if not hasattr(rules, "grade_identifier"):
            # Legacy content with grade_identifier in grading rule,
            # move first found grade_identifier up to rules.

            rules.grade_identifier = None
            rules.grade_aggregation_strategy = None

            for grule in rules.grading:
                if grule.grade_identifier is not None:
                    rules.grade_identifier = grule.grade_identifier
                    rules.grade_aggregation_strategy = \
                            grule.grade_aggregation_strategy
                    break

    return flow_desc
Beispiel #2
0
def normalize_flow_desc(flow_desc):
    if hasattr(flow_desc, "pages"):
        pages = flow_desc.pages
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(flow_desc)
        del d["pages"]
        d["groups"] = [Struct({"id": "main", "pages": pages})]
        return Struct(d)

    if hasattr(flow_desc, "rules"):
        rules = flow_desc.rules
        if not hasattr(rules, "grade_identifier"):
            # Legacy content with grade_identifier in grading rule,
            # move first found grade_identifier up to rules.

            rules.grade_identifier = None
            rules.grade_aggregation_strategy = None

            for grule in rules.grading:
                if grule.grade_identifier is not None:
                    rules.grade_identifier = grule.grade_identifier
                    rules.grade_aggregation_strategy = \
                            grule.grade_aggregation_strategy
                    break

    return flow_desc
Beispiel #3
0
def normalize_page_desc(page_desc):
    if hasattr(page_desc, "content"):
        content = page_desc.content
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(page_desc)
        del d["content"]
        d["chunks"] = [Struct({"id": "main", "content": content})]
        return Struct(d)

    return page_desc
Beispiel #4
0
def normalize_page_desc(page_desc):
    if hasattr(page_desc, "content"):
        content = page_desc.content
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(page_desc)
        del d["content"]
        d["chunks"] = [Struct({"id": "main", "content": content})]
        return Struct(d)

    return page_desc
Beispiel #5
0
def normalize_flow_desc(flow_desc):
    if hasattr(flow_desc, "pages"):
        pages = flow_desc.pages
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(flow_desc)
        del d["pages"]
        d["groups"] = [Struct({"id": "main", "pages": pages})]
        return Struct(d)

    return flow_desc
Beispiel #6
0
def normalize_flow_desc(flow_desc):
    if hasattr(flow_desc, "pages"):
        pages = flow_desc.pages
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(flow_desc)
        del d["pages"]
        d["groups"] = [Struct({"id": "main", "pages": pages})]
        return Struct(d)

    return flow_desc
Beispiel #7
0
def normalize_page_desc(page_desc):
    # type: (StaticPageDesc) -> StaticPageDesc
    if hasattr(page_desc, "content"):
        content = page_desc.content
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(page_desc)
        del d["content"]
        d["chunks"] = [Struct({"id": "main", "content": content})]
        return cast(StaticPageDesc, Struct(d))

    return page_desc
Beispiel #8
0
def normalize_page_desc(page_desc):
    # type: (StaticPageDesc) -> StaticPageDesc
    if hasattr(page_desc, "content"):
        content = page_desc.content
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(page_desc)
        del d["content"]
        d["chunks"] = [Struct({"id": "main", "content": content})]
        return cast(StaticPageDesc, Struct(d))

    return page_desc
Beispiel #9
0
    def __init__(self, vctx, location, page_desc):
        super(InlineMultiQuestion, self).__init__(vctx, location, page_desc)

        expanded_question = page_desc.question

        self.embedded_wrapped_name_list = WRAPPED_NAME_RE.findall(
            expanded_question)
        self.embedded_name_list = NAME_RE.findall(expanded_question)

        answer_instance_list = []

        for idx, name in enumerate(self.embedded_name_list):
            answers_desc = getattr(self.page_desc.answers, name)

            parsed_answer = parse_question(vctx, location, name, answers_desc)
            answer_instance_list.append(parsed_answer)

        self.answer_instance_list = answer_instance_list

        from relate.utils import struct_to_dict
        answers_name_list = struct_to_dict(page_desc.answers).keys()

        invalid_answer_name = []
        invalid_embedded_name = []

        if not answer_instance_list:
            raise ValidationError(
                string_concat(
                    "%(location)s: ",
                    _("InlineMultiQuestion requires at least one "
                      "answer field to be defined.")) % {'location': location})

        for answers_name in answers_name_list:
            if NAME_VALIDATE_RE.match(answers_name) is None:
                invalid_answer_name.append(answers_name)
        if len(invalid_answer_name) > 0:
            raise ValidationError(
                string_concat(
                    "%s: ", _("invalid answers name %s. "),
                    _("A valid name should start with letters. "
                      "Alphanumeric with underscores. "
                      "Do not use spaces.")) % (location, ", ".join(
                          ["'" + name + "'" for name in invalid_answer_name])))

        for embedded_name in self.embedded_name_list:
            if NAME_VALIDATE_RE.match(embedded_name) is None:
                invalid_embedded_name.append(embedded_name)
        if len(invalid_embedded_name) > 0:
            raise ValidationError(
                string_concat(
                    "%s: ", _("invalid embedded question name %s. "),
                    _("A valid name should start with letters. "
                      "Alphanumeric with underscores. "
                      "Do not use spaces.")) % (location, ", ".join(
                          ["'" + name + "'"
                           for name in invalid_embedded_name])))

        if len(set(self.embedded_name_list)) < len(self.embedded_name_list):
            duplicated = list(
                set([
                    x for x in self.embedded_name_list
                    if self.embedded_name_list.count(x) > 1
                ]))
            raise ValidationError(
                string_concat("%s: ",
                              _("embedded question name %s not unique.")) %
                (location, ", ".join(duplicated)))

        no_answer_set = set(self.embedded_name_list) - set(answers_name_list)
        redundant_answer_list = list(
            set(answers_name_list) - set(self.embedded_name_list))

        if no_answer_set:
            raise ValidationError(
                string_concat(
                    "%s: ",
                    _("correct answer(s) not provided for question %s.")) %
                (location, ", ".join(
                    ["'" + item + "'" for item in list(no_answer_set)])))

        if redundant_answer_list:
            if vctx is not None:
                vctx.add_warning(
                    location,
                    _("redundant answers %s provided for "
                      "non-existing question(s).") % ", ".join(
                          ["'" + item + "'"
                           for item in redundant_answer_list]))

        if vctx is not None:
            validate_markup(vctx, location, page_desc.question)

            def reverse_func(*args, **kwargs):
                pass

            # FIXME This is a bit redundant since validate_markup already calls
            # markup_to_html.
            remainder_html = markup_to_html(vctx,
                                            page_desc.question,
                                            reverse_func=reverse_func)

            html_list = []
            for wrapped_name in self.embedded_wrapped_name_list:
                [html, remainder_html] = remainder_html.split(wrapped_name)
                html_list.append(html)

            if remainder_html != "":
                html_list.append(remainder_html)

            # make sure all [[ and ]] are paired.
            embedded_removed = " ".join(html_list)

            for sep in ["[[", "]]"]:
                if sep in embedded_removed:
                    raise ValidationError(
                        string_concat("%s: ", _("have unpaired '%s'.")) %
                        (location, sep))

            for idx, name in enumerate(self.embedded_name_list):
                answers_desc = getattr(page_desc.answers, name)

                parse_question(vctx, location, name, answers_desc)
Beispiel #10
0
    def __init__(self, vctx, location, page_desc):
        super(InlineMultiQuestion, self).__init__(
                vctx, location, page_desc)

        expanded_question = page_desc.question

        self.embedded_wrapped_name_list = WRAPPED_NAME_RE.findall(expanded_question)
        self.embedded_name_list = NAME_RE.findall(expanded_question)

        answer_instance_list = []

        for idx, name in enumerate(self.embedded_name_list):
            answers_desc = getattr(self.page_desc.answers, name)

            parsed_answer = parse_question(
                    vctx, location, name, answers_desc)
            answer_instance_list.append(parsed_answer)

        self.answer_instance_list = answer_instance_list

        from relate.utils import struct_to_dict
        answers_name_list = struct_to_dict(page_desc.answers).keys()

        invalid_answer_name = []

        if not answer_instance_list:
            raise ValidationError(
                    string_concat(
                        "%(location)s: ",
                        _("InlineMultiQuestion requires at least one "
                        "answer field to be defined."))
                    % {'location': location})

        for answers_name in answers_name_list:
            if NAME_VALIDATE_RE.match(answers_name) is None:
                invalid_answer_name.append(answers_name)
        if invalid_answer_name:
            raise ValidationError(
                    string_concat(
                        "%s: ",
                        _("invalid answers name %s. "),
                        _("A valid name should start with letters. "
                            "Alphanumeric with underscores. "
                            "Do not use spaces."))
                    % (
                        location,
                        ", ".join([
                            "'" + name + "'"
                            for name in invalid_answer_name])
                        ))

        if len(set(self.embedded_name_list)) < len(self.embedded_name_list):
            duplicated = list(
                 set([x for x in self.embedded_name_list
                      if self.embedded_name_list.count(x) > 1]))
            raise ValidationError(
                 string_concat(
                     "%s: ",
                     _("embedded question name %s not unique."))
                 % (location, ", ".join(["'%s'" % d for d in sorted(duplicated)])))

        redundant_answer_list = list(set(answers_name_list)
                - set(self.embedded_name_list))

        if redundant_answer_list:
            if vctx is not None:
                vctx.add_warning(location,
                        _("redundant answers %s provided for "
                            "non-existing question(s).")
                        % ", ".join(
                            ["'" + item + "'"
                                for item in redundant_answer_list]))

        if vctx is not None:
            validate_markup(vctx, location, page_desc.question)

            remainder_html = page_desc.question
            html_list = []
            for wrapped_name in self.embedded_wrapped_name_list:
                [html, remainder_html] = remainder_html.split(wrapped_name)
                html_list.append(html)

            if remainder_html.strip():
                html_list.append(remainder_html)

            # make sure all [[ and ]] are paired.
            embedded_removed = " ".join(html_list)

            for sep in ["[[", "]]"]:
                if sep in embedded_removed:
                    raise ValidationError(
                        string_concat(
                            "%s: ",
                            _("question has unpaired '%s'."))
                        % (location, sep))

            for idx, name in enumerate(self.embedded_name_list):
                answers_desc = getattr(page_desc.answers, name)

                parse_question(vctx, location, name, answers_desc)
Beispiel #11
0
    def __init__(self, vctx, location, page_desc):
        super(InlineMultiQuestion, self).__init__(
                vctx, location, page_desc)

        self.embeded_wrapped_name_list = WRAPPED_NAME_RE.findall(
                page_desc.question)
        self.embeded_name_list = NAME_RE.findall(page_desc.question)

        from relate.utils import struct_to_dict
        answers_name_list = struct_to_dict(page_desc.answers).keys()

        invalid_answer_name = []
        invalid_embeded_name = []

        for answers_name in answers_name_list:
            if NAME_VALIDATE_RE.match(answers_name) is None:
                invalid_answer_name.append(answers_name)
        if len(invalid_answer_name) > 0:
            raise ValidationError(
                    string_concat(
                        "%s: ",
                        _("invalid answers name %s. "),
                        _("A valid name should start with letters. "
                            "Alphanumeric with underscores. "
                            "Do not use spaces."))
                    % (
                        location,
                        ", ".join([
                            "'" + name + "'"
                            for name in invalid_answer_name])
                        ))

        for embeded_name in self.embeded_name_list:
            if NAME_VALIDATE_RE.match(embeded_name) is None:
                invalid_embeded_name.append(embeded_name)
        if len(invalid_embeded_name) > 0:
            raise ValidationError(
                    string_concat(
                        "%s: ",
                        _("invalid embeded question name %s. "),
                        _("A valid name should start with letters. "
                            "Alphanumeric with underscores. "
                            "Do not use spaces."))
                        % (
                            location,
                            ", ".join([
                                "'" + name + "'"
                                for name in invalid_embeded_name])
                            ))

        if len(set(self.embeded_name_list)) < len(self.embeded_name_list):
            duplicated = list(
                 set([x for x in self.embeded_name_list
                      if self.embeded_name_list.count(x) > 1]))
            raise ValidationError(
                 string_concat(
                     "%s: ",
                     _("embeded question name %s not unique."))
                 % (location, ", ".join(duplicated)))

        no_answer_set = set(self.embeded_name_list) - set(answers_name_list)
        redundant_answer_list = list(set(answers_name_list)
                - set(self.embeded_name_list))

        if no_answer_set:
            raise ValidationError(
                 string_concat(
                     "%s: ",
                     _("correct answer(s) not provided for question %s."))
                 % (location, ", ".join(
                     ["'" + item + "'"
                         for item in list(no_answer_set)])))

        if redundant_answer_list:
            if vctx is not None:
                vctx.add_warning(location,
                        _("redundant answers %s provided for "
                            "non-existing question(s).")
                        % ", ".join(
                            ["'" + item + "'"
                                for item in redundant_answer_list]))

        # for correct render of question with more than one
        # paragraph, remove heading <p> tags and change </p>
        # to line break.
        from course.content import markup_to_html  # noqa
        self.question = remainder_html = markup_to_html(
                course=None,
                repo=None,
                commit_sha=None,
                text=page_desc.question,
                ).replace("<p>", "").replace("</p>", "<br/>")

        self.html_list = []
        for wrapped_name in self.embeded_wrapped_name_list:
            [html, remainder_html] = remainder_html.split(wrapped_name)
            self.html_list.append(html)

        if remainder_html != "":
            self.html_list.append(remainder_html)

        # make sure all [[ and ]] are paired.
        embeded_removed = " ".join(self.html_list)

        for sep in ["[[", "]]"]:
            if sep in embeded_removed:
                raise ValidationError(
                    string_concat(
                        "%s: ",
                        _("have unpaired '%s'."))
                    % (location, sep))

        self.answer_instance_list = []
        self.total_weight = 0

        for idx, name in enumerate(self.embeded_name_list):
            answers_desc = getattr(page_desc.answers, name)

            parsed_answer = parse_question(
                    vctx, location, name, answers_desc)

            self.answer_instance_list.append(parsed_answer)
            self.total_weight += self.answer_instance_list[idx].weight
Beispiel #12
0
    def __init__(self, vctx, location, page_desc):
        super(InlineMultiQuestion, self).__init__(vctx, location, page_desc)

        self.embeded_wrapped_name_list = WRAPPED_NAME_RE.findall(
            page_desc.question)
        self.embeded_name_list = NAME_RE.findall(page_desc.question)

        from relate.utils import struct_to_dict
        answers_name_list = struct_to_dict(page_desc.answers).keys()

        invalid_answer_name = []
        invalid_embeded_name = []

        for answers_name in answers_name_list:
            if NAME_VALIDATE_RE.match(answers_name) is None:
                invalid_answer_name.append(answers_name)
        if len(invalid_answer_name) > 0:
            raise ValidationError(
                string_concat(
                    "%s: ", _("invalid answers name %s. "),
                    _("A valid name should start with letters. "
                      "Alphanumeric with underscores. "
                      "Do not use spaces.")) % (location, ", ".join(
                          ["'" + name + "'" for name in invalid_answer_name])))

        for embeded_name in self.embeded_name_list:
            if NAME_VALIDATE_RE.match(embeded_name) is None:
                invalid_embeded_name.append(embeded_name)
        if len(invalid_embeded_name) > 0:
            raise ValidationError(
                string_concat(
                    "%s: ", _("invalid embeded question name %s. "),
                    _("A valid name should start with letters. "
                      "Alphanumeric with underscores. "
                      "Do not use spaces.")) % (location, ", ".join(
                          ["'" + name + "'"
                           for name in invalid_embeded_name])))

        if len(set(self.embeded_name_list)) < len(self.embeded_name_list):
            duplicated = list(
                set([
                    x for x in self.embeded_name_list
                    if self.embeded_name_list.count(x) > 1
                ]))
            raise ValidationError(
                string_concat("%s: ",
                              _("embeded question name %s not unique.")) %
                (location, ", ".join(duplicated)))

        no_answer_set = set(self.embeded_name_list) - set(answers_name_list)
        redundant_answer_list = list(
            set(answers_name_list) - set(self.embeded_name_list))

        if no_answer_set:
            raise ValidationError(
                string_concat(
                    "%s: ",
                    _("correct answer(s) not provided for question %s.")) %
                (location, ", ".join(
                    ["'" + item + "'" for item in list(no_answer_set)])))

        if redundant_answer_list:
            if vctx is not None:
                vctx.add_warning(
                    location,
                    _("redundant answers %s provided for "
                      "non-existing question(s).") % ", ".join(
                          ["'" + item + "'"
                           for item in redundant_answer_list]))

        # for correct render of question with more than one
        # paragraph, remove heading <p> tags and change </p>
        # to line break.
        from course.content import markup_to_html  # noqa
        self.question = remainder_html = markup_to_html(
            course=None,
            repo=None,
            commit_sha=None,
            text=page_desc.question,
        ).replace("<p>", "").replace("</p>", "<br/>")

        self.html_list = []
        for wrapped_name in self.embeded_wrapped_name_list:
            [html, remainder_html] = remainder_html.split(wrapped_name)
            self.html_list.append(html)

        if remainder_html != "":
            self.html_list.append(remainder_html)

        # make sure all [[ and ]] are paired.
        embeded_removed = " ".join(self.html_list)

        for sep in ["[[", "]]"]:
            if sep in embeded_removed:
                raise ValidationError(
                    string_concat("%s: ", _("have unpaired '%s'.")) %
                    (location, sep))

        self.answer_instance_list = []
        self.total_weight = 0

        for idx, name in enumerate(self.embeded_name_list):
            answers_desc = getattr(page_desc.answers, name)

            parsed_answer = parse_question(vctx, location, name, answers_desc)

            self.answer_instance_list.append(parsed_answer)
            self.total_weight += self.answer_instance_list[idx].weight