示例#1
0
    def get(self, comma_separated_skill_ids):
        """Handles GET requests."""
        start_cursor = self.request.get('cursor')
        skill_ids = comma_separated_skill_ids.split(',')

        for skill_id in skill_ids:
            try:
                skill_domain.Skill.require_valid_skill_id(skill_id)
            except Exception:
                raise self.PageNotFoundException(Exception('Invalid skill id'))

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

        question_summaries, skill_descriptions_list, next_start_cursor = (
            question_services.get_question_summaries_and_skill_descriptions(
                constants.NUM_QUESTIONS_PER_PAGE, skill_ids, start_cursor)
        )
        return_dicts = []
        for index, summary in enumerate(question_summaries):
            return_dicts.append({
                'summary': summary.to_dict(),
                'skill_descriptions': skill_descriptions_list[index]
            })

        self.values.update({
            'question_summary_dicts': return_dicts,
            'next_start_cursor': next_start_cursor
        })
        self.render_json(self.values)
示例#2
0
    def test_get_multi_skills(self):
        example_1 = skill_domain.WorkedExample(
            state_domain.SubtitledHtml('2', '<p>Example Question 1</p>'),
            state_domain.SubtitledHtml('3', '<p>Example Explanation 1</p>'))
        self.save_new_skill(
            'skill_a',
            self.user_id_admin,
            description='Description A',
            misconceptions=[],
            skill_contents=skill_domain.SkillContents(
                state_domain.SubtitledHtml('1', '<p>Explanation</p>'),
                [example_1],
                state_domain.RecordedVoiceovers.from_dict(
                    {'voiceovers_mapping': {
                        '1': {},
                        '2': {},
                        '3': {}
                    }}),
                state_domain.WrittenTranslations.from_dict(
                    {'translations_mapping': {
                        '1': {},
                        '2': {},
                        '3': {}
                    }})))
        self.save_new_skill(
            'skill_b',
            self.user_id_admin,
            description='Description B',
            misconceptions=[],
            skill_contents=skill_domain.SkillContents(
                state_domain.SubtitledHtml('1', '<p>Explanation</p>'),
                [example_1],
                state_domain.RecordedVoiceovers.from_dict(
                    {'voiceovers_mapping': {
                        '1': {},
                        '2': {},
                        '3': {}
                    }}),
                state_domain.WrittenTranslations.from_dict(
                    {'translations_mapping': {
                        '1': {},
                        '2': {},
                        '3': {}
                    }})))

        skills = skill_services.get_multi_skills(['skill_a', 'skill_b'])

        self.assertEqual(len(skills), 2)

        self.assertEqual(skills[0].id, 'skill_a')
        self.assertEqual(skills[0].description, 'Description A')
        self.assertEqual(skills[0].misconceptions, [])

        self.assertEqual(skills[1].id, 'skill_b')
        self.assertEqual(skills[1].description, 'Description B')
        self.assertEqual(skills[1].misconceptions, [])

        with self.assertRaisesRegexp(Exception,
                                     'No skill exists for ID skill_c'):
            skill_services.get_multi_skills(['skill_a', 'skill_c'])
示例#3
0
    def get(self):
        """Handles GET requests."""
        comma_separated_skill_ids = (
            self.request.get('comma_separated_skill_ids'))
        if not comma_separated_skill_ids:
            raise self.InvalidInputException(
                'Expected request to contain parameter '
                'comma_separated_skill_ids.')

        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('Invalid skill ID %s' % skill_id)

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

        degrees_of_mastery = skill_services.get_multi_user_skill_mastery(
            self.user_id, skill_ids)

        self.values.update({'degrees_of_mastery': degrees_of_mastery})
        self.render_json(self.values)
