コード例 #1
0
    def test_get_public_and_filtered_private_summary_dicts_for_creator(self):
        # If a new exploration is created by another user (Bob) and not public,
        # then Albert cannot see it when querying for explorations.
        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5],
                editor_user_id=self.albert_id))

        self.assertEqual(len(displayable_summaries), 2)
        self.assertEqual(displayable_summaries[0]['id'], self.EXP_ID_1)
        self.assertEqual(displayable_summaries[1]['id'], self.EXP_ID_2)

        # However, if Albert is granted editor access to Bob's exploration,
        # then Albert has access to the corresponding summary.
        rights_manager.assign_role_for_exploration(
            self.bob_id, self.EXP_ID_5, self.albert_id,
            rights_manager.ROLE_EDITOR)

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5],
                editor_user_id=self.albert_id))

        self.assertEqual(len(displayable_summaries), 3)
        self.assertEqual(displayable_summaries[0]['status'], 'private')
        self.assertEqual(displayable_summaries[0]['id'], self.EXP_ID_1)

        self.assertEqual(displayable_summaries[1]['status'], 'public')
        self.assertEqual(displayable_summaries[1]['id'], self.EXP_ID_2)

        self.assertEqual(displayable_summaries[2]['status'], 'private')
        self.assertEqual(displayable_summaries[2]['id'], self.EXP_ID_5)
コード例 #2
0
ファイル: library.py プロジェクト: sajalasati/oppia
    def get(self):
        """Handles GET requests."""
        exp_ids = self.normalized_request.get('stringified_exp_ids')
        include_private_exps = self.normalized_request.get(
            'include_private_explorations')

        editor_user_id = self.user_id if include_private_exps else None
        if not editor_user_id:
            include_private_exps = False

        if (not isinstance(exp_ids, list) or not all(
                isinstance(
                    exp_id, python_utils.BASESTRING) for exp_id in exp_ids)):
            raise self.PageNotFoundException

        if include_private_exps:
            summaries = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids, user=self.user))
        else:
            summaries = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids))
        self.values.update({
            'summaries': summaries
        })
        self.render_json(self.values)
コード例 #3
0
    def get(self):
        """Handles GET requests."""
        try:
            exp_ids = json.loads(self.request.get('stringified_exp_ids'))
        except Exception:
            raise self.PageNotFoundException
        include_private_exps_str = self.request.get(
            'include_private_explorations')
        include_private_exps = (
            include_private_exps_str.lower() == 'true'
            if include_private_exps_str else False)

        editor_user_id = self.user_id if include_private_exps else None
        if not editor_user_id:
            include_private_exps = False

        if (not isinstance(exp_ids, list) or not all([
                isinstance(exp_id, basestring) for exp_id in exp_ids])):
            raise self.PageNotFoundException

        if include_private_exps:
            summaries = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids, user=self.user))
        else:
            summaries = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids))
        self.values.update({
            'summaries': summaries
        })
        self.render_json(self.values)
コード例 #4
0
    def test_get_public_and_filtered_private_summary_dicts_for_creator(self):
        # If a new exploration is created by another user (Bob) and not public,
        # then Albert cannot see it when querying for explorations.
        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5],
                user=self.albert))

        self.assertEqual(len(displayable_summaries), 2)
        self.assertEqual(displayable_summaries[0]['id'], self.EXP_ID_1)
        self.assertEqual(displayable_summaries[1]['id'], self.EXP_ID_2)

        # However, if Albert is granted editor access to Bob's exploration,
        # then Albert has access to the corresponding summary.
        rights_manager.assign_role_for_exploration(
            self.bob, self.EXP_ID_5, self.albert_id,
            rights_domain.ROLE_EDITOR)

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5],
                user=self.albert))

        self.assertEqual(len(displayable_summaries), 3)
        self.assertEqual(displayable_summaries[0]['status'], 'private')
        self.assertEqual(displayable_summaries[0]['id'], self.EXP_ID_1)

        self.assertEqual(displayable_summaries[1]['status'], 'public')
        self.assertEqual(displayable_summaries[1]['id'], self.EXP_ID_2)

        self.assertEqual(displayable_summaries[2]['status'], 'private')
        self.assertEqual(displayable_summaries[2]['id'], self.EXP_ID_5)
コード例 #5
0
ファイル: library.py プロジェクト: MaryamZi/oppia
    def get(self):
        """Handles GET requests."""
        try:
            exp_ids = json.loads(self.request.get('stringified_exp_ids'))
        except Exception:
            raise self.PageNotFoundException
        include_private_exps_str = self.request.get(
            'include_private_explorations')
        include_private_exps = (
            include_private_exps_str.lower() == 'true'
            if include_private_exps_str else False)

        editor_user_id = self.user_id if include_private_exps else None
        if not editor_user_id:
            include_private_exps = False

        if (not isinstance(exp_ids, list) or not all([
                isinstance(exp_id, basestring) for exp_id in exp_ids])):
            raise self.PageNotFoundException

        if include_private_exps:
            summaries = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids,
                    editor_user_id=editor_user_id))
        else:
            summaries = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids))
        self.values.update({
            'summaries': summaries
        })
        self.render_json(self.values)
コード例 #6
0
ファイル: galleries.py プロジェクト: CuriousLearner/oppia
    def get(self):
        """Handles GET requests."""
        # TODO(sll): Figure out what to do about explorations in categories
        # other than those explicitly listed.

        query_string = self.request.get('q')
        search_cursor = self.request.get('cursor', None)
        exp_ids, search_cursor = (
            exp_services.get_exploration_ids_matching_query(
                query_string, cursor=search_cursor))

        explorations_list = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                exp_ids))

        if len(explorations_list) == feconf.DEFAULT_QUERY_LIMIT:
            logging.error(
                '%s explorations were fetched to load the gallery page. '
                'You may be running up against the default query limits.'
                % feconf.DEFAULT_QUERY_LIMIT)

        preferred_language_codes = [feconf.DEFAULT_LANGUAGE_CODE]
        if self.user_id:
            user_settings = user_services.get_user_settings(self.user_id)
            preferred_language_codes = user_settings.preferred_language_codes

        self.values.update({
            'explorations_list': explorations_list,
            'preferred_language_codes': preferred_language_codes,
            'search_cursor': search_cursor,
        })
        self.render_json(self.values)
コード例 #7
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration
        # EXP_ID_2 -- pubished exploration
        # EXP_ID_3 -- deleted exploration
        # Should only return [EXP_ID_2]

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3]))

        self.assertEqual(len(displayable_summaries), 1)
        self.assertEqual(
            displayable_summaries[0]['id'], self.EXP_ID_2)
        self.assertEqual(
            displayable_summaries[0]['status'],
            rights_manager.ACTIVITY_STATUS_PUBLIC)
        self.assertEqual(
            displayable_summaries[0]['community_owned'], False)
        self.assertEqual(
            displayable_summaries[0]['language_code'],
            feconf.DEFAULT_LANGUAGE_CODE)
        self.assertEqual(
            displayable_summaries[0]['category'], 'A category')
        self.assertEqual(
            displayable_summaries[0]['ratings'], feconf.get_empty_ratings())
        self.assertEqual(
            displayable_summaries[0]['title'], 'Exploration 2 Albert title')
        self.assertEqual(
            displayable_summaries[0]['contributor_names'], [self.ALBERT_NAME])
        self.assertEqual(
            displayable_summaries[0]['objective'], 'An objective')
        self.assertEqual(displayable_summaries[0]['num_views'], 0)
        self.assertIn('last_updated_msec', displayable_summaries[0])
