Example #1
0
    def get(self):
        cursor = self.request.get('cursor')
        num_queries_to_fetch = self.request.get('num_queries_to_fetch')

        # num_queries_to_fetch should be convertible to int type and positive.
        if not num_queries_to_fetch.isdigit():
            raise self.InvalidInputException(
                '400 Invalid input for query results.')

        query_models, next_cursor, more = (
            user_models.UserQueryModel.fetch_page(
                int(num_queries_to_fetch), cursor))

        submitters_settings = user_services.get_users_settings(
            list(set([model.submitter_id for model in query_models])))

        submitter_details = {
            submitter.user_id: submitter.username
            for submitter in submitters_settings
        }

        queries_list = [{
            'id': model.id,
            'submitter_username': submitter_details[model.submitter_id],
            'created_on': model.created_on.strftime('%d-%m-%y %H:%M:%S'),
            'status': model.query_status,
            'num_qualified_users': len(model.user_ids)
        } for model in query_models]

        data = {
            'recent_queries': queries_list,
            'cursor': next_cursor if (next_cursor and more) else None
        }

        self.render_json(data)
Example #2
0
def compute_collection_contributors_summary(collection_id):
    """Computes the contributors' summary for a given collection.

    Args:
        collection_id: str. ID of the collection.

    Returns:
        dict. A dict whose keys are user_ids and whose values are the number of
        (non-revert) commits made to the given collection by that user_id.
        This does not count commits which have since been reverted.
    """
    snapshots_metadata = get_collection_snapshots_metadata(collection_id)
    current_version = len(snapshots_metadata)
    contributors_summary = collections.defaultdict(int)
    while True:
        snapshot_metadata = snapshots_metadata[current_version - 1]
        committer_id = snapshot_metadata['committer_id']
        if committer_id not in constants.SYSTEM_USER_IDS:
            contributors_summary[committer_id] += 1

        if current_version == 1:
            break

        current_version -= 1

    contributor_ids = list(contributors_summary)
    # Remove IDs that are deleted or do not exist.
    users_settings = user_services.get_users_settings(contributor_ids)
    for contributor_id, user_settings in python_utils.ZIP(
            contributor_ids, users_settings):
        if user_settings is None:
            del contributors_summary[contributor_id]

    return contributors_summary
Example #3
0
    def get(self):
        cursor = self.request.get('cursor')
        num_queries_to_fetch = self.request.get('num_queries_to_fetch')

        # num_queries_to_fetch should be convertible to int type and positive.
        if not num_queries_to_fetch.isdigit():
            raise self.InvalidInputException(
                '400 Invalid input for query results.')

        query_models, next_cursor, more = (
            user_models.UserQueryModel.fetch_page(
                int(num_queries_to_fetch), cursor))

        submitters_settings = user_services.get_users_settings(
            list(set([model.submitter_id for model in query_models])))

        submitter_details = {
            submitter.user_id: submitter.username
            for submitter in submitters_settings
        }

        queries_list = [{
            'id': model.id,
            'submitter_username': submitter_details[model.submitter_id],
            'created_on': model.created_on.strftime('%d-%m-%y %H:%M:%S'),
            'status': model.query_status,
            'num_qualified_users': len(model.user_ids)
        } for model in query_models]

        data = {
            'recent_queries': queries_list,
            'cursor': next_cursor if (next_cursor and more) else None
        }

        self.render_json(data)
Example #4
0
    def get(self, blog_post_id: str) -> None:
        """Populates the data on the blog dashboard editor page."""
        blog_domain.BlogPost.require_valid_blog_post_id(blog_post_id)
        blog_post = (blog_services.get_blog_post_by_id(blog_post_id,
                                                       strict=False))
        if blog_post is None:
            raise self.PageNotFoundException(
                'The blog post with the given id or url doesn\'t exist.')
        user_settings = user_services.get_users_settings(
            [blog_post.author_id], strict=False, include_marked_deleted=True)
        username = user_settings[0].username

        max_no_of_tags = config_domain.Registry.get_config_property(
            'max_number_of_tags_assigned_to_blog_post').value
        list_of_default_tags = config_domain.Registry.get_config_property(
            'list_of_default_tags_for_blog_post').value

        blog_post_dict = blog_post.to_dict()
        del blog_post_dict['author_id']
        blog_post_dict['author_username'] = username

        self.values.update({
            'blog_post_dict':
            blog_post_dict,
            'username':
            username,
            'profile_picture_data_url':
            (user_settings[0].profile_picture_data_url),
            'max_no_of_tags':
            max_no_of_tags,
            'list_of_default_tags':
            list_of_default_tags
        })

        self.render_json(self.values)
