def handle(self, *args, **options):
        SearchIndex.objects.all().delete()
        indexed_comment_count = 0
        indexed_post_count = 0
        indexed_user_count = 0

        for chunk in chunked_queryset(
            Comment.visible_objects().filter(is_deleted=False, post__is_visible=True)
        ):
            for comment in chunk:
                self.stdout.write(f"Indexing comment: {comment.id}")
                SearchIndex.update_comment_index(comment)
                indexed_comment_count += 1

        for chunk in chunked_queryset(
            Post.visible_objects().filter(is_shadow_banned=False)
        ):
            for post in chunk:
                self.stdout.write(f"Indexing post: {post.slug}")
                SearchIndex.update_post_index(post)
                indexed_post_count += 1

        for chunk in chunked_queryset(
            User.objects.filter(moderation_status=User.MODERATION_STATUS_APPROVED)
        ):
            for user in chunk:
                self.stdout.write(f"Indexing user: {user.slug}")
                SearchIndex.update_user_index(user)
                SearchIndex.update_user_tags(user)
                indexed_user_count += 1

        self.stdout.write(
            f"Done 🥙 "
            f"Comments: {indexed_comment_count} Posts: {indexed_post_count} Users: {indexed_user_count}"
        )
Esempio n. 2
0
def bookmarks(request):
    user = request.me

    posts = Post.visible_objects().filter(
        bookmarks__user=user).order_by('-bookmarks__created_at').all()

    return render(request, "bookmarks.html", {
        "posts": paginate(request, posts),
    })
Esempio n. 3
0
def command_top(update: Update, context: CallbackContext) -> None:
    # Top posts
    top_posts = Post.visible_objects()\
        .filter(published_at__gte=datetime.utcnow() - TOP_TIMEDELTA)\
        .filter(Q(is_approved_by_moderator=True) | Q(upvotes__gte=settings.COMMUNITY_APPROVE_UPVOTES)) \
         .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST])\
        .order_by("-upvotes")[:5]

    # Hot posts
    hot_posts = Post.visible_objects()\
        .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST]) \
        .exclude(id__in=[p.id for p in top_posts]) \
        .order_by("-hotness")[:3]

    # Top intros
    top_intros = Post.visible_objects()\
        .filter(type=Post.TYPE_INTRO, published_at__gte=datetime.utcnow() - TOP_TIMEDELTA)\
        .select_related("author")\
        .order_by("-upvotes")[:3]

    # Top comments
    top_comment = Comment.visible_objects() \
        .filter(created_at__gte=datetime.utcnow() - TOP_TIMEDELTA) \
        .filter(is_deleted=False)\
        .exclude(post__type=Post.TYPE_BATTLE) \
        .select_related("author") \
        .order_by("-upvotes") \
        .first()

    update.effective_chat.send_message(
        render_html_message(
            template="top.html",
            top_posts=top_posts,
            hot_posts=hot_posts,
            top_intros=top_intros,
            top_comment=top_comment,
        ),
        parse_mode=ParseMode.HTML,
        disable_web_page_preview=True,
    )
    def handle(self, *args, **options):
        new_posts = Post.visible_objects()\
            .filter(
                is_approved_by_moderator=True,
                published_at__gte=datetime.utcnow() - timedelta(hours=24),
            )\
            .exclude(type=Post.TYPE_INTRO)\
            .order_by("-upvotes")[:6]

        send_telegram_message(
            chat=ADMIN_CHAT,
            text=render_html_message("good_morning.html",
                                     posts=new_posts,
                                     greetings=random.choice(DUMB_GREETINGS)),
        )

        self.stdout.write("Done 🥙")
Esempio n. 5
0
    def handle(self, *args, **options):
        LinkedPost.objects.all().delete()

        posts = Post.visible_objects().exclude(
            type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST])
        for post in posts:
            print(f"Parsing post: {post.slug}")
            LinkedPost.create_links_from_text(post, post.text)

        del posts

        comments = Comment.visible_objects()
        for comment in comments:
            print(f"Parsing comment: {comment.id}")
            LinkedPost.create_links_from_text(comment.post, comment.text)

        print("Done 🥙")
