예제 #1
0
 def test_get_by_reviewer(self):
     queries = [('final_reviewer_id', self.reviewer_id_1)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      1)
     queries = [('final_reviewer_id', self.reviewer_id_2)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      2)
예제 #2
0
 def test_get_by_author(self):
     queries = [('author_id', self.author_id_1)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      3)
     queries = [('author_id', self.author_id_2)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      2)
예제 #3
0
 def test_get_by_target_id(self):
     queries = [('target_type', suggestion_models.TARGET_TYPE_EXPLORATION),
                ('target_id', self.target_id_1)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      4)
     queries = [('target_type', suggestion_models.TARGET_TYPE_EXPLORATION),
                ('target_id', self.target_id_2)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      1)
예제 #4
0
    def test_accept_suggestion_and_send_email_to_author(self):
        enable_recording_of_scores_swap = self.swap(
            feconf, 'ENABLE_RECORDING_OF_SCORES', True)
        send_suggestion_review_related_emails_swap = self.swap(
            feconf, 'SEND_SUGGESTION_REVIEW_RELATED_EMAILS', True)

        change_list = [
            exp_domain.ExplorationChange({
                'cmd': exp_domain.CMD_ADD_STATE,
                'state_name': 'state 1',
            })
        ]
        exp_services.update_exploration(self.author_id, self.target_id,
                                        change_list, 'Add state.')

        new_suggestion_content = state_domain.SubtitledHtml(
            'content', 'new suggestion content html').to_dict()
        change_dict = {
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'property_name': exp_domain.STATE_PROPERTY_CONTENT,
            'state_name': 'state 1',
            'new_value': new_suggestion_content
        }

        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, self.target_id,
            self.target_version_at_submission, self.author_id, change_dict,
            'test description', self.reviewer_id)

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.target_id)
        ])[0]
        self.assertEqual(suggestion.status, suggestion_models.STATUS_IN_REVIEW)
        self.assertFalse(
            suggestion_services.check_if_email_has_been_sent_to_user(
                self.author_id, suggestion.score_category))

        suggestion_services.increment_score_for_user(self.author_id,
                                                     suggestion.score_category,
                                                     10)

        with enable_recording_of_scores_swap, (
                send_suggestion_review_related_emails_swap):
            suggestion_services.accept_suggestion(suggestion, self.reviewer_id,
                                                  self.COMMIT_MESSAGE,
                                                  'review message')

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.target_id)
        ])[0]
        self.assertEqual(suggestion.status, suggestion_models.STATUS_ACCEPTED)
        self.assertTrue(
            suggestion_services.check_if_email_has_been_sent_to_user(
                self.author_id, suggestion.score_category))
예제 #5
0
    def test_post_feedback_threads_with_updated_suggestion_status_raises_400(
            self):
        self.login(self.OWNER_EMAIL_1)
        csrf_token = self.get_new_csrf_token()

        new_content = state_domain.SubtitledHtml(
            'content', '<p>new content html</p>').to_dict()
        change = {
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'property_name': exp_domain.STATE_PROPERTY_CONTENT,
            'state_name': 'Welcome!',
            'new_value': new_content
        }
        suggestion_services.create_suggestion(
            feconf.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            feconf.ENTITY_TYPE_EXPLORATION, self.EXP_ID, 1,
            self.owner_id_1, change, 'sample description')

        thread_id = suggestion_services.query_suggestions(
            [('author_id', self.owner_id_1),
             ('target_id', self.EXP_ID)])[0].suggestion_id

        thread_url = '%s/%s' % (feconf.FEEDBACK_THREAD_URL_PREFIX, thread_id)
        response = self.post_json(
            thread_url, {
                'text': 'Message 1',
                'updated_subject': None,
                'updated_status': 'open'
            }, csrf_token=csrf_token, expected_status_int=400)

        self.assertEqual(
            response['error'],
            'Suggestion thread status cannot be changed manually.')

        self.logout()
