Пример #1
0
    def test_exploration_subscription(self):
        with self.swap(
                subscription_services, 'subscribe_to_thread', self._null_fn
            ), self.swap(
                subscription_services, 'subscribe_to_exploration',
                self._null_fn):
            # User A adds user B as an editor to the exploration.
            rights_manager.assign_role_for_exploration(
                self.user_a_id, self.EXP_ID_1, self.user_b_id,
                rights_manager.ROLE_EDITOR)
            # User A adds user C as a viewer of the exploration.
            rights_manager.assign_role_for_exploration(
                self.user_a_id, self.EXP_ID_1, self.user_c_id,
                rights_manager.ROLE_VIEWER)

        self._run_one_off_job()

        # Users A and B are subscribed to the exploration. User C is not.
        user_a_subscriptions_model = user_models.UserSubscriptionsModel.get(
            self.user_a_id)
        user_b_subscriptions_model = user_models.UserSubscriptionsModel.get(
            self.user_b_id)
        user_c_subscriptions_model = user_models.UserSubscriptionsModel.get(
            self.user_c_id, strict=False)

        self.assertEqual(
            user_a_subscriptions_model.activity_ids, [self.EXP_ID_1])
        self.assertEqual(
            user_b_subscriptions_model.activity_ids, [self.EXP_ID_1])
        self.assertEqual(user_a_subscriptions_model.feedback_thread_ids, [])
        self.assertEqual(user_b_subscriptions_model.feedback_thread_ids, [])
        self.assertEqual(user_c_subscriptions_model, None)
Пример #2
0
    def test_root_redirect_rules_for_logged_in_editors(self):
        self.login(self.TEST_CREATOR_EMAIL)
        creator_user_id = self.get_user_id_from_email(self.TEST_CREATOR_EMAIL)
        editor_user_id = self.get_user_id_from_email(self.TEST_EDITOR_EMAIL)
        exploration_id = '1_en_test_exploration'
        self.save_new_valid_exploration(
            exploration_id, creator_user_id, title='Test',
            category='Test', language_code='en')
        rights_manager.assign_role_for_exploration(
            creator_user_id, exploration_id, editor_user_id,
            rights_manager.ROLE_EDITOR)
        self.logout()
        self.login(self.TEST_EDITOR_EMAIL)
        exp_services.update_exploration(
            editor_user_id, exploration_id, [{
                'cmd': 'edit_exploration_property',
                'property_name': 'title',
                'new_value': 'edited title'
            }, {
                'cmd': 'edit_exploration_property',
                'property_name': 'category',
                'new_value': 'edited category'
            }], 'Change title and category')

        # Since user has edited one exploration created by another user,
        # going to '/' should redirect to the dashboard page.
        response = self.testapp.get('/')
        self.assertEqual(response.status_int, 302)
        self.assertIn('dashboard', response.headers['location'])
        self.logout()
Пример #3
0
    def test_deletion_rights_for_published_exploration(self):
        """Test rights management for deletion of published explorations."""
        published_exp_id = 'published_eid'
        exploration = exp_domain.Exploration.create_default_exploration(
            published_exp_id, 'A title', 'A category')
        exp_services.save_new_exploration(self.owner_id, exploration)

        rights_manager.assign_role_for_exploration(
            self.owner_id, published_exp_id, self.editor_id,
            rights_manager.ROLE_EDITOR)
        rights_manager.publish_exploration(self.owner_id, published_exp_id)

        self.login(self.EDITOR_EMAIL)
        response = self.testapp.delete(
            '/createhandler/data/%s' % published_exp_id, expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.VIEWER_EMAIL)
        response = self.testapp.delete(
            '/createhandler/data/%s' % published_exp_id, expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.OWNER_EMAIL)
        response = self.testapp.delete(
            '/createhandler/data/%s' % published_exp_id, expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.ADMIN_EMAIL)
        response = self.testapp.delete(
            '/createhandler/data/%s' % published_exp_id)
        self.assertEqual(response.status_int, 200)
        self.logout()
Пример #4
0
    def test_adding_new_exploration_viewer_role_does_not_result_in_subscription(self):
        exploration = exp_domain.Exploration.create_default_exploration(EXP_ID, "Title", "Category")
        exp_services.save_new_exploration(self.owner_id, exploration)

        self.assertEqual(self._get_exploration_ids_subscribed_to(self.viewer_id), [])
        rights_manager.assign_role_for_exploration(self.owner_id, EXP_ID, self.viewer_id, rights_manager.ROLE_VIEWER)
        self.assertEqual(self._get_exploration_ids_subscribed_to(self.viewer_id), [])
Пример #5
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)
Пример #6
0
    def test_collaborators_can_see_explorations(self):
        self.save_new_default_exploration(
            self.EXP_ID, self.owner_id, title=self.EXP_TITLE)
        rights_manager.assign_role_for_exploration(
            self.owner_id, self.EXP_ID, self.collaborator_id,
            rights_manager.ROLE_EDITOR)
        self.set_admins([self.OWNER_USERNAME])

        self.login(self.COLLABORATOR_EMAIL)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)
        self.assertEqual(
            response['explorations_list'][0]['status'],
            rights_manager.ACTIVITY_STATUS_PRIVATE)

        rights_manager.publish_exploration(self.owner_id, self.EXP_ID)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)
        self.assertEqual(
            response['explorations_list'][0]['status'],
            rights_manager.ACTIVITY_STATUS_PUBLIC)

        rights_manager.publicize_exploration(self.owner_id, self.EXP_ID)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)
        self.assertEqual(
            response['explorations_list'][0]['status'],
            rights_manager.ACTIVITY_STATUS_PUBLICIZED)

        self.logout()
Пример #7
0
    def test_community_owned_exploration(self):
        with self.swap(
                subscription_services, 'subscribe_to_thread', self._null_fn
            ), self.swap(
                subscription_services, 'subscribe_to_exploration',
                self._null_fn):
            # User A adds user B as an editor to the exploration.
            rights_manager.assign_role_for_exploration(
                self.user_a_id, self.EXP_ID_1, self.user_b_id,
                rights_manager.ROLE_EDITOR)
            # The exploration becomes community-owned.
            rights_manager.publish_exploration(self.user_a_id, self.EXP_ID_1)
            rights_manager.release_ownership_of_exploration(
                self.user_a_id, self.EXP_ID_1)
            # User C edits the exploration.
            exp_services.update_exploration(
                self.user_c_id, self.EXP_ID_1, [], 'Update exploration')

        self._run_one_off_job()

        # User A and user B are subscribed to the exploration; user C is not.
        user_a_subscriptions_model = user_models.UserSubscriptionsModel.get(
            self.user_a_id)
        user_b_subscriptions_model = user_models.UserSubscriptionsModel.get(
            self.user_b_id)
        user_c_subscriptions_model = user_models.UserSubscriptionsModel.get(
            self.user_c_id, strict=False)

        self.assertEqual(
            user_a_subscriptions_model.activity_ids, [self.EXP_ID_1])
        self.assertEqual(
            user_b_subscriptions_model.activity_ids, [self.EXP_ID_1])
        self.assertEqual(user_c_subscriptions_model, None)
