def create_question(self, title_text=None, points=True):
        env = self.state.document.settings.env
        env.question_count += 1

        # Create base element and data.
        node = aplus_nodes.html('div', {
            'class': ' '.join(self.get_classes()),
        })
        data = {
            'type': self.grader_field_type(),
            'extra_info': self.get_extra_info(),
        }
        key = self.options.get('key', None)
        if key:
            data['key'] = key

        # Add title.
        if not title_text is None:
            data['title'] = title_text
        elif env.questionnaire_is_feedback:
            data['title'] = title_text = ''
        else:
            # "#" in the question title is converted to a number in the MOOC-grader.
            # The questions of a "pick randomly" questionnaire should be numbered
            # in the MOOC-grader since they are randomly selected.
            postfix = '{#}' if env.aplus_pick_randomly_quiz else "{:d}".format(
                env.question_count)
            data['title|i18n'] = translations.opt('question', postfix=postfix)
            title_text = "{} {:d}".format(translations.get(env, 'question'),
                                          env.question_count)
        if title_text:
            title = aplus_nodes.html('label', {})
            title.append(nodes.Text(title_text))
            node.append(title)

        # Add configuration.
        if points and len(self.arguments) > 0:
            question_points = int(self.arguments[0])
            data['points'] = question_points
            env.aplus_quiz_total_points += question_points
            if env.aplus_pick_randomly_quiz:
                if env.aplus_single_question_points is None:
                    env.aplus_single_question_points = question_points
                else:
                    if env.aplus_single_question_points != question_points:
                        source, line = self.state_machine.get_source_and_line(
                            self.lineno)
                        logger.warning(
                            "Each question must have equal points when "
                            "the questionnaire uses the 'pick randomly' option.",
                            location=(source, line))

        if 'required' in self.options:
            data['required'] = True
        node.set_yaml(data, 'question')

        return env, node, data