예제 #6
0
    def test_resubmit_rejected_suggestion(self):

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

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.EXP_ID)
        ])[0]
        suggestion_services.reject_suggestion(suggestion, self.reviewer_id,
                                              'reject message')
        self.logout()

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

        self.put_json(
            '%s/resubmit/%s' %
            (feconf.SUGGESTION_ACTION_URL_PREFIX, suggestion.suggestion_id), {
                'summary_message': 'summary message',
                'action': u'resubmit',
                'change': {
                    'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
                    'property_name': exp_domain.STATE_PROPERTY_CONTENT,
                    'state_name': 'State 1',
                    'new_value': self.resubmit_change_content,
                    'old_value': self.old_content
                }
            },
            csrf_token=csrf_token)

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.EXP_ID)
        ])[0]
        self.assertEqual(suggestion.status, suggestion_models.STATUS_IN_REVIEW)
        self.assertEqual(suggestion.change.new_value['html'],
                         self.resubmit_change_content['html'])
        self.assertEqual(suggestion.change.cmd,
                         exp_domain.CMD_EDIT_STATE_PROPERTY)
        self.assertEqual(suggestion.change.property_name,
                         exp_domain.STATE_PROPERTY_CONTENT)
        self.assertEqual(suggestion.change.state_name, 'State 1')
        self.logout()
예제 #7
0
    def test_query_suggestions(self):
        queries = [('target_type', suggestion_models.TARGET_TYPE_EXPLORATION),
                   ('target_id', self.target_id_1),
                   ('author_id', self.author_id_2)]
        self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                         1)

        queries = [('target_type', suggestion_models.TARGET_TYPE_EXPLORATION),
                   ('target_id', self.target_id_1),
                   ('author_id', self.author_id_1),
                   ('status', suggestion_models.STATUS_IN_REVIEW)]
        self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                         3)

        queries = [('target_type', suggestion_models.TARGET_TYPE_EXPLORATION),
                   ('target_id', self.target_id_1), ('invalid_field', 'value')]
        with self.assertRaisesRegexp(
                Exception, 'Not allowed to query on field invalid_field'):
            suggestion_services.query_suggestions(queries)
예제 #8
0
파일: cron.py 프로젝트: wdempsey96/oppia
 def get(self):
     """Handles get requests."""
     if feconf.SEND_SUGGESTION_REVIEW_RELATED_EMAILS:
         score_categories = suggestion_models.get_all_score_categories()
         for score_category in score_categories:
             suggestions = suggestion_services.query_suggestions(
                 [('score_category', score_category),
                  ('status', suggestion_models.STATUS_ACCEPTED)])
             if len(suggestions) > 0:
                 reviewer_id = suggestion_services.get_next_user_in_rotation(
                     score_category)
                 email_manager.send_mail_to_notify_users_to_review(
                     reviewer_id, score_category)
예제 #9
0
    def test_email_is_not_sent_to_unregistered_user(self):
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, self.target_id,
            self.target_version_at_submission, self.author_id, self.change,
            'test description', self.reviewer_id)

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.target_id)
        ])[0]

        self.assertFalse(
            suggestion_services.check_if_email_has_been_sent_to_user(
                'unregistered_user_id', suggestion.score_category))
예제 #10
0
    def test_cannot_reject_suggestion_with_empty_review_message(self):
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, self.target_id,
            self.target_version_at_submission, self.author_id, self.change,
            'test description', self.reviewer_id)

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.target_id)
        ])[0]

        with self.assertRaisesRegexp(Exception,
                                     'Review message cannot be empty.'):
            suggestion_services.reject_suggestion(suggestion, self.reviewer_id,
                                                  '')
예제 #11
0
    def test_cannot_mark_review_completed_with_invalid_status(self):
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION,
            self.target_id, self.target_version_at_submission,
            self.author_id, self.change, 'test description',
            self.reviewer_id)

        suggestion = suggestion_services.query_suggestions(
            [('author_id', self.author_id), (
                'target_id', self.target_id)])[0]

        with self.assertRaisesRegexp(Exception, 'Invalid status after review.'):
            suggestion_services.mark_review_completed(
                suggestion, 'invalid_status', self.reviewer_id)
예제 #12
0
    def test_cannot_mark_email_has_been_sent_to_user_with_no_user_scoring_model(
            self):
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, self.target_id,
            self.target_version_at_submission, self.author_id, self.change,
            'test description', self.reviewer_id)

        suggestion = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', self.target_id)
        ])[0]

        with self.assertRaisesRegexp(
                Exception, 'Expected user scoring model to exist for user'):
            suggestion_services.mark_email_has_been_sent_to_user(
                'unregistered_user_id', suggestion.score_category)