示例#4
0
    def put(self):
        """Handles PUT requests."""
        mastery_change_per_skill = (
            self.payload.get('mastery_change_per_skill'))
        if (not mastery_change_per_skill
                or not isinstance(mastery_change_per_skill, dict)):
            raise self.InvalidInputException(
                'Expected payload to contain mastery_change_per_skill '
                'as a dict.')

        skill_ids = list(mastery_change_per_skill.keys())

        current_degrees_of_mastery = (
            skill_services.get_multi_user_skill_mastery(
                self.user_id, skill_ids))
        new_degrees_of_mastery = {}

        for skill_id in skill_ids:
            try:
                skill_domain.Skill.require_valid_skill_id(skill_id)
            except utils.ValidationError:
                raise self.InvalidInputException('Invalid skill ID %s' %
                                                 skill_id)

            # float(bool) will not raise an error.
            if isinstance(mastery_change_per_skill[skill_id], bool):
                raise self.InvalidInputException(
                    'Expected degree of mastery of skill %s to be a number, '
                    'received %s.' %
                    (skill_id, mastery_change_per_skill[skill_id]))

            try:
                mastery_change_per_skill[skill_id] = (float(
                    mastery_change_per_skill[skill_id]))
            except (TypeError, ValueError):
                raise self.InvalidInputException(
                    'Expected degree of mastery of skill %s to be a number, '
                    'received %s.' %
                    (skill_id, mastery_change_per_skill[skill_id]))

            if current_degrees_of_mastery[skill_id] is None:
                current_degrees_of_mastery[skill_id] = 0.0
            new_degrees_of_mastery[skill_id] = (
                current_degrees_of_mastery[skill_id] +
                mastery_change_per_skill[skill_id])

            if new_degrees_of_mastery[skill_id] < 0.0:
                new_degrees_of_mastery[skill_id] = 0.0
            elif new_degrees_of_mastery[skill_id] > 1.0:
                new_degrees_of_mastery[skill_id] = 1.0

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

        skill_services.create_multi_user_skill_mastery(self.user_id,
                                                       new_degrees_of_mastery)

        self.render_json({})
示例#5
0
    def get(self, comma_separated_skill_ids):
        """Handles GET requests."""
        start_cursor = self.request.get('cursor')
        skill_ids = comma_separated_skill_ids.split(',')

        for skill_id in skill_ids:
            try:
                skill_domain.Skill.require_valid_skill_id(skill_id)
            except Exception:
                raise self.PageNotFoundException(Exception('Invalid skill id'))

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

        (
            question_summaries, merged_question_skill_links,
            next_start_cursor) = (
                question_services.get_displayable_question_skill_link_details(
                    constants.NUM_QUESTIONS_PER_PAGE, skill_ids, start_cursor)
            )
        return_dicts = []
        for index, summary in enumerate(question_summaries):
            if summary is not None:
                if len(skill_ids) == 1:
                    return_dicts.append({
                        'summary': summary.to_dict(),
                        'skill_id': merged_question_skill_links[
                            index].skill_ids[0],
                        'skill_description': (
                            merged_question_skill_links[
                                index].skill_descriptions[0]),
                        'skill_difficulty': (
                            merged_question_skill_links[
                                index].skill_difficulties[0])
                    })
                else:
                    return_dicts.append({
                        'summary': summary.to_dict(),
                        'skill_ids': merged_question_skill_links[
                            index].skill_ids,
                        'skill_descriptions': (
                            merged_question_skill_links[
                                index].skill_descriptions),
                        'skill_difficulties': (
                            merged_question_skill_links[
                                index].skill_difficulties)
                    })

        self.values.update({
            'question_summary_dicts': return_dicts,
            'next_start_cursor': next_start_cursor
        })
        self.render_json(self.values)
示例#6
0
    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)