Example #5
0
    def get(self, thread_id):
        """Handles GET requests."""
        messages = feedback_services.get_messages(thread_id)
        author_ids = [m.author_id for m in messages]
        authors_settings = user_services.get_users_settings(author_ids)

        message_ids = [m.message_id for m in messages]
        feedback_services.update_messages_read_by_the_user(
            self.user_id, thread_id, message_ids)

        message_summary_list = []
        suggestion = suggestion_services.get_suggestion_by_id(thread_id)
        suggestion_thread = feedback_services.get_thread(thread_id)

        exploration_id = feedback_services.get_exp_id_from_thread_id(thread_id)
        if suggestion:
            exploration = exp_fetchers.get_exploration_by_id(exploration_id)
            current_content_html = (
                exploration.states[suggestion.change.state_name].content.html)
            suggestion_summary = {
                'suggestion_html':
                suggestion.change.new_value['html'],
                'current_content_html':
                current_content_html,
                'description':
                suggestion_thread.subject,
                'author_username':
                authors_settings[0].username,
                'author_picture_data_url':
                (authors_settings[0].profile_picture_data_url),
                'created_on_msecs':
                utils.get_time_in_millisecs(messages[0].created_on)
            }
            message_summary_list.append(suggestion_summary)
            messages.pop(0)
            authors_settings.pop(0)

        for m, author_settings in python_utils.ZIP(messages, authors_settings):

            if author_settings is None:
                author_username = None
                author_picture_data_url = None
            else:
                author_username = author_settings.username
                author_picture_data_url = (
                    author_settings.profile_picture_data_url)

            message_summary = {
                'message_id': m.message_id,
                'text': m.text,
                'updated_status': m.updated_status,
                'author_username': author_username,
                'author_picture_data_url': author_picture_data_url,
                'created_on_msecs': utils.get_time_in_millisecs(m.created_on)
            }
            message_summary_list.append(message_summary)

        self.render_json({'message_summary_list': message_summary_list})
Example #6
0
def _send_bulk_mail(
    recipient_ids, sender_id, intent, email_subject, email_html_body, sender_email, sender_name, instance_id=None
):
    """Sends an email to all given recipients.

    Args:
        recipient_ids: list(str). The user IDs of the email recipients.
        sender_id: str. The ID of the user sending the email.
        intent: str. The intent string, i.e. the purpose of the email.
        email_subject: str. The subject of the email.
        email_html_body: str. The body (message) of the email.
        sender_email: str. The sender's email address.
        sender_name: str. The name to be shown in the "sender" field of the
            email.
        instance_id: str or None. The ID of the BulkEmailModel entity instance.
    """
    _require_sender_id_is_valid(intent, sender_id)

    recipients_settings = user_services.get_users_settings(recipient_ids)
    recipient_emails = [user.email for user in recipients_settings]

    cleaned_html_body = html_cleaner.clean(email_html_body)
    if cleaned_html_body != email_html_body:
        log_new_error(
            "Original email HTML body does not match cleaned HTML body:\n"
            "Original:\n%s\n\nCleaned:\n%s\n" % (email_html_body, cleaned_html_body)
        )
        return

    raw_plaintext_body = (
        cleaned_html_body.replace("<br/>", "\n")
        .replace("<br>", "\n")
        .replace("<li>", "<li>- ")
        .replace("</p><p>", "</p>\n<p>")
    )
    cleaned_plaintext_body = html_cleaner.strip_html_tags(raw_plaintext_body)

    def _send_bulk_mail_in_transaction(instance_id=None):
        sender_name_email = "%s <%s>" % (sender_name, sender_email)

        email_services.send_bulk_mail(
            sender_name_email, recipient_emails, email_subject, cleaned_plaintext_body, cleaned_html_body
        )

        if instance_id is None:
            instance_id = email_models.BulkEmailModel.get_new_id("")
        email_models.BulkEmailModel.create(
            instance_id,
            recipient_ids,
            sender_id,
            sender_name_email,
            intent,
            email_subject,
            cleaned_html_body,
            datetime.datetime.utcnow(),
        )

    return transaction_services.run_in_transaction(_send_bulk_mail_in_transaction, instance_id)