コード例 #8
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration owned by Albert.
        # EXP_ID_2 -- pubished exploration owned by Albert.
        # EXP_ID_3 -- deleted exploration.
        # EXP_ID_5 -- private exploration owned by Bob.
        # Should only return [EXP_ID_2].

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5]))
        expected_summary = {
            'category': u'A category',
            'community_owned': False,
            'id': self.EXP_ID_2,
            'language_code': constants.DEFAULT_LANGUAGE_CODE,
            'num_views': 0,
            'objective': u'An objective',
            'ratings': feconf.get_empty_ratings(),
            'status': 'public',
            'tags': [],
            'thumbnail_bg_color': '#a33f40',
            'thumbnail_icon_url': '/subjects/Lightbulb.svg',
            'title': u'Exploration 2 Albert title',
        }
        self.assertIn('last_updated_msec', displayable_summaries[0])
        self.assertDictContainsSubset(
            expected_summary, displayable_summaries[0])
コード例 #9
0
ファイル: library.py プロジェクト: singhankit03/oppia
def get_matching_activity_dicts(query_string, search_cursor):
    """Given a query string and a search cursor, returns a list of activity
    dicts that satisfy the search query.
    """
    # We only populate collections in the initial load, since the current
    # frontend search infrastructure is set up to only deal with one search
    # cursor at a time.
    # TODO(sll): Remove this special casing.
    collection_ids = []
    if not search_cursor:
        collection_ids, _ = (
            collection_services.get_collection_ids_matching_query(
                query_string))

    exp_ids, new_search_cursor = (
        exp_services.get_exploration_ids_matching_query(
            query_string, cursor=search_cursor))
    activity_list = []
    activity_list = (
        summary_services.get_displayable_collection_summary_dicts_matching_ids(
            collection_ids))
    activity_list += (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))

    if len(activity_list) == feconf.DEFAULT_QUERY_LIMIT:
        logging.error(
            '%s activities were fetched to load the library page. '
            'You may be running up against the default query limits.'
            % feconf.DEFAULT_QUERY_LIMIT)
    return activity_list, new_search_cursor
コード例 #10
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration owned by Albert
        # EXP_ID_2 -- pubished exploration owned by Albert
        # EXP_ID_3 -- deleted exploration
        # EXP_ID_5 -- private exploration owned by Bob
        # Should only return [EXP_ID_2]

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5]))
        expected_summary = {
            'category': u'A category',
            'community_owned': False,
            'id': self.EXP_ID_2,
            'language_code': feconf.DEFAULT_LANGUAGE_CODE,
            'num_views': 0,
            'objective': u'An objective',
            'ratings': feconf.get_empty_ratings(),
            'status': 'public',
            'tags': [],
            'thumbnail_bg_color': '#a33f40',
            'thumbnail_icon_url': self.get_static_asset_url(
                '/images/subjects/Lightbulb.svg'),
            'title': u'Exploration 2 Albert title',
        }
        self.assertIn('last_updated_msec', displayable_summaries[0])
        self.assertDictContainsSubset(expected_summary,
                                      displayable_summaries[0])
コード例 #11
0
    def get(self):
        """Handles GET requests."""
        # TODO(sll): Figure out what to do about explorations in categories
        # other than those explicitly listed.

        query_string = self.request.get('q')
        search_cursor = self.request.get('cursor', None)
        exp_ids, search_cursor = (
            exp_services.get_exploration_ids_matching_query(
                query_string, cursor=search_cursor))

        explorations_list = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                exp_ids))

        if len(explorations_list) == feconf.DEFAULT_QUERY_LIMIT:
            logging.error(
                '%s explorations were fetched to load the gallery page. '
                'You may be running up against the default query limits.' %
                feconf.DEFAULT_QUERY_LIMIT)

        preferred_language_codes = [feconf.DEFAULT_LANGUAGE_CODE]
        if self.user_id:
            user_settings = user_services.get_user_settings(self.user_id)
            preferred_language_codes = user_settings.preferred_language_codes

        self.values.update({
            'explorations_list': explorations_list,
            'preferred_language_codes': preferred_language_codes,
            'search_cursor': search_cursor,
        })
        self.render_json(self.values)
コード例 #12
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)

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

        ordered_node_dicts = [
            node.to_dict() for node in story.story_contents.get_ordered_nodes()
        ]
        for node in ordered_node_dicts:
            node['completed'] = False
            if node['id'] in completed_node_ids:
                node['completed'] = True

        exp_ids = [
            node['exploration_id'] for node in ordered_node_dicts]
        exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                exp_ids, user=self.user))

        for ind, node in enumerate(ordered_node_dicts):
            node['exp_summary_dict'] = exp_summary_dicts[ind]

        self.values.update({
            'story_title': story.title,
            'story_description': story.description,
            'story_nodes': ordered_node_dicts
        })
        self.render_json(self.values)
コード例 #13
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration
        # EXP_ID_2 -- pubished exploration
        # EXP_ID_3 -- deleted exploration
        # Should only return [EXP_ID_2]

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3]))
        expected_summary = {
            'status': u'public',
            'thumbnail_bg_color': '#05a69a',
            'community_owned': False,
            'tags': [],
            'thumbnail_icon_url': '/images/gallery/thumbnails/Lightbulb.svg',
            'language_code': feconf.DEFAULT_LANGUAGE_CODE,
            'human_readable_contributors_summary': {
                self.ALBERT_NAME: {
                    'num_commits': 2,
                    'profile_picture_data_url': None
                }
            },
            'id': self.EXP_ID_2,
            'category': u'A category',
            'ratings': feconf.get_empty_ratings(),
            'title': u'Exploration 2 Albert title',
            'num_views': 0,
            'objective': u'An objective'
        }
        self.assertIn('last_updated_msec', displayable_summaries[0])
        self.assertDictContainsSubset(expected_summary,
                                      displayable_summaries[0])
コード例 #14
0
ファイル: library.py プロジェクト: abhijit5893/oppia
def get_matching_activity_dicts(query_string, search_cursor):
    """Given a query string and a search cursor, returns a list of activity
    dicts that satisfy the search query.
    """
    # We only populate collections in the initial load, since the current
    # frontend search infrastructure is set up to only deal with one search
    # cursor at a time.
    # TODO(sll): Remove this special casing.
    collection_ids = []
    if not search_cursor:
        collection_ids, _ = (
            collection_services.get_collection_ids_matching_query(
                query_string))

    exp_ids, new_search_cursor = (
        exp_services.get_exploration_ids_matching_query(
            query_string, cursor=search_cursor))
    activity_list = []
    activity_list = (
        summary_services.get_displayable_collection_summary_dicts_matching_ids(
            collection_ids))
    activity_list += (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))

    if len(activity_list) == feconf.DEFAULT_QUERY_LIMIT:
        logging.error(
            '%s activities were fetched to load the library page. '
            'You may be running up against the default query limits.'
            % feconf.DEFAULT_QUERY_LIMIT)
    return activity_list, new_search_cursor
コード例 #15
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration
        # EXP_ID_2 -- pubished exploration
        # EXP_ID_3 -- deleted exploration
        # Should only return [EXP_ID_2]

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3]))

        self.assertEqual(len(displayable_summaries), 1)
        self.assertEqual(
            displayable_summaries[0]['id'], self.EXP_ID_2)
        self.assertEqual(
            displayable_summaries[0]['status'],
            rights_manager.ACTIVITY_STATUS_PUBLIC)
        self.assertEqual(
            displayable_summaries[0]['community_owned'], False)
        self.assertEqual(
            displayable_summaries[0]['language_code'],
            feconf.DEFAULT_LANGUAGE_CODE)
        self.assertEqual(
            displayable_summaries[0]['category'], 'A category')
        self.assertEqual(
            displayable_summaries[0]['ratings'], feconf.get_empty_ratings())
        self.assertEqual(
            displayable_summaries[0]['title'], 'Exploration 2 Albert title')
        self.assertEqual(
            displayable_summaries[0]['contributor_names'], [self.ALBERT_NAME])
        self.assertEqual(
            displayable_summaries[0]['objective'], 'An objective')
        self.assertEqual(displayable_summaries[0]['num_views'], 0)
        self.assertIn('last_updated_msec', displayable_summaries[0])