Пример #8
0
    def test_inviting_playtester_to_exploration(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        self.assertFalse(
            rights_manager.Actor(self.user_id_b).can_play(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).can_view(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).can_edit(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).can_delete(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))

        rights_manager.assign_role_for_exploration(
            self.user_id_a, self.EXP_ID, self.user_id_b,
            rights_manager.ROLE_VIEWER)

        self.assertTrue(
            rights_manager.Actor(self.user_id_b).can_play(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertTrue(
            rights_manager.Actor(self.user_id_b).can_view(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).can_edit(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).can_delete(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
Пример #9
0
    def test_adding_new_exploration_owner_or_editor_role_results_in_subscription(self):
        exploration = exp_domain.Exploration.create_default_exploration(EXP_ID, "Title", "Category")
        exp_services.save_new_exploration(self.owner_id, exploration)

        self.assertEqual(self._get_exploration_ids_subscribed_to(self.owner_2_id), [])
        rights_manager.assign_role_for_exploration(self.owner_id, EXP_ID, self.owner_2_id, rights_manager.ROLE_OWNER)
        self.assertEqual(self._get_exploration_ids_subscribed_to(self.owner_2_id), [EXP_ID])

        self.assertEqual(self._get_exploration_ids_subscribed_to(self.editor_id), [])
        rights_manager.assign_role_for_exploration(self.owner_id, EXP_ID, self.editor_id, rights_manager.ROLE_EDITOR)
        self.assertEqual(self._get_exploration_ids_subscribed_to(self.editor_id), [EXP_ID])
Пример #10
0
    def test_ownership_of_exploration(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(self.user_a, self.EXP_ID,
                                                   self.user_id_b,
                                                   rights_manager.ROLE_EDITOR)
        exp_rights = rights_manager.get_exploration_rights(self.EXP_ID)

        self.assertTrue(exp_rights.is_owner(self.user_id_a))
        self.assertFalse(exp_rights.is_owner(self.user_id_b))
        self.assertFalse(exp_rights.is_owner(self.user_id_admin))
Пример #11
0
    def post(self, unused_entity_type, entity_id):
        """Handles Post requests."""
        voice_artist = self.payload.get('username')
        voice_artist_id = user_services.get_user_id_from_username(voice_artist)
        if voice_artist_id is None:
            raise self.InvalidInputException(
                'Sorry, we could not find the specified user.')
        rights_manager.assign_role_for_exploration(
            self.user, entity_id, voice_artist_id,
            rights_domain.ROLE_VOICE_ARTIST)

        self.render_json({})
Пример #12
0
    def test_can_get_editable_private_exploration_summaries(self):
        self.login(self.VIEWER_EMAIL)

        response_dict = self.get_json(
            feconf.EXPLORATION_SUMMARIES_DATA_URL, {
                'stringified_exp_ids':
                json.dumps([
                    self.PRIVATE_EXP_ID_EDITOR, self.PUBLIC_EXP_ID_EDITOR,
                    self.PRIVATE_EXP_ID_VIEWER
                ]),
                'include_private_explorations':
                True
            })
        self.assertIn('summaries', response_dict)

        summaries = response_dict['summaries']
        self.assertEqual(len(summaries), 2)

        self.assertEqual(summaries[0]['id'], self.PUBLIC_EXP_ID_EDITOR)
        self.assertEqual(summaries[0]['status'], 'public')
        self.assertEqual(summaries[1]['id'], self.PRIVATE_EXP_ID_VIEWER)
        self.assertEqual(summaries[1]['status'], 'private')

        # If the viewer user is granted edit access to the editor user's
        # private exploration, then it will show up for the next request.
        rights_manager.assign_role_for_exploration(self.editor,
                                                   self.PRIVATE_EXP_ID_EDITOR,
                                                   self.viewer_id,
                                                   rights_manager.ROLE_EDITOR)

        response_dict = self.get_json(
            feconf.EXPLORATION_SUMMARIES_DATA_URL, {
                'stringified_exp_ids':
                json.dumps([
                    self.PRIVATE_EXP_ID_EDITOR, self.PUBLIC_EXP_ID_EDITOR,
                    self.PRIVATE_EXP_ID_VIEWER
                ]),
                'include_private_explorations':
                True
            })
        self.assertIn('summaries', response_dict)

        summaries = response_dict['summaries']
        self.assertEqual(len(summaries), 3)

        self.assertEqual(summaries[0]['id'], self.PRIVATE_EXP_ID_EDITOR)
        self.assertEqual(summaries[0]['status'], 'private')
        self.assertEqual(summaries[1]['id'], self.PUBLIC_EXP_ID_EDITOR)
        self.assertEqual(summaries[1]['status'], 'public')
        self.assertEqual(summaries[2]['id'], self.PRIVATE_EXP_ID_VIEWER)
        self.assertEqual(summaries[2]['status'], 'private')

        self.logout()
Пример #13
0
    def put(self, exploration_id):
        """Updates the editing rights for the given exploration."""
        exploration = exp_fetchers.get_exploration_by_id(exploration_id)
        version = self.payload.get('version')
        _require_valid_version(version, exploration.version)

        make_community_owned = self.payload.get('make_community_owned')
        new_member_username = self.payload.get('new_member_username')
        new_member_role = self.payload.get('new_member_role')
        viewable_if_private = self.payload.get('viewable_if_private')

        if new_member_username:
            new_member_id = user_services.get_user_id_from_username(
                new_member_username)
            if new_member_id is None:
                raise self.InvalidInputException(
                    'Sorry, we could not find the specified user.')
            if new_member_id == self.user_id:
                raise self.InvalidInputException(
                    'Users are not allowed to assign other roles to themselves'
                )
            rights_manager.assign_role_for_exploration(self.user,
                                                       exploration_id,
                                                       new_member_id,
                                                       new_member_role)
            email_manager.send_role_notification_email(self.user_id,
                                                       new_member_id,
                                                       new_member_role,
                                                       exploration_id,
                                                       exploration.title)

        elif make_community_owned:
            exploration = exp_fetchers.get_exploration_by_id(exploration_id)
            try:
                exploration.validate(strict=True)
            except utils.ValidationError as e:
                raise self.InvalidInputException(e)

            rights_manager.release_ownership_of_exploration(
                self.user, exploration_id)

        elif viewable_if_private is not None:
            rights_manager.set_private_viewability_of_exploration(
                self.user, exploration_id, viewable_if_private)

        else:
            raise self.InvalidInputException(
                'No change was made to this exploration.')

        self.render_json({
            'rights':
            rights_manager.get_exploration_rights(exploration_id).to_dict()
        })
Пример #14
0
def accept_voiceover_application(voiceover_application_id, reviewer_id):
    """Accept the voiceover application of given voiceover application id.

    Args:
        voiceover_application_id: str. The id of the voiceover application which
            need to be accepted.
        reviewer_id: str. The user ID of the reviewer.
    """
    voiceover_application = get_voiceover_application_by_id(
        voiceover_application_id)
    if reviewer_id == voiceover_application.author_id:
        raise Exception('Applicants are not allowed to review their own '
                        'voiceover application.')

    reviewer = user_services.get_user_actions_info(reviewer_id)

    voiceover_application.accept(reviewer_id)

    _save_voiceover_applications([voiceover_application])

    if voiceover_application.target_type == feconf.ENTITY_TYPE_EXPLORATION:
        rights_manager.assign_role_for_exploration(
            reviewer, voiceover_application.target_id,
            voiceover_application.author_id, rights_domain.ROLE_VOICE_ARTIST)
        opportunity_services.update_exploration_voiceover_opportunities(
            voiceover_application.target_id,
            voiceover_application.language_code)
        opportunities = (
            opportunity_services.get_exploration_opportunity_summaries_by_ids(
                [voiceover_application.target_id]))
        email_manager.send_accepted_voiceover_application_email(
            voiceover_application.author_id,
            opportunities[voiceover_application.target_id].chapter_title,
            voiceover_application.language_code)
    # TODO(#7969): Add notification to the user's dashboard for the accepted
    # voiceover application.

    voiceover_application_models = (
        suggestion_models.GeneralVoiceoverApplicationModel.
        get_voiceover_applications(voiceover_application.target_type,
                                   voiceover_application.target_id,
                                   voiceover_application.language_code))
    rejected_voiceover_applications = []
    for model in voiceover_application_models:
        voiceover_application = _get_voiceover_application_from_model(model)
        if not voiceover_application.is_handled:
            voiceover_application.reject(
                reviewer_id, 'We have to reject your application as another '
                'application for the same opportunity got accepted.')
            rejected_voiceover_applications.append(voiceover_application)

    _save_voiceover_applications(rejected_voiceover_applications)
Пример #15
0
    def test_adding_new_exploration_viewer_role_does_not_result_in_subscription(
            self) -> None:
        exploration = exp_domain.Exploration.create_default_exploration(
            EXP_ID)  # type: ignore[no-untyped-call]
        exp_services.save_new_exploration(
            self.owner_id, exploration)  # type: ignore[no-untyped-call]

        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.viewer_id), [])
        rights_manager.assign_role_for_exploration(  # type: ignore[no-untyped-call]
            self.owner, EXP_ID, self.viewer_id, rights_domain.ROLE_VIEWER)
        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.viewer_id), [])
Пример #16
0
    def test_adding_new_exploration_viewer_role_does_not_result_in_subscription(
            self):
        exploration = exp_domain.Exploration.create_default_exploration(
            EXP_ID, 'Title', 'Category')
        exp_services.save_new_exploration(self.owner_id, exploration)

        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.viewer_id), [])
        rights_manager.assign_role_for_exploration(self.owner_id, EXP_ID,
                                                   self.viewer_id,
                                                   rights_manager.ROLE_VIEWER)
        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.viewer_id), [])