예제 #13
0
    def test_suggestion_to_exploration_handler_with_invalid_target_type(self):
        self.login(self.EDITOR_EMAIL)

        question_dict = {
            'question_state_data':
            self._create_valid_question_data('default_state').to_dict(),
            'language_code':
            'en',
            'question_state_data_schema_version':
            (feconf.CURRENT_STATE_SCHEMA_VERSION)
        }

        exp_id = 'new_exp_id'
        self.save_new_default_exploration(exp_id, self.editor_id)

        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_ADD_QUESTION,
            suggestion_models.TARGET_TYPE_TOPIC, exp_id, 1, self.author_id, {
                'cmd':
                (question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION),
                'question_dict': question_dict,
                'skill_id': None
            }, None, None)

        suggestion_id = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', exp_id)
        ])[0].suggestion_id

        response = self.get_html_response('/explore/%s' % exp_id)
        csrf_token = self.get_csrf_token_from_response(response)

        response = self.put_json(
            '%s/exploration/%s/%s' %
            (feconf.SUGGESTION_ACTION_URL_PREFIX, exp_id, suggestion_id), {
                'action': u'reject',
                'review_message': u'Rejected!'
            },
            csrf_token=csrf_token,
            expected_status_int=400)

        self.assertEqual(
            response['error'],
            'This handler allows actions only on suggestions to explorations.')

        self.logout()
예제 #14
0
    def get(self):
        # The query_fields_and_values variable is a list of tuples. The first
        # element in each tuple is the field being queried and the second
        # element is the value of the field being queried.
        # request.GET.items() parses the params from the url into the above
        # format. So in the url, the query should be passed as:
        # ?field1=value1&field2=value2...fieldN=valueN.
        query_fields_and_values = self.request.GET.items()

        for query in query_fields_and_values:
            if query[0] not in suggestion_models.ALLOWED_QUERY_FIELDS:
                raise Exception('Not allowed to query on field %s' % query[0])

        suggestions = suggestion_services.query_suggestions(
            query_fields_and_values)

        self.values.update({'suggestions': [s.to_dict() for s in suggestions]})
        self.render_json(self.values)
예제 #15
0
    def test_suggestion_to_topic_handler_with_invalid_target_type(self):
        self.login(self.ADMIN_EMAIL)

        exp_id = 'new_exp_id'
        self.save_new_default_exploration(exp_id, self.admin_id)

        new_content = state_domain.SubtitledHtml('content',
                                                 'new content html').to_dict()
        change_cmd = {
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'property_name': exp_domain.STATE_PROPERTY_CONTENT,
            'state_name': 'State 1',
            'new_value': new_content
        }
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, exp_id, 1,
            self.author_id, change_cmd, 'sample description', None)

        suggestion_id = suggestion_services.query_suggestions([
            ('author_id', self.author_id), ('target_id', exp_id)
        ])[0].suggestion_id

        response = self.get_html_response(feconf.CREATOR_DASHBOARD_URL)
        csrf_token = self.get_csrf_token_from_response(response)

        with self.swap(constants, 'ENABLE_NEW_STRUCTURE_PLAYERS', True):
            response = self.put_json('%s/topic/%s/%s' %
                                     (feconf.SUGGESTION_ACTION_URL_PREFIX,
                                      self.topic_id, suggestion_id), {
                                          'action': u'reject',
                                          'review_message': u'Rejected!'
                                      },
                                     csrf_token=csrf_token,
                                     expected_status_int=400)

        self.assertEqual(
            response['error'],
            'This handler allows actions only on suggestions to topics.')

        self.logout()
예제 #16
0
    def test_owner_of_exploration_cannot_repond_to_own_suggestion(self):
        self.login(self.EDITOR_EMAIL)

        exp_id = 'new_exp_id'
        self.save_new_default_exploration(exp_id, self.editor_id)

        new_content = state_domain.SubtitledHtml('content',
                                                 'new content html').to_dict()
        change_cmd = {
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'property_name': exp_domain.STATE_PROPERTY_CONTENT,
            'state_name': 'State 1',
            'new_value': new_content
        }
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, exp_id, 1,
            self.editor_id, change_cmd, 'sample description', None)

        suggestion_id = suggestion_services.query_suggestions([
            ('author_id', self.editor_id), ('target_id', exp_id)
        ])[0].suggestion_id

        response = self.get_html_response('/explore/%s' % exp_id)
        csrf_token = self.get_csrf_token_from_response(response)

        response = self.put_json(
            '%s/exploration/%s/%s' %
            (feconf.SUGGESTION_ACTION_URL_PREFIX, exp_id, suggestion_id), {
                'action': u'reject',
                'review_message': u'Rejected!'
            },
            csrf_token=csrf_token,
            expected_status_int=401)

        self.assertEqual(response['error'],
                         'You cannot accept/reject your own suggestion.')

        self.logout()
