Esempio n. 1
0
def ajax_author_overview(user_id, page):
    author = Author.get(id=user_id)
    if not author:
        abort(404)

    comments_list = StoryComment.select(lambda x: x.author == author and not x.deleted and x.story_published)
    comments_list = comments_list.order_by(StoryComment.id.desc())
    comments_count = comments_list.count()

    paged = Paginator(
        number=page,
        total=comments_count,
        per_page=current_app.config['COMMENTS_COUNT']['author_page'],
    )  # TODO: restore orphans?
    comments = paged.slice(comments_list)
    if not comments and page != 1:
        abort(404)

    data = {
        'author': author,
        'comments': comments,
        'page_obj': paged,
        'comments_short': True,
    }
    data.update(cached_lists([x.story.id for x in comments]))

    return jsonify({
        'success': True,
        'link': url_for('author.info', user_id=author.id, comments_page=page),
        'comments_count': comments_count,
        'comments_list': render_template('includes/story_comments_list.html', **data),
        'pagination': render_template('includes/comments_pagination_author_overview.html', **data),
    })
Esempio n. 2
0
def comments(page):
    objects = StoryComment.select(lambda x: x.story_published)
    filter_deleted = current_user.is_staff and request.args.get(
        'deleted') == '1'
    if filter_deleted:
        objects = objects.filter(lambda x: x.deleted).order_by(
            StoryComment.last_deleted_at.desc())
    else:
        objects = objects.filter(lambda x: not x.deleted).order_by(
            StoryComment.id.desc())

    page_obj = Paginator(
        page,
        objects.count(),
        per_page=current_app.config['COMMENTS_COUNT']['stream'])
    objects = [('story', x) for x in page_obj.slice_or_404(objects)]

    comment_votes_cache = Story.bl.select_comment_votes(
        current_user._get_current_object(),
        [x[1].id for x in objects]) if current_user.is_authenticated else {}

    return render_template('stream/comments.html',
                           page_title='Лента комментариев',
                           tab='story',
                           comments=objects,
                           filter_deleted=filter_deleted,
                           with_target_link=True,
                           comment_votes_cache=comment_votes_cache,
                           page_obj=page_obj,
                           robots_noindex=True,
                           **cached_lists([x[1].story.id for x in objects]))
Esempio n. 3
0
def comments(page):
    objects = StoryComment.select(lambda x: x.story_published)
    filter_deleted = current_user.is_staff and request.args.get('deleted') == '1'
    if filter_deleted:
        objects = objects.filter(lambda x: x.deleted).order_by(StoryComment.last_deleted_at.desc())
    else:
        objects = objects.filter(lambda x: not x.deleted).order_by(StoryComment.id.desc())

    page_obj = Paginator(page, objects.count(), per_page=current_app.config['COMMENTS_COUNT']['stream'])
    objects = [('story', x) for x in page_obj.slice_or_404(objects)]

    comment_votes_cache = Story.bl.select_comment_votes(
        current_user._get_current_object(),
        [x[1].id for x in objects]
    ) if current_user.is_authenticated else {}

    return render_template(
        'stream/comments.html',
        page_title='Лента комментариев',
        tab='story',
        comments=objects,
        filter_deleted=filter_deleted,
        with_target_link=True,
        comment_votes_cache=comment_votes_cache,
        page_obj=page_obj,
        robots_noindex=True,
        **cached_lists([x[1].story.id for x in objects])
    )
Esempio n. 4
0
def edit(story_id, local_id):
    comment = StoryComment.get(story=story_id, local_id=local_id, deleted=False)
    if not comment:
        abort(404)

    return common_comment.edit(
        'story',
        comment,
        template='story_comment_work.html',
    )