Пример #17
0
    def setUp(self):
        super(VoiceArtistTest, self).setUp()
        self.login(self.OWNER_EMAIL)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
        rights_manager.assign_role_for_exploration(
            self.owner, self.EXP_ID, self.voice_artist_id,
            rights_manager.ROLE_VOICE_ARTIST)
        self.logout()

        self.login(self.VOICE_ARTIST_EMAIL)
        # Generate CSRF token.
        self.csrf_token = self.get_new_csrf_token()
Пример #18
0
    def test_viewer_cannot_be_reassigned_as_viewer(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID, self.user_id_b,
            rights_domain.ROLE_VIEWER)

        with self.assertRaisesRegexp(
            Exception, 'This user already can view this'):
            rights_manager.assign_role_for_exploration(
                self.user_a, self.EXP_ID, self.user_id_b,
                rights_domain.ROLE_VIEWER)
Пример #19
0
    def test_stats_for_multiple_explorations_with_multiple_owners(self):
        exploration_1 = self.save_new_default_exploration(
            self.EXP_ID_1, self.owner_id_1, title=self.EXP_TITLE_1)
        exploration_2 = self.save_new_default_exploration(
            self.EXP_ID_2, self.owner_id_1, title=self.EXP_TITLE_2)

        rights_manager.assign_role_for_exploration(
            self.owner_id_1, self.EXP_ID_1, self.owner_id_2,
            rights_manager.ROLE_OWNER)
        rights_manager.assign_role_for_exploration(
            self.owner_id_1, self.EXP_ID_2, self.owner_id_2,
            rights_manager.ROLE_OWNER)

        self.login(self.OWNER_EMAIL_2)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 2)

        exp_version = self.EXP_DEFAULT_VERSION

        exp_id_1 = self.EXP_ID_1
        state_1 = exploration_1.init_state_name
        exp_id_2 = self.EXP_ID_2
        state_2 = exploration_2.init_state_name

        self._record_start(exp_id_1, exp_version, state_1)
        self._record_start(exp_id_1, exp_version, state_1)
        self._record_start(exp_id_2, exp_version, state_2)
        self._record_start(exp_id_2, exp_version, state_2)
        self._run_stats_aggregator_jobs()

        self._rate_exploration(exp_id_1, [3])
        self._rate_exploration(exp_id_2, [2])

        self._run_user_stats_aggregator_job()
        user_model_2 = user_models.UserStatsModel.get(self.owner_id_2)
        self.assertEquals(user_model_2.total_plays, 4)
        self.assertEquals(
            user_model_2.impact_score, self.USER_IMPACT_SCORE_DEFAULT)
        self.assertEquals(user_model_2.average_ratings, 2.5)
        self.logout()

        self.login(self.OWNER_EMAIL_1)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 2)

        user_model_1 = user_models.UserStatsModel.get(self.owner_id_1)
        self.assertEquals(user_model_1.total_plays, 4)
        self.assertEquals(
            user_model_1.impact_score, self.USER_IMPACT_SCORE_DEFAULT)
        self.assertEquals(user_model_1.average_ratings, 2.5)
        self.logout()
Пример #20
0
    def test_contribution_msec_does_not_update_until_exp_is_published(self):
        exploration = self.save_new_valid_exploration(self.EXP_ID,
                                                      self.admin_id,
                                                      end_state_name='End')
        init_state_name = exploration.init_state_name

        # Test that saving an exploration does not update first contribution
        # time.
        self.assertIsNone(
            user_services.get_user_settings(
                self.admin_id).first_contribution_msec)

        # Test that commit to unpublished exploration does not update
        # contribution time.
        exp_services.update_exploration(self.admin_id, self.EXP_ID, [
            exp_domain.ExplorationChange({
                'cmd': 'edit_state_property',
                'state_name': init_state_name,
                'property_name': 'widget_id',
                'new_value': 'MultipleChoiceInput'
            })
        ], '')
        self.assertIsNone(
            user_services.get_user_settings(
                self.admin_id).first_contribution_msec)

        # Test that another user who commits to unpublished exploration does not
        # have updated first contribution time.
        rights_manager.assign_role_for_exploration(self.admin, self.EXP_ID,
                                                   self.editor_id, 'editor')
        exp_services.update_exploration(self.editor_id, self.EXP_ID, [
            exp_domain.ExplorationChange({
                'cmd': 'rename_state',
                'old_state_name': feconf.DEFAULT_INIT_STATE_NAME,
                'new_state_name': u'¡Hola! αβγ',
            })
        ], '')
        self.assertIsNone(
            user_services.get_user_settings(
                self.editor_id).first_contribution_msec)

        # Test that after an exploration is published, all contributors have
        # updated first contribution time.
        exp_services.publish_exploration_and_update_user_profiles(
            self.admin, self.EXP_ID)
        self.assertIsNotNone(
            user_services.get_user_settings(
                self.admin_id).first_contribution_msec)
        self.assertIsNotNone(
            user_services.get_user_settings(
                self.editor_id).first_contribution_msec)
Пример #21
0
    def test_contribution_msec_does_not_change_if_no_contribution_to_exp(self):
        self.save_new_valid_exploration(
            self.EXP_ID, self.admin_id, end_state_name='End')
        rights_manager.assign_role_for_exploration(
            self.admin_id, self.EXP_ID, self.editor_id, 'editor')
        exp_services.publish_exploration_and_update_user_profiles(
            self.admin_id, self.EXP_ID)

        # Test that contribution time is not given to an editor that has not
        # contributed.
        self.assertIsNotNone(user_services.get_user_settings(
            self.admin_id).first_contribution_msec)
        self.assertIsNone(user_services.get_user_settings(
            self.editor_id).first_contribution_msec)
Пример #22
0
    def setUp(self):
        super(TranslationFirstTimeTutorialTest, self).setUp()
        self.login(self.OWNER_EMAIL)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
        self.publish_exploration(self.owner_id, self.EXP_ID)
        rights_manager.assign_role_for_exploration(
            self.voiceover_admin, self.EXP_ID, self.voice_artist_id,
            rights_domain.ROLE_VOICE_ARTIST)
        self.logout()

        self.login(self.VOICE_ARTIST_EMAIL)
        # Generate CSRF token.
        self.csrf_token = self.get_new_csrf_token()
Пример #23
0
    def setUp(self):
        super(TranslatorTest, self).setUp()
        self.login(self.OWNER_EMAIL)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
        rights_manager.assign_role_for_exploration(
            self.owner, self.EXP_ID, self.translator_id,
            rights_manager.ROLE_TRANSLATOR)
        self.logout()

        self.login(self.TRANSLATOR_EMAIL)
        # Generate CSRF token.
        response = self.testapp.get('/create/%s' % self.EXP_ID)
        self.csrf_token = self.get_csrf_token_from_response(response)
Пример #24
0
    def setUp(self):
        super(TranslationFirstTimeTutorialTest, self).setUp()
        self.login(self.OWNER_EMAIL)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
        rights_manager.assign_role_for_exploration(
            self.owner, self.EXP_ID, self.voice_artist_id,
            rights_manager.ROLE_VOICE_ARTIST)
        self.logout()

        self.login(self.VOICE_ARTIST_EMAIL)
        # Generate CSRF token.
        response = self.get_html_response('/create/%s' % self.EXP_ID)
        self.csrf_token = self.get_csrf_token_from_response(response)
Пример #25
0
    def test_contribution_msec_does_not_change_if_no_contribution_to_exp(self):
        self.save_new_valid_exploration(
            self.EXP_ID, self.admin_id, end_state_name='End')
        rights_manager.assign_role_for_exploration(
            self.admin_id, self.EXP_ID, self.editor_id, 'editor')
        exp_services.publish_exploration_and_update_user_profiles(
            self.admin_id, self.EXP_ID)

        # Test that contribution time is not given to an editor that has not
        # contributed.
        self.assertIsNotNone(user_services.get_user_settings(
            self.admin_id).first_contribution_msec)
        self.assertIsNone(user_services.get_user_settings(
            self.editor_id).first_contribution_msec)
