def test_link_multiple_skills_for_question_increments_question_count(self):
        opportunity_services.create_skill_opportunity(self.SKILL_ID,
                                                      'description')
        self.save_new_question(self.QUESTION_ID, self.USER_ID,
                               self._create_valid_question_data('ABC'),
                               ['skill_2'])

        question_services.link_multiple_skills_for_question(
            self.USER_ID, self.QUESTION_ID, [self.SKILL_ID], [0.3])

        skill_opportunities, _, _ = (
            opportunity_services.get_skill_opportunities(None))
        opportunity = skill_opportunities[0]
        self.assertEqual(opportunity.question_count, 1)
Exemple #2
0
    def test_create_multi_question_skill_links_for_question(self):
        self.question = self.save_new_question(
            self.question_id, self.editor_id,
            self._create_valid_question_data('ABC'), ['skill_1'])

        with self.assertRaisesRegexp(
            Exception, 'Skill difficulties and skill ids should match. '
            'The lengths of the two lists are different.'):
            question_services.link_multiple_skills_for_question(
                self.editor_id, self.question_id, ['skill_1', 'skill_2'],
                [0.5])
        question_services.link_multiple_skills_for_question(
            self.editor_id, self.question_id, ['skill_1', 'skill_2'],
            [0.5, 0.7])
        skill_ids = [skill.id for skill in
                     question_services.get_skills_linked_to_question(
                         self.question_id)]
        self.assertItemsEqual(skill_ids, ['skill_1', 'skill_2'])
Exemple #3
0
class QuestionCreationHandler(base.BaseHandler):
    """A handler that creates the question model given a question dict."""
    @acl_decorators.can_manage_question_skill_status
    def post(self, comma_separated_skill_ids):
        """Handles POST requests."""
        skill_ids = comma_separated_skill_ids.split(',')
        try:
            for skill_id in skill_ids:
                skill_domain.Skill.require_valid_skill_id(skill_id)
        except Exception:
            raise self.InvalidInputException

        try:
            skill_services.get_multi_skills(skill_ids)
        except Exception, e:
            raise self.PageNotFoundException(e)

        question_dict = self.payload.get('question_dict')
        if ((question_dict['id'] is not None)
                or ('question_state_data' not in question_dict)
                or ('language_code' not in question_dict)
                or (question_dict['version'] != 1)):
            raise self.InvalidInputException

        question_dict['question_state_data_schema_version'] = (
            feconf.CURRENT_STATE_SCHEMA_VERSION)
        question_dict['id'] = question_services.get_new_question_id()
        question_dict['linked_skill_ids'] = skill_ids
        try:
            question = question_domain.Question.from_dict(question_dict)
        except Exception:
            raise self.InvalidInputException
        question_services.add_question(self.user_id, question)
        # TODO(vinitamurthi): Replace DEFAULT_SKILL_DIFFICULTY
        # with a value passed from the frontend.
        question_services.link_multiple_skills_for_question(
            self.user_id, question.id, skill_ids,
            [constants.DEFAULT_SKILL_DIFFICULTY] * len(skill_ids))

        self.values.update({'question_id': question.id})
        self.render_json(self.values)
    def post(self):
        """Handles POST requests."""
        skill_ids = self.payload.get('skill_ids')

        if not skill_ids:
            raise self.InvalidInputException(
                'skill_ids parameter isn\'t present in the payload')

        if len(skill_ids) > constants.MAX_SKILLS_PER_QUESTION:
            raise self.InvalidInputException(
                'More than %d QuestionSkillLinks for one question '
                'is not supported.' % constants.MAX_SKILLS_PER_QUESTION)
        try:
            for skill_id in skill_ids:
                skill_domain.Skill.require_valid_skill_id(skill_id)
        except Exception as e:
            raise self.InvalidInputException('Skill ID(s) aren\'t valid: ', e)

        try:
            skill_fetchers.get_multi_skills(skill_ids)
        except Exception as e:
            raise self.PageNotFoundException(e)

        question_dict = self.payload.get('question_dict')
        if ((question_dict['id'] is not None)
                or ('question_state_data' not in question_dict)
                or ('language_code' not in question_dict)
                or (question_dict['version'] != 0)):
            raise self.InvalidInputException(
                'Question Data should contain id, state data, language code, '
                + 'and its version should be set as 0')

        question_dict['question_state_data_schema_version'] = (
            feconf.CURRENT_STATE_SCHEMA_VERSION)
        question_dict['id'] = question_services.get_new_question_id()
        question_dict['linked_skill_ids'] = skill_ids

        try:
            question = question_domain.Question.from_dict(question_dict)
        except Exception as e:
            raise self.InvalidInputException('Question structure is invalid:',
                                             e)

        skill_difficulties = self.payload.get('skill_difficulties')

        if not skill_difficulties:
            raise self.InvalidInputException(
                'skill_difficulties not present in the payload')
        if len(skill_ids) != len(skill_difficulties):
            raise self.InvalidInputException(
                'Skill difficulties don\'t match up with skill IDs')

        try:
            skill_difficulties = [
                float(difficulty) for difficulty in skill_difficulties
            ]
        except (ValueError, TypeError) as e:
            raise self.InvalidInputException(
                'Skill difficulties must be a float value') from e
        if any((difficulty < 0 or difficulty > 1)
               for difficulty in skill_difficulties):
            raise self.InvalidInputException(
                'Skill difficulties must be between 0 and 1')

        question_services.add_question(self.user_id, question)
        question_services.link_multiple_skills_for_question(
            self.user_id, question.id, skill_ids, skill_difficulties)
        html_list = question.question_state_data.get_all_html_content_strings()
        filenames = (
            html_cleaner.get_image_filenames_from_html_strings(html_list))
        image_validation_error_message_suffix = (
            'Please go to the question editor for question with id %s and edit '
            'the image.' % question.id)
        for filename in filenames:
            image = self.request.get(filename)
            if not image:
                logging.exception(
                    'Image not provided for file with name %s when the question'
                    ' with id %s was created.' % (filename, question.id))
                raise self.InvalidInputException(
                    'No image data provided for file with name %s. %s' %
                    (filename, image_validation_error_message_suffix))
            try:
                file_format = (
                    image_validation_services.validate_image_and_filename(
                        image, filename))
            except utils.ValidationError as e:
                e = '%s %s' % (e, image_validation_error_message_suffix)
                raise self.InvalidInputException(e)
            image_is_compressible = (file_format
                                     in feconf.COMPRESSIBLE_IMAGE_FORMATS)
            fs_services.save_original_and_compressed_versions_of_image(
                filename, feconf.ENTITY_TYPE_QUESTION, question.id, image,
                'image', image_is_compressible)

        self.values.update({'question_id': question.id})
        self.render_json(self.values)