Esempio n. 5
0
def comments_updates(params):
    comments_html = None
    if not current_user.is_authenticated:
        comments_html = current_app.cache.get('index_comments_html_guest')

    if not comments_html:
        # Старая логика, при которой могли появляться несколько комментариев одной сущности

        # story_comments = StoryComment.select(lambda x: x.story_published and not x.deleted).order_by(StoryComment.id.desc())
        # story_comments = story_comments[:current_app.config['COMMENTS_COUNT']['main']]

        # news_comments = NewsComment.select(lambda x: not x.deleted).order_by(NewsComment.id.desc())
        # news_comments = news_comments[:current_app.config['COMMENTS_COUNT']['main']]

        stories = select(x for x in Story
                         if x.published and x.last_comment_id > 0).order_by(
                             Story.last_comment_id.desc(
                             ))[:current_app.config['COMMENTS_COUNT']['main']]
        story_comment_ids = [x.last_comment_id for x in stories]
        story_comments = StoryComment.select(
            lambda x: x.id in story_comment_ids).order_by(StoryComment.id.desc(
            ))[:current_app.config['COMMENTS_COUNT']['main']]

        news_list = select(
            x for x in NewsItem
            if x.last_comment_id > 0).order_by(NewsItem.last_comment_id.desc(
            ))[:current_app.config['COMMENTS_COUNT']['main']]
        news_comment_ids = [x.last_comment_id for x in news_list]
        news_comments = NewsComment.select(
            lambda x: x.id in news_comment_ids).order_by(NewsComment.id.desc(
            ))[:current_app.config['COMMENTS_COUNT']['main']]

        comments = [('story', x) for x in story_comments]
        comments += [('news', x) for x in news_comments]
        comments.sort(key=lambda x: x[1].date, reverse=True)
        comments = comments[:current_app.config['COMMENTS_COUNT']['main']]

        data = dict(
            comments=comments,
            comments_short=True,
        )

        # Для счётчика непрочитанных комментариев
        data.update(cached_lists([x.id for x in stories]))

        comments_html = render_template('includes/comments_list.html', **data)

        if not current_user.is_authenticated:
            current_app.cache.set('index_comments_html_guest', comments_html,
                                  3600)

    return render_template('sidebar/comments_updates.html',
                           comments_html=comments_html)
Esempio n. 6
0
def restore(story_id, local_id):
    comment = StoryComment.get(story=story_id, local_id=local_id, deleted=True)
    if not comment:
        abort(404)

    return common_comment.restore(
        'story',
        comment,
        template='story_comment_restore.html',
        template_ajax='includes/ajax/story_comment_restore.html',
        template_ajax_modal=True,
    )
Esempio n. 7
0
def show(story_id, local_id):
    story = Story.get(id=story_id)
    if not story:
        abort(404)

    if not story.bl.has_comments_access(current_user._get_current_object()):
        abort(403)

    comment = StoryComment.get(story=story_id, local_id=local_id)
    if not comment or (comment.deleted and not current_user.is_staff):
        abort(404)

    return common_comment.show('story', comment)
Esempio n. 8
0
def comments_updates(params):
    comments_html = None
    if not current_user.is_authenticated:
        comments_html = current_app.cache.get('index_comments_html_guest')

    if not comments_html:
        # Старая логика, при которой могли появляться несколько комментариев одной сущности

        # story_comments = StoryComment.select(lambda x: x.story_published and not x.deleted).order_by(StoryComment.id.desc())
        # story_comments = story_comments[:current_app.config['COMMENTS_COUNT']['main']]

        # news_comments = NewsComment.select(lambda x: not x.deleted).order_by(NewsComment.id.desc())
        # news_comments = news_comments[:current_app.config['COMMENTS_COUNT']['main']]

        stories = select(x for x in Story if x.published and x.last_comment_id > 0).order_by(Story.last_comment_id.desc())[:current_app.config['COMMENTS_COUNT']['main']]
        story_comment_ids = [x.last_comment_id for x in stories]
        story_comments = StoryComment.select(lambda x: x.id in story_comment_ids).order_by(StoryComment.id.desc())[:current_app.config['COMMENTS_COUNT']['main']]

        news_list = select(x for x in NewsItem if x.last_comment_id > 0).order_by(NewsItem.last_comment_id.desc())[:current_app.config['COMMENTS_COUNT']['main']]
        news_comment_ids = [x.last_comment_id for x in news_list]
        news_comments = NewsComment.select(lambda x: x.id in news_comment_ids).order_by(NewsComment.id.desc())[:current_app.config['COMMENTS_COUNT']['main']]

        comments = [('story', x) for x in story_comments]
        comments += [('news', x) for x in news_comments]
        comments.sort(key=lambda x: x[1].date, reverse=True)
        comments = comments[:current_app.config['COMMENTS_COUNT']['main']]

        data = dict(
            comments=comments,
            comments_short=True,
        )

        # Для счётчика непрочитанных комментариев
        data.update(cached_lists([x.id for x in stories]))

        comments_html = render_template(
            'includes/comments_list.html',
            **data
        )

        if not current_user.is_authenticated:
            current_app.cache.set('index_comments_html_guest', comments_html, 3600)

    return render_template('sidebar/comments_updates.html', comments_html=comments_html)