Esempio n. 6
0
    def handle(self, *args, **options):
        SearchIndex.objects.all().delete()

        for comment in Comment.visible_objects().filter(is_deleted=False,
                                                        post__is_visible=True):
            self.stdout.write(f"Indexing comment: {comment.id}")
            SearchIndex.update_comment_index(comment)

        for post in Post.visible_objects().filter(is_shadow_banned=False):
            self.stdout.write(f"Indexing post: {post.slug}")
            SearchIndex.update_post_index(post)

        for user in User.objects.filter(
                moderation_status=User.MODERATION_STATUS_APPROVED):
            self.stdout.write(f"Indexing user: {user.slug}")
            SearchIndex.update_user_index(user)
            SearchIndex.update_user_tags(user)

        self.stdout.write("Done 🥙")
Esempio n. 7
0
def command_random(update: Update, context: CallbackContext) -> None:
    post = None
    attempt = 0

    while not post and attempt < 5:
        attempt += 1
        random_date = settings.LAUNCH_DATE + timedelta(
            seconds=randint(0, int((datetime.utcnow() - settings.LAUNCH_DATE).total_seconds())),
        )

        post = Post.visible_objects() \
            .filter(published_at__lte=random_date, published_at__gte=random_date - timedelta(days=2)) \
            .filter(is_approved_by_moderator=True) \
            .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST]) \
            .order_by("?") \
            .first()

    update.effective_chat.send_message(
        render_html_message("channel_post_announce.html", post=post),
        parse_mode=ParseMode.HTML,
        disable_web_page_preview=True,
    )
Esempio n. 8
0
def weekly_digest(request):
    end_date = datetime.utcnow()
    start_date = end_date - timedelta(days=7)

    if settings.DEBUG:
        start_date = end_date - timedelta(days=1000)

    created_at_condition = dict(created_at__gte=start_date,
                                created_at__lte=end_date)
    published_at_condition = dict(published_at__gte=start_date,
                                  published_at__lte=end_date)

    # New users
    intros = Post.visible_objects()\
        .filter(type=Post.TYPE_INTRO, **published_at_condition)\
        .order_by("-upvotes")

    newbie_count = User.objects\
        .filter(
            moderation_status=User.MODERATION_STATUS_APPROVED,
            **created_at_condition
        )\
        .count()

    # Best posts
    featured_post = Post.visible_objects()\
        .exclude(type=Post.TYPE_INTRO)\
        .filter(
            label__isnull=False,
            label__code="top_week",
            **published_at_condition
         )\
        .order_by("-upvotes")\
        .first()

    posts = Post.visible_objects()\
        .filter(is_approved_by_moderator=True, **published_at_condition)\
        .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST])\
        .exclude(id=featured_post.id if featured_post else None)\
        .exclude(label__isnull=False, label__code="ad")\
        .exclude(is_shadow_banned=True)\
        .order_by("-upvotes")

    post_count = posts.count()
    posts = posts[:12]

    # Video of the week
    top_video_comment = Comment.visible_objects()\
        .filter(**created_at_condition)\
        .filter(is_deleted=False)\
        .filter(upvotes__gte=3)\
        .filter(Q(text__contains="https://youtu.be/") | Q(text__contains="youtube.com/watch"))\
        .order_by("-upvotes")\
        .first()

    top_video_post = None
    if not top_video_comment:
        top_video_post = Post.visible_objects() \
            .filter(type=Post.TYPE_LINK, upvotes__gte=3) \
            .filter(**published_at_condition) \
            .filter(Q(url__contains="https://youtu.be/") | Q(url__contains="youtube.com/watch")) \
            .order_by("-upvotes") \
            .first()

    # Best comments
    comments = Comment.visible_objects() \
        .filter(**created_at_condition) \
        .filter(is_deleted=False)\
        .exclude(post__type=Post.TYPE_BATTLE)\
        .exclude(post__is_visible=False)\
        .exclude(id=top_video_comment.id if top_video_comment else None)\
        .order_by("-upvotes")[:3]

    # Intro from author
    author_intro = GodSettings.objects.first().digest_intro

    if not author_intro and not posts and not comments:
        raise Http404()

    # New achievements
    achievements = UserAchievement.objects\
        .filter(**created_at_condition)\
        .select_related("user", "achievement")\
        .order_by("achievement")  # required for grouping

    # Exclude footer for archive
    is_footer_excluded = "no_footer" in request.GET

    return render(
        request, "emails/weekly.html", {
            "posts": posts,
            "comments": comments,
            "intros": intros,
            "achievements": achievements,
            "newbie_count": newbie_count,
            "post_count": post_count,
            "top_video_comment": top_video_comment,
            "top_video_post": top_video_post,
            "featured_post": featured_post,
            "author_intro": author_intro,
            "issue_number": (end_date - settings.LAUNCH_DATE).days // 7,
            "is_footer_excluded": is_footer_excluded
        })