Пример #26
0
    def test_contribution_msec_does_not_update_until_exploration_is_published(self):
        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
        self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL)

        self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME)
        self.editor_id = self.get_user_id_from_email(self.EDITOR_EMAIL)

        exploration = self.save_new_valid_exploration(
            self.EXP_ID, self.admin_id, end_state_name='End')
        self.init_state_name = exploration.init_state_name

        # Test that saving an exploration does not update first contribution
        # time.
        self.assertIsNone(user_services.get_user_settings(
            self.admin_id).first_contribution_msec)

        # Test that commit to unpublished exploration does not update
        # contribution time.
        exp_services.update_exploration(
            self.admin_id, self.EXP_ID, [{
                'cmd': 'edit_state_property',
                'state_name': self.init_state_name,
                'property_name': 'widget_id',
                'new_value': 'MultipleChoiceInput'
            }], '')
        self.assertIsNone(user_services.get_user_settings(
            self.admin_id).first_contribution_msec)

        # Test that another user who commits to unpublished exploration does not
        # have updated first contribution time.
        rights_manager.assign_role_for_exploration(
            self.admin_id, self.EXP_ID, self.editor_id, 'editor')
        exp_services.update_exploration(
            self.editor_id, self.EXP_ID, [{
            'cmd': 'rename_state',
            'old_state_name': feconf.DEFAULT_INIT_STATE_NAME,
            'new_state_name': u'¡Hola! αβγ',
            }], '')
        self.assertIsNone(user_services.get_user_settings(
            self.editor_id).first_contribution_msec)

        # Test that after an exploration is published, all contributors have
        # updated first contribution time.
        exp_services.publish_exploration_and_update_user_profiles(
            self.admin_id, self.EXP_ID)
        self.assertIsNotNone(user_services.get_user_settings(
            self.admin_id).first_contribution_msec)
        self.assertIsNotNone(user_services.get_user_settings(
            self.editor_id).first_contribution_msec)
Пример #27
0
    def test_assign_voice_artist_to_role_owner(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID, self.user_id_b,
            rights_domain.ROLE_VOICE_ARTIST)
        exp_rights = rights_manager.get_exploration_rights(self.EXP_ID)

        self.assertFalse(exp_rights.is_owner(self.user_id_b))

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID, self.user_id_b, rights_domain.ROLE_OWNER)
        exp_rights = rights_manager.get_exploration_rights(self.EXP_ID)

        self.assertTrue(exp_rights.is_owner(self.user_id_b))
Пример #28
0
    def test_stats_for_single_exploration_with_multiple_owners(self):
        exploration = self.save_new_default_exploration(self.EXP_ID_1,
                                                        self.owner_id_1,
                                                        title=self.EXP_TITLE_1)

        rights_manager.assign_role_for_exploration(self.owner_id_1,
                                                   self.EXP_ID_1,
                                                   self.owner_id_2,
                                                   rights_manager.ROLE_OWNER)

        self.login(self.OWNER_EMAIL_1)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)

        exp_version = self.EXP_DEFAULT_VERSION
        exp_id = self.EXP_ID_1
        state = exploration.init_state_name

        self._record_start(exp_id, exp_version, state)
        self._record_start(exp_id, exp_version, state)
        self._run_stats_aggregator_jobs()

        self._rate_exploration(exp_id, [3, 4, 5])
        self.logout()

        self.login(self.OWNER_EMAIL_2)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)

        self._rate_exploration(exp_id, [3, 4, 5])

        self._run_user_stats_aggregator_job()

        user_model_1 = user_models.UserStatsModel.get(self.owner_id_1)
        self.assertEquals(user_model_1.total_plays, 2)
        self.assertEquals(user_model_1.impact_score,
                          self.USER_IMPACT_SCORE_DEFAULT)
        self.assertEquals(user_model_1.num_ratings, 3)
        self.assertEquals(user_model_1.average_ratings, 4)

        user_model_2 = user_models.UserStatsModel.get(self.owner_id_2)
        self.assertEquals(user_model_2.total_plays, 2)
        self.assertEquals(user_model_2.impact_score,
                          self.USER_IMPACT_SCORE_DEFAULT)
        self.assertEquals(user_model_2.num_ratings, 3)
        self.assertEquals(user_model_2.average_ratings, 4)
        self.logout()
Пример #29
0
    def test_adding_new_exploration_owner_or_editor_role_results_in_subscription(self): # pylint: disable=line-too-long
        exploration = exp_domain.Exploration.create_default_exploration(EXP_ID)
        exp_services.save_new_exploration(self.owner_id, exploration)

        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.owner_2_id), [])
        rights_manager.assign_role_for_exploration(
            self.owner_id, EXP_ID, self.owner_2_id, rights_manager.ROLE_OWNER)
        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.owner_2_id), [EXP_ID])

        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.editor_id), [])
        rights_manager.assign_role_for_exploration(
            self.owner_id, EXP_ID, self.editor_id, rights_manager.ROLE_EDITOR)
        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.editor_id), [EXP_ID])
Пример #30
0
    def test_viewer_cannot_see_explorations(self):
        self.save_new_default_exploration(
            self.EXP_ID, self.owner_id, title=self.EXP_TITLE)
        rights_manager.assign_role_for_exploration(
            self.owner, self.EXP_ID, self.viewer_id,
            rights_domain.ROLE_VIEWER)
        self.set_admins([self.OWNER_USERNAME])

        self.login(self.VIEWER_EMAIL)
        response = self.get_json(feconf.CREATOR_DASHBOARD_DATA_URL)
        self.assertEqual(response['explorations_list'], [])

        rights_manager.publish_exploration(self.owner, self.EXP_ID)
        response = self.get_json(feconf.CREATOR_DASHBOARD_DATA_URL)
        self.assertEqual(response['explorations_list'], [])

        self.logout()
    def setUp(self):
        super(SuggestionMigrationOneOffJobTest, self).setUp()

        self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME)
        self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME)
        self.signup(self.AUTHOR_EMAIL, 'author')
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.editor_id = self.get_user_id_from_email(self.EDITOR_EMAIL)
        self.author_id = self.get_user_id_from_email(self.AUTHOR_EMAIL)

        self.editor = user_services.UserActionsInfo(self.editor_id)

        # Login and create exploration and suggestions.
        self.login(self.EDITOR_EMAIL)

        # Create exploration.
        self.save_new_valid_exploration(self.EXP_ID,
                                        self.editor_id,
                                        title='Exploration for suggestions',
                                        category='Algebra',
                                        objective='Test a suggestion.')

        exploration = exp_services.get_exploration_by_id(self.EXP_ID)
        init_state = exploration.states[exploration.init_state_name]
        init_interaction = init_state.interaction
        init_interaction.default_outcome.dest = exploration.init_state_name
        self.old_content = state_domain.SubtitledHtml('content',
                                                      'old content').to_dict()
        exp_services.update_exploration(self.editor_id, self.EXP_ID, [
            exp_domain.ExplorationChange({
                'cmd': exp_domain.CMD_ADD_STATE,
                'state_name': 'State 1',
            }),
            exp_domain.ExplorationChange({
                'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
                'state_name': 'State 1',
                'property_name': exp_domain.STATE_PROPERTY_CONTENT,
                'new_value': self.old_content
            })
        ], 'Add state name')

        rights_manager.publish_exploration(self.editor, self.EXP_ID)
        rights_manager.assign_role_for_exploration(self.editor, self.EXP_ID,
                                                   self.owner_id,
                                                   rights_manager.ROLE_EDITOR)