Example #7
0
def pre_delete_user(user_id):
    """Prepare user for the full deletion.
        1. Mark all the activities that are private and solely owned by the user
           being deleted as deleted.
        2. Disable all the email preferences.
        3. Mark the user as to be deleted.
        4. Create PendingDeletionRequestModel for the user.

    Args:
        user_id: str. The id of the user to be deleted. If the user_id
            corresponds to a profile user then only that profile is deleted.
            For a full user, all of its associated profile users are deleted
            too.
    """
    pending_deletion_requests = []
    user_settings = user_services.get_user_settings(user_id, strict=True)

    linked_profile_user_ids = [
        user.user_id for user in
        user_services.get_all_profiles_auth_details_by_parent_user_id(user_id)
    ]
    profile_users_settings_list = user_services.get_users_settings(
        linked_profile_user_ids)
    for profile_user_settings in profile_users_settings_list:
        profile_id = profile_user_settings.user_id
        user_services.mark_user_for_deletion(profile_id)
        pending_deletion_requests.append(
            wipeout_domain.PendingDeletionRequest.create_default(
                profile_id, profile_user_settings.email,
                profile_user_settings.role))
    if user_settings.role != feconf.ROLE_ID_LEARNER:
        taskqueue_services.defer(
            taskqueue_services.FUNCTION_ID_REMOVE_USER_FROM_RIGHTS_MODELS,
            taskqueue_services.QUEUE_NAME_ONE_OFF_JOBS,
            user_id,
        )
        # Set all the user's email preferences to False in order to disable all
        # ordinary emails that could be sent to the users.
        user_services.update_email_preferences(user_id, False, False, False,
                                               False)

    date_now = datetime.datetime.utcnow()
    date_before_which_username_should_be_saved = (
        date_now - PERIOD_AFTER_WHICH_USERNAME_CANNOT_BE_REUSED)
    user_services.mark_user_for_deletion(user_id)

    normalized_long_term_username = (
        user_settings.normalized_username if
        user_settings.created_on < date_before_which_username_should_be_saved
        else None)
    pending_deletion_requests.append(
        wipeout_domain.PendingDeletionRequest.create_default(
            user_id,
            user_settings.email,
            user_settings.role,
            normalized_long_term_username=normalized_long_term_username))

    save_pending_deletion_requests(pending_deletion_requests)
Example #8
0
def _send_bulk_mail(recipient_ids,
                    sender_id,
                    intent,
                    email_subject,
                    email_html_body,
                    sender_email,
                    sender_name,
                    instance_id=None):
    """Sends an email to all given recipients.

    Args:
        recipient_ids: list(str). The user IDs of the email recipients.
        sender_id: str. The ID of the user sending the email.
        intent: str. The intent string, i.e. the purpose of the email.
        email_subject: str. The subject of the email.
        email_html_body: str. The body (message) of the email.
        sender_email: str. The sender's email address.
        sender_name: str. The name to be shown in the "sender" field of the
            email.
        instance_id: str or None. The ID of the BulkEmailModel entity instance.
    """
    _require_sender_id_is_valid(intent, sender_id)

    recipients_settings = user_services.get_users_settings(recipient_ids)
    recipient_emails = [user.email for user in recipients_settings]

    cleaned_html_body = html_cleaner.clean(email_html_body)
    if cleaned_html_body != email_html_body:
        log_new_error(
            'Original email HTML body does not match cleaned HTML body:\n'
            'Original:\n%s\n\nCleaned:\n%s\n' %
            (email_html_body, cleaned_html_body))
        return

    raw_plaintext_body = cleaned_html_body.replace('<br/>', '\n').replace(
        '<br>', '\n').replace('<li>',
                              '<li>- ').replace('</p><p>', '</p>\n<p>')
    cleaned_plaintext_body = html_cleaner.strip_html_tags(raw_plaintext_body)

    def _send_bulk_mail_in_transaction(instance_id=None):
        """Sends the emails in bulk to the recipients."""
        sender_name_email = '%s <%s>' % (sender_name, sender_email)

        email_services.send_bulk_mail(sender_name_email, recipient_emails,
                                      email_subject, cleaned_plaintext_body,
                                      cleaned_html_body)

        if instance_id is None:
            instance_id = email_models.BulkEmailModel.get_new_id('')
        email_models.BulkEmailModel.create(instance_id, recipient_ids,
                                           sender_id, sender_name_email,
                                           intent, email_subject,
                                           cleaned_html_body,
                                           datetime.datetime.utcnow())

    transaction_services.run_in_transaction(_send_bulk_mail_in_transaction,
                                            instance_id)