Esempio n. 9
0
def daily_digest(request, user_slug):
    user = get_object_or_404(User, slug=user_slug)

    end_date = datetime.utcnow()
    start_date = end_date - timedelta(days=1)
    if end_date.weekday() == 1:
        # we don't have daily on sundays and mondays, we need to include all these posts at tuesday
        start_date = end_date - timedelta(days=3)

    if settings.DEBUG:
        start_date = end_date - timedelta(days=1000)

    created_at_condition = dict(created_at__gte=start_date,
                                created_at__lte=end_date)
    published_at_condition = dict(published_at__gte=start_date,
                                  published_at__lte=end_date)

    # Moon
    moon_phase = parse_horoscope()

    # New actions
    subscription_comments = Comment.visible_objects()\
        .filter(
            post__subscriptions__user=user,
            **created_at_condition
        )\
        .values("post__type", "post__slug", "post__title", "post__author_id")\
        .annotate(count=Count("id"))\
        .order_by()

    replies = Comment.visible_objects()\
        .filter(
            reply_to__author=user,
            **created_at_condition
        )\
        .values("post__type", "post__slug", "post__title")\
        .annotate(count=Count("reply_to_id"))\
        .order_by()

    new_events = [{
        "type":
        "my_post_comment",
        "post_url":
        reverse("show_post",
                kwargs={
                    "post_type": e["post__type"],
                    "post_slug": e["post__slug"]
                }),
        "post_title":
        e["post__title"],
        "count":
        e["count"],
    } for e in subscription_comments if e["post__author_id"] == user.id] + [{
        "type":
        "subscribed_post_comment",
        "post_url":
        reverse("show_post",
                kwargs={
                    "post_type": e["post__type"],
                    "post_slug": e["post__slug"]
                }),
        "post_title":
        e["post__title"],
        "count":
        e["count"],
    } for e in subscription_comments if e["post__author_id"] != user.id] + [{
        "type":
        "reply",
        "post_url":
        reverse("show_post",
                kwargs={
                    "post_type": e["post__type"],
                    "post_slug": e["post__slug"]
                }),
        "post_title":
        e["post__title"],
        "count":
        e["count"],
    } for e in replies]

    upvotes = PostVote.objects.filter(post__author=user, **created_at_condition).count() \
        + CommentVote.objects.filter(comment__author=user, **created_at_condition).count()

    if upvotes:
        new_events = [{
            "type": "upvotes",
            "count": upvotes,
        }] + new_events

    # Mentions
    mentions = Comment.visible_objects() \
        .filter(**created_at_condition) \
        .filter(text__regex=fr"@\y{user.slug}\y", is_deleted=False)\
        .exclude(reply_to__author=user)\
        .order_by("-upvotes")[:5]

    # Best posts
    posts = Post.visible_objects()\
        .filter(is_approved_by_moderator=True, **published_at_condition)\
        .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST])\
        .exclude(is_shadow_banned=True)\
        .order_by("-upvotes")[:100]

    # New joiners
    intros = Post.visible_objects()\
        .filter(type=Post.TYPE_INTRO, **published_at_condition)\
        .order_by("-upvotes")

    if not posts and not mentions and not intros:
        raise Http404()

    return render(
        request, "emails/daily.html", {
            "user": user,
            "events": new_events,
            "intros": intros,
            "posts": posts,
            "mentions": mentions,
            "date": end_date,
            "moon_phase": moon_phase,
        })
Esempio n. 10
0
 def items(self):
     return Post.visible_objects()\
        .filter(is_approved_by_moderator=True)\
        .exclude(type=Post.TYPE_INTRO)\
        .order_by("-published_at", "-created_at")[:self.limit]