示例#7
0
    def put(self):
        """Handles PUT requests."""
        degree_of_mastery_per_skill = (
            self.payload.get('degree_of_mastery_per_skill'))
        if (not degree_of_mastery_per_skill
                or not isinstance(degree_of_mastery_per_skill, dict)):
            raise self.InvalidInputException(
                'Expected payload to contain degree_of_mastery_per_skill '
                'as a dict.')

        skill_ids = degree_of_mastery_per_skill.keys()

        for skill_id in skill_ids:
            try:
                skill_domain.Skill.require_valid_skill_id(skill_id)
            except utils.ValidationError:
                raise self.InvalidInputException('Invalid skill ID %s' %
                                                 skill_id)

            # float(bool) will not raise an error.
            if isinstance(degree_of_mastery_per_skill[skill_id], bool):
                raise self.InvalidInputException(
                    'Expected degree of mastery of skill %s to be a number, '
                    'received %s.' %
                    (skill_id, degree_of_mastery_per_skill[skill_id]))

            try:
                degree_of_mastery_per_skill[skill_id] = (float(
                    degree_of_mastery_per_skill[skill_id]))
            except (TypeError, ValueError):
                raise self.InvalidInputException(
                    'Expected degree of mastery of skill %s to be a number, '
                    'received %s.' %
                    (skill_id, degree_of_mastery_per_skill[skill_id]))

            if (degree_of_mastery_per_skill[skill_id] < 0.0
                    or degree_of_mastery_per_skill[skill_id] > 1.0):
                raise self.InvalidInputException(
                    'Expected degree of mastery of skill %s to be a float '
                    'between 0.0 and 1.0, received %s.' %
                    (skill_id, degree_of_mastery_per_skill[skill_id]))

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

        skill_services.create_multi_user_skill_mastery(
            self.user_id, degree_of_mastery_per_skill)

        self.render_json({})
    def test_get_multi_skills(self):
        self.save_new_skill('skill_a',
                            self.user_id_admin,
                            'Description A',
                            misconceptions=[],
                            skill_contents=skill_domain.SkillContents(
                                state_domain.SubtitledHtml('1', 'Explanation'),
                                [state_domain.SubtitledHtml('2', 'Example 1')],
                                {
                                    '1': {},
                                    '2': {}
                                },
                                state_domain.WrittenTranslations.from_dict({
                                    'translations_mapping': {
                                        '1': {},
                                        '2': {}
                                    }
                                })))
        self.save_new_skill('skill_b',
                            self.user_id_admin,
                            'Description B',
                            misconceptions=[],
                            skill_contents=skill_domain.SkillContents(
                                state_domain.SubtitledHtml('1', 'Explanation'),
                                [state_domain.SubtitledHtml('2', 'Example 1')],
                                {
                                    '1': {},
                                    '2': {}
                                },
                                state_domain.WrittenTranslations.from_dict({
                                    'translations_mapping': {
                                        '1': {},
                                        '2': {}
                                    }
                                })))

        skills = skill_services.get_multi_skills(['skill_a', 'skill_b'])

        self.assertEqual(len(skills), 2)

        self.assertEqual(skills[0].id, 'skill_a')
        self.assertEqual(skills[0].description, 'Description A')
        self.assertEqual(skills[0].misconceptions, [])

        self.assertEqual(skills[1].id, 'skill_b')
        self.assertEqual(skills[1].description, 'Description B')
        self.assertEqual(skills[1].misconceptions, [])

        with self.assertRaisesRegexp(Exception,
                                     'No skill exists for ID skill_c'):
            skill_services.get_multi_skills(['skill_a', 'skill_c'])
示例#9
0
    def get(self, comma_separated_skill_ids):
        """Handles GET requests."""
        start_cursor = self.request.get('cursor')
        skill_ids = comma_separated_skill_ids.split(',')

        for skill_id in skill_ids:
            try:
                skill_domain.Skill.require_valid_skill_id(skill_id)
            except Exception:
                raise self.PageNotFoundException(Exception('Invalid skill id'))

        try:
            skill_services.get_multi_skills(skill_ids)
        except Exception, e:
            raise self.PageNotFoundException(e)
示例#10
0
    def get(self, question_id):
        """Gets the data for the question overview page."""

        if not constants.ENABLE_NEW_STRUCTURES:
            raise self.PageNotFoundException

        question = question_services.get_question_by_id(question_id,
                                                        strict=False)

        if question is None:
            raise self.PageNotFoundException(
                'The question with the given id doesn\'t exist.')

        associated_skill_ids = [
            link.skill_id
            for link in (question_services.
                         get_question_skill_links_of_question(question_id))
        ]
        associated_skills = skill_services.get_multi_skills(
            associated_skill_ids)
        associated_skill_dicts = [
            skill.to_dict() for skill in associated_skills
        ]

        self.values.update({
            'question_dict': question.to_dict(),
            'associated_skill_dicts': associated_skill_dicts
        })
        self.render_json(self.values)