Exemple #5
0
    def post(self):
        """Handles POST requests."""
        skill_ids = self.payload.get('skill_ids')

        if not skill_ids:
            raise self.InvalidInputException(
                'skill_ids parameter isn\'t present in the payload')

        if len(skill_ids) > constants.MAX_SKILLS_PER_QUESTION:
            raise self.InvalidInputException(
                'More than %d QuestionSkillLinks for one question '
                'is not supported.' % constants.MAX_SKILLS_PER_QUESTION)
        try:
            for skill_id in skill_ids:
                skill_domain.Skill.require_valid_skill_id(skill_id)
        except Exception as e:
            raise self.InvalidInputException('Skill ID(s) aren\'t valid: ', e)

        try:
            skill_services.get_multi_skills(skill_ids)
        except Exception as e:
            raise self.PageNotFoundException(e)

        question_dict = self.payload.get('question_dict')
        if ((question_dict['id'] is not None)
                or ('question_state_data' not in question_dict)
                or ('language_code' not in question_dict)
                or (question_dict['version'] != 1)):
            raise self.InvalidInputException(
                'Question Data should contain id, state data, language code, '
                + 'and its version should be set as 1')

        question_dict['question_state_data_schema_version'] = (
            feconf.CURRENT_STATE_SCHEMA_VERSION)
        question_dict['id'] = question_services.get_new_question_id()
        question_dict['linked_skill_ids'] = skill_ids

        try:
            question = question_domain.Question.from_dict(question_dict)
        except Exception as e:
            raise self.InvalidInputException('Question structure is invalid:',
                                             e)

        skill_difficulties = self.payload.get('skill_difficulties')

        if not skill_difficulties:
            raise self.InvalidInputException(
                'skill_difficulties not present in the payload')
        if len(skill_ids) != len(skill_difficulties):
            raise self.InvalidInputException(
                'Skill difficulties don\'t match up with skill IDs')

        try:
            skill_difficulties = [
                float(difficulty) for difficulty in skill_difficulties
            ]
        except (ValueError, TypeError):
            raise self.InvalidInputException(
                'Skill difficulties must be a float value')

        if any((difficulty < 0 or difficulty > 1)
               for difficulty in skill_difficulties):
            raise self.InvalidInputException(
                'Skill difficulties must be between 0 and 1')

        question_services.add_question(self.user_id, question)
        question_services.link_multiple_skills_for_question(
            self.user_id, question.id, skill_ids, skill_difficulties)

        self.values.update({'question_id': question.id})
        self.render_json(self.values)