Esempio n. 11
0
def generate_daily_digest(user):
    end_date = datetime.utcnow()
    start_date = end_date - timedelta(days=1)
    if end_date.weekday() == 1:
        # we don't have daily on sundays and mondays, we need to include all these posts at tuesday
        start_date = end_date - timedelta(days=3)

    if settings.DEBUG:
        start_date = end_date - timedelta(days=1000)

    created_at_condition = dict(created_at__gte=start_date, created_at__lte=end_date)
    published_at_condition = dict(published_at__gte=start_date, published_at__lte=end_date)

    # Moon
    moon_phase = parse_horoscope()

    # New actions
    subscription_comments = Comment.visible_objects()\
        .filter(
            post__subscriptions__user=user,
            **created_at_condition
        )\
        .values("post__type", "post__slug", "post__title", "post__author_id")\
        .annotate(count=Count("id"))\
        .order_by()

    replies = Comment.visible_objects()\
        .filter(
            reply_to__author=user,
            **created_at_condition
        )\
        .values("post__type", "post__slug", "post__title")\
        .annotate(count=Count("reply_to_id"))\
        .order_by()

    new_events = [
        {
            "type": "my_post_comment",
            "post_url": reverse("show_post", kwargs={"post_type": e["post__type"], "post_slug": e["post__slug"]}),
            "post_title": e["post__title"],
            "count": e["count"],
        } for e in subscription_comments if e["post__author_id"] == user.id
    ] + [
        {
            "type": "subscribed_post_comment",
            "post_url": reverse("show_post", kwargs={"post_type": e["post__type"], "post_slug": e["post__slug"]}),
            "post_title": e["post__title"],
            "count": e["count"],
        } for e in subscription_comments if e["post__author_id"] != user.id
    ] + [
        {
            "type": "reply",
            "post_url": reverse("show_post", kwargs={"post_type": e["post__type"], "post_slug": e["post__slug"]}),
            "post_title": e["post__title"],
            "count": e["count"],
        } for e in replies
    ]

    upvotes = PostVote.objects.filter(post__author=user, **created_at_condition).count() \
        + CommentVote.objects.filter(comment__author=user, **created_at_condition).count()

    if upvotes:
        new_events = [
            {
                "type": "upvotes",
                "count": upvotes,
            }
        ] + new_events

    # Mentions
    mentions = Comment.visible_objects() \
        .filter(**created_at_condition) \
        .filter(text__regex=fr"@\y{user.slug}\y", is_deleted=False)\
        .exclude(reply_to__author=user)\
        .order_by("-upvotes")[:5]

    # Best posts
    posts = Post.visible_objects()\
        .filter(**published_at_condition)\
        .filter(Q(is_approved_by_moderator=True) | Q(upvotes__gte=settings.COMMUNITY_APPROVE_UPVOTES))\
        .filter(is_visible_in_feeds=True)\
        .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST])\
        .exclude(is_shadow_banned=True)\
        .order_by("-upvotes")[:100]

    # New joiners
    intros = Post.visible_objects()\
        .filter(type=Post.TYPE_INTRO, **published_at_condition)\
        .order_by("-upvotes")

    if not posts and not mentions and not intros:
        raise NotFound()

    og_params = urlencode({
        **settings.OG_IMAGE_GENERATOR_DEFAULTS,
        "title": f"Ежедневный дайджест пользователя {user.slug}",
        "author": "THE MACHINE",
        "ava": settings.OG_MACHINE_AUTHOR_LOGO
    })

    return render_to_string("emails/daily.html", {
        "user": user,
        "events": new_events,
        "intros": intros,
        "posts": posts,
        "mentions": mentions,
        "date": end_date,
        "moon_phase": moon_phase,
        "og_image_url": f"{settings.OG_IMAGE_GENERATOR_URL}?{og_params}"
    })