Exemple #2
0
    def create_question(self, title_text=None, points=True):
        env = self.state.document.settings.env
        env.question_count += 1

        # Create base element and data.
        node = aplus_nodes.html(u'div', {
            u'class': u' '.join(self.get_classes()),
        })
        data = {
            u'type': self.grader_field_type(),
            u'extra_info': self.get_extra_info(),
        }
        key = self.options.get('key', None)
        if key:
            data[u'key'] = yaml_writer.ensure_unicode(key)

        # Add title.
        if not title_text is None:
            data[u'title'] = title_text
        elif env.questionnaire_is_feedback:
            data[u'title'] = title_text = u''
        else:
            data[u'title|i18n'] = translations.opt('question',
                                                   postfix=u" {:d}".format(
                                                       env.question_count))
            title_text = u"{} {:d}".format(translations.get(env, 'question'),
                                           env.question_count)
        if title_text:
            title = aplus_nodes.html(u'label', {})
            title.append(nodes.Text(title_text))
            node.append(title)

        # Add configuration.
        if points and len(self.arguments) > 0:
            question_points = int(self.arguments[0])
            data['points'] = question_points
            env.aplus_quiz_total_points += question_points
            if env.aplus_pick_randomly_quiz:
                if env.aplus_single_question_points is None:
                    env.aplus_single_question_points = question_points
                else:
                    if env.aplus_single_question_points != question_points:
                        source, line = self.state_machine.get_source_and_line(
                            self.lineno)
                        logger.warning(
                            "Each question must have equal points when "
                            "the questionnaire uses the 'pick randomly' option.",
                            location=(source, line))

        if 'required' in self.options:
            data[u'required'] = True
        node.set_yaml(data, u'question')

        return env, node, data
 def generate_options(self, env, node):
     options = []
     for i, key in enumerate(['agreement4', 'agreement3', 'agreement2', 'agreement1', 'agreement0']):
         options.append({
             u'value': 4 - i,
             u'label|i18n': translations.opt(key),
         })
         choice = aplus_nodes.html(u'div', {u'class':u'radio'})
         label = aplus_nodes.html(u'label', {})
         label.append(aplus_nodes.html(u'input', {
             u'type': u'radio',
             u'name': u'field_{:d}'.format(env.question_count - 1),
             u'value': 4 - i,
         }))
         label.append(nodes.Text(translations.get(env, key)))
         choice.append(label)
         node.append(choice)
     return options
 def generate_options(self, env, node):
     options = []
     for i, key in enumerate(['agreement4', 'agreement3', 'agreement2', 'agreement1', 'agreement0']):
         options.append({
             u'value': 4 - i,
             u'label|i18n': translations.opt(key),
         })
         choice = aplus_nodes.html(u'div', {u'class':u'radio'})
         label = aplus_nodes.html(u'label', {})
         label.append(aplus_nodes.html(u'input', {
             u'type': u'radio',
             u'name': u'field_{:d}'.format(env.question_count - 1),
             u'value': 4 - i,
         }))
         label.append(nodes.Text(translations.get(env, key)))
         choice.append(label)
         node.append(choice)
     return options
    def create_question(self, title_text=None, points=True):
        env = self.state.document.settings.env
        env.question_count += 1

        # Create base element and data.
        node = aplus_nodes.html(u'div', {
            u'class': u' '.join(self.get_classes()),
        })
        data = {
            u'type': self.grader_field_type(),
            u'extra_info': self.get_extra_info(),
        }
        key = self.options.get('key', None)
        if key:
            data[u'key'] = yaml_writer.ensure_unicode(key)

        # Add title.
        if not title_text is None:
            data[u'title'] = title_text
        elif env.questionnaire_is_feedback:
            data[u'title'] = title_text = u''
        else:
            data[u'title|i18n'] = translations.opt('question',
                                                   postfix=u" {:d}".format(
                                                       env.question_count))
            title_text = u"{} {:d}".format(translations.get(env, 'question'),
                                           env.question_count)
        if title_text:
            title = aplus_nodes.html(u'label', {})
            title.append(nodes.Text(title_text))
            node.append(title)

        # Add configuration.
        if points and len(self.arguments) > 0:
            env.aplus_quiz_total_points += int(self.arguments[0])
            data[u'points'] = int(self.arguments[0])
        if 'required' in self.options:
            data[u'required'] = True
        node.set_yaml(data, u'question')

        return env, node, data
    def create_question(self, title_text=None, points=True):
        env = self.state.document.settings.env
        env.question_count += 1

        # Create base element and data.
        node = aplus_nodes.html(u'div', {
            u'class': u' '.join(self.get_classes()),
        })
        data = {
            u'type': self.grader_field_type(),
            u'extra_info': self.get_extra_info(),
        }
        key = self.options.get('key', None)
        if key:
            data[u'key'] = yaml_writer.ensure_unicode(key)

        # Add title.
        if not title_text is None:
            data[u'title'] = title_text
        elif env.questionnaire_is_feedback:
            data[u'title'] = title_text = u''
        else:
            data[u'title|i18n'] = translations.opt('question', postfix=u" {:d}".format(env.question_count))
            title_text = u"{} {:d}".format(translations.get(env, 'question'), env.question_count)
        if title_text:
            title = aplus_nodes.html(u'label', {})
            title.append(nodes.Text(title_text))
            node.append(title)

        # Add configuration.
        if points and len(self.arguments) > 0:
            data[u'points'] = int(self.arguments[0])
        if 'required' in self.options:
            data[u'required'] = True
        node.set_yaml(data, u'question')

        return env, node, data