Esempio n. 9
0
    def get_notifications(self, older=None, offset=0, count=50):
        from mini_fiction.models import Notification, Story, Chapter, StoryComment, StoryLocalThread, StoryLocalComment, NewsComment

        user = self.model

        if older is None and offset == 0 and count <= 101:
            result = current_app.cache.get('bell_content_{}'.format(user.id))
            if result is not None:
                return result[:count]

        result = []

        # Забираем уведомления
        items = user.notifications.filter(lambda x: x.id < older) if older is not None else user.notifications
        items = items.order_by(Notification.id.desc()).prefetch(Notification.caused_by_user)[offset:offset + count]

        # Группируем таргеты по типам, чтобы брать их одним sql-запросом
        story_ids = set()
        chapter_ids = set()
        story_comment_ids = set()
        local_comment_ids = set()
        news_comment_ids = set()
        for n in items:
            if n.type in ('story_publish', 'story_draft', 'author_story'):
                story_ids.add(n.target_id)
            elif n.type == 'story_chapter':
                chapter_ids.add(n.target_id)
            elif n.type in ('story_reply', 'story_comment'):
                story_comment_ids.add(n.target_id)
            elif n.type in ('story_lreply', 'story_lcomment'):
                local_comment_ids.add(n.target_id)
            elif n.type in ('news_reply', 'news_comment'):
                news_comment_ids.add(n.target_id)

        # И забираем все эти таргеты
        stories = {
            x.id: x for x in Story.select(
                lambda x: x.id in story_ids
            )
        } if story_ids else {}

        chapters = {
            x.id: x for x in Chapter.select(
                lambda x: x.id in chapter_ids
            )
        } if chapter_ids else {}

        story_comments = {
            x.id: x for x in StoryComment.select(
                lambda x: x.id in story_comment_ids
            ).prefetch(StoryComment.story)
        } if story_comment_ids else {}

        local_comments = {
            x.id: x for x in StoryLocalComment.select(
                lambda x: x.id in local_comment_ids
            ).prefetch(StoryLocalComment.local, StoryLocalThread.story)
        } if local_comment_ids else {}

        news_comments = {
            x.id: x for x in NewsComment.select(
                lambda x: x.id in news_comment_ids
            ).prefetch(NewsComment.newsitem)
        } if news_comment_ids else {}

        # Преобразуем каждое уведомление в json-совместимый формат со всеми дополнениями
        for n in items:
            item = {
                'id': n.id,
                'created_at': n.created_at,
                'type': n.type,
                'viewed': n.id <= user.last_viewed_notification_id,
                'user': {
                    'id': n.caused_by_user.id,
                    'username': n.caused_by_user.username,
                    'is_staff': n.caused_by_user.is_staff,
                } if n.caused_by_user else None,
                'extra': json.loads(n.extra or '{}'),
            }

            if n.type in ('story_publish', 'story_draft', 'author_story'):
                if n.target_id not in stories:
                    item['broken'] = True
                    result.append(item)
                    continue
                item['story'] = {
                    'id': n.target_id,
                    'title': stories[n.target_id].title,
                }
                if n.type == 'author_story':
                    item['story']['words'] = stories[n.target_id].words
                    item['story']['authors'] = [{'id': x.id, 'username': x.username} for x in stories[n.target_id].authors]

            elif n.type == 'story_chapter':
                c = chapters.get(n.target_id)
                if not c:
                    item['broken'] = True
                    result.append(item)
                    continue

                item['story'] = {'id': c.story.id, 'title': c.story.title}
                item['chapter'] = {'id': c.id, 'order': c.order, 'title': c.title, 'autotitle': c.autotitle, 'words': c.words}

            elif n.type in ('story_reply', 'story_comment', 'story_lreply', 'story_lcomment', 'news_reply', 'news_comment'):
                if n.type in ('story_reply', 'story_comment'):
                    c = story_comments.get(n.target_id)
                elif n.type in ('story_lreply', 'story_lcomment'):
                    c = local_comments.get(n.target_id)
                elif n.type in ('news_reply', 'news_comment'):
                    c = news_comments.get(n.target_id)

                if not c:
                    item['broken'] = True
                    result.append(item)
                    continue

                if c.deleted and not user.is_staff:
                    item['comment'] = {
                        'id': c.id,
                        'local_id': c.local_id,
                        'permalink': c.bl.get_permalink(),
                        'can_vote': c.bl.can_vote,
                        'deleted': True,
                    }
                else:
                    item['comment'] = {
                        'id': c.id,
                        'local_id': c.local_id,
                        'permalink': c.bl.get_permalink(),
                        'date': c.date,
                        'brief_text_as_html': str(c.brief_text_as_html),
                        'can_vote': c.bl.can_vote,
                        'deleted': c.deleted,
                        'author': {
                            'id': c.author.id if c.author else None,
                            'username': c.author.username if c.author else c.author_username,
                        }
                    }
                    if hasattr(c, 'vote_total'):
                        item['comment']['vote_total'] = c.vote_total

                if n.type in ('story_reply', 'story_comment'):
                    item['story'] = {'id': c.story.id, 'title': c.story.title}
                elif n.type in ('story_lreply', 'story_lcomment'):
                    item['story'] = {'id': c.local.story.id, 'title': c.local.story.title}
                elif n.type in ('news_reply', 'news_comment'):
                    item['newsitem'] = {'id': c.newsitem.id, 'name': c.newsitem.name, 'title': c.newsitem.title}

            result.append(item)

        if older is None and offset == 0 and count >= 101:
            current_app.cache.set('bell_content_{}'.format(user.id), result[:101], 600)
        return result