Пример #32
0
    def test_ownership_of_exploration(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(
            self.user_id_a, self.EXP_ID, self.user_id_b,
            rights_manager.ROLE_EDITOR)

        self.assertTrue(
            rights_manager.Actor(self.user_id_a).is_owner(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).is_owner(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))

        self.assertFalse(
            rights_manager.Actor(self.user_id_admin).is_owner(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
Пример #33
0
    def test_ownership_of_exploration(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(self.user_id_a, self.EXP_ID,
                                                   self.user_id_b,
                                                   rights_manager.ROLE_EDITOR)

        self.assertTrue(
            rights_manager.Actor(self.user_id_a).is_owner(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
        self.assertFalse(
            rights_manager.Actor(self.user_id_b).is_owner(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))

        self.assertFalse(
            rights_manager.Actor(self.user_id_admin).is_owner(
                rights_manager.ACTIVITY_TYPE_EXPLORATION, self.EXP_ID))
Пример #34
0
    def test_can_get_editable_private_exploration_summaries(self):
        self.login(self.VIEWER_EMAIL)

        response_dict = self.get_json(feconf.EXPLORATION_SUMMARIES_DATA_URL, {
            'stringified_exp_ids': json.dumps([
                self.PRIVATE_EXP_ID_EDITOR, self.PUBLIC_EXP_ID_EDITOR,
                self.PRIVATE_EXP_ID_VIEWER]),
            'include_private_explorations': True
        })
        self.assertIn('summaries', response_dict)

        summaries = response_dict['summaries']
        self.assertEqual(len(summaries), 2)

        self.assertEqual(summaries[0]['id'], self.PUBLIC_EXP_ID_EDITOR)
        self.assertEqual(summaries[0]['status'], 'public')
        self.assertEqual(summaries[1]['id'], self.PRIVATE_EXP_ID_VIEWER)
        self.assertEqual(summaries[1]['status'], 'private')

        # If the viewer user is granted edit access to the editor user's
        # private exploration, then it will show up for the next request.
        rights_manager.assign_role_for_exploration(
            self.editor_id, self.PRIVATE_EXP_ID_EDITOR, self.viewer_id,
            rights_manager.ROLE_EDITOR)

        response_dict = self.get_json(feconf.EXPLORATION_SUMMARIES_DATA_URL, {
            'stringified_exp_ids': json.dumps([
                self.PRIVATE_EXP_ID_EDITOR, self.PUBLIC_EXP_ID_EDITOR,
                self.PRIVATE_EXP_ID_VIEWER]),
            'include_private_explorations': True
        })
        self.assertIn('summaries', response_dict)

        summaries = response_dict['summaries']
        self.assertEqual(len(summaries), 3)

        self.assertEqual(summaries[0]['id'], self.PRIVATE_EXP_ID_EDITOR)
        self.assertEqual(summaries[0]['status'], 'private')
        self.assertEqual(summaries[1]['id'], self.PUBLIC_EXP_ID_EDITOR)
        self.assertEqual(summaries[1]['status'], 'public')
        self.assertEqual(summaries[2]['id'], self.PRIVATE_EXP_ID_VIEWER)
        self.assertEqual(summaries[2]['status'], 'private')

        self.logout()
Пример #35
0
    def test_stats_for_single_exploration_with_multiple_owners(self):
        exploration = self.save_new_default_exploration(
            self.EXP_ID_1, self.owner_id_1, title=self.EXP_TITLE_1)

        rights_manager.assign_role_for_exploration(
            self.owner_1, self.EXP_ID_1, self.owner_id_2,
            rights_domain.ROLE_OWNER)

        self.login(self.OWNER_EMAIL_1)
        response = self.get_json(feconf.CREATOR_DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)

        exp_version = self.EXP_DEFAULT_VERSION
        exp_id = self.EXP_ID_1
        state = exploration.init_state_name

        self._record_start(exp_id, exp_version, state)
        self._record_start(exp_id, exp_version, state)

        self._rate_exploration(exp_id, [3, 4, 5])
        self.logout()

        self.login(self.OWNER_EMAIL_2)
        response = self.get_json(feconf.CREATOR_DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)

        self._rate_exploration(exp_id, [3, 4, 5])

        user_model_1 = user_models.UserStatsModel.get(
            self.owner_id_1)
        self.assertEqual(user_model_1.total_plays, 2)
        # TODO(#11475): Calculate impact_score with an Apache Beam job.
        self.assertIsNone(user_model_1.impact_score)
        self.assertEqual(user_model_1.num_ratings, 3)
        self.assertEqual(user_model_1.average_ratings, 4)

        user_model_2 = user_models.UserStatsModel.get(
            self.owner_id_2)
        self.assertEqual(user_model_2.total_plays, 2)
        # TODO(#11475): Calculate impact_score with an Apache Beam job.
        self.assertIsNone(user_model_2.impact_score)
        self.assertEqual(user_model_2.num_ratings, 3)
        self.assertEqual(user_model_2.average_ratings, 4)
        self.logout()
    def test_realtime_layer_batch_job_single_exploration_multiple_owners(self):
        exploration = self._create_exploration(
            self.EXP_ID_1, self.user_a_id)

        rights_manager.assign_role_for_exploration(
            self.user_a_id, self.EXP_ID_1, self.user_b_id,
            rights_manager.ROLE_OWNER)

        exp_version = self.EXP_DEFAULT_VERSION
        exp_id = self.EXP_ID_1
        state = exploration.init_state_name

        self._record_start(exp_id, exp_version, state)
        self._record_start(exp_id, exp_version, state)
        self._record_exploration_rating(exp_id, [3, 4, 5])
        self._record_exploration_rating(exp_id, [1, 5, 4])

        expected_results = {
            'total_plays': 2,
            'num_ratings': 6,
            'average_ratings': 22/6.0
        }

        user_stats_1 = (
            user_jobs_continuous.UserStatsAggregator.get_dashboard_stats(
                self.user_a_id))
        self.assertEquals(
            user_stats_1['total_plays'], expected_results['total_plays'])
        self.assertEquals(
            user_stats_1['num_ratings'], expected_results['num_ratings'])
        self.assertEquals(
            user_stats_1['average_ratings'],
            expected_results['average_ratings'])

        user_stats_2 = (
            user_jobs_continuous.UserStatsAggregator.get_dashboard_stats(
                self.user_b_id))
        self.assertEquals(
            user_stats_2['total_plays'], expected_results['total_plays'])
        self.assertEquals(
            user_stats_2['num_ratings'], expected_results['num_ratings'])
        self.assertEquals(
            user_stats_2['average_ratings'],
            expected_results['average_ratings'])
Пример #37
0
    def test_realtime_layer_batch_job_single_exploration_multiple_owners(self):
        exploration = self._create_exploration(
            self.EXP_ID_1, self.user_a_id)

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID_1, self.user_b_id,
            rights_manager.ROLE_OWNER)

        exp_version = self.EXP_DEFAULT_VERSION
        exp_id = self.EXP_ID_1
        state = exploration.init_state_name

        self._record_start(exp_id, exp_version, state)
        self._record_start(exp_id, exp_version, state)
        self._record_exploration_rating(exp_id, [3, 4, 5])
        self._record_exploration_rating(exp_id, [1, 5, 4])

        expected_results = {
            'total_plays': 2,
            'num_ratings': 6,
            'average_ratings': 22 / 6.0
        }

        user_stats_1 = (
            user_jobs_continuous.UserStatsAggregator.get_dashboard_stats(
                self.user_a_id))
        self.assertEqual(
            user_stats_1['total_plays'], expected_results['total_plays'])
        self.assertEqual(
            user_stats_1['num_ratings'], expected_results['num_ratings'])
        self.assertEqual(
            user_stats_1['average_ratings'],
            expected_results['average_ratings'])

        user_stats_2 = (
            user_jobs_continuous.UserStatsAggregator.get_dashboard_stats(
                self.user_b_id))
        self.assertEqual(
            user_stats_2['total_plays'], expected_results['total_plays'])
        self.assertEqual(
            user_stats_2['num_ratings'], expected_results['num_ratings'])
        self.assertEqual(
            user_stats_2['average_ratings'],
            expected_results['average_ratings'])
Пример #38
0
    def test_pre_delete_user_with_activities_multiple_owners(self):
        user_services.update_user_role(
            self.user_1_id, feconf.ROLE_ID_COLLECTION_EDITOR)
        user_1_actions = user_services.UserActionsInfo(self.user_1_id)
        self.save_new_valid_exploration('exp_id', self.user_1_id)
        rights_manager.assign_role_for_exploration(
            user_1_actions, 'exp_id', self.user_2_id, rights_manager.ROLE_OWNER)
        self.save_new_valid_collection(
            'col_id', self.user_1_id, exploration_id='exp_id')
        rights_manager.assign_role_for_collection(
            user_1_actions, 'col_id', self.user_2_id, rights_manager.ROLE_OWNER)

        wipeout_service.pre_delete_user(self.user_1_id)

        pending_deletion_model = (
            user_models.PendingDeletionRequestModel.get_by_id(self.user_1_id))
        self.assertEqual(
            pending_deletion_model.exploration_ids, [])
        self.assertEqual(pending_deletion_model.collection_ids, [])
Пример #39
0
    def test_viewer_cannot_see_explorations(self):
        self.save_new_default_exploration(
            self.EXP_ID, self.owner_id, title=self.EXP_TITLE)
        rights_manager.assign_role_for_exploration(
            self.owner_id, self.EXP_ID, self.viewer_id,
            rights_manager.ROLE_VIEWER)
        self.set_admins([self.OWNER_USERNAME])

        self.login(self.VIEWER_EMAIL)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(response['explorations_list'], [])

        rights_manager.publish_exploration(self.owner_id, self.EXP_ID)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(response['explorations_list'], [])

        rights_manager.publicize_exploration(self.owner_id, self.EXP_ID)
        response = self.get_json(feconf.DASHBOARD_DATA_URL)
        self.assertEqual(response['explorations_list'], [])
        self.logout()
Пример #40
0
    def test_viewer_cannot_see_explorations(self):
        self.save_new_default_exploration(self.EXP_ID,
                                          self.owner_id,
                                          title=self.EXP_TITLE)
        rights_manager.assign_role_for_exploration(self.owner_id, self.EXP_ID,
                                                   self.viewer_id,
                                                   rights_manager.ROLE_VIEWER)
        self.set_admins([self.OWNER_EMAIL])

        self.login(self.VIEWER_EMAIL)
        response = self.get_json(self.MY_EXPLORATIONS_DATA_URL)
        self.assertEqual(response['explorations_list'], [])

        rights_manager.publish_exploration(self.owner_id, self.EXP_ID)
        response = self.get_json(self.MY_EXPLORATIONS_DATA_URL)
        self.assertEqual(response['explorations_list'], [])

        rights_manager.publicize_exploration(self.owner_id, self.EXP_ID)
        response = self.get_json(self.MY_EXPLORATIONS_DATA_URL)
        self.assertEqual(response['explorations_list'], [])
        self.logout()
Пример #41
0
    def setUp(self):
        super(VoiceArtistAutosaveTest, self).setUp()
        self.login(self.OWNER_EMAIL)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
        rights_manager.assign_role_for_exploration(
            self.owner, self.EXP_ID, self.voice_artist_id,
            rights_manager.ROLE_VOICE_ARTIST)
        self.logout()

        self.login(self.VOICE_ARTIST_EMAIL)
        user_models.ExplorationUserDataModel(
            id='%s.%s' % (self.voice_artist_id, self.EXP_ID),
            user_id=self.voice_artist_id, exploration_id=self.EXP_ID,
            draft_change_list=self.VALID_DRAFT_CHANGELIST,
            draft_change_list_last_updated=self.OLDER_DATETIME,
            draft_change_list_exp_version=1,
            draft_change_list_id=1).put()

        # Generate CSRF token.
        self.csrf_token = self.get_new_csrf_token()
Пример #42
0
    def test_check_exploration_rights(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID, self.user_id_b,
            rights_manager.ROLE_VIEWER)

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID, self.user_id_c,
            rights_manager.ROLE_EDITOR)

        rights_manager.assign_role_for_exploration(
            self.user_a, self.EXP_ID, self.user_id_d,
            rights_manager.ROLE_TRANSLATOR)

        exp_rights = rights_manager.get_exploration_rights(self.EXP_ID)

        self.assertTrue(exp_rights.is_owner(self.user_id_a))
        self.assertTrue(exp_rights.is_editor(self.user_id_c))
        self.assertTrue(exp_rights.is_viewer(self.user_id_b))
        self.assertFalse(exp_rights.is_viewer(self.user_id_a))
        self.assertFalse(exp_rights.is_owner(self.user_id_b))
        self.assertFalse(exp_rights.is_editor(self.user_id_b))
        self.assertTrue(exp_rights.is_translator(self.user_id_d))
        self.assertFalse(exp_rights.is_translator(self.user_id_b))
Пример #43
0
    def test_deletion_rights_for_published_exploration(self):
        """Test rights management for deletion of published explorations."""
        PUBLISHED_EXP_ID = 'published_eid'
        exploration = exp_domain.Exploration.create_default_exploration(
            PUBLISHED_EXP_ID, 'A title', 'A category')
        exp_services.save_new_exploration(self.owner_id, exploration)

        rights_manager.assign_role_for_exploration(self.owner_id,
                                                   PUBLISHED_EXP_ID,
                                                   self.editor_id,
                                                   rights_manager.ROLE_EDITOR)
        rights_manager.publish_exploration(self.owner_id, PUBLISHED_EXP_ID)

        self.login(self.EDITOR_EMAIL)
        response = self.testapp.delete('/createhandler/data/%s' %
                                       PUBLISHED_EXP_ID,
                                       expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.VIEWER_EMAIL)
        response = self.testapp.delete('/createhandler/data/%s' %
                                       PUBLISHED_EXP_ID,
                                       expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.OWNER_EMAIL)
        response = self.testapp.delete('/createhandler/data/%s' %
                                       PUBLISHED_EXP_ID,
                                       expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.ADMIN_EMAIL)
        response = self.testapp.delete('/createhandler/data/%s' %
                                       PUBLISHED_EXP_ID)
        self.assertEqual(response.status_int, 200)
        self.logout()
Пример #44
0
    def setUp(self):
        super(TranslatorAutosaveTest, self).setUp()
        self.login(self.OWNER_EMAIL)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
        rights_manager.assign_role_for_exploration(
            self.owner, self.EXP_ID, self.translator_id,
            rights_manager.ROLE_TRANSLATOR)
        self.logout()

        self.login(self.TRANSLATOR_EMAIL)
        user_models.ExplorationUserDataModel(
            id='%s.%s' % (self.translator_id, self.EXP_ID),
            user_id=self.translator_id, exploration_id=self.EXP_ID,
            draft_change_list=self.VALID_DRAFT_CHANGELIST,
            draft_change_list_last_updated=self.OLDER_DATETIME,
            draft_change_list_exp_version=1,
            draft_change_list_id=1).put()

        # Generate CSRF token.
        response = self.testapp.get('/create/%s' % self.EXP_ID)
        self.csrf_token = self.get_csrf_token_from_response(response)
Пример #45
0
    def test_collaborators_can_see_explorations(self):
        self.save_new_default_exploration(self.EXP_ID,
                                          self.owner_id,
                                          title=self.EXP_TITLE)
        rights_manager.assign_role_for_exploration(self.owner, self.EXP_ID,
                                                   self.collaborator_id,
                                                   rights_domain.ROLE_EDITOR)
        self.set_curriculum_admins([self.OWNER_USERNAME])

        self.login(self.COLLABORATOR_EMAIL)
        response = self.get_json(feconf.CREATOR_DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)
        self.assertEqual(response['explorations_list'][0]['status'],
                         rights_domain.ACTIVITY_STATUS_PRIVATE)

        rights_manager.publish_exploration(self.owner, self.EXP_ID)
        response = self.get_json(feconf.CREATOR_DASHBOARD_DATA_URL)
        self.assertEqual(len(response['explorations_list']), 1)
        self.assertEqual(response['explorations_list'][0]['status'],
                         rights_domain.ACTIVITY_STATUS_PUBLIC)

        self.logout()
Пример #46
0
    def test_adding_new_exploration_owner_or_editor_role_results_in_subscription(
            self):
        EXP_ID = 'exp_id'
        exploration = exp_domain.Exploration.create_default_exploration(
            EXP_ID, 'Title', 'Category')
        exp_services.save_new_exploration(self.owner_id, exploration)

        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.owner_2_id), [])
        rights_manager.assign_role_for_exploration(self.owner_id, EXP_ID,
                                                   self.owner_2_id,
                                                   rights_manager.ROLE_OWNER)
        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.owner_2_id), [EXP_ID])

        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.editor_id), [])
        rights_manager.assign_role_for_exploration(self.owner_id, EXP_ID,
                                                   self.editor_id,
                                                   rights_manager.ROLE_EDITOR)
        self.assertEqual(
            self._get_exploration_ids_subscribed_to(self.editor_id), [EXP_ID])