コード例 #16
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration
        # EXP_ID_2 -- pubished exploration
        # EXP_ID_3 -- deleted exploration
        # Should only return [EXP_ID_2]

        displayable_summaries = summary_services.get_displayable_exp_summary_dicts_matching_ids(
            [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3]
        )
        expected_summary = {
            "status": u"public",
            "thumbnail_bg_color": "#05a69a",
            "community_owned": False,
            "tags": [],
            "thumbnail_icon_url": "/images/gallery/thumbnails/Lightbulb.svg",
            "language_code": feconf.DEFAULT_LANGUAGE_CODE,
            "human_readable_contributors_summary": {self.ALBERT_NAME: 2},
            "id": self.EXP_ID_2,
            "category": u"A category",
            "ratings": feconf.get_empty_ratings(),
            "title": u"Exploration 2 Albert title",
            "num_views": 0,
            "objective": u"An objective",
            "contributor_names": [self.ALBERT_NAME],
        }
        self.assertIn("last_updated_msec", displayable_summaries[0])
        self.assertDictContainsSubset(expected_summary, displayable_summaries[0])
コード例 #17
0
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration
        # EXP_ID_2 -- pubished exploration
        # EXP_ID_3 -- deleted exploration
        # Should only return [EXP_ID_2]

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3]))
        expected_summary = {
            'status': u'public',
            'thumbnail_bg_color': '#05a69a',
            'community_owned': False,
            'tags': [],
            'thumbnail_icon_url': '/images/gallery/thumbnails/Lightbulb.svg',
            'language_code': feconf.DEFAULT_LANGUAGE_CODE,
            'human_readable_contributors_summary': {self.ALBERT_NAME: 2},
            'id': self.EXP_ID_2,
            'category': u'A category',
            'ratings': feconf.get_empty_ratings(),
            'title': u'Exploration 2 Albert title',
            'num_views': 0,
            'objective': u'An objective',
            'contributor_names': [self.ALBERT_NAME]
        }
        self.assertIn('last_updated_msec', displayable_summaries[0])
        self.assertDictContainsSubset(expected_summary,
                                      displayable_summaries[0])
コード例 #18
0
ファイル: profile.py プロジェクト: DSeanLaw/oppia
    def get(self, username):
        """Handles GET requests."""
        if not username:
            raise self.PageNotFoundException

        user_settings = user_services.get_user_settings_from_username(username)
        if not user_settings:
            raise self.PageNotFoundException

        created_exp_summary_dicts = []
        edited_exp_summary_dicts = []

        subscriber_ids = subscription_services.get_all_subscribers_of_creator(
            user_settings.user_id)
        is_already_subscribed = (self.user_id in subscriber_ids)
        is_user_visiting_own_profile = (self.user_id == user_settings.user_id)

        user_contributions = user_services.get_user_contributions(
            user_settings.user_id)
        if user_contributions:
            created_exp_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.created_exploration_ids))
            edited_exp_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.edited_exploration_ids))
        profile_is_of_current_user = (self.username == username)

        self.values.update({
            'profile_is_of_current_user': profile_is_of_current_user,
            'profile_username': user_settings.username,
            'user_bio': user_settings.user_bio,
            'subject_interests': user_settings.subject_interests,
            'first_contribution_msec': (
                user_settings.first_contribution_msec
                if user_settings.first_contribution_msec else None),
            'profile_picture_data_url': user_settings.profile_picture_data_url,
            'user_impact_score':user_services.get_user_impact_score(
                user_settings.user_id),
            'created_exp_summary_dicts': created_exp_summary_dicts,
            'edited_exp_summary_dicts': edited_exp_summary_dicts,
            'is_already_subscribed': is_already_subscribed,
            'is_user_visiting_own_profile': is_user_visiting_own_profile
        })
        self.render_json(self.values)
コード例 #19
0
ファイル: profile.py プロジェクト: wdempsey96/oppia
    def get(self, username):
        """Handles GET requests."""

        user_settings = user_services.get_user_settings_from_username(username)
        if not user_settings:
            raise self.PageNotFoundException

        created_exp_summary_dicts = []
        edited_exp_summary_dicts = []

        subscriber_ids = subscription_services.get_all_subscribers_of_creator(
            user_settings.user_id)
        is_already_subscribed = (self.user_id in subscriber_ids)
        is_user_visiting_own_profile = (self.user_id == user_settings.user_id)

        user_contributions = user_services.get_user_contributions(
            user_settings.user_id)
        if user_contributions:
            created_exp_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.created_exploration_ids))
            edited_exp_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.edited_exploration_ids))
        profile_is_of_current_user = (self.username == username)

        self.values.update({
            'profile_is_of_current_user': profile_is_of_current_user,
            'profile_username': user_settings.username,
            'user_bio': user_settings.user_bio,
            'subject_interests': user_settings.subject_interests,
            'first_contribution_msec': (
                user_settings.first_contribution_msec
                if user_settings.first_contribution_msec else None),
            'profile_picture_data_url': user_settings.profile_picture_data_url,
            'user_impact_score': user_services.get_user_impact_score(
                user_settings.user_id),
            'created_exp_summary_dicts': created_exp_summary_dicts,
            'edited_exp_summary_dicts': edited_exp_summary_dicts,
            'is_already_subscribed': is_already_subscribed,
            'is_user_visiting_own_profile': is_user_visiting_own_profile
        })
        self.render_json(self.values)
コード例 #20
0
def get_matching_activity_dicts(query_string, categories, language_codes,
                                search_offset):
    """Given the details of a query and a search offset, returns a list of
    activity dicts that satisfy the query.

    Args:
        query_string: str. The search query string (this is what the user
            enters).
        categories: list(str). The list of categories to query for. If it is
            empty, no category filter is applied to the results. If it is not
            empty, then a result is considered valid if it matches at least one
            of these categories.
        language_codes: list(str). The list of language codes to query for. If
            it is empty, no language code filter is applied to the results. If
            it is not empty, then a result is considered valid if it matches at
            least one of these language codes.
        search_offset: int or None. Offset indicating where, in the list of
            exploration search results, to start the search from. If None,
            collection search results are returned first before the
            explorations.

    Returns:
        tuple. A tuple consisting of two elements:
            - list(dict). Each element in this list is a collection or
                exploration summary dict, representing a search result.
            - int. The exploration index offset from which to start the
                next search.
    """
    # We only populate collections in the initial load, since the current
    # frontend search infrastructure is set up to only deal with one search
    # offset at a time.
    # TODO(sll): Remove this special casing.
    collection_ids = []
    if not search_offset:
        collection_ids, _ = (
            collection_services.get_collection_ids_matching_query(
                query_string, categories, language_codes))

    exp_ids, new_search_offset = (
        exp_services.get_exploration_ids_matching_query(query_string,
                                                        categories,
                                                        language_codes,
                                                        offset=search_offset))
    activity_list = (
        summary_services.get_displayable_collection_summary_dicts_matching_ids(
            collection_ids) +
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))

    if len(activity_list) == feconf.DEFAULT_QUERY_LIMIT:
        logging.exception(
            '%s activities were fetched to load the library page. '
            'You may be running up against the default query limits.' %
            feconf.DEFAULT_QUERY_LIMIT)
    return activity_list, new_search_offset