Esempio n. 10
0
    def get_notifications(self, older=None, offset=0, count=50):
        from mini_fiction.models import Notification, Story, Chapter, StoryComment, StoryLocalThread, StoryLocalComment, NewsComment

        user = self.model

        if older is None and offset == 0 and count <= 101:
            result = current_app.cache.get('bell_content_{}'.format(user.id))
            if result is not None:
                return result[:count]

        result = []

        # Забираем уведомления
        items = user.notifications.filter(
            lambda x: x.id < older
        ) if older is not None else user.notifications
        items = items.order_by(Notification.id.desc()).prefetch(
            Notification.caused_by_user)[offset:offset + count]

        # Группируем таргеты по типам, чтобы брать их одним sql-запросом
        story_ids = set()
        chapter_ids = set()
        story_comment_ids = set()
        local_comment_ids = set()
        news_comment_ids = set()
        for n in items:
            if n.type in ('story_publish', 'story_draft', 'author_story'):
                story_ids.add(n.target_id)
            elif n.type == 'story_chapter':
                chapter_ids.add(n.target_id)
            elif n.type in ('story_reply', 'story_comment'):
                story_comment_ids.add(n.target_id)
            elif n.type in ('story_lreply', 'story_lcomment'):
                local_comment_ids.add(n.target_id)
            elif n.type in ('news_reply', 'news_comment'):
                news_comment_ids.add(n.target_id)

        # И забираем все эти таргеты
        stories = {x.id: x
                   for x in Story.select(lambda x: x.id in story_ids)
                   } if story_ids else {}

        chapters = {
            x.id: x
            for x in Chapter.select(lambda x: x.id in chapter_ids)
        } if chapter_ids else {}

        story_comments = {
            x.id: x
            for x in StoryComment.select(lambda x: x.id in story_comment_ids).
            prefetch(StoryComment.story)
        } if story_comment_ids else {}

        local_comments = {
            x.id: x
            for x in StoryLocalComment.select(
                lambda x: x.id in local_comment_ids).prefetch(
                    StoryLocalComment.local, StoryLocalThread.story)
        } if local_comment_ids else {}

        news_comments = {
            x.id: x
            for x in NewsComment.select(lambda x: x.id in news_comment_ids).
            prefetch(NewsComment.newsitem)
        } if news_comment_ids else {}

        # Преобразуем каждое уведомление в json-совместимый формат со всеми дополнениями
        for n in items:
            item = {
                'id': n.id,
                'created_at': n.created_at,
                'type': n.type,
                'viewed': n.id <= user.last_viewed_notification_id,
                'user': {
                    'id': n.caused_by_user.id,
                    'username': n.caused_by_user.username,
                    'is_staff': n.caused_by_user.is_staff,
                } if n.caused_by_user else None,
                'extra': json.loads(n.extra or '{}'),
            }

            if n.type in ('story_publish', 'story_draft', 'author_story'):
                if n.target_id not in stories:
                    item['broken'] = True
                    result.append(item)
                    continue
                item['story'] = {
                    'id': n.target_id,
                    'title': stories[n.target_id].title,
                }
                if n.type == 'author_story':
                    item['story']['words'] = stories[n.target_id].words
                    item['story']['authors'] = [{
                        'id': x.id,
                        'username': x.username
                    } for x in stories[n.target_id].authors]

            elif n.type == 'story_chapter':
                c = chapters.get(n.target_id)
                if not c:
                    item['broken'] = True
                    result.append(item)
                    continue

                item['story'] = {'id': c.story.id, 'title': c.story.title}
                item['chapter'] = {
                    'id': c.id,
                    'order': c.order,
                    'title': c.title,
                    'autotitle': c.autotitle,
                    'words': c.words
                }

            elif n.type in ('story_reply', 'story_comment', 'story_lreply',
                            'story_lcomment', 'news_reply', 'news_comment'):
                if n.type in ('story_reply', 'story_comment'):
                    c = story_comments.get(n.target_id)
                elif n.type in ('story_lreply', 'story_lcomment'):
                    c = local_comments.get(n.target_id)
                elif n.type in ('news_reply', 'news_comment'):
                    c = news_comments.get(n.target_id)

                if not c:
                    item['broken'] = True
                    result.append(item)
                    continue

                if c.deleted and not user.is_staff:
                    item['comment'] = {
                        'id': c.id,
                        'local_id': c.local_id,
                        'permalink': c.bl.get_permalink(),
                        'can_vote': c.bl.can_vote,
                        'deleted': True,
                    }
                else:
                    item['comment'] = {
                        'id': c.id,
                        'local_id': c.local_id,
                        'permalink': c.bl.get_permalink(),
                        'date': c.date,
                        'brief_text_as_html': str(c.brief_text_as_html),
                        'can_vote': c.bl.can_vote,
                        'deleted': c.deleted,
                        'author': {
                            'id':
                            c.author.id if c.author else None,
                            'username':
                            c.author.username
                            if c.author else c.author_username,
                        }
                    }
                    if hasattr(c, 'vote_total'):
                        item['comment']['vote_total'] = c.vote_total

                if n.type in ('story_reply', 'story_comment'):
                    item['story'] = {'id': c.story.id, 'title': c.story.title}
                elif n.type in ('story_lreply', 'story_lcomment'):
                    item['story'] = {
                        'id': c.local.story.id,
                        'title': c.local.story.title
                    }
                elif n.type in ('news_reply', 'news_comment'):
                    item['newsitem'] = {
                        'id': c.newsitem.id,
                        'name': c.newsitem.name,
                        'title': c.newsitem.title
                    }

            result.append(item)

        if older is None and offset == 0 and count >= 101:
            current_app.cache.set('bell_content_{}'.format(user.id),
                                  result[:101], 600)
        return result