Пример #47
0
    def test_deletion_rights_for_unpublished_exploration(self):
        """Test rights management for deletion of unpublished explorations."""
        UNPUBLISHED_EXP_ID = "unpublished_eid"
        exploration = exp_domain.Exploration.create_default_exploration(UNPUBLISHED_EXP_ID, "A title", "A category")
        exp_services.save_new_exploration(self.owner_id, exploration)

        rights_manager.assign_role_for_exploration(
            self.owner_id, UNPUBLISHED_EXP_ID, self.editor_id, rights_manager.ROLE_EDITOR
        )

        self.login(self.EDITOR_EMAIL)
        response = self.testapp.delete("/createhandler/data/%s" % UNPUBLISHED_EXP_ID, expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.VIEWER_EMAIL)
        response = self.testapp.delete("/createhandler/data/%s" % UNPUBLISHED_EXP_ID, expect_errors=True)
        self.assertEqual(response.status_int, 401)
        self.logout()

        self.login(self.OWNER_EMAIL)
        response = self.testapp.delete("/createhandler/data/%s" % UNPUBLISHED_EXP_ID)
        self.assertEqual(response.status_int, 200)
        self.logout()
Пример #48
0
    def setUp(self):
        super(SuggestionsIntegrationTests, self).setUp()

        # Register users.
        self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME)
        self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME)
        self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.editor_id = self.get_user_id_from_email(self.EDITOR_EMAIL)
        self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL)

        # Load exploration 0.
        exp_services.delete_demo(self.EXP_ID)
        exp_services.load_demo(self.EXP_ID)

        # Login and create exploration and suggestions.
        self.login(self.EDITOR_EMAIL)

        # Create exploration.
        self.save_new_valid_exploration(
            self.EXP_ID, self.editor_id,
            title='Exploration for suggestions',
            category='This is just a test category',
            objective='Test a suggestion.')

        exploration = exp_services.get_exploration_by_id(self.EXP_ID)
        init_state = exploration.states[exploration.init_state_name]
        init_interaction = init_state.interaction
        init_interaction.default_outcome.dest = exploration.init_state_name
        exploration.add_states(['State A', 'State 2', 'State 3'])
        exploration.states['State A'].update_interaction_id('TextInput')
        exploration.states['State 2'].update_interaction_id('TextInput')
        exploration.states['State 3'].update_interaction_id('TextInput')
        exp_services._save_exploration(self.editor_id, exploration, '', [])  # pylint: disable=protected-access
        rights_manager.publish_exploration(self.editor_id, self.EXP_ID)
        rights_manager.assign_role_for_exploration(
            self.editor_id, self.EXP_ID, self.owner_id,
            rights_manager.ROLE_EDITOR)

        response = self.testapp.get('/explore/%s' % self.EXP_ID)
        csrf_token = self.get_csrf_token_from_response(response)

        # Create suggestions.
        self.post_json(
            '%s/%s' % (feconf.SUGGESTION_URL_PREFIX, self.EXP_ID), {
                'exploration_version': 3,
                'state_name': u'State A',
                'description': u'Suggestion for state A.',
                'suggestion_content': {
                    'type': 'text',
                    'value': u'new accepted suggestion for state A'},
            }, csrf_token)
        self.post_json(
            '%s/%s' % (feconf.SUGGESTION_URL_PREFIX, self.EXP_ID), {
                'exploration_version': 1,
                'state_name': u'State 2',
                'description': u'A new value.',
                'suggestion_content': {
                    'type': 'text', 'value': 'some new value'},
            }, csrf_token)
        self.post_json(
            '%s/%s' % (feconf.SUGGESTION_URL_PREFIX, self.EXP_ID), {
                'exploration_version': 2,
                'state_name': u'State 3',
                'description': u'Empty suggestion',
                'suggestion_content': {'type': 'text', 'value': ''},
            }, csrf_token)
        self.post_json(
            '%s/%s' % (feconf.SUGGESTION_URL_PREFIX, self.EXP_ID), {
                'exploration_version': 2,
                'state_name': u'State A',
                'description': u'Just a space.',
                'suggestion_content': {'type': 'text', 'value': ' '},
            }, csrf_token)
        self.post_json(
            '%s/%s' % (feconf.SUGGESTION_URL_PREFIX, self.EXP_ID), {
                'exploration_version': 1,
                'state_name': u'State 2',
                'description': u'Random characters.',
                'suggestion_content': {'type': 'text', 'value': '#!$%'},
            }, csrf_token)
        self.post_json(
            '%s/%s' % (feconf.SUGGESTION_URL_PREFIX, self.EXP_ID), {
                'exploration_version': 2,
                'state_name': u'State 3',
                'description': u'Very bizarre characters.',
                'suggestion_content': {'type': 'text', 'value': u'Ֆݓॵক'},
            }, csrf_token)
        self.logout()