示例#11
0
def _get_target_id_to_skill_opportunity_dict(suggestions):
    """Returns a dict of target_id to skill opportunity summary dict.

    Args:
        suggestions: list(BaseSuggestion). A list of suggestions to retrieve
            opportunity dicts.

    Returns:
        dict. Dict mapping target_id to corresponding skill opportunity dict.
    """
    target_ids = set([s.target_id for s in suggestions])
    opportunities = (opportunity_services.get_skill_opportunities_by_ids(
        list(target_ids)))
    opportunity_skill_ids = [opp.id for opp in opportunities]
    opportunity_id_to_skill = {
        skill.id: skill
        for skill in skill_services.get_multi_skills(opportunity_skill_ids)
    }
    opportunity_id_to_opportunity = {}
    for opp in opportunities:
        opp_dict = opp.to_dict()
        skill = opportunity_id_to_skill.get(opp.id)
        if skill is not None:
            opp_dict['skill_rubrics'] = [
                rubric.to_dict() for rubric in skill.rubrics
            ]
        opportunity_id_to_opportunity[opp.id] = opp_dict
    return opportunity_id_to_opportunity
示例#12
0
    def get(self, topic_name):

        if not constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            raise self.PageNotFoundException

        # Topic cannot be None as an exception will be thrown from its decorator
        # if so.
        topic = topic_fetchers.get_topic_by_name(topic_name)
        comma_separated_subtopic_ids = self.request.get(
            'selected_subtopic_ids')
        selected_subtopic_ids = comma_separated_subtopic_ids.split(',')

        selected_skill_ids = []
        for subtopic in topic.subtopics:
            # An error is not thrown here, since it's fine to just ignore the
            # passed in subtopic IDs, if they don't exist, which would be the
            # case if the creator deletes subtopics after the learner has
            # loaded the topic viewer page.
            if python_utils.UNICODE(subtopic.id) in selected_subtopic_ids:
                selected_skill_ids.extend(subtopic.skill_ids)
        try:
            skills = skill_services.get_multi_skills(selected_skill_ids)
        except Exception as e:
            raise self.PageNotFoundException(e)
        skill_ids_to_descriptions_map = {}
        for skill in skills:
            skill_ids_to_descriptions_map[skill.id] = skill.description

        self.values.update({
            'topic_name':
            topic.name,
            'skill_ids_to_descriptions_map':
            skill_ids_to_descriptions_map
        })
        self.render_json(self.values)
示例#13
0
    def get(self, story_id):
        """Handles GET requests."""
        if not constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            raise self.PageNotFoundException

        story = story_fetchers.get_story_by_id(story_id)
        latest_completed_node_ids = (
            story_fetchers.get_latest_completed_node_ids(
                self.user_id, story_id))

        if len(latest_completed_node_ids) == 0:
            raise self.PageNotFoundException

        try:
            skills = skill_services.get_multi_skills(
                story.get_acquired_skill_ids_for_node_ids(
                    latest_completed_node_ids))
        except Exception as e:
            raise self.PageNotFoundException(e)
        skill_descriptions = {}
        for skill in skills:
            skill_descriptions[skill.id] = skill.description

        self.values.update({
            'skill_descriptions': skill_descriptions,
            'story_name': story.title
        })
        self.render_json(self.values)
示例#14
0
    def test_get_multi_skills(self):
        self.save_new_skill('skill_a',
                            self.user_id_admin,
                            'Description A',
                            misconceptions=[],
                            skill_contents=skill_domain.SkillContents(
                                state_domain.SubtitledHtml('1', 'Explanation'),
                                [state_domain.SubtitledHtml('2', 'Example 1')],
                                {
                                    '1': {},
                                    '2': {}
                                },
                                state_domain.WrittenTranslations.from_dict({
                                    'translations_mapping': {
                                        '1': {},
                                        '2': {}
                                    }
                                })))
        self.save_new_skill('skill_b',
                            self.user_id_admin,
                            'Description B',
                            misconceptions=[],
                            skill_contents=skill_domain.SkillContents(
                                state_domain.SubtitledHtml('1', 'Explanation'),
                                [state_domain.SubtitledHtml('2', 'Example 1')],
                                {
                                    '1': {},
                                    '2': {}
                                },
                                state_domain.WrittenTranslations.from_dict({
                                    'translations_mapping': {
                                        '1': {},
                                        '2': {}
                                    }
                                })))
        try:
            skill_services.get_multi_skills(['skill_a', 'skill_b'])
        except Exception:
            self.fail(msg='Unexpected exception raised.')

        with self.assertRaisesRegexp(Exception,
                                     'No skill exists for ID skill_c'):
            skill_services.get_multi_skills(['skill_a', 'skill_c'])