コード例 #21
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 ((len(exp_summaries) != 0 and len(completed_nodes) %
             constants.NUM_EXPLORATIONS_PER_REVIEW_TEST == 0)
                or (len(completed_nodes) == len(ordered_nodes))):
            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
        })
コード例 #22
0
ファイル: profile.py プロジェクト: yjli216/oppia
    def get(self, username):
        """Handles GET requests."""
        if not username:
            raise self.PageNotFoundException

        user_settings = user_services.get_user_settings_from_username(username)
        if not user_settings:
            raise self.PageNotFoundException

        created_exploration_summary_dicts = []
        edited_exploration_summary_dicts = []

        user_contributions = user_services.get_user_contributions(
            user_settings.user_id)
        if user_contributions:
            created_exploration_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.created_exploration_ids))
            edited_exploration_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.edited_exploration_ids))

        self.values.update({
            'user_bio': user_settings.user_bio,
            'subject_interests': user_settings.subject_interests,
            'first_contribution_msec': (
                user_settings.first_contribution_msec
                if user_settings.first_contribution_msec else None),
            'profile_picture_data_url': user_settings.profile_picture_data_url,
            'user_impact_score':user_services.get_user_impact_score(
                user_settings.user_id),
            'created_exploration_summary_dicts': (
                created_exploration_summary_dicts),
            'edited_exploration_summary_dicts': (
                edited_exploration_summary_dicts)
        })
        self.render_json(self.values)
コード例 #23
0
ファイル: reader.py プロジェクト: thedeveloperr/oppia
    def get(self, exploration_id):
        """Handles GET requests."""
        collection_id = self.request.get('collection_id')
        include_system_recommendations = self.request.get(
            'include_system_recommendations')
        try:
            author_recommended_exp_ids = json.loads(
                self.request.get('stringified_author_recommended_ids'))
        except Exception:
            raise self.PageNotFoundException

        auto_recommended_exp_ids = []
        if self.user_id and collection_id:
            next_exp_ids_in_collection = (
                collection_services.
                get_next_exploration_ids_to_complete_by_user(  # pylint: disable=line-too-long
                    self.user_id, collection_id))
            auto_recommended_exp_ids = list(
                set(next_exp_ids_in_collection) -
                set(author_recommended_exp_ids))
        else:
            next_exp_ids_in_collection = []
            if collection_id:
                collection = collection_services.get_collection_by_id(
                    collection_id)
                next_exp_ids_in_collection = (
                    collection.get_next_exploration_ids_in_sequence(
                        exploration_id))
            if next_exp_ids_in_collection:
                auto_recommended_exp_ids = list(
                    set(next_exp_ids_in_collection) -
                    set(author_recommended_exp_ids))
            elif include_system_recommendations:
                system_chosen_exp_ids = (
                    recommendations_services.get_exploration_recommendations(
                        exploration_id))
                filtered_exp_ids = list(
                    set(system_chosen_exp_ids) -
                    set(author_recommended_exp_ids))
                auto_recommended_exp_ids = random.sample(
                    filtered_exp_ids,
                    min(MAX_SYSTEM_RECOMMENDATIONS, len(filtered_exp_ids)))

        self.values.update({
            'summaries':
            (summary_services.get_displayable_exp_summary_dicts_matching_ids(
                author_recommended_exp_ids + auto_recommended_exp_ids)),
        })
        self.render_json(self.values)
コード例 #24
0
ファイル: profile.py プロジェクト: yarinf/oppia
    def get(self, username):
        """Handles GET requests."""
        if not username:
            raise self.PageNotFoundException

        user_settings = user_services.get_user_settings_from_username(username)
        if not user_settings:
            raise self.PageNotFoundException

        created_exp_summary_dicts = []
        edited_exp_summary_dicts = []

        user_contributions = user_services.get_user_contributions(
            user_settings.user_id)
        if user_contributions:
            created_exp_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.created_exploration_ids))
            edited_exp_summary_dicts = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    user_contributions.edited_exploration_ids))

        self.values.update({
            'profile_username': user_settings.username,
            'user_bio': user_settings.user_bio,
            'subject_interests': user_settings.subject_interests,
            'first_contribution_msec': (
                user_settings.first_contribution_msec
                if user_settings.first_contribution_msec else None),
            'profile_picture_data_url': user_settings.profile_picture_data_url,
            'user_impact_score':user_services.get_user_impact_score(
                user_settings.user_id),
            'created_exp_summary_dicts': created_exp_summary_dicts,
            'edited_exp_summary_dicts': edited_exp_summary_dicts,
        })
        self.render_json(self.values)
コード例 #25
0
ファイル: reader.py プロジェクト: 526avijitgupta/oppia
    def get(self, exploration_id):
        """Handles GET requests."""
        collection_id = self.request.get('collection_id')
        include_system_recommendations = self.request.get(
            'include_system_recommendations')
        try:
            author_recommended_exp_ids = json.loads(self.request.get(
                'stringified_author_recommended_ids'))
        except Exception:
            raise self.PageNotFoundException

        auto_recommended_exp_ids = []
        if self.user_id and collection_id:
            next_exp_ids_in_collection = (
                collection_services.get_next_exploration_ids_to_complete_by_user( # pylint: disable=line-too-long
                    self.user_id, collection_id))
            auto_recommended_exp_ids = list(
                set(next_exp_ids_in_collection) -
                set(author_recommended_exp_ids))
        else:
            next_exp_ids_in_collection = []
            if collection_id:
                collection = collection_services.get_collection_by_id(
                    collection_id)
                next_exp_ids_in_collection = (
                    collection.get_next_exploration_ids_in_sequence(
                        exploration_id))
            if next_exp_ids_in_collection:
                auto_recommended_exp_ids = list(
                    set(next_exp_ids_in_collection) -
                    set(author_recommended_exp_ids))
            elif include_system_recommendations:
                system_chosen_exp_ids = (
                    recommendations_services.get_exploration_recommendations(
                        exploration_id))
                filtered_exp_ids = list(
                    set(system_chosen_exp_ids) -
                    set(author_recommended_exp_ids))
                auto_recommended_exp_ids = random.sample(
                    filtered_exp_ids,
                    min(MAX_SYSTEM_RECOMMENDATIONS, len(filtered_exp_ids)))

        self.values.update({
            'summaries': (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    author_recommended_exp_ids + auto_recommended_exp_ids)),
        })
        self.render_json(self.values)
コード例 #26
0
ファイル: galleries.py プロジェクト: CuriousLearner/oppia
    def get(self):
        """Handles GET requests."""
        try:
            exp_ids = json.loads(self.request.get('stringified_exp_ids'))
        except Exception:
            raise self.PageNotFoundException

        if (not isinstance(exp_ids, list) or not all([
                isinstance(exp_id, basestring) for exp_id in exp_ids])):
            raise self.PageNotFoundException

        self.values.update({
            'summaries': (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    exp_ids))
        })
        self.render_json(self.values)