예제 #17
0
    def get(self):
        """Handles GET requests."""
        def _round_average_ratings(rating):
            """Returns the rounded average rating to display on the creator
            dashboard.

            Args:
                rating: float. The rating of the lesson.

            Returns:
                float. The rounded average value of rating.
            """
            return python_utils.ROUND(
                rating, feconf.AVERAGE_RATINGS_DASHBOARD_PRECISION)

        subscribed_exploration_summaries = (
            exp_fetchers.get_exploration_summaries_subscribed_to(self.user_id))
        subscribed_collection_summaries = (
            collection_services.get_collection_summaries_subscribed_to(
                self.user_id))

        exploration_ids_subscribed_to = [
            summary.id for summary in subscribed_exploration_summaries
        ]

        exp_summary_dicts = summary_services.get_displayable_exp_summary_dicts(
            subscribed_exploration_summaries)
        collection_summary_dicts = []

        feedback_thread_analytics = (
            feedback_services.get_thread_analytics_multi(
                exploration_ids_subscribed_to))

        # TODO(bhenning): Update this to use unresolved answers from
        # stats_services once the training interface is enabled and it's cheaper
        # to retrieve top answers from stats_services.
        for ind, exploration in enumerate(exp_summary_dicts):
            exploration.update(feedback_thread_analytics[ind].to_dict())

        exp_summary_dicts = sorted(
            exp_summary_dicts,
            key=lambda x: (x['num_open_threads'], x['last_updated_msec']),
            reverse=True)

        if constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            topic_summaries = topic_services.get_all_topic_summaries()
            topic_summary_dicts = [
                summary.to_dict() for summary in topic_summaries
            ]

        if role_services.ACTION_CREATE_COLLECTION in self.user.actions:
            for collection_summary in subscribed_collection_summaries:
                # TODO(sll): Reuse _get_displayable_collection_summary_dicts()
                # in summary_services, instead of replicating it like this.
                collection_summary_dicts.append({
                    'id':
                    collection_summary.id,
                    'title':
                    collection_summary.title,
                    'category':
                    collection_summary.category,
                    'objective':
                    collection_summary.objective,
                    'language_code':
                    collection_summary.language_code,
                    'last_updated_msec':
                    utils.get_time_in_millisecs(
                        collection_summary.collection_model_last_updated),
                    'created_on':
                    utils.get_time_in_millisecs(
                        collection_summary.collection_model_created_on),
                    'status':
                    collection_summary.status,
                    'node_count':
                    collection_summary.node_count,
                    'community_owned':
                    collection_summary.community_owned,
                    'thumbnail_icon_url':
                    (utils.get_thumbnail_icon_url_for_category(
                        collection_summary.category)),
                    'thumbnail_bg_color':
                    utils.get_hex_color_for_category(
                        collection_summary.category),
                })

        dashboard_stats = (
            user_jobs_continuous.UserStatsAggregator.get_dashboard_stats(
                self.user_id))
        dashboard_stats.update({
            'total_open_feedback':
            feedback_services.get_total_open_threads(feedback_thread_analytics)
        })
        if dashboard_stats and dashboard_stats.get('average_ratings'):
            dashboard_stats['average_ratings'] = (_round_average_ratings(
                dashboard_stats['average_ratings']))

        last_week_stats = (user_services.get_last_week_dashboard_stats(
            self.user_id))

        if last_week_stats and len(list(last_week_stats.keys())) != 1:
            logging.error(
                '\'last_week_stats\' should contain only one key-value pair'
                ' denoting last week dashboard stats of the user keyed by a'
                ' datetime string.')
            last_week_stats = None

        if last_week_stats:
            # 'last_week_stats' is a dict with only one key-value pair denoting
            # last week dashboard stats of the user keyed by a datetime string.
            datetime_of_stats = list(last_week_stats.keys())[0]
            last_week_stats_average_ratings = (list(
                last_week_stats.values())[0].get('average_ratings'))
            if last_week_stats_average_ratings:
                last_week_stats[datetime_of_stats]['average_ratings'] = (
                    _round_average_ratings(last_week_stats_average_ratings))

        subscriber_ids = subscription_services.get_all_subscribers_of_creator(
            self.user_id)
        subscribers_settings = user_services.get_users_settings(subscriber_ids)
        subscribers_list = []
        for index, subscriber_settings in enumerate(subscribers_settings):
            subscriber_summary = {
                'subscriber_picture_data_url':
                (subscriber_settings.profile_picture_data_url),
                'subscriber_username':
                subscriber_settings.username,
                'subscriber_impact':
                (user_services.get_user_impact_score(subscriber_ids[index]))
            }

            subscribers_list.append(subscriber_summary)

        user_settings = user_services.get_user_settings(self.user_id,
                                                        strict=False)
        creator_dashboard_display_pref = (
            user_settings.creator_dashboard_display_pref)

        suggestions_created_by_user = suggestion_services.query_suggestions([
            ('author_id', self.user_id),
            ('suggestion_type',
             suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT)
        ])
        suggestions_which_can_be_reviewed = (
            suggestion_services.
            get_all_suggestions_that_can_be_reviewed_by_user(self.user_id))

        for s in suggestions_created_by_user:
            s.populate_old_value_of_change()

        for s in suggestions_which_can_be_reviewed:
            s.populate_old_value_of_change()

        suggestion_dicts_created_by_user = ([
            s.to_dict() for s in suggestions_created_by_user
        ])
        suggestion_dicts_which_can_be_reviewed = ([
            s.to_dict() for s in suggestions_which_can_be_reviewed
        ])

        ids_of_suggestions_created_by_user = ([
            s['suggestion_id'] for s in suggestion_dicts_created_by_user
        ])
        ids_of_suggestions_which_can_be_reviewed = ([
            s['suggestion_id'] for s in suggestion_dicts_which_can_be_reviewed
        ])

        threads_linked_to_suggestions_by_user = ([
            t.to_dict() for t in feedback_services.get_multiple_threads(
                ids_of_suggestions_created_by_user)
        ])
        threads_linked_to_suggestions_which_can_be_reviewed = ([
            t.to_dict() for t in feedback_services.get_multiple_threads(
                ids_of_suggestions_which_can_be_reviewed)
        ])

        self.values.update({
            'explorations_list':
            exp_summary_dicts,
            'collections_list':
            collection_summary_dicts,
            'dashboard_stats':
            dashboard_stats,
            'last_week_stats':
            last_week_stats,
            'subscribers_list':
            subscribers_list,
            'display_preference':
            creator_dashboard_display_pref,
            'threads_for_created_suggestions_list':
            (threads_linked_to_suggestions_by_user),
            'threads_for_suggestions_to_review_list':
            (threads_linked_to_suggestions_which_can_be_reviewed),
            'created_suggestions_list':
            suggestion_dicts_created_by_user,
            'suggestions_to_review_list':
            suggestion_dicts_which_can_be_reviewed
        })
        if constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            self.values.update({'topic_summary_dicts': topic_summary_dicts})
        self.render_json(self.values)