Esempio n. 11
0
def abuse_storycomment(story_id, local_id):
    story = get_story(story_id)  # Здесь проверка доступа
    return abuse_common('storycomment', StoryComment.get(story=story.id, local_id=local_id, deleted=False))
Esempio n. 12
0
def abuse_storycomment(story_id, local_id):
    story = get_story(story_id)  # Здесь проверка доступа
    return abuse_common(
        'storycomment',
        StoryComment.get(story=story.id, local_id=local_id, deleted=False))
Esempio n. 13
0
def vote(story_id, local_id):
    comment = StoryComment.get(story=story_id, local_id=local_id, deleted=False)
    if not comment:
        abort(404)

    return common_comment.vote('story', comment)
Esempio n. 14
0
def info(user_id=None, comments_page=1):
    if user_id is not None:
        try:
            user_id = int(user_id)
        except ValueError:
            abort(404)

    data = {}

    if user_id is None:
        if not current_user.is_authenticated:
            abort(403)
        author = current_user._get_current_object()
        comments_list = StoryComment.bl.select_by_story_author(author)
        comments_list = comments_list.order_by(StoryComment.id.desc())
        stories = list(author.stories)
        stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True)
        contributing_stories = list(author.contributing_stories)
        contributing_stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True)

        data['all_views'] = Story.bl.get_all_views_for_author(author)

        data['page_title'] = gettext('My cabinet')
        template = 'author_dashboard.html'
    else:
        author = Author.get(id=user_id)
        if not author:
            abort(404)
        author_id = author.id  # обход утечки памяти
        comments_list = StoryComment.select(lambda x: x.author.id == author_id and not x.deleted and x.story_published)
        comments_list = comments_list.order_by(StoryComment.id.desc())
        data['page_title'] = gettext('Author: {author}').format(author=author.username)
        stories = list(Story.bl.select_by_author(author, for_user=current_user))
        stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True)
        contributing_stories = None
        template = 'author_overview.html'

    comments_count = comments_list.count()
    series = list(author.series)
    paged = Paginator(
        number=comments_page,
        total=comments_count,
        per_page=current_app.config['COMMENTS_COUNT']['author_page'],
        page_arg_name='comments_page',
    )  # TODO: restore orphans?
    comments = paged.slice(comments_list)
    if not comments and comments_page != 1:
        abort(404)

    data.update({
        'author': author,
        'is_system_user': author.id == current_app.config['SYSTEM_USER_ID'],
        'sub': author.bl.get_stories_subscription(current_user._get_current_object()),
        'stories': stories,
        'contributing_stories': contributing_stories,
        'series': series,
        'comments': comments,
        'comments_count': comments_count,
        'comments_short': True,
        'page_obj': paged,
    })

    story_ids = set(x.id for x in stories)
    if contributing_stories:
        story_ids |= set(x.id for x in contributing_stories)
    story_ids |= set(x.story.id for x in comments)

    data.update(cached_lists(story_ids))

    return render_template(template, **data)