コード例 #27
0
    def get(self):
        """Handles GET requests for group pages."""
        # TODO(sll): Support index pages for other language codes.
        group_name = self.request.get('group_name')
        activity_list = []
        header_i18n_id = ''

        if group_name == feconf.LIBRARY_GROUP_RECENTLY_PUBLISHED:
            recently_published_summary_dicts = (
                summary_services.get_recently_published_exp_summary_dicts(
                    feconf.RECENTLY_PUBLISHED_QUERY_LIMIT_FULL_PAGE))
            if recently_published_summary_dicts:
                activity_list = recently_published_summary_dicts
                header_i18n_id = feconf.LIBRARY_CATEGORY_RECENTLY_PUBLISHED

        elif group_name == feconf.LIBRARY_GROUP_TOP_RATED:
            top_rated_activity_summary_dicts = (
                summary_services.get_top_rated_exploration_summary_dicts(
                    [feconf.DEFAULT_LANGUAGE_CODE],
                    feconf.NUMBER_OF_TOP_RATED_EXPLORATIONS_FULL_PAGE))
            if top_rated_activity_summary_dicts:
                activity_list = top_rated_activity_summary_dicts
                header_i18n_id = feconf.LIBRARY_CATEGORY_TOP_RATED_EXPLORATIONS

        # TODO: create a Splash controller and implement this properly.
        elif group_name == feconf.LIBRARY_CATEGORY_SPLASH_PAGE_FEATURED:
            splash_page_featured_exploration_ids = [
                '0', 'yvqBFOQNDz5e', 'BvpDpLSmO2Iu', 'gC4_ggkWar-L']
            activity_list = (
                summary_services.get_displayable_exp_summary_dicts_matching_ids(
                    splash_page_featured_exploration_ids))

        else:
            return self.PageNotFoundException

        preferred_language_codes = [feconf.DEFAULT_LANGUAGE_CODE]
        if self.user_id:
            user_settings = user_services.get_user_settings(self.user_id)
            preferred_language_codes = user_settings.preferred_language_codes

        self.values.update({
            'activity_list': activity_list,
            'header_i18n_id': header_i18n_id,
            'preferred_language_codes': preferred_language_codes,
        })
        self.render_json(self.values)
コード例 #28
0
ファイル: library.py プロジェクト: MaryamZi/oppia
def get_matching_exploration_dicts(query_string, search_cursor):
    """Given a query string and a search cursor, returns a list of exploration
       dicts that satisfy the search query.
    """
    exp_ids, new_search_cursor = (
        exp_services.get_exploration_ids_matching_query(
            query_string, cursor=search_cursor))

    explorations_list = (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))

    if len(explorations_list) == feconf.DEFAULT_QUERY_LIMIT:
        logging.error(
            '%s explorations were fetched to load the search results. '
            'You may be running up against the default query limits.'
            % feconf.DEFAULT_QUERY_LIMIT)
    return explorations_list, new_search_cursor
コード例 #29
0
def get_matching_exploration_dicts(query_string, search_cursor):
    """Given a query string and a search cursor, returns a list of exploration
       dicts that satisfy the search query.
    """
    exp_ids, new_search_cursor = (
        exp_services.get_exploration_ids_matching_query(query_string,
                                                        cursor=search_cursor))

    explorations_list = (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))

    if len(explorations_list) == feconf.DEFAULT_QUERY_LIMIT:
        logging.error(
            '%s explorations were fetched to load the search results. '
            'You may be running up against the default query limits.' %
            feconf.DEFAULT_QUERY_LIMIT)
    return explorations_list, new_search_cursor
コード例 #30
0
    def get(self):
        """Handles GET requests."""
        try:
            exp_ids = json.loads(self.request.get('stringified_exp_ids'))
        except Exception:
            raise self.PageNotFoundException

        if (not isinstance(exp_ids, list) or
                not all([isinstance(exp_id, basestring)
                         for exp_id in exp_ids])):
            raise self.PageNotFoundException

        self.values.update({
            'summaries':
            (summary_services.get_displayable_exp_summary_dicts_matching_ids(
                exp_ids))
        })
        self.render_json(self.values)
コード例 #31
0
    def test_library_handler_with_given_category_and_language_code(self):
        self.login(self.ADMIN_EMAIL)

        exp_id = exp_fetchers.get_new_exploration_id()
        self.save_new_valid_exploration(exp_id, self.admin_id)
        self.publish_exploration(self.admin_id, exp_id)
        exp_services.index_explorations_given_ids([exp_id])
        response_dict = self.get_json(
            feconf.LIBRARY_SEARCH_DATA_URL, params={
                'category': 'A category',
                'language_code': 'en'
            })
        activity_list = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [exp_id]))

        self.assertEqual(response_dict['activity_list'], activity_list)

        self.logout()
コード例 #32
0
    def post(self, story_id, node_id):
        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 = story.story_contents.get_ordered_nodes()

        (next_exp_ids, next_node_id,
         completed_node_ids) = (self._record_node_completion(
             story_id, node_id, completed_node_ids, ordered_nodes))

        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_fetchers.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_node_ids) == len(ordered_nodes)
        learner_at_review_point_in_story = (
            len(exp_summaries) != 0
            and (len(completed_node_ids)
                 & 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
        })
コード例 #33
0
ファイル: story_viewer.py プロジェクト: natoriaray/oppia
    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)

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

        ordered_node_dicts = [
            node.to_dict()
            for node in story.story_contents.get_ordered_nodes()
            # TODO(aks681): Once the story publication is done, add a check so
            # that only if all explorations in the story are published, can the
            # story itself be published. After which, remove the following
            # condition.
            if node.exploration_id
        ]
        for node in ordered_node_dicts:
            node['completed'] = False
            if node['id'] in completed_node_ids:
                node['completed'] = True

        exp_ids = [node['exploration_id'] for node in ordered_node_dicts]
        exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                exp_ids, user=self.user))

        for ind, node in enumerate(ordered_node_dicts):
            node['exp_summary_dict'] = exp_summary_dicts[ind]

        self.values.update({
            'story_title': story.title,
            'story_description': story.description,
            'story_nodes': ordered_node_dicts
        })
        self.render_json(self.values)
コード例 #34
0
    def get(self, story_id):
        """Handles GET requests."""
        story = story_fetchers.get_story_by_id(story_id)
        topic_id = story.corresponding_topic_id
        topic_name = topic_fetchers.get_topic_by_id(topic_id).name

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

        ordered_node_dicts = [
            node.to_dict()
            for node in story.story_contents.get_ordered_nodes()
        ]
        for node in ordered_node_dicts:
            node['completed'] = False
            if node['id'] in completed_node_ids:
                node['completed'] = True

        exp_ids = [node['exploration_id'] for node in ordered_node_dicts]
        exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                exp_ids, user=self.user))

        for ind, node in enumerate(ordered_node_dicts):
            node['exp_summary_dict'] = exp_summary_dicts[ind]

        self.values.update({
            'story_id': story.id,
            'story_title': story.title,
            'story_description': story.description,
            'story_nodes': ordered_node_dicts,
            'topic_name': topic_name,
            'meta_tag_content': story.meta_tag_content
        })
        self.render_json(self.values)
コード例 #35
0
ファイル: library.py プロジェクト: MinhHuong/oppia
def get_matching_activity_dicts(query_string, search_cursor):
    """Given a query string and a search cursor, returns a list of activity
       dicts that satisfy the search query.
    """
    collection_ids, search_cursor = (
        collection_services.get_collection_ids_matching_query(
            query_string, cursor=search_cursor))
    exp_ids, new_search_cursor = (
        exp_services.get_exploration_ids_matching_query(
            query_string, cursor=search_cursor))
    activity_list = []
    activity_list = (
        summary_services.get_displayable_collection_summary_dicts_matching_ids(
            collection_ids))
    activity_list += (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))

    if len(activity_list) == feconf.DEFAULT_QUERY_LIMIT:
        logging.error(
            '%s activities were fetched to load the library page. '
            'You may be running up against the default query limits.'
            % feconf.DEFAULT_QUERY_LIMIT)
    return activity_list, new_search_cursor