예제 #18
0
 def test_get_by_type(self):
     queries = [('suggestion_type',
                 suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      5)
예제 #19
0
 def test_get_by_status(self):
     queries = [('status', suggestion_models.STATUS_IN_REVIEW)]
     self.assertEqual(len(suggestion_services.query_suggestions(queries)),
                      5)
예제 #20
0
    def get(self):
        """Handles GET requests."""

        def _get_intro_card_color(category):
            return (
                constants.CATEGORIES_TO_COLORS[category] if
                category in constants.CATEGORIES_TO_COLORS else
                constants.DEFAULT_COLOR)

        def _round_average_ratings(rating):
            return round(rating, feconf.AVERAGE_RATINGS_DASHBOARD_PRECISION)

        # We need to do the filtering because some activities that were
        # originally subscribed to may have been deleted since.
        subscribed_exploration_summaries = [
            summary for summary in
            exp_services.get_exploration_summaries_matching_ids(
                subscription_services.get_exploration_ids_subscribed_to(
                    self.user_id))
            if summary is not None]
        subscribed_collection_summaries = [
            summary for summary in
            collection_services.get_collection_summaries_matching_ids(
                subscription_services.get_collection_ids_subscribed_to(
                    self.user_id))
            if summary is not None]

        exploration_ids_subscribed_to = [
            summary.id for summary in subscribed_exploration_summaries]

        exp_summary_dicts = summary_services.get_displayable_exp_summary_dicts(
            subscribed_exploration_summaries)
        collection_summary_dicts = []

        feedback_thread_analytics = (
            feedback_services.get_thread_analytics_multi(
                exploration_ids_subscribed_to))

        # TODO(bhenning): Update this to use unresolved answers from
        # stats_services once the training interface is enabled and it's cheaper
        # to retrieve top answers from stats_services.
        for ind, exploration in enumerate(exp_summary_dicts):
            exploration.update(feedback_thread_analytics[ind].to_dict())

        exp_summary_dicts = sorted(
            exp_summary_dicts,
            key=lambda x: (x['num_open_threads'], x['last_updated_msec']),
            reverse=True)

        if constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            topic_summaries = topic_services.get_all_topic_summaries()
            topic_summary_dicts = [
                summary.to_dict() for summary in topic_summaries]

        if role_services.ACTION_CREATE_COLLECTION in self.user.actions:
            for collection_summary in subscribed_collection_summaries:
                # TODO(sll): Reuse _get_displayable_collection_summary_dicts()
                # in summary_services, instead of replicating it like this.
                collection_summary_dicts.append({
                    'id': collection_summary.id,
                    'title': collection_summary.title,
                    'category': collection_summary.category,
                    'objective': collection_summary.objective,
                    'language_code': collection_summary.language_code,
                    'last_updated': utils.get_time_in_millisecs(
                        collection_summary.collection_model_last_updated),
                    'created_on': utils.get_time_in_millisecs(
                        collection_summary.collection_model_created_on),
                    'status': collection_summary.status,
                    'node_count': collection_summary.node_count,
                    'community_owned': collection_summary.community_owned,
                    'thumbnail_icon_url': (
                        utils.get_thumbnail_icon_url_for_category(
                            collection_summary.category)),
                    'thumbnail_bg_color': utils.get_hex_color_for_category(
                        collection_summary.category),
                })

        dashboard_stats = (
            user_jobs_continuous.UserStatsAggregator.get_dashboard_stats(
                self.user_id))
        dashboard_stats.update({
            'total_open_feedback': feedback_services.get_total_open_threads(
                feedback_thread_analytics)
        })
        if dashboard_stats and dashboard_stats.get('average_ratings'):
            dashboard_stats['average_ratings'] = (
                _round_average_ratings(dashboard_stats['average_ratings']))

        last_week_stats = (
            user_services.get_last_week_dashboard_stats(self.user_id))
        if last_week_stats and last_week_stats.get('average_ratings'):
            last_week_stats['average_ratings'] = (
                _round_average_ratings(last_week_stats['average_ratings']))

        subscriber_ids = subscription_services.get_all_subscribers_of_creator(
            self.user_id)
        subscribers_settings = user_services.get_users_settings(subscriber_ids)
        subscribers_list = []
        for index, subscriber_settings in enumerate(subscribers_settings):
            subscriber_summary = {
                'subscriber_picture_data_url': (
                    subscriber_settings.profile_picture_data_url),
                'subscriber_username': subscriber_settings.username,
                'subscriber_impact': (
                    user_services.get_user_impact_score(subscriber_ids[index]))
            }

            subscribers_list.append(subscriber_summary)

        user_settings = user_services.get_user_settings(
            self.user_id, strict=False)
        creator_dashboard_display_pref = (
            user_settings.creator_dashboard_display_pref)

        suggestions_created_by_user = suggestion_services.query_suggestions(
            [('author_id', self.user_id),
             (
                 'suggestion_type',
                 suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT)])
        suggestions_which_can_be_reviewed = (
            suggestion_services
            .get_all_suggestions_that_can_be_reviewed_by_user(self.user_id))

        for s in suggestions_created_by_user:
            s.populate_old_value_of_change()

        for s in suggestions_which_can_be_reviewed:
            s.populate_old_value_of_change()

        suggestion_dicts_created_by_user = (
            [s.to_dict() for s in suggestions_created_by_user])
        suggestion_dicts_which_can_be_reviewed = (
            [s.to_dict() for s in suggestions_which_can_be_reviewed])

        ids_of_suggestions_created_by_user = (
            [s['suggestion_id'] for s in suggestion_dicts_created_by_user])
        ids_of_suggestions_which_can_be_reviewed = (
            [s['suggestion_id']
             for s in suggestion_dicts_which_can_be_reviewed])

        threads_linked_to_suggestions_by_user = (
            [t.to_dict() for t in feedback_services.get_multiple_threads(
                ids_of_suggestions_created_by_user)])
        threads_linked_to_suggestions_which_can_be_reviewed = (
            [t.to_dict() for t in feedback_services.get_multiple_threads(
                ids_of_suggestions_which_can_be_reviewed)])

        self.values.update({
            'explorations_list': exp_summary_dicts,
            'collections_list': collection_summary_dicts,
            'dashboard_stats': dashboard_stats,
            'last_week_stats': last_week_stats,
            'subscribers_list': subscribers_list,
            'display_preference': creator_dashboard_display_pref,
            'threads_for_created_suggestions_list': (
                threads_linked_to_suggestions_by_user),
            'threads_for_suggestions_to_review_list': (
                threads_linked_to_suggestions_which_can_be_reviewed),
            'created_suggestions_list': suggestion_dicts_created_by_user,
            'suggestions_to_review_list': suggestion_dicts_which_can_be_reviewed
        })
        if constants.ENABLE_NEW_STRUCTURE_PLAYERS:
            self.values.update({
                'topic_summary_dicts': topic_summary_dicts
            })
        self.render_json(self.values)
예제 #21
0
파일: cron_test.py 프로젝트: ledriod/oppia
    def test_cron_mail_reviewers_in_rotation_handler(self):
        self.login(self.ADMIN_EMAIL, is_super_admin=True)

        reviewer_ids = []
        score_categories = []

        def _mock_send_mail_to_notify_users_to_review(reviewer_id,
                                                      score_category):
            """Mocks email_manager.send_mail_to_notify_users_to_review() as its
            not possible to send mail with self.testapp_swap, i.e with the URLs
            defined in main_cron.
            """
            reviewer_ids.append(reviewer_id)
            score_categories.append(score_category)

        send_mail_to_notify_users_to_review_swap = self.swap(
            email_manager, 'send_mail_to_notify_users_to_review',
            _mock_send_mail_to_notify_users_to_review)

        self.save_new_valid_exploration('exp_id',
                                        self.admin_id,
                                        title='A title',
                                        category='Algebra')

        new_content = state_domain.SubtitledHtml(
            'content', '<p>new suggestion content</p>').to_dict()
        change = {
            'cmd': 'edit_state_property',
            'property_name': 'content',
            'state_name': 'Introduction',
            'new_value': new_content
        }
        suggestion_services.create_suggestion(
            suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT,
            suggestion_models.TARGET_TYPE_EXPLORATION, 'exp_id', 1,
            feconf.SYSTEM_COMMITTER_ID, change, 'change title', self.admin_id)

        exploration = exp_services.get_exploration_by_id('exp_id')
        self.assertEqual(exploration.states['Introduction'].content.to_dict(),
                         {
                             'content_id': 'content',
                             'html': ''
                         })

        suggestion = suggestion_services.query_suggestions([
            ('author_id', feconf.SYSTEM_COMMITTER_ID), ('target_id', 'exp_id')
        ])[0]
        suggestion_services.accept_suggestion(
            suggestion, self.admin_id,
            suggestion_models.DEFAULT_SUGGESTION_ACCEPT_MESSAGE, None)

        exploration = exp_services.get_exploration_by_id('exp_id')
        self.assertEqual(exploration.states['Introduction'].content.to_dict(),
                         {
                             'content_id': 'content',
                             'html': '<p>new suggestion content</p>'
                         })

        send_suggestion_review_related_emails_swap = self.swap(
            feconf, 'SEND_SUGGESTION_REVIEW_RELATED_EMAILS', True)

        with self.testapp_swap, send_suggestion_review_related_emails_swap, (
                send_mail_to_notify_users_to_review_swap):
            self.get_html_response('/cron/suggestions/notify_reviewers')

        self.assertEqual(reviewer_ids, [None])
        self.assertEqual(score_categories, ['content.Algebra'])