Example #9
0
    def get(self):
        """Handles GET requests."""
        user_settings = user_services.get_user_settings(self.user_id)
        user_email_preferences = user_services.get_email_preferences(
            self.user_id)

        creators_subscribed_to = subscription_services.get_all_creators_subscribed_to(  # pylint: disable=line-too-long
            self.user_id)
        creators_settings = user_services.get_users_settings(
            creators_subscribed_to)
        subscription_list = []

        for index, creator_settings in enumerate(creators_settings):
            subscription_summary = {
                'creator_picture_data_url':
                (creator_settings.profile_picture_data_url),
                'creator_username':
                creator_settings.username,
                'creator_impact': (user_services.get_user_impact_score(
                    creators_subscribed_to[index]))
            }

            subscription_list.append(subscription_summary)

        self.values.update({
            'preferred_language_codes':
            user_settings.preferred_language_codes,
            'preferred_site_language_code':
            (user_settings.preferred_site_language_code),
            'preferred_audio_language_code':
            (user_settings.preferred_audio_language_code),
            'profile_picture_data_url':
            user_settings.profile_picture_data_url,
            'default_dashboard':
            user_settings.default_dashboard,
            'user_bio':
            user_settings.user_bio,
            'subject_interests':
            user_settings.subject_interests,
            'can_receive_email_updates':
            (user_email_preferences.can_receive_email_updates),
            'can_receive_editor_role_email':
            (user_email_preferences.can_receive_editor_role_email),
            'can_receive_feedback_message_email':
            (user_email_preferences.can_receive_feedback_message_email),
            'can_receive_subscription_email':
            (user_email_preferences.can_receive_subscription_email),
            'subscription_list':
            subscription_list
        })
        self.render_json(self.values)
Example #10
0
    def get(self):
        """Handles GET requests."""
        (learner_progress, number_of_nonexistent_explorations) = (
            learner_progress_services.get_exploration_progress(self.user_id))

        completed_exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                learner_progress.completed_exp_summaries))

        incomplete_exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                learner_progress.incomplete_exp_summaries))

        exploration_playlist_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                learner_progress.exploration_playlist_summaries))

        creators_subscribed_to = (
            subscription_services.get_all_creators_subscribed_to(self.user_id))
        creators_settings = user_services.get_users_settings(
            creators_subscribed_to)
        subscription_list = []

        for index, creator_settings in enumerate(creators_settings):
            subscription_summary = {
                'creator_picture_data_url':
                (creator_settings.profile_picture_data_url),
                'creator_username':
                creator_settings.username,
                'creator_impact': (user_services.get_user_impact_score(
                    creators_subscribed_to[index]))
            }

            subscription_list.append(subscription_summary)

        self.values.update({
            'completed_explorations_list':
            completed_exp_summary_dicts,
            'incomplete_explorations_list':
            incomplete_exp_summary_dicts,
            'exploration_playlist':
            exploration_playlist_summary_dicts,
            'number_of_nonexistent_explorations':
            (number_of_nonexistent_explorations),
            'subscription_list':
            subscription_list
        })
        self.render_json(self.values)
Example #11
0
def pre_delete_user(user_id):
    """Prepare user for the full deletion.
        1. Mark all the activities that are private and solely owned by the user
           being deleted as deleted.
        2. Disable all the email preferences.
        3. Mark the user as to be deleted.
        4. Create PendingDeletionRequestModel for the user.

    Args:
        user_id: str. The id of the user to be deleted. If the user_id
            corresponds to a profile user then only that profile is deleted.
            For a full user, all of its associated profile users are deleted
            too.
    """
    pending_deletion_requests = []
    user_settings = user_services.get_user_settings(user_id, strict=True)

    linked_profile_user_ids = [
        user.user_id for user in
        user_services.get_all_profiles_auth_details_by_parent_user_id(user_id)
    ]
    profile_users_settings_list = user_services.get_users_settings(
        linked_profile_user_ids)
    for profile_user_settings in profile_users_settings_list:
        profile_id = profile_user_settings.user_id
        user_services.mark_user_for_deletion(profile_id)
        pending_deletion_requests.append(
            wipeout_domain.PendingDeletionRequest.create_default(
                profile_id, profile_user_settings.email,
                profile_user_settings.role))
    if user_settings.role != feconf.ROLE_ID_LEARNER:
        _remove_user_from_activities_with_associated_rights_models(
            user_id, True)

        # Set all the user's email preferences to False in order to disable all
        # ordinary emails that could be sent to the users.
        user_services.update_email_preferences(user_id, False, False, False,
                                               False)

    user_services.mark_user_for_deletion(user_id)
    pending_deletion_requests.append(
        wipeout_domain.PendingDeletionRequest.create_default(
            user_id, user_settings.email, user_settings.role))

    save_pending_deletion_requests(pending_deletion_requests)