示例#15
0
    def get(self, topic_name):

        if not constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            raise self.PageNotFoundException

        # Topic cannot be None as an exception will be thrown from its decorator
        # if so.
        topic = topic_fetchers.get_topic_by_name(topic_name)
        try:
            skills = skill_services.get_multi_skills(topic.get_all_skill_ids())
        except Exception, e:
            raise self.PageNotFoundException(e)
示例#16
0
def get_skills_linked_to_question(question_id):
    """Returns a list of skills linked to a particular question.

    Args:
        question_id: str. ID of the question.

    Returns:
        list(Skill). The list of skills that are linked to the question.
    """
    question = get_question_by_id(question_id)
    skills = skill_services.get_multi_skills(question.linked_skill_ids)
    return skills
示例#17
0
def get_skills_linked_to_question(question_id):
    """Returns a list of skills linked to a particular question.

    Args:
        question_id: str. ID of the question.

    Returns:
        list(Skill). The list of skills that are linked to the question.
    """
    question_skill_link_models = (question_models.QuestionSkillLinkModel.
                                  get_models_by_question_id(question_id))
    skill_ids = [model.skill_id for model in question_skill_link_models]
    skills = skill_services.get_multi_skills(skill_ids)
    return skills
示例#18
0
    def get(self):
        """Returns all skill IDs linked to some topic."""

        skill_ids = topic_services.get_all_skill_ids_assigned_to_some_topic()

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

        skill_dicts = [skill.to_dict() for skill in skills]
        self.values.update({'skills': skill_dicts})

        self.render_json(self.values)
示例#19
0
    def get(self, question_id):
        """Gets the data for the question overview page."""
        question = question_services.get_question_by_id(question_id,
                                                        strict=False)

        associated_skill_dicts = [
            skill.to_dict() for skill in skill_services.get_multi_skills(
                question.linked_skill_ids)
        ]

        self.values.update({
            'question_dict': question.to_dict(),
            'associated_skill_dicts': associated_skill_dicts
        })
        self.render_json(self.values)
示例#20
0
    def get(self, comma_separated_skill_ids):
        """Handles GET requests."""

        if not constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            raise self.PageNotFoundException

        skill_ids = comma_separated_skill_ids.split(',')
        skills = skill_services.get_multi_skills(skill_ids)

        concept_card_dicts = []
        for skill in skills:
            concept_card_dicts.append(skill.skill_contents.to_dict())

        self.values.update({'concept_card_dicts': concept_card_dicts})

        self.render_json(self.values)
示例#21
0
    def get(self, question_id):
        """Gets the data for the question overview page."""
        question = question_services.get_question_by_id(question_id,
                                                        strict=False)

        if question is None:
            raise self.PageNotFoundException(
                'The question with the given id doesn\'t exist.')

        associated_skill_dicts = [
            skill.to_dict() for skill in skill_services.get_multi_skills(
                question.linked_skill_ids)
        ]

        self.values.update({
            'question_dict': question.to_dict(),
            'associated_skill_dicts': associated_skill_dicts
        })
        self.render_json(self.values)
示例#22
0
    def get(self, story_id):
        """Handles GET requests."""
        if not constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            raise self.PageNotFoundException

        story = story_services.get_story_by_id(story_id)
        latest_completed_node_ids = (
            story_services.get_latest_completed_node_ids(
                self.user_id, story_id))

        if len(latest_completed_node_ids) == 0:
            raise self.PageNotFoundException

        try:
            skills = skill_services.get_multi_skills(
                story.get_acquired_skill_ids_for_node_ids(
                    latest_completed_node_ids))
        except Exception, e:
            raise self.PageNotFoundException(e)