Esempio n. 12
0
def generate_weekly_digest(no_footer=False):
    end_date = datetime.utcnow()
    start_date = end_date - timedelta(days=8)

    if settings.DEBUG:
        start_date = end_date - timedelta(days=1000)

    created_at_condition = dict(created_at__gte=start_date, created_at__lte=end_date)
    published_at_condition = dict(published_at__gte=start_date, published_at__lte=end_date)

    # New users
    intros = Post.visible_objects()\
        .filter(type=Post.TYPE_INTRO, **published_at_condition)\
        .order_by("-upvotes")

    newbie_count = User.objects\
        .filter(
            moderation_status=User.MODERATION_STATUS_APPROVED,
            **created_at_condition
        )\
        .count()

    # Best posts
    featured_post = Post.visible_objects()\
        .exclude(type=Post.TYPE_INTRO)\
        .filter(
            label_code__isnull=False,
            label_code="top_week",
            **published_at_condition
         )\
        .order_by("-upvotes")\
        .first()

    posts = Post.visible_objects()\
        .filter(**published_at_condition)\
        .filter(Q(is_approved_by_moderator=True) | Q(upvotes__gte=settings.COMMUNITY_APPROVE_UPVOTES))\
        .filter(is_visible_in_feeds=True)\
        .exclude(type__in=[Post.TYPE_INTRO, Post.TYPE_WEEKLY_DIGEST])\
        .exclude(id=featured_post.id if featured_post else None)\
        .exclude(label_code__isnull=False, label_code="ad")\
        .exclude(is_shadow_banned=True)\
        .order_by("-upvotes")

    post_count = posts.count()
    posts = posts[:12]

    # Video of the week
    top_video_comment = Comment.visible_objects()\
        .filter(**created_at_condition)\
        .filter(is_deleted=False)\
        .filter(upvotes__gte=3)\
        .filter(Q(text__contains="https://youtu.be/") | Q(text__contains="youtube.com/watch"))\
        .order_by("-upvotes")\
        .first()

    top_video_post = None
    if not top_video_comment:
        top_video_post = Post.visible_objects() \
            .filter(type=Post.TYPE_LINK, upvotes__gte=3) \
            .filter(**published_at_condition) \
            .filter(Q(url__contains="https://youtu.be/") | Q(url__contains="youtube.com/watch")) \
            .order_by("-upvotes") \
            .first()

    # Best comments
    comments = Comment.visible_objects() \
        .filter(**created_at_condition) \
        .filter(is_deleted=False)\
        .exclude(post__type=Post.TYPE_BATTLE)\
        .exclude(post__is_visible=False)\
        .exclude(post__is_visible_in_feeds=False)\
        .exclude(id=top_video_comment.id if top_video_comment else None)\
        .order_by("-upvotes")[:3]

    # Get intro and title
    god_settings = GodSettings.objects.first()
    digest_title = god_settings.digest_title
    digest_intro = god_settings.digest_intro

    if not digest_intro and not posts and not comments:
        raise NotFound()

    # New achievements
    achievements = UserAchievement.objects\
        .filter(**created_at_condition)\
        .select_related("user", "achievement")\
        .order_by("achievement")  # required for grouping

    issue_number = (end_date - settings.LAUNCH_DATE).days // 7

    og_params = urlencode({
        **settings.OG_IMAGE_GENERATOR_DEFAULTS,
        "title": f"Клубный журнал. Итоги недели. Выпуск #{issue_number}.",
        "author": "THE MACHINE",
        "ava": settings.OG_MACHINE_AUTHOR_LOGO
    })

    return render_to_string("emails/weekly.html", {
        "posts": posts,
        "comments": comments,
        "intros": intros,
        "achievements": achievements,
        "newbie_count": newbie_count,
        "post_count": post_count,
        "top_video_comment": top_video_comment,
        "top_video_post": top_video_post,
        "featured_post": featured_post,
        "digest_title": digest_title,
        "digest_intro": digest_intro,
        "issue_number": issue_number,
        "is_footer_excluded": no_footer,
        "og_image_url": f"{settings.OG_IMAGE_GENERATOR_URL}?{og_params}"
    })
Esempio n. 13
0
 def create_links_from_text(cls, post_from, text):
     links = CLUB_POST_URL_RE.findall(text)
     for post_slug in links:
         post_to = Post.visible_objects().filter(slug=post_slug).first()
         if post_to:
             cls.link(post_from.author, post_from, post_to)