Example #12
0
    def get(self):
        """Handles GET requests."""
        user_settings = user_services.get_user_settings(self.user_id)
        user_email_preferences = user_services.get_email_preferences(
            self.user_id)

        creators_subscribed_to = subscription_services.get_all_creators_subscribed_to( # pylint: disable=line-too-long
            self.user_id)
        creators_settings = user_services.get_users_settings(
            creators_subscribed_to)
        subscription_list = []

        for index, creator_settings in enumerate(creators_settings):
            subscription_summary = {
                'creator_picture_data_url': (
                    creator_settings.profile_picture_data_url),
                'creator_username': creator_settings.username,
                'creator_impact': (
                    user_services.get_user_impact_score(
                        creators_subscribed_to[index]))
            }

            subscription_list.append(subscription_summary)

        self.values.update({
            'preferred_language_codes': user_settings.preferred_language_codes,
            'preferred_site_language_code': (
                user_settings.preferred_site_language_code),
            'profile_picture_data_url': user_settings.profile_picture_data_url,
            'user_bio': user_settings.user_bio,
            'subject_interests': user_settings.subject_interests,
            'can_receive_email_updates': (
                user_email_preferences.can_receive_email_updates),
            'can_receive_editor_role_email': (
                user_email_preferences.can_receive_editor_role_email),
            'can_receive_feedback_message_email': (
                user_email_preferences.can_receive_feedback_message_email),
            'can_receive_subscription_email': (
                user_email_preferences.can_receive_subscription_email),
            'subscription_list': subscription_list
        })
        self.render_json(self.values)
Example #13
0
def _generate_user_query_dicts(user_queries):
    """Generate data dicts for the user queries.

    Args:
        user_queries: list(UserQuery). List of user queries to transform.

    Returns:
        list(dict(str, str)). List of data dicts for the user queries.
    """
    submitters_settings = user_services.get_users_settings(
        list(set(model.submitter_id for model in user_queries)))
    user_id_to_username = {
        submitter.user_id: submitter.username
        for submitter in submitters_settings
    }
    return [{
        'id': user_query.id,
        'submitter_username': user_id_to_username[user_query.submitter_id],
        'created_on': user_query.created_on.strftime('%d-%m-%y %H:%M:%S'),
        'status': user_query.status,
        'num_qualified_users': len(user_query.user_ids)
    } for user_query in user_queries]
Example #14
0
def _send_bulk_mail(
        recipient_ids, sender_id, intent, email_subject, email_html_body,
        sender_email, sender_name, instance_id=None):
    """Sends an email to all given recipients."""
    _require_sender_id_is_valid(intent, sender_id)

    recipients_settings = user_services.get_users_settings(recipient_ids)
    recipient_emails = [user.email for user in recipients_settings]

    cleaned_html_body = html_cleaner.clean(email_html_body)
    if cleaned_html_body != email_html_body:
        log_new_error(
            'Original email HTML body does not match cleaned HTML body:\n'
            'Original:\n%s\n\nCleaned:\n%s\n' %
            (email_html_body, cleaned_html_body))
        return

    raw_plaintext_body = cleaned_html_body.replace('<br/>', '\n').replace(
        '<br>', '\n').replace('<li>', '<li>- ').replace('</p><p>', '</p>\n<p>')
    cleaned_plaintext_body = html_cleaner.strip_html_tags(raw_plaintext_body)

    def _send_bulk_mail_in_transaction(instance_id=None):
        sender_name_email = '%s <%s>' % (sender_name, sender_email)

        email_services.send_bulk_mail(
            sender_name_email, recipient_emails, email_subject,
            cleaned_plaintext_body, cleaned_html_body)

        if instance_id is None:
            instance_id = email_models.BulkEmailModel.get_new_id('')
        email_models.BulkEmailModel.create(
            instance_id, recipient_ids, sender_id, sender_name_email, intent,
            email_subject, cleaned_html_body, datetime.datetime.utcnow())

    return transaction_services.run_in_transaction(
        _send_bulk_mail_in_transaction, instance_id)