コード例 #36
0
ファイル: summary_services_test.py プロジェクト: yarinf/oppia
    def test_get_displayable_exp_summary_dicts_matching_ids(self):
        # A list of exp_id's are passed in:
        # EXP_ID_1 -- private exploration owned by Albert
        # EXP_ID_2 -- pubished exploration owned by Albert
        # EXP_ID_3 -- deleted exploration
        # EXP_ID_5 -- private exploration owned by Bob
        # Should only return [EXP_ID_2]

        displayable_summaries = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_1, self.EXP_ID_2, self.EXP_ID_3, self.EXP_ID_5]))
        expected_summary = {
            'category': u'A category',
            'community_owned': False,
            'human_readable_contributors_summary': {
                self.ALBERT_NAME: {
                    'num_commits':
                    2,
                    'profile_picture_data_url':
                    (user_services.DEFAULT_IDENTICON_DATA_URL)
                }
            },
            'id': self.EXP_ID_2,
            'language_code': feconf.DEFAULT_LANGUAGE_CODE,
            'num_views': 0,
            'objective': u'An objective',
            'ratings': feconf.get_empty_ratings(),
            'status': 'public',
            'tags': [],
            'thumbnail_bg_color': '#a33f40',
            'thumbnail_icon_url': '/images/subjects/Lightbulb.svg',
            'title': u'Exploration 2 Albert title',
        }
        self.assertIn('last_updated_msec', displayable_summaries[0])
        self.assertDictContainsSubset(expected_summary,
                                      displayable_summaries[0])
コード例 #37
0
    def setUp(self):
        """Completes the sign up process for the various users."""
        super(BaseStoryViewerControllerTests, self).setUp()
        self.VIEWER_EMAIL = '*****@*****.**'
        self.VIEWER_USERNAME = '******'
        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
        self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL)
        self.set_admins([self.ADMIN_USERNAME])
        self.admin = user_services.UserActionsInfo(self.admin_id)
        self.login(self.ADMIN_EMAIL)
        self.TOPIC_ID = 'topic_id'
        self.STORY_ID = 'story_id'
        self.STORY_URL_FRAGMENT = 'title-one'
        self.NODE_ID_1 = 'node_1'
        self.NODE_ID_2 = 'node_2'
        self.NODE_ID_3 = 'node_3'
        self.EXP_ID_0 = '0'
        self.EXP_ID_1 = '1'
        self.EXP_ID_7 = '7'

        self.save_new_valid_exploration(self.EXP_ID_0,
                                        self.admin_id,
                                        title='Title 1',
                                        end_state_name='End')
        self.save_new_valid_exploration(self.EXP_ID_1,
                                        self.admin_id,
                                        title='Title 2',
                                        end_state_name='End')
        self.save_new_valid_exploration(self.EXP_ID_7,
                                        self.admin_id,
                                        title='Title 3',
                                        end_state_name='End')
        self.publish_exploration(self.admin_id, self.EXP_ID_0)
        self.publish_exploration(self.admin_id, self.EXP_ID_1)
        self.publish_exploration(self.admin_id, self.EXP_ID_7)

        story = story_domain.Story.create_default_story(
            self.STORY_ID, 'Title', 'Description', self.TOPIC_ID,
            self.STORY_URL_FRAGMENT)

        exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_0, self.EXP_ID_1, self.EXP_ID_7],
                user=self.admin))
        self.node_1 = {
            'id':
            self.NODE_ID_1,
            'title':
            'Title 1',
            'description':
            'Description 1',
            'thumbnail_filename':
            'image_1.svg',
            'thumbnail_bg_color':
            constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0],
            'destination_node_ids': ['node_3'],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline':
            '',
            'outline_is_finalized':
            False,
            'exploration_id':
            self.EXP_ID_1,
            'exp_summary_dict':
            exp_summary_dicts[1],
            'completed':
            False
        }
        self.node_2 = {
            'id':
            self.NODE_ID_2,
            'title':
            'Title 2',
            'description':
            'Description 2',
            'thumbnail_filename':
            'image_2.svg',
            'thumbnail_bg_color':
            constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0],
            'destination_node_ids': ['node_1'],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline':
            '',
            'outline_is_finalized':
            False,
            'exploration_id':
            self.EXP_ID_0,
            'exp_summary_dict':
            exp_summary_dicts[0],
            'completed':
            True
        }
        self.node_3 = {
            'id':
            self.NODE_ID_3,
            'title':
            'Title 3',
            'description':
            'Description 3',
            'thumbnail_filename':
            'image_3.svg',
            'thumbnail_bg_color':
            constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0],
            'destination_node_ids': [],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline':
            '',
            'outline_is_finalized':
            False,
            'exploration_id':
            self.EXP_ID_7,
            'exp_summary_dict':
            exp_summary_dicts[2],
            'completed':
            False
        }
        story.story_contents.nodes = [
            story_domain.StoryNode.from_dict(self.node_1),
            story_domain.StoryNode.from_dict(self.node_2),
            story_domain.StoryNode.from_dict(self.node_3)
        ]
        self.nodes = story.story_contents.nodes
        story.story_contents.initial_node_id = 'node_2'
        story.story_contents.next_node_id = 'node_4'
        story_services.save_new_story(self.admin_id, story)
        self.save_new_topic(self.TOPIC_ID,
                            'user',
                            name='Topic',
                            description='A new topic',
                            canonical_story_ids=[story.id],
                            additional_story_ids=[],
                            uncategorized_skill_ids=[],
                            subtopics=[],
                            next_subtopic_id=0)
        topic_services.publish_topic(self.TOPIC_ID, self.admin_id)
        topic_services.publish_story(self.TOPIC_ID, self.STORY_ID,
                                     self.admin_id)
        self.logout()
        self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME)
        self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL)
        self.login(self.VIEWER_EMAIL)
        self._record_completion(self.viewer_id, self.STORY_ID, self.NODE_ID_2)
コード例 #38
0
def get_learner_collection_dict_by_id(
        collection_id, user_id, strict=True, allow_invalid_explorations=False,
        version=None):
    """Creates and returns a dictionary representation of a collection given by
    the provided collection ID. This dictionary contains extra information
    along with the dict returned by collection_domain.Collection.to_dict()
    which includes useful data for the collection learner view. The information
    includes progress in the collection, information about explorations
    referenced within the collection, and a slightly nicer data structure for
    frontend work.

    This raises a ValidationError if the collection retrieved using the given ID
    references non-existent explorations.
    """
    collection = get_collection_by_id(
        collection_id, strict=strict, version=version)

    exp_ids = collection.exploration_ids
    exp_summary_dicts = (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))
    exp_summaries_dict_map = {
        exp_summary_dict['id']: exp_summary_dict
        for exp_summary_dict in exp_summary_dicts
    }

    # TODO(bhenning): Users should not be recommended explorations they have
    # completed outside the context of a collection (see #1461).
    next_exploration_ids = None
    completed_exploration_ids = None
    if user_id:
        completed_exploration_ids = _get_valid_completed_exploration_ids(
            user_id, collection_id, collection)
        next_exploration_ids = collection.get_next_exploration_ids(
            completed_exploration_ids)
    else:
        # If the user is not logged in or they have not completed any of
        # the explorations yet within the context of this collection,
        # recommend the initial explorations.
        next_exploration_ids = collection.init_exploration_ids
        completed_exploration_ids = []

    collection_dict = collection.to_dict()
    collection_dict['skills'] = collection.skills
    collection_dict['playthrough_dict'] = {
        'next_exploration_ids': next_exploration_ids,
        'completed_exploration_ids': completed_exploration_ids
    }
    collection_dict['version'] = collection.version

    collection_is_public = rights_manager.is_collection_public(collection_id)

    # Insert an 'exploration' dict into each collection node, where the
    # dict includes meta information about the exploration (ID and title).
    for collection_node in collection_dict['nodes']:
        exploration_id = collection_node['exploration_id']
        summary_dict = exp_summaries_dict_map.get(exploration_id)
        if not allow_invalid_explorations:
            if not summary_dict:
                raise utils.ValidationError(
                    'Expected collection to only reference valid '
                    'explorations, but found an exploration with ID: %s (was '
                    'the exploration deleted?)' % exploration_id)
            if collection_is_public and rights_manager.is_exploration_private(
                    exploration_id):
                raise utils.ValidationError(
                    'Cannot reference a private exploration within a public '
                    'collection, exploration ID: %s' % exploration_id)

        collection_node['exploration'] = {
            'exists': bool(summary_dict)
        }
        if summary_dict:
            collection_node['exploration'].update(summary_dict)

    return collection_dict