Esempio n. 15
0
def info(user_id=None, comments_page=1):
    if user_id is not None:
        try:
            user_id = int(user_id)
        except ValueError:
            abort(404)

    data = {}

    if user_id is None:
        if not current_user.is_authenticated:
            abort(403)
        author = current_user._get_current_object()
        comments_list = StoryComment.bl.select_by_story_author(author)
        comments_list = comments_list.order_by(StoryComment.id.desc())
        stories = list(author.stories)
        stories.sort(key=lambda x: x.first_published_at or x.date,
                     reverse=True)
        contributing_stories = list(author.contributing_stories)
        contributing_stories.sort(key=lambda x: x.first_published_at or x.date,
                                  reverse=True)

        data['all_views'] = Story.bl.get_all_views_for_author(author)

        data['page_title'] = gettext('My cabinet')
        template = 'author_dashboard.html'
    else:
        author = Author.get(id=user_id)
        if not author:
            abort(404)
        author_id = author.id  # обход утечки памяти
        comments_list = StoryComment.select(
            lambda x: x.author.id == author_id and not x.deleted and x.
            story_published)
        comments_list = comments_list.order_by(StoryComment.id.desc())
        data['page_title'] = gettext('Author: {author}').format(
            author=author.username)
        stories = list(Story.bl.select_by_author(author,
                                                 for_user=current_user))
        stories.sort(key=lambda x: x.first_published_at or x.date,
                     reverse=True)
        contributing_stories = None
        template = 'author_overview.html'

    comments_count = comments_list.count()
    series = list(author.series)
    paged = Paginator(
        number=comments_page,
        total=comments_count,
        per_page=current_app.config['COMMENTS_COUNT']['author_page'],
        page_arg_name='comments_page',
    )  # TODO: restore orphans?
    comments = paged.slice(comments_list)
    if not comments and comments_page != 1:
        abort(404)

    data.update({
        'author':
        author,
        'is_system_user':
        author.id == current_app.config['SYSTEM_USER_ID'],
        'sub':
        author.bl.get_stories_subscription(current_user._get_current_object()),
        'stories':
        stories,
        'contributing_stories':
        contributing_stories,
        'series':
        series,
        'comments':
        comments,
        'comments_count':
        comments_count,
        'comments_short':
        True,
        'page_obj':
        paged,
    })

    story_ids = set(x.id for x in stories)
    if contributing_stories:
        story_ids |= set(x.id for x in contributing_stories)
    story_ids |= set(x.story.id for x in comments)

    data.update(cached_lists(story_ids))

    return render_template(template, **data)