Example #15
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)
Example #16
0
    def get(self):
        """Handles GET requests."""
        if self.user_id is None:
            raise self.PageNotFoundException

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

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

        exploration_ids_subscribed_to = (
            subscription_services.get_exploration_ids_subscribed_to(
                self.user_id))

        subscribed_exploration_summaries = filter(
            None, (exp_services.get_exploration_summaries_matching_ids(
                exploration_ids_subscribed_to)))
        subscribed_collection_summaries = filter(
            None, (collection_services.get_collection_summaries_matching_ids(
                subscription_services.get_collection_ids_subscribed_to(
                    self.user_id))))

        exp_summary_list = summary_services.get_displayable_exp_summary_dicts(
            subscribed_exploration_summaries)
        collection_summary_list = []

        feedback_thread_analytics = (
            feedback_services.get_thread_analytics_multi(
                exploration_ids_subscribed_to))

        unresolved_answers_dict = (
            stats_services.get_exps_unresolved_answers_for_default_rule(
                exploration_ids_subscribed_to))

        total_unresolved_answers = 0

        for ind, exploration in enumerate(exp_summary_list):
            exploration.update(feedback_thread_analytics[ind].to_dict())
            exploration.update({
                'num_unresolved_answers':
                (unresolved_answers_dict[exploration['id']]['count']
                 if exploration['id'] in unresolved_answers_dict else 0),
                'top_unresolved_answers':
                (unresolved_answers_dict[
                    exploration['id']]['unresolved_answers']
                 [:feconf.TOP_UNRESOLVED_ANSWERS_COUNT_DASHBOARD])
            })
            total_unresolved_answers += exploration['num_unresolved_answers']

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

        if (self.username in
                config_domain.WHITELISTED_COLLECTION_EDITOR_USERNAMES.value):
            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_list.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),
            'total_unresolved_answers':
            total_unresolved_answers
        })
        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)

        self.values.update({
            'explorations_list': exp_summary_list,
            'collections_list': collection_summary_list,
            'dashboard_stats': dashboard_stats,
            'last_week_stats': last_week_stats,
            'subscribers_list': subscribers_list
        })
        self.render_json(self.values)
Example #17
0
    def get(self):
        """Handles GET requests."""
        (
            learner_progress, number_of_nonexistent_activities,
            completed_to_incomplete_collections) = (
                learner_progress_services.get_activity_progress(self.user_id))

        completed_exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                learner_progress.completed_exp_summaries))

        incomplete_exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                learner_progress.incomplete_exp_summaries))

        completed_collection_summary_dicts = (
            learner_progress_services.get_collection_summary_dicts(
                learner_progress.completed_collection_summaries))
        incomplete_collection_summary_dicts = (
            learner_progress_services.get_collection_summary_dicts(
                learner_progress.incomplete_collection_summaries))

        exploration_playlist_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                learner_progress.exploration_playlist_summaries))
        collection_playlist_summary_dicts = (
            learner_progress_services.get_collection_summary_dicts(
                learner_progress.collection_playlist_summaries))

        full_thread_ids = subscription_services.get_all_threads_subscribed_to(
            self.user_id)
        if len(full_thread_ids) > 0:
            thread_summaries, number_of_unread_threads = (
                feedback_services.get_exp_thread_summaries(
                    self.user_id, full_thread_ids))
        else:
            thread_summaries, number_of_unread_threads = [], 0

        creators_subscribed_to = (
            subscription_services.get_all_creators_subscribed_to(self.user_id))
        creators_settings = user_services.get_users_settings(
            creators_subscribed_to)
        subscription_list = []

        for index, creator_settings in enumerate(creators_settings):
            subscription_summary = {
                'creator_picture_data_url': (
                    creator_settings.profile_picture_data_url),
                'creator_username': creator_settings.username,
                'creator_impact': (
                    user_services.get_user_impact_score(
                        creators_subscribed_to[index]))
            }

            subscription_list.append(subscription_summary)

        self.values.update({
            'completed_explorations_list': completed_exp_summary_dicts,
            'completed_collections_list': completed_collection_summary_dicts,
            'incomplete_explorations_list': incomplete_exp_summary_dicts,
            'incomplete_collections_list': incomplete_collection_summary_dicts,
            'exploration_playlist': exploration_playlist_summary_dicts,
            'collection_playlist': collection_playlist_summary_dicts,
            'number_of_nonexistent_activities': (
                number_of_nonexistent_activities),
            'completed_to_incomplete_collections': (
                completed_to_incomplete_collections),
            'thread_summaries': [s.to_dict() for s in thread_summaries],
            'number_of_unread_threads': number_of_unread_threads,
            'subscription_list': subscription_list
        })
        self.render_json(self.values)