Esempio n. 14
0
def feed(request, post_type=POST_TYPE_ALL, topic_slug=None, label_code=None, ordering=ORDERING_ACTIVITY):
    post_type = post_type or Post

    if request.me:
        request.me.update_last_activity()
        posts = Post.objects_for_user(request.me)
    else:
        posts = Post.visible_objects()

    # filter posts by type
    if post_type != POST_TYPE_ALL:
        posts = posts.filter(type=post_type)

    # filter by topic
    topic = None
    if topic_slug:
        topic = get_object_or_404(Topic, slug=topic_slug)
        posts = posts.filter(topic=topic)

    # filter by label
    if label_code:
        posts = posts.filter(label_code=label_code)

    # hide muted users
    if request.me:
        muted = Muted.objects.filter(user_from=request.me).values_list("user_to_id").all()
        if muted:
            posts = posts.exclude(author_id__in=muted)

    # hide non-public posts and intros from unauthorized users
    if not request.me:
        posts = posts.exclude(is_public=False).exclude(type=Post.TYPE_INTRO)

    # exclude shadow banned posts, but show them in "new" tab
    if ordering != ORDERING_NEW:
        if request.me:
            posts = posts.exclude(Q(is_shadow_banned=True) & ~Q(author_id=request.me.id))
        else:
            posts = posts.exclude(is_shadow_banned=True)

    # hide no-feed posts (show only inside rooms and topics)
    if not topic and not label_code:
        posts = posts.filter(is_visible_in_feeds=True)

    # order posts by some metric
    if ordering:
        if ordering == ORDERING_ACTIVITY:
            posts = posts.order_by("-last_activity_at")
        elif ordering == ORDERING_NEW:
            posts = posts.order_by("-published_at", "-created_at")
        elif ordering == ORDERING_TOP:
            posts = posts.order_by("-upvotes")
        elif ordering == ORDERING_HOT:
            posts = posts.order_by("-hotness")
        elif ordering == ORDERING_TOP_WEEK:
            posts = posts.filter(
                published_at__gte=datetime.utcnow() - timedelta(days=7)
            ).order_by("-upvotes")
        elif ordering == ORDERING_TOP_MONTH:
            posts = posts.filter(
                published_at__gte=datetime.utcnow() - timedelta(days=31)
            ).order_by("-upvotes")
        elif ordering == ORDERING_TOP_YEAR:
            posts = posts.filter(
                published_at__gte=datetime.utcnow() - timedelta(days=365)
            ).order_by("-upvotes")
        else:
            raise Http404()

    # split results into pinned and unpinned posts on main page
    pinned_posts = []
    if ordering == ORDERING_ACTIVITY:
        pinned_posts = posts.filter(is_pinned_until__gte=datetime.utcnow())
        posts = posts.exclude(id__in=[p.id for p in pinned_posts])

    return render(request, "feed.html", {
        "post_type": post_type or POST_TYPE_ALL,
        "ordering": ordering,
        "topic": topic,
        "label_code": label_code,
        "posts": paginate(request, posts),
        "pinned_posts": pinned_posts,
        "date_month_ago": datetime.utcnow() - timedelta(days=30),
    })
Esempio n. 15
0
 def items(self):
     return Post.visible_objects().filter(is_public=True)
Esempio n. 16
0
def feed(request,
         post_type=POST_TYPE_ALL,
         topic_slug=None,
         ordering=ORDERING_ACTIVITY):
    post_type = post_type or Post

    if request.me:
        request.me.update_last_activity()
        posts = Post.objects_for_user(request.me)
    else:
        posts = Post.visible_objects()

    # filter posts by type
    if post_type != POST_TYPE_ALL:
        posts = posts.filter(type=post_type)

    # filter by topic
    topic = None
    if topic_slug:
        topic = get_object_or_404(Topic, slug=topic_slug)
        posts = posts.filter(topic=topic)

    # hide non-public posts and intros from unauthorized users
    if not request.me:
        posts = posts.exclude(is_public=False).exclude(type=Post.TYPE_INTRO)

    # exclude shadow banned posts, but show them in "new" tab
    if ordering != ORDERING_NEW:
        if request.me:
            posts = posts.exclude(
                Q(is_shadow_banned=True) & ~Q(author_id=request.me.id))
        else:
            posts = posts.exclude(is_shadow_banned=True)

    # no type and topic? probably it's the main page, let's apply some more filters
    if not topic and post_type == POST_TYPE_ALL:
        posts = posts.filter(is_visible_on_main_page=True)

    # order posts by some metric
    if ordering:
        if ordering == ORDERING_ACTIVITY:
            posts = posts.order_by("-last_activity_at")
        elif ordering == ORDERING_NEW:
            posts = posts.order_by("-published_at", "-created_at")
        elif ordering == ORDERING_TOP:
            posts = posts.order_by("-upvotes")
        elif ordering == ORDERING_TOP_WEEK:
            posts = posts.filter(published_at__gte=datetime.utcnow() -
                                 timedelta(days=7)).order_by("-upvotes")
        elif ordering == ORDERING_TOP_MONTH:
            posts = posts.filter(published_at__gte=datetime.utcnow() -
                                 timedelta(days=31)).order_by("-upvotes")
        else:
            raise Http404()

    # split results into pinned and unpinned posts on main page
    pinned_posts = []
    if ordering == ORDERING_ACTIVITY:
        pinned_posts = posts.filter(is_pinned_until__gte=datetime.utcnow())
        posts = posts.exclude(id__in=[p.id for p in pinned_posts])

    return render(
        request, "feed.html", {
            "post_type": post_type or POST_TYPE_ALL,
            "ordering": ordering,
            "topic": topic,
            "posts": paginate(request, posts),
            "pinned_posts": pinned_posts,
        })