Пример #49
0
    def test_correct_email_is_sent_for_multiple_recipients(self):
        rights_manager.assign_role_for_exploration(
            self.editor_id, self.exploration.id, self.owner_id,
            rights_manager.ROLE_OWNER)

        expected_editor_email_html_body = (
            'Hi editor,<br>'
            'newuser has submitted a new suggestion for your Oppia '
            'exploration, '
            '<a href="https://www.oppia.org/create/A">"Title"</a>.<br>'
            'You can accept or reject this suggestion by visiting the '
            '<a href="https://www.oppia.org/create/A#/feedback">'
            'feedback page</a> '
            'for your exploration.<br>'
            '<br>'
            'Thanks!<br>'
            '- The Oppia Team<br>'
            '<br>'
            'You can change your email preferences via the '
            '<a href="https://www.example.com">Preferences</a> page.')

        expected_owner_email_html_body = (
            'Hi owner,<br>'
            'newuser has submitted a new suggestion for your Oppia '
            'exploration, '
            '<a href="https://www.oppia.org/create/A">"Title"</a>.<br>'
            'You can accept or reject this suggestion by visiting the '
            '<a href="https://www.oppia.org/create/A#/feedback">'
            'feedback page</a> '
            'for your exploration.<br>'
            '<br>'
            'Thanks!<br>'
            '- The Oppia Team<br>'
            '<br>'
            'You can change your email preferences via the '
            '<a href="https://www.example.com">Preferences</a> page.')

        expected_editor_email_text_body = (
            'Hi editor,\n'
            'newuser has submitted a new suggestion for your Oppia '
            'exploration, "Title".\n'
            'You can accept or reject this suggestion by visiting the '
            'feedback page for your exploration.\n'
            '\n'
            'Thanks!\n'
            '- The Oppia Team\n'
            '\n'
            'You can change your email preferences via the Preferences page.')

        expected_owner_email_text_body = (
            'Hi owner,\n'
            'newuser has submitted a new suggestion for your Oppia '
            'exploration, "Title".\n'
            'You can accept or reject this suggestion by visiting the '
            'feedback page for your exploration.\n'
            '\n'
            'Thanks!\n'
            '- The Oppia Team\n'
            '\n'
            'You can change your email preferences via the Preferences page.')

        with self.can_send_emails_ctx, self.can_send_feedback_email_ctx:
            feedback_services.create_suggestion(
                self.exploration.id, self.new_user_id, self.exploration.version,
                'a state', 'simple description', {'content': {}})

            self.process_and_flush_pending_tasks()

            editor_messages = (
                self.mail_stub.get_sent_messages(to=self.EDITOR_EMAIL))
            self.assertEqual(len(editor_messages), 1)
            self.assertEqual(
                editor_messages[0].html.decode(),
                expected_editor_email_html_body)
            self.assertEqual(
                editor_messages[0].body.decode(),
                expected_editor_email_text_body)

            owner_messages = (
                self.mail_stub.get_sent_messages(to=self.OWNER_EMAIL))
            self.assertEqual(len(owner_messages), 1)
            self.assertEqual(
                owner_messages[0].html.decode(),
                expected_owner_email_html_body)
            self.assertEqual(
                owner_messages[0].body.decode(),
                expected_owner_email_text_body)
Пример #50
0
    def put(self, exploration_id):
        """Updates the editing rights for the given exploration."""
        exploration = exp_services.get_exploration_by_id(exploration_id)
        version = self.payload.get('version')
        _require_valid_version(version, exploration.version)

        is_public = self.payload.get('is_public')
        is_publicized = self.payload.get('is_publicized')
        is_community_owned = self.payload.get('is_community_owned')
        new_member_username = self.payload.get('new_member_username')
        new_member_role = self.payload.get('new_member_role')
        viewable_if_private = self.payload.get('viewable_if_private')

        if new_member_username:
            if not rights_manager.Actor(
                    self.user_id).can_modify_roles(
                        rights_manager.ACTIVITY_TYPE_EXPLORATION,
                        exploration_id):
                raise self.UnauthorizedUserException(
                    'Only an owner of this exploration can add or change '
                    'roles.')

            new_member_id = user_services.get_user_id_from_username(
                new_member_username)
            if new_member_id is None:
                raise Exception(
                    'Sorry, we could not find the specified user.')

            rights_manager.assign_role_for_exploration(
                self.user_id, exploration_id, new_member_id, new_member_role)

        elif is_public is not None:
            exploration = exp_services.get_exploration_by_id(exploration_id)
            if is_public:
                try:
                    exploration.validate(strict=True)
                except utils.ValidationError as e:
                    raise self.InvalidInputException(e)

                exp_services.publish_exploration_and_update_user_profiles(
                    self.user_id, exploration_id)
                exp_services.index_explorations_given_ids([exploration_id])
            else:
                rights_manager.unpublish_exploration(
                    self.user_id, exploration_id)
                exp_services.delete_documents_from_search_index([
                    exploration_id])

        elif is_publicized is not None:
            exploration = exp_services.get_exploration_by_id(exploration_id)
            if is_publicized:
                try:
                    exploration.validate(strict=True)
                except utils.ValidationError as e:
                    raise self.InvalidInputException(e)

                rights_manager.publicize_exploration(
                    self.user_id, exploration_id)
            else:
                rights_manager.unpublicize_exploration(
                    self.user_id, exploration_id)

        elif is_community_owned:
            exploration = exp_services.get_exploration_by_id(exploration_id)
            try:
                exploration.validate(strict=True)
            except utils.ValidationError as e:
                raise self.InvalidInputException(e)

            rights_manager.release_ownership_of_exploration(
                self.user_id, exploration_id)

        elif viewable_if_private is not None:
            rights_manager.set_private_viewability_of_exploration(
                self.user_id, exploration_id, viewable_if_private)

        else:
            raise self.InvalidInputException(
                'No change was made to this exploration.')

        self.render_json({
            'rights': rights_manager.get_exploration_rights(
                exploration_id).to_dict()
        })