Example #18
0
    def get(self):
        """Handles GET requests."""
        if self.user_id is None:
            raise self.PageNotFoundException

        def _get_intro_card_color(category):
            return (feconf.CATEGORIES_TO_COLORS[category] if category
                    in feconf.CATEGORIES_TO_COLORS else feconf.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 (self.username in
                config_domain.WHITELISTED_COLLECTION_EDITOR_USERNAMES.value):
            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)

        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
        })
        self.render_json(self.values)
Example #19
0
    def get(self):
        """Handles GET requests."""
        if self.user_id is None:
            raise self.PageNotFoundException

        incomplete_exp_summaries, num_deleted_incomplete_exps = (
            learner_progress_services.get_incomplete_exp_summaries(
                self.user_id))

        completed_exp_summaries, num_deleted_completed_exps = (
            learner_progress_services.get_completed_exp_summaries(
                self.user_id))

        (completed_collection_summaries, num_deleted_completed_collections,
         completed_to_incomplete_collections) = (
             learner_progress_services.get_completed_collection_summaries(
                 self.user_id))

        incomplete_collection_summaries, num_deleted_incomplete_collections = (
            learner_progress_services.get_incomplete_collection_summaries(
                self.user_id))

        completed_exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                completed_exp_summaries))

        incomplete_exp_summary_dicts = (
            summary_services.get_displayable_exp_summary_dicts(
                incomplete_exp_summaries))

        completed_collection_summary_dicts = (
            learner_progress_services.get_collection_summary_dicts(
                completed_collection_summaries))
        incomplete_collection_summary_dicts = (
            learner_progress_services.get_collection_summary_dicts(
                incomplete_collection_summaries))

        creators_subscribed_to = (
            subscription_services.get_all_creators_subscribed_to(self.user_id))
        creators_settings = user_services.get_users_settings(
            creators_subscribed_to)
        subscription_list = []

        for index, creator_settings in enumerate(creators_settings):
            subscription_summary = {
                'creator_picture_data_url':
                (creator_settings.profile_picture_data_url),
                'creator_username':
                creator_settings.username,
                'creator_impact': (user_services.get_user_impact_score(
                    creators_subscribed_to[index]))
            }

            subscription_list.append(subscription_summary)

        self.values.update({
            'completed_explorations_list':
            completed_exp_summary_dicts,
            'completed_collections_list':
            completed_collection_summary_dicts,
            'incomplete_explorations_list':
            incomplete_exp_summary_dicts,
            'incomplete_collections_list':
            incomplete_collection_summary_dicts,
            'number_of_deleted_activities': {
                'incomplete_explorations': num_deleted_incomplete_exps,
                'incomplete_collections': num_deleted_incomplete_collections,
                'completed_explorations': num_deleted_completed_exps,
                'completed_collections': num_deleted_completed_collections
            },
            'completed_to_incomplete_collections':
            (completed_to_incomplete_collections),
            'subscription_list':
            subscription_list
        })
        self.render_json(self.values)