示例#23
0
    def get(self, comma_separated_skill_ids):
        """Populates the data on skill pages of the skill ids."""

        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 as e:
            raise self.PageNotFoundException('Invalid skill id.')
        try:
            skills = skill_services.get_multi_skills(skill_ids)
        except Exception as e:
            raise self.PageNotFoundException(e)

        skill_dicts = [skill.to_dict() for skill in skills]
        self.values.update({'skills': skill_dicts})

        self.render_json(self.values)
示例#24
0
class SkillDataHandler(base.BaseHandler):
    """A handler for accessing skills data."""

    GET_HANDLER_ERROR_RETURN_TYPE = feconf.HANDLER_TYPE_JSON

    @acl_decorators.open_access
    def get(self, comma_separated_skill_ids):
        """Populates the data on skill pages of the skill ids."""

        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, e:
            raise self.PageNotFoundException('Invalid skill id.')
        try:
            skills = skill_services.get_multi_skills(skill_ids)
        except Exception, e:
            raise self.PageNotFoundException(e)
示例#25
0
    def get(self, topic_name):

        if not constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            raise self.PageNotFoundException

        # Topic cannot be None as an exception will be thrown from its decorator
        # if so.
        topic = topic_fetchers.get_topic_by_name(topic_name)
        try:
            skills = skill_services.get_multi_skills(topic.get_all_skill_ids())
        except Exception as e:
            raise self.PageNotFoundException(e)
        skill_descriptions = {}
        for skill in skills:
            skill_descriptions[skill.id] = skill.description

        self.values.update({
            'topic_name': topic.name,
            'skill_descriptions': skill_descriptions
        })
        self.render_json(self.values)
示例#26
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'] != 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):
            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)
        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.error(
                    '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)
示例#27
0
    def post(self, story_id, node_id):
        if not constants.ENABLE_NEW_STRUCTURE_VIEWER_UPDATES:
            raise self.PageNotFoundException

        try:
            story_fetchers.get_node_index_by_story_id_and_node_id(
                story_id, node_id)
        except Exception as e:
            raise self.PageNotFoundException(e)

        story = story_fetchers.get_story_by_id(story_id)
        completed_nodes = story_fetchers.get_completed_nodes_in_story(
            self.user_id, story_id)
        completed_node_ids = [
            completed_node.id for completed_node in completed_nodes
        ]

        ordered_nodes = [
            node for node in story.story_contents.get_ordered_nodes()
        ]

        next_exp_ids = []
        next_node_id = None
        if not node_id in completed_node_ids:
            story_services.record_completed_node_in_story_context(
                self.user_id, story_id, node_id)

            completed_nodes = story_fetchers.get_completed_nodes_in_story(
                self.user_id, story_id)
            completed_node_ids = [
                completed_node.id for completed_node in completed_nodes
            ]

            for node in ordered_nodes:
                if node.id not in completed_node_ids:
                    next_exp_ids = [node.exploration_id]
                    next_node_id = node.id
                    break

        ready_for_review_test = False
        exp_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                next_exp_ids))

        # If there are no questions for any of the acquired skills that the
        # learner has completed, do not show review tests.
        acquired_skills = skill_services.get_multi_skills(
            story.get_acquired_skill_ids_for_node_ids(completed_node_ids))

        acquired_skill_ids = [skill.id for skill in acquired_skills]
        questions_available = len(
            question_services.get_questions_by_skill_ids(
                1, acquired_skill_ids, False)) > 0

        learner_completed_story = len(completed_nodes) == len(ordered_nodes)
        learner_at_review_point_in_story = (
            len(exp_summaries) != 0 and
            (len(completed_nodes) & constants.NUM_EXPLORATIONS_PER_REVIEW_TEST
             == 0))
        if questions_available and (learner_at_review_point_in_story
                                    or learner_completed_story):
            ready_for_review_test = True

        return self.render_json({
            'summaries': exp_summaries,
            'ready_for_review_test': ready_for_review_test,
            'next_node_id': next_node_id
        })
示例#28
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)