Пример #51
0
    def test_setting_rights_of_exploration(self):
        exp = exp_domain.Exploration.create_default_exploration(self.EXP_ID)
        exp_services.save_new_exploration(self.user_id_a, exp)

        rights_manager.assign_role_for_exploration(
            self.user_id_a, self.EXP_ID, self.user_id_b,
            rights_manager.ROLE_VIEWER)

        with self.assertRaisesRegexp(Exception, 'Could not assign new role.'):
            rights_manager.assign_role_for_exploration(
                self.user_id_b, self.EXP_ID, self.user_id_c,
                rights_manager.ROLE_VIEWER)

        rights_manager.assign_role_for_exploration(
            self.user_id_a, self.EXP_ID, self.user_id_b,
            rights_manager.ROLE_EDITOR)

        with self.assertRaisesRegexp(Exception, 'Could not assign new role.'):
            rights_manager.assign_role_for_exploration(
                self.user_id_b, self.EXP_ID, self.user_id_c,
                rights_manager.ROLE_VIEWER)

        rights_manager.assign_role_for_exploration(
            self.user_id_a, self.EXP_ID, self.user_id_b,
            rights_manager.ROLE_OWNER)

        rights_manager.assign_role_for_exploration(
            self.user_id_b, self.EXP_ID, self.user_id_c,
            rights_manager.ROLE_OWNER)
        rights_manager.assign_role_for_exploration(
            self.user_id_b, self.EXP_ID, self.user_id_d,
            rights_manager.ROLE_EDITOR)
        rights_manager.assign_role_for_exploration(
            self.user_id_b, self.EXP_ID, self.user_id_e,
            rights_manager.ROLE_VIEWER)
Пример #52
0
    def test_subscribing_to_exploration_subscribes_to_its_feedback_threads(self):
        with self.swap(
                jobs_registry, 'ALL_CONTINUOUS_COMPUTATION_MANAGERS',
                self.ALL_CONTINUOUS_COMPUTATION_MANAGERS_FOR_TESTS):
            EXP_ID = 'eid'
            EXP_TITLE = 'Title'
            FEEDBACK_THREAD_SUBJECT = 'feedback thread subject'

            USER_A_EMAIL = '*****@*****.**'
            USER_A_USERNAME = '******'
            self.signup(USER_A_EMAIL, USER_A_USERNAME)
            user_a_id = self.get_user_id_from_email(USER_A_EMAIL)

            USER_B_EMAIL = '*****@*****.**'
            USER_B_USERNAME = '******'
            self.signup(USER_B_EMAIL, USER_B_USERNAME)
            user_b_id = self.get_user_id_from_email(USER_B_EMAIL)

            # User A creates an exploration.
            self.save_new_valid_exploration(
                EXP_ID, user_a_id, title=EXP_TITLE, category='Category')
            exp_last_updated_ms = (
                self._get_most_recent_exp_snapshot_created_on_ms(EXP_ID))

            # User B starts a feedback thread.
            feedback_services.create_thread(
                EXP_ID, None, user_b_id, FEEDBACK_THREAD_SUBJECT, 'text')
            thread_id = (
                feedback_services.get_threadlist(EXP_ID)[0]['thread_id'])
            message = feedback_services.get_messages(thread_id)[0]

            # User A adds user B as an editor of the exploration.
            rights_manager.assign_role_for_exploration(
                user_a_id, EXP_ID, user_b_id, rights_manager.ROLE_EDITOR)

            ModifiedRecentUpdatesAggregator.start_computation()
            self.assertEqual(
                self.count_jobs_in_taskqueue(
                    queue_name=taskqueue_services.QUEUE_NAME_DEFAULT),
                1)
            self.process_and_flush_pending_tasks()

            recent_notifications_for_user_a = (
                ModifiedRecentUpdatesAggregator.get_recent_notifications(
                    user_a_id)[1])
            recent_notifications_for_user_b = (
                ModifiedRecentUpdatesAggregator.get_recent_notifications(
                    user_b_id)[1])
            expected_feedback_thread_notification_dict = {
                'activity_id': EXP_ID,
                'activity_title': EXP_TITLE,
                'author_id': user_b_id,
                'last_updated_ms': message['created_on'],
                'subject': FEEDBACK_THREAD_SUBJECT,
                'type': feconf.UPDATE_TYPE_FEEDBACK_MESSAGE,
            }
            expected_exploration_created_notification_dict = (
                self._get_expected_activity_created_dict(
                    user_a_id, EXP_ID, EXP_TITLE, 'exploration',
                    feconf.UPDATE_TYPE_EXPLORATION_COMMIT,
                    exp_last_updated_ms))

            # User A sees A's commit and B's feedback thread.
            self.assertEqual(recent_notifications_for_user_a, [
                expected_feedback_thread_notification_dict,
                expected_exploration_created_notification_dict
            ])
            # User B sees A's commit and B's feedback thread.
            self.assertEqual(recent_notifications_for_user_b, [
                expected_feedback_thread_notification_dict,
                expected_exploration_created_notification_dict,
            ])
Пример #53
0
    def test_subscribing_to_exploration_subscribes_to_its_feedback_threads(
            self):
        with self._get_test_context():
            self.signup(USER_A_EMAIL, USER_A_USERNAME)
            user_a_id = self.get_user_id_from_email(USER_A_EMAIL)
            self.signup(USER_B_EMAIL, USER_B_USERNAME)
            user_b_id = self.get_user_id_from_email(USER_B_EMAIL)

            # User A creates an exploration.
            self.save_new_valid_exploration(
                EXP_ID, user_a_id, title=EXP_TITLE, category='Category')
            exp_last_updated_ms = (
                self._get_most_recent_exp_snapshot_created_on_ms(EXP_ID))

            # User B starts a feedback thread.
            feedback_services.create_thread(
                EXP_ID, None, user_b_id, FEEDBACK_THREAD_SUBJECT, 'text')
            thread_id = feedback_services.get_all_threads(
                EXP_ID, False)[0].get_thread_id()
            message = feedback_services.get_messages(
                EXP_ID, thread_id)[0]

            # User A adds user B as an editor of the exploration.
            rights_manager.assign_role_for_exploration(
                user_a_id, EXP_ID, user_b_id, rights_manager.ROLE_EDITOR)

            ModifiedRecentUpdatesAggregator.start_computation()
            self.assertEqual(
                self.count_jobs_in_taskqueue(
                    queue_name=taskqueue_services.QUEUE_NAME_DEFAULT),
                1)
            self.process_and_flush_pending_tasks()

            recent_notifications_for_user_a = (
                ModifiedRecentUpdatesAggregator.get_recent_notifications(
                    user_a_id)[1])
            recent_notifications_for_user_b = (
                ModifiedRecentUpdatesAggregator.get_recent_notifications(
                    user_b_id)[1])
            expected_thread_notification = {
                'activity_id': EXP_ID,
                'activity_title': EXP_TITLE,
                'author_id': user_b_id,
                'last_updated_ms': utils.get_time_in_millisecs(
                    message.created_on),
                'subject': FEEDBACK_THREAD_SUBJECT,
                'type': feconf.UPDATE_TYPE_FEEDBACK_MESSAGE,
            }
            expected_creation_notification = (
                self._get_expected_activity_created_dict(
                    user_a_id, EXP_ID, EXP_TITLE, 'exploration',
                    feconf.UPDATE_TYPE_EXPLORATION_COMMIT,
                    exp_last_updated_ms))

            # User A sees A's commit and B's feedback thread.
            self.assertEqual(recent_notifications_for_user_a, [
                expected_thread_notification,
                expected_creation_notification
            ])
            # User B sees A's commit and B's feedback thread.
            self.assertEqual(recent_notifications_for_user_b, [
                expected_thread_notification,
                expected_creation_notification,
            ])