Exemple #7
0
    def run(self):
        self.assert_has_content()
        key, difficulty, points = self.extract_exercise_arguments()

        # Parse options.
        classes = [u'exercise']
        is_feedback = False
        if 'chapter-feedback' in self.options:
            classes.append(u'chapter-feedback')
            is_feedback = True
        if 'weekly-feedback' in self.options:
            classes.append(u'weekly-feedback')
            is_feedback = True
        if 'appendix-feedback' in self.options:
            classes.append(u'appendix-feedback')
            is_feedback = True
        if 'course-feedback' in self.options:
            classes.append(u'course-feedback-questionnaire')
            is_feedback = True
        if 'feedback' in self.options:
            is_feedback = True
        if is_feedback:
            key = u'feedback'
            category = u'feedback'
            classes.append(u'feedback')
        else:
            category = u'questionnaire'
            if difficulty:
                classes.append(u'difficulty-' + difficulty)

        if 'category' in self.options:
            category = str(self.options.get('category'))

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        env.questionnaire_is_feedback = is_feedback
        env.question_count = 0
        env.aplus_single_question_points = None
        env.aplus_quiz_total_points = 0
        env.aplus_pick_randomly_quiz = 'pick_randomly' in self.options

        # Create document elements.
        node = aplus_nodes.html(
            u'div', {
                u'class': u' '.join(classes),
                u'data-aplus-exercise': u'yes',
                u'data-aplus-quiz': u'yes',
            })
        form = aplus_nodes.html(u'form', {
            u'action': key,
            u'method': u'post',
        })
        nested_parse_with_titles(self.state, self.content, form)

        submit = aplus_nodes.html(u'input', {
            u'type': u'submit',
            u'value': translations.get(env, u'submit'),
            u'class': u'btn btn-primary',
        },
                                  skip_html=True)
        form.append(submit)
        node.append(form)

        # Write configuration file.
        data = {
            u'key':
            name,
            u'category':
            category,
            u'difficulty':
            difficulty or '',
            u'max_submissions':
            self.options.get(
                'submissions', 0 if is_feedback else
                env.config.questionnaire_default_submissions),
            u'min_group_size':
            1 if is_feedback else env.config.default_min_group_size,
            u'max_group_size':
            1 if is_feedback else env.config.default_max_group_size,
            u'points_to_pass':
            self.options.get('points-to-pass', 0),
            u'feedback':
            is_feedback,
            u'view_type':
            u'access.types.stdsync.createForm',
            u'status':
            self.options.get('status', 'unlisted'),
            u'fieldgroups': [{
                u'title': '',
                u'fields': (u'#!children', None),
            }],
        }
        self.set_assistant_permissions(data)

        points_set_in_arguments = len(
            self.arguments) == 2 and difficulty != self.arguments[1]

        if 'pick_randomly' in self.options:
            calculated_max_points = (self.options.get('pick_randomly') *
                                     env.aplus_single_question_points
                                     if env.aplus_single_question_points
                                     is not None else 0)
        else:
            calculated_max_points = env.aplus_quiz_total_points

        if calculated_max_points == 0 and is_feedback:
            data['max_points'] = points
        else:
            if points_set_in_arguments and calculated_max_points != points:
                source, line = self.state_machine.get_source_and_line(
                    self.lineno)
                raise SphinxError(
                    source + ": line " + str(line) +
                    "\nThe points of the questions in the questionnaire must add up to the total points of the questionnaire!"
                )
            data['max_points'] = calculated_max_points

        if 'title' in self.options:
            data['title'] = self.options.get('title')
        else:
            data[u'title|i18n'] = translations.opt(
                'feedback') if is_feedback else translations.opt(
                    'exercise', postfix=u" {}".format(key))

        if not 'no-override' in self.options and category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)
        if "pick_randomly" in self.options:
            pick_randomly = self.options.get('pick_randomly', 0)
            if pick_randomly < 1:
                raise SphinxError(
                    u'Number of fields to sample randomly should greater than zero.'
                )
            data[u'fieldgroups'][0]['pick_randomly'] = pick_randomly

        form.write_yaml(env, name, data, 'exercise')

        return [node]
    def run(self):
        self.assert_has_content()
        key, difficulty, points = self.extract_exercise_arguments()

        # Parse options.
        classes = ['exercise']
        is_feedback = False
        if 'chapter-feedback' in self.options:
            classes.append('chapter-feedback')
            is_feedback = True
        if 'weekly-feedback' in self.options:
            classes.append('weekly-feedback')
            is_feedback = True
        if 'appendix-feedback' in self.options:
            classes.append('appendix-feedback')
            is_feedback = True
        if 'course-feedback' in self.options:
            classes.append('course-feedback-questionnaire')
            is_feedback = True
        if 'feedback' in self.options:
            is_feedback = True
        if is_feedback:
            key = 'feedback'
            category = 'feedback'
            classes.append('feedback')
        else:
            category = 'questionnaire'
            if difficulty:
                classes.append('difficulty-' + difficulty)

        if 'category' in self.options:
            category = str(self.options.get('category'))

        env = self.state.document.settings.env
        name = "{}_{}".format(env.docname.replace('/', '_'), key)
        override = env.config.override

        env.questionnaire_is_feedback = is_feedback
        env.question_count = 0
        env.aplus_single_question_points = None
        env.aplus_quiz_total_points = 0
        env.aplus_pick_randomly_quiz = 'pick_randomly' in self.options
        env.aplus_random_question_exists = False

        # Create document elements.
        node = aplus_nodes.html('div', {
            'class': ' '.join(classes),
            'data-aplus-exercise': 'yes',
        })
        form = aplus_nodes.html('form', {
            'action': key,
            'method': 'post',
        })
        nested_parse_with_titles(self.state, self.content, form)

        submit = aplus_nodes.html('input', {
            'type': 'submit',
            'value': translations.get(env, 'submit'),
            'class': 'btn btn-primary',
        },
                                  skip_html=True)
        form.append(submit)
        node.append(form)

        # Write configuration file.
        data = {
            'key':
            name,
            'category':
            category,
            'difficulty':
            difficulty or '',
            'max_submissions':
            self.options.get(
                'submissions', 0 if is_feedback else
                env.config.questionnaire_default_submissions),
            'min_group_size':
            1 if is_feedback else env.config.default_min_group_size,
            'max_group_size':
            1 if is_feedback else env.config.default_max_group_size,
            'points_to_pass':
            self.options.get('points-to-pass', 0),
            'feedback':
            is_feedback,
            'view_type':
            'access.types.stdsync.createForm',
            'status':
            self.options.get('status', 'unlisted'),
            'fieldgroups': [{
                'title': '',
                'fields': ('#!children', None),
            }],
            # The RST source file path is needed for fixing relative URLs
            # in the exercise description.
            # Replace the Windows path separator backslash \ with the Unix forward slash /.
            '_rst_srcpath':
            env.doc2path(env.docname, None).replace('\\', '/'),
        }

        meta_data = env.metadata[env.app.config.master_doc]
        # Show the model answer after the last submission.
        if 'reveal-model-at-max-submissions' in self.options:
            data['reveal_model_at_max_submissions'] = str_to_bool(
                self.options['reveal-model-at-max-submissions'])
        else:
            default_reveal = str_to_bool(
                meta_data.get(
                    'questionnaire-default-reveal-model-at-max-submissions',
                    'false'),
                error_msg_prefix=env.app.config.master_doc +
                " questionnaire-default-reveal-model-at-max-submissions: ")
            if default_reveal:
                data['reveal_model_at_max_submissions'] = default_reveal
        # Show the model answer after the module deadline.
        if 'show-model' in self.options:
            data['show_model_answer'] = str_to_bool(self.options['show-model'])
        else:
            show_default = str_to_bool(
                meta_data.get('questionnaire-default-show-model', 'true'),
                error_msg_prefix=env.app.config.master_doc +
                " questionnaire-default-show-model: ")
            if not show_default:
                data['show_model_answer'] = show_default

        if env.aplus_pick_randomly_quiz:
            pick_randomly = self.options.get('pick_randomly', 0)
            if pick_randomly < 1:
                source, line = self.state_machine.get_source_and_line(
                    self.lineno)
                raise SphinxError(
                    source + ": line " + str(line) +
                    "\nNumber of fields to sample randomly should be greater than zero "
                    "(option pick_randomly in the questionnaire directive).")
            data['fieldgroups'][0]['pick_randomly'] = pick_randomly
            if 'preserve-questions-between-attempts' in self.options:
                data['fieldgroups'][0]['resample_after_attempt'] = False
        elif not env.aplus_random_question_exists:
            # The HTML attribute data-aplus-quiz makes the A+ frontend show the
            # questionnaire feedback in place of the exercise description once
            # the student has submitted at least once. In randomized questionnaires,
            # the same form may not be submitted again due to one-time use nonce
            # values, hence the attribute must not be used in randomized
            # questionnaires.
            node.attributes['data-aplus-quiz'] = 'yes'

        if 'autosave' in self.options or env.config.enable_autosave:
            node.attributes['data-aplus-autosave'] = 'yes'

        self.set_assistant_permissions(data)

        points_set_in_arguments = len(
            self.arguments) == 2 and difficulty != self.arguments[1]

        if env.aplus_pick_randomly_quiz:
            calculated_max_points = (self.options.get('pick_randomly') *
                                     env.aplus_single_question_points
                                     if env.aplus_single_question_points
                                     is not None else 0)
        else:
            calculated_max_points = env.aplus_quiz_total_points

        if calculated_max_points == 0 and is_feedback:
            data['max_points'] = points
        else:
            if points_set_in_arguments and calculated_max_points != points:
                source, line = self.state_machine.get_source_and_line(
                    self.lineno)
                raise SphinxError(
                    source + ": line " + str(line) +
                    "\nThe points of the questions in the questionnaire must add up to the total points of the questionnaire!"
                )
            data['max_points'] = calculated_max_points

        if 'title' in self.options:
            data['title'] = self.options.get('title')
        else:
            data['title|i18n'] = translations.opt(
                'feedback') if is_feedback else translations.opt(
                    'exercise', postfix=" {}".format(key))

        source, line = self.state_machine.get_source_and_line(self.lineno)
        if 'reveal-submission-feedback' in self.options:
            data['reveal_submission_feedback'] = parse_reveal_rule(
                self.options['reveal-submission-feedback'],
                source,
                line,
                'reveal-submission-feedback',
            )
        if 'reveal-model-solutions' in self.options:
            data['reveal_model_solutions'] = parse_reveal_rule(
                self.options['reveal-model-solutions'],
                source,
                line,
                'reveal-model-solutions',
            )

        if 'grading-mode' in self.options:
            data['grading_mode'] = self.options['grading-mode']

        if not 'no-override' in self.options and category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        form.write_yaml(env, name, data, 'exercise')

        return [node]
    def run(self):
        self.assert_has_content()
        key, difficulty, points = self.extract_exercise_arguments()

        # Parse options.
        classes = [u'exercise']
        is_feedback = False
        if 'chapter-feedback' in self.options:
            classes.append(u'chapter-feedback')
            is_feedback = True
        if 'weekly-feedback' in self.options:
            classes.append(u'weekly-feedback')
            is_feedback = True
        if 'appendix-feedback' in self.options:
            classes.append(u'appendix-feedback')
            is_feedback = True
        if 'course-feedback' in self.options:
            classes.append(u'course-feedback-questionnaire')
            is_feedback = True
        if 'feedback' in self.options:
            is_feedback = True
        if is_feedback:
            key = u'feedback'
            category = u'feedback'
            classes.append(u'feedback')
        else:
            category = u'questionnaire'
            if difficulty:
                classes.append(u'difficulty-' + difficulty)

        if 'category' in self.options:
            category = str(self.options.get('category'))

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        env.questionnaire_is_feedback = is_feedback
        env.question_count = 0

        # Create document elements.
        node = aplus_nodes.html(u'div', {
            u'class': u' '.join(classes),
            u'data-aplus-exercise': u'yes',
            u'data-aplus-quiz': u'yes',
        })
        form = aplus_nodes.html(u'form', {
            u'action': key,
            u'method': u'post',
        })
        nested_parse_with_titles(self.state, self.content, form)

        submit = aplus_nodes.html(u'input', {
            u'type': u'submit',
            u'value': translations.get(env, u'submit'),
            u'class': u'btn btn-primary',
        }, skip_html=True)
        form.append(submit)
        node.append(form)

        # Write configuration file.
        data = {
            u'key': name,
            u'category': category,
            u'max_points': points,
            u'difficulty': difficulty or '',
            u'max_submissions': self.options.get('submissions', 0 if is_feedback else env.config.questionnaire_default_submissions),
            u'min_group_size': 1 if is_feedback else env.config.default_min_group_size,
            u'max_group_size': 1 if is_feedback else env.config.default_max_group_size,
            u'points_to_pass': self.options.get('points-to-pass', 0),
            u'feedback': is_feedback,
            u'view_type': u'access.types.stdsync.createForm',
            u'title|i18n': translations.opt('feedback') if is_feedback else translations.opt('exercise', postfix=u" {}".format(key)),
            u'fieldgroups': [{
                u'title': '',
                u'fields': (u'#!children', None),
            }],
        }
        if not 'no-override' in self.options and category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)
        if "pick_randomly" in self.options:
            pick_randomly = self.options.get('pick_randomly', 0)
            if pick_randomly < 1:
                raise SphinxError(u'Number of fields to sample randomly should greater than zero.')
            data[u'fieldgroups'][0]['pick_randomly'] = pick_randomly

        form.write_yaml(env, name, data, 'exercise')

        return [node]