Example #20
0
def pre_delete_user(user_id):
    """Prepare user for the full deletion.
        1. Mark all the activities that are private and solely owned by the user
           being deleted as deleted.
        2. Disable all the email preferences.
        3. Mark the user as to be deleted.
        4. Create PendingDeletionRequestModel for the user.

    Args:
        user_id: str. The id of the user to be deleted. If the user_id
            corresponds to a profile user then only that profile is deleted.
            For a full user, all of its associated profile users are deleted
            too.
    """
    pending_deletion_requests = []
    user_settings = user_services.get_user_settings(user_id, strict=True)

    linked_profile_user_ids = [
        user.user_id for user in
        user_services.get_all_profiles_auth_details_by_parent_user_id(user_id)
    ]
    profile_users_settings_list = user_services.get_users_settings(
        linked_profile_user_ids)
    for profile_user_settings in profile_users_settings_list:
        profile_id = profile_user_settings.user_id
        user_services.mark_user_for_deletion(profile_id)
        pending_deletion_requests.append(
            wipeout_domain.PendingDeletionRequest.create_default(
                profile_id, profile_user_settings.email,
                profile_user_settings.role, [], []))
    explorations_to_be_deleted_ids = []
    collections_to_be_deleted_ids = []
    if user_settings.role != feconf.ROLE_ID_LEARNER:
        subscribed_exploration_summaries = (
            exp_fetchers.get_exploration_summaries_subscribed_to(user_id))

        explorations_to_be_deleted_ids = [
            exp_summary.id for exp_summary in subscribed_exploration_summaries
            if exp_summary.is_private()
            and exp_summary.is_solely_owned_by_user(user_id)
        ]
        exp_services.delete_explorations(user_id,
                                         explorations_to_be_deleted_ids)

        # Release ownership of explorations that are public and are solely owned
        # by the to-be-deleted user.
        explorations_to_release_ownership_ids = [
            exp_summary.id for exp_summary in subscribed_exploration_summaries
            if not exp_summary.is_private()
            and exp_summary.is_solely_owned_by_user(user_id)
        ]
        for exp_id in explorations_to_release_ownership_ids:
            rights_manager.release_ownership_of_exploration(
                user_services.get_system_user(), exp_id)

        explorations_to_remove_user_from_ids = [
            exp_summary.id for exp_summary in subscribed_exploration_summaries
            if not exp_summary.is_solely_owned_by_user(user_id)
        ]
        for exp_id in explorations_to_remove_user_from_ids:
            rights_manager.deassign_role_for_exploration(
                user_services.get_system_user(), exp_id, user_id)

        subscribed_collection_summaries = (
            collection_services.get_collection_summaries_subscribed_to(user_id)
        )
        collections_to_be_deleted_ids = [
            col_summary.id for col_summary in subscribed_collection_summaries
            if col_summary.is_private()
            and col_summary.is_solely_owned_by_user(user_id)
        ]
        collection_services.delete_collections(user_id,
                                               collections_to_be_deleted_ids)

        # Release ownership of collections that are public and are solely owned
        # by the to-be-deleted user.
        collections_to_release_ownership_ids = [
            col_summary.id for col_summary in subscribed_collection_summaries
            if not col_summary.is_private()
            and col_summary.is_solely_owned_by_user(user_id)
        ]
        for col_id in collections_to_release_ownership_ids:
            rights_manager.release_ownership_of_collection(
                user_services.get_system_user(), col_id)

        collections_to_remove_user_from_ids = [
            col_summary.id for col_summary in subscribed_collection_summaries
            if not col_summary.is_solely_owned_by_user(user_id)
        ]
        for col_id in collections_to_remove_user_from_ids:
            rights_manager.deassign_role_for_collection(
                user_services.get_system_user(), col_id, user_id)

        topic_services.deassign_user_from_all_topics(
            user_services.get_system_user(), user_id)

        # Set all the user's email preferences to False in order to disable all
        # ordinary emails that could be sent to the users.
        user_services.update_email_preferences(user_id, False, False, False,
                                               False)

    user_services.mark_user_for_deletion(user_id)
    pending_deletion_requests.append(
        wipeout_domain.PendingDeletionRequest.create_default(
            user_id, user_settings.email, user_settings.role,
            explorations_to_be_deleted_ids, collections_to_be_deleted_ids))

    save_pending_deletion_requests(pending_deletion_requests)
Example #21
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)
Example #22
0
    def get(self):
        """Handles GET requests."""
        if self.user_id is None:
            raise self.PageNotFoundException

        def _get_intro_card_color(category):
            return (
                feconf.CATEGORIES_TO_COLORS[category] if
                category in feconf.CATEGORIES_TO_COLORS else
                feconf.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 (self.username in
                config_domain.WHITELISTED_COLLECTION_EDITOR_USERNAMES.value):
            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)

        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
        })
        self.render_json(self.values)