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
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
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]