コード例 #39
0
 def test_get_displayable_exp_summary_dicts_matching_ids_with_invalid_exp_id(
         self):
     displayable_summaries = (
         summary_services.get_displayable_exp_summary_dicts_matching_ids(
             ['invalid_exp_id']))
     self.assertEqual(displayable_summaries, [])
コード例 #40
0
    def setUp(self):
        """Completes the sign up process for the various users."""
        super(BaseStoryViewerControllerTests, self).setUp()
        self.VIEWER_EMAIL = '*****@*****.**'
        self.VIEWER_USERNAME = '******'
        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
        self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL)
        self.set_admins([self.ADMIN_USERNAME])
        self.admin = user_services.UserActionsInfo(self.admin_id)
        self.login(self.ADMIN_EMAIL)
        self.TOPIC_ID = 'topic_id'
        self.STORY_ID_1 = 'story_id_1'
        self.NODE_ID_1 = 'node_1'
        self.NODE_ID_2 = 'node_2'
        self.NODE_ID_3 = 'node_3'
        self.EXP_ID = 'exp_id'

        self.save_new_valid_exploration(
            self.EXP_ID, self.admin_id, title='Bridges in England',
            category='Architecture', language_code='en')
        rights_manager.publish_exploration(self.admin, self.EXP_ID)
        story = story_domain.Story.create_default_story(
            self.STORY_ID_1, 'Title', self.TOPIC_ID)
        story.description = ('Description')
        exp_summary_dict = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID], user=self.admin)[0])
        self.node_1 = {
            'id': self.NODE_ID_1,
            'title': 'Title 1',
            'destination_node_ids': ['node_3'],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline': '',
            'outline_is_finalized': False,
            'exploration_id': self.EXP_ID,
            'exp_summary_dict': exp_summary_dict,
            'completed': False
        }
        self.node_2 = {
            'id': self.NODE_ID_2,
            'title': 'Title 2',
            'destination_node_ids': ['node_1'],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline': '',
            'outline_is_finalized': False,
            'exploration_id': self.EXP_ID,
            'exp_summary_dict': exp_summary_dict,
            'completed': True
        }
        self.node_3 = {
            'id': self.NODE_ID_3,
            'title': 'Title 3',
            'destination_node_ids': [],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline': '',
            'outline_is_finalized': False,
            'exploration_id': None
        }
        story.story_contents.nodes = [
            story_domain.StoryNode.from_dict(self.node_1),
            story_domain.StoryNode.from_dict(self.node_2),
            story_domain.StoryNode.from_dict(self.node_3)
        ]
        self.nodes = story.story_contents.nodes
        story.story_contents.initial_node_id = 'node_2'
        story.story_contents.next_node_id = 'node_4'
        story_services.save_new_story(self.admin_id, story)
        self.save_new_topic(
            self.TOPIC_ID, 'user', 'Topic', 'A new topic', [story.id],
            [], [], [], 0)
        topic_services.publish_topic(self.TOPIC_ID, self.admin_id)
        topic_services.publish_story(
            self.TOPIC_ID, self.STORY_ID_1, self.admin_id)
        self.logout()
        self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME)
        self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL)
        self.login(self.VIEWER_EMAIL)
        self._record_completion(self.viewer_id, self.STORY_ID_1, self.NODE_ID_2)
コード例 #41
0
    def test_mark_topic_as_learnt_and_story_as_completed(self):
        self.NEW_USER_EMAIL = '*****@*****.**'
        self.NEW_USER_USERNAME = '******'

        self.save_new_valid_exploration(self.EXP_ID_3,
                                        self.admin_id,
                                        title='Title 3',
                                        end_state_name='End',
                                        correctness_feedback_enabled=True)
        self.publish_exploration(self.admin_id, self.EXP_ID_3)

        story = story_domain.Story.create_default_story(
            self.NEW_STORY_ID, 'Title', 'Description', self.TOPIC_ID,
            self.STORY_URL_FRAGMENT_TWO)
        story.meta_tag_content = 'story meta content'

        exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_3], user=self.admin))
        self.node_1 = {
            'id':
            self.NODE_ID_1,
            'title':
            'Title 1',
            'description':
            'Description 1',
            'thumbnail_filename':
            'image_1.svg',
            'thumbnail_bg_color':
            constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0],
            'thumbnail_size_in_bytes':
            21131,
            'destination_node_ids': [],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline':
            '',
            'outline_is_finalized':
            False,
            'exploration_id':
            self.EXP_ID_3,
            'exp_summary_dict':
            exp_summary_dicts[0],
            'completed':
            False
        }
        story.story_contents.nodes = [
            story_domain.StoryNode.from_dict(self.node_1)
        ]
        self.nodes = story.story_contents.nodes
        story.story_contents.initial_node_id = 'node_1'
        story.story_contents.next_node_id = 'node_2'
        story_services.save_new_story(self.admin_id, story)
        topic_services.add_canonical_story(self.admin_id, self.TOPIC_ID,
                                           self.NEW_STORY_ID)
        topic_services.publish_story(self.TOPIC_ID, self.NEW_STORY_ID,
                                     self.admin_id)

        csrf_token = self.get_new_csrf_token()
        story_services.record_completed_node_in_story_context(
            self.viewer_id, self.STORY_ID, self.NODE_ID_2)
        story_services.record_completed_node_in_story_context(
            self.viewer_id, self.STORY_ID, self.NODE_ID_1)
        with self.swap(constants, 'ENABLE_NEW_STRUCTURE_VIEWER_UPDATES', True):
            self.post_json('%s/staging/topic/%s/%s' %
                           (feconf.STORY_PROGRESS_URL_PREFIX,
                            self.STORY_URL_FRAGMENT, self.NODE_ID_3), {},
                           csrf_token=csrf_token)

        self.assertEqual(
            len(
                learner_progress_services.get_all_learnt_topic_ids(
                    self.viewer_id)), 1)
        self.assertEqual(
            len(
                learner_progress_services.get_all_completed_story_ids(
                    self.viewer_id)), 1)

        def _mock_none_function(_):
            """Mocks None."""
            return None

        story_fetchers_swap = self.swap(story_fetchers, 'get_story_by_id',
                                        _mock_none_function)

        with story_fetchers_swap:
            with self.capture_logging(
                    min_level=logging.ERROR) as captured_logs:
                self.post_json('%s/staging/topic/%s/%s' %
                               (feconf.STORY_PROGRESS_URL_PREFIX,
                                self.STORY_URL_FRAGMENT, self.NODE_ID_3), {},
                               csrf_token=csrf_token)
                self.assertEqual(captured_logs, [
                    'Could not find a story corresponding to %s '
                    'id.' % self.STORY_ID
                ])
コード例 #42
0
    def test_redirect_for_single_node_story(self):
        self.login(self.CURRICULUM_ADMIN_EMAIL)
        self.STORY_URL_FRAGMENT = 'story-two'
        self.NEW_USER_EMAIL = '*****@*****.**'
        self.NEW_USER_USERNAME = '******'

        self.save_new_valid_exploration(self.EXP_ID_0,
                                        self.admin_id,
                                        title='Title 1',
                                        end_state_name='End',
                                        correctness_feedback_enabled=True)
        self.publish_exploration(self.admin_id, self.EXP_ID_0)

        story = story_domain.Story.create_default_story(
            self.NEW_STORY_ID, 'Title', 'Description', self.NEW_TOPIC_ID,
            self.STORY_URL_FRAGMENT)
        story.meta_tag_content = 'story meta content'

        exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts_matching_ids(
                [self.EXP_ID_0], user=self.admin))
        self.node_1 = {
            'id':
            self.NODE_ID_1,
            'title':
            'Title 1',
            'description':
            'Description 1',
            'thumbnail_filename':
            'image_1.svg',
            'thumbnail_bg_color':
            constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0],
            'thumbnail_size_in_bytes':
            21131,
            'destination_node_ids': [],
            'acquired_skill_ids': [],
            'prerequisite_skill_ids': [],
            'outline':
            '',
            'outline_is_finalized':
            False,
            'exploration_id':
            self.EXP_ID_1,
            'exp_summary_dict':
            exp_summary_dicts[0],
            'completed':
            False
        }
        story.story_contents.nodes = [
            story_domain.StoryNode.from_dict(self.node_1)
        ]
        self.nodes = story.story_contents.nodes
        story.story_contents.initial_node_id = 'node_1'
        story.story_contents.next_node_id = 'node_2'
        story_services.save_new_story(self.admin_id, story)
        subtopic_1 = topic_domain.Subtopic.create_default_subtopic(
            1, 'Subtopic Title 1', 'url-frag-one')
        subtopic_1.skill_ids = ['skill_id_1']
        subtopic_1.url_fragment = 'sub-one-frag'
        self.save_new_topic(self.NEW_TOPIC_ID,
                            'user',
                            name='new topic',
                            url_fragment='topic-frag',
                            description='A new topic',
                            canonical_story_ids=[story.id],
                            additional_story_ids=[],
                            uncategorized_skill_ids=[],
                            subtopics=[subtopic_1],
                            next_subtopic_id=2)
        topic_services.publish_topic(self.NEW_TOPIC_ID, self.admin_id)
        topic_services.publish_story(self.NEW_TOPIC_ID, self.NEW_STORY_ID,
                                     self.admin_id)
        self.logout()
        self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME)
        self.login(self.NEW_USER_EMAIL)
        with self.swap(constants, 'ENABLE_NEW_STRUCTURE_VIEWER_UPDATES', True):
            response = self.get_html_response(
                '%s/staging/topic-frag/%s/%s' %
                (feconf.STORY_PROGRESS_URL_PREFIX, self.STORY_URL_FRAGMENT,
                 self.NODE_ID_1),
                expected_status_int=302)
            self.assertEqual(
                'http://localhost/learn/staging/topic-frag/story/story-two',
                response.headers['location'])
コード例 #43
0
def get_learner_collection_dict_by_id(collection_id,
                                      user_id,
                                      strict=True,
                                      allow_invalid_explorations=False,
                                      version=None):
    """Creates and returns a dictionary representation of a collection given by
    the provided collection ID. This dictionary contains extra information
    along with the dict returned by collection_domain.Collection.to_dict()
    which includes useful data for the collection learner view. The information
    includes progress in the collection, information about explorations
    referenced within the collection, and a slightly nicer data structure for
    frontend work.

    This raises a ValidationError if the collection retrieved using the given ID
    references non-existent explorations.
    """
    collection = get_collection_by_id(collection_id,
                                      strict=strict,
                                      version=version)

    exp_ids = collection.exploration_ids
    exp_summary_dicts = (
        summary_services.get_displayable_exp_summary_dicts_matching_ids(
            exp_ids))
    exp_summaries_dict_map = {
        exp_summary_dict['id']: exp_summary_dict
        for exp_summary_dict in exp_summary_dicts
    }

    # TODO(bhenning): Users should not be recommended explorations they have
    # completed outside the context of a collection (see #1461).
    next_exploration_ids = None
    completed_exploration_ids = None
    if user_id:
        completed_exploration_ids = _get_valid_completed_exploration_ids(
            user_id, collection_id, collection)
        next_exploration_ids = collection.get_next_exploration_ids(
            completed_exploration_ids)
    else:
        # If the user is not logged in or they have not completed any of
        # the explorations yet within the context of this collection,
        # recommend the initial explorations.
        next_exploration_ids = collection.init_exploration_ids
        completed_exploration_ids = []

    collection_dict = collection.to_dict()
    collection_dict['skills'] = collection.skills
    collection_dict['playthrough_dict'] = {
        'next_exploration_ids': next_exploration_ids,
        'completed_exploration_ids': completed_exploration_ids
    }
    collection_dict['version'] = collection.version

    collection_is_public = rights_manager.is_collection_public(collection_id)

    # Insert an 'exploration' dict into each collection node, where the
    # dict includes meta information about the exploration (ID and title).
    for collection_node in collection_dict['nodes']:
        exploration_id = collection_node['exploration_id']
        summary_dict = exp_summaries_dict_map.get(exploration_id)
        if not allow_invalid_explorations:
            if not summary_dict:
                raise utils.ValidationError(
                    'Expected collection to only reference valid '
                    'explorations, but found an exploration with ID: %s (was '
                    'the exploration deleted?)' % exploration_id)
            if collection_is_public and rights_manager.is_exploration_private(
                    exploration_id):
                raise utils.ValidationError(
                    'Cannot reference a private exploration within a public '
                    'collection, exploration ID: %s' % exploration_id)

        collection_node['exploration'] = {'exists': bool(summary_dict)}
        if summary_dict:
            collection_node['exploration'].update(summary_dict)

    return collection_dict
コード例 #44
0
    def post(self, story_id, node_id):
        story = story_fetchers.get_story_by_id(story_id)
        if story is None:
            logging.error('Could not find a story corresponding to '
                          '%s id.' % story_id)
            self.render_json({})
            return
        topic = topic_fetchers.get_topic_by_id(story.corresponding_topic_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 = story.story_contents.get_ordered_nodes()

        (next_exp_ids, next_node_id,
         completed_node_ids) = (self._record_node_completion(
             story_id, node_id, completed_node_ids, ordered_nodes))

        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_fetchers.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_node_ids) == len(ordered_nodes)
        learner_at_review_point_in_story = (
            len(exp_summaries) != 0
            and (len(completed_node_ids)
                 & 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

        # If there is no next_node_id, the story is marked as completed else
        # mark the story as incomplete.
        if next_node_id is None:
            learner_progress_services.mark_story_as_completed(
                self.user_id, story_id)
        else:
            learner_progress_services.record_story_started(
                self.user_id, story.id)

        completed_story_ids = (
            learner_progress_services.get_all_completed_story_ids(
                self.user_id))
        story_ids_in_topic = []
        for story in topic.canonical_story_references:
            story_ids_in_topic.append(story.story_id)

        is_topic_completed = set(story_ids_in_topic).intersection(
            set(completed_story_ids))

        # If at least one story in the topic is completed,
        # mark the topic as learnt else mark it as partially learnt.
        if not is_topic_completed:
            learner_progress_services.record_topic_started(
                self.user_id, topic.id)
        else:
            learner_progress_services.mark_topic_as_learnt(
                self.user_id, topic.id)

        return self.render_json({
            'summaries': exp_summaries,
            'ready_for_review_test': ready_for_review_test,
            'next_node_id': next_node_id
        })
コード例 #45
0
ファイル: story_viewer.py プロジェクト: accio112/oppia
    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_fetchers.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
        })