From b2671e78ef63064ca059a1bbde13f11e1b93430b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 09:48:11 -0700 Subject: [PATCH 1/7] Moves privacy filter to model class --- bookwyrm/models/base_model.py | 73 ++++++++++++++++++++++++++++++++++- bookwyrm/views/helpers.py | 52 ------------------------- 2 files changed, 72 insertions(+), 53 deletions(-) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index ca32521a..cde181bd 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -2,8 +2,9 @@ import base64 from Crypto import Random -from django.core.exceptions import PermissionDenied +from django.core.exceptions import PermissionDenied, FieldError from django.db import models +from django.db.models import Q from django.dispatch import receiver from django.http import Http404 from django.utils.translation import gettext_lazy as _ @@ -105,6 +106,76 @@ class BookWyrmModel(models.Model): raise PermissionDenied() + @classmethod + def privacy_filter( + cls, viewer, privacy_levels=None, following_only=False, **filters + ): + """filter objects that have "user" and "privacy" fields""" + queryset = cls.objects + if hasattr(queryset, "select_subclasses"): + queryset = queryset.select_subclasses() + + privacy_levels = privacy_levels or ["public", "unlisted", "followers", "direct"] + # if there'd a deleted field, exclude deleted items + try: + queryset = queryset.filter(deleted=False) + except FieldError: + pass + + # exclude blocks from both directions + if not viewer.is_anonymous: + queryset = queryset.exclude( + Q(user__blocked_by=viewer) | Q(user__blocks=viewer) + ) + + # you can't see followers only or direct messages if you're not logged in + if viewer.is_anonymous: + privacy_levels = [ + p for p in privacy_levels if not p in ["followers", "direct"] + ] + + # filter to only privided privacy levels + queryset = queryset.filter(privacy__in=privacy_levels) + + # only include statuses the user follows + if following_only: + queryset = queryset.exclude( + ~Q( # remove everythign except + Q(user__followers=viewer) + | Q(user=viewer) # user following + | Q(mention_users=viewer) # is self # mentions user + ), + ) + # exclude followers-only statuses the user doesn't follow + elif "followers" in privacy_levels: + queryset = cls.followers_filter(queryset, viewer) + + # exclude direct messages not intended for the user + if "direct" in privacy_levels: + queryset = cls.direct_filter(queryset, viewer) + + return queryset + + @classmethod + def followers_filter(cls, queryset, viewer): + """Override-able filter for "followers" privacy level""" + return queryset.exclude( + ~Q( # user isn't following and it isn't their own status + Q(user__followers=viewer) | Q(user=viewer) + ), + privacy="followers", # and the status is followers only + ) + + @classmethod + def direct_filter(cls, queryset, viewer): + """Override-able filter for "direct" privacy level""" + try: + return queryset.exclude( + ~Q(Q(user=viewer) | Q(mention_users=viewer)), privacy="direct" + ) + except FieldError: + return queryset.exclude(~Q(user=viewer), privacy="direct") + @receiver(models.signals.post_save) # pylint: disable=unused-argument diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index 7e469f7f..f31b41ff 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -6,8 +6,6 @@ import dateutil.tz from dateutil.parser import ParserError from requests import HTTPError -from django.core.exceptions import FieldError -from django.db.models import Q from django.http import Http404 from bookwyrm import activitypub, models @@ -50,56 +48,6 @@ def is_bookwyrm_request(request): return True -def privacy_filter(viewer, queryset, privacy_levels=None, following_only=False): - """filter objects that have "user" and "privacy" fields""" - privacy_levels = privacy_levels or ["public", "unlisted", "followers", "direct"] - # if there'd a deleted field, exclude deleted items - try: - queryset = queryset.filter(deleted=False) - except FieldError: - pass - - # exclude blocks from both directions - if not viewer.is_anonymous: - queryset = queryset.exclude(Q(user__blocked_by=viewer) | Q(user__blocks=viewer)) - - # you can't see followers only or direct messages if you're not logged in - if viewer.is_anonymous: - privacy_levels = [p for p in privacy_levels if not p in ["followers", "direct"]] - - # filter to only privided privacy levels - queryset = queryset.filter(privacy__in=privacy_levels) - - # only include statuses the user follows - if following_only: - queryset = queryset.exclude( - ~Q( # remove everythign except - Q(user__followers=viewer) - | Q(user=viewer) # user following - | Q(mention_users=viewer) # is self # mentions user - ), - ) - # exclude followers-only statuses the user doesn't follow - elif "followers" in privacy_levels: - queryset = queryset.exclude( - ~Q( # user isn't following and it isn't their own status - Q(user__followers=viewer) | Q(user=viewer) - ), - privacy="followers", # and the status is followers only - ) - - # exclude direct messages not intended for the user - if "direct" in privacy_levels: - try: - queryset = queryset.exclude( - ~Q(Q(user=viewer) | Q(mention_users=viewer)), privacy="direct" - ) - except FieldError: - queryset = queryset.exclude(~Q(user=viewer), privacy="direct") - - return queryset - - def handle_remote_webfinger(query): """webfingerin' other servers""" user = None From 97cc129478f2d59b9d405c49b703951cd6092dca Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 10:37:09 -0700 Subject: [PATCH 2/7] Updates calls to privacy_filter --- bookwyrm/activitystreams.py | 47 +++++++++++++------------- bookwyrm/models/base_model.py | 4 +-- bookwyrm/templatetags/bookwyrm_tags.py | 6 ++-- bookwyrm/views/books/books.py | 15 ++++---- bookwyrm/views/feed.py | 30 ++++++++-------- bookwyrm/views/list.py | 14 +++----- bookwyrm/views/rss_feed.py | 8 ++--- bookwyrm/views/search.py | 5 ++- bookwyrm/views/shelf.py | 12 +++---- bookwyrm/views/user.py | 5 ++- 10 files changed, 68 insertions(+), 78 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index f843641f..997f3329 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -8,7 +8,6 @@ from django.utils import timezone from bookwyrm import models from bookwyrm.redis_store import RedisStore, r from bookwyrm.tasks import app -from bookwyrm.views.helpers import privacy_filter class ActivityStream(RedisStore): @@ -43,7 +42,7 @@ class ActivityStream(RedisStore): def add_user_statuses(self, viewer, user): """add a user's statuses to another user's feed""" # only add the statuses that the viewer should be able to see (ie, not dms) - statuses = privacy_filter(viewer, user.status_set.all()) + statuses = models.Status.privacy_filter(viewer).filter(user=user) self.bulk_add_objects_to_store(statuses, self.stream_id(viewer)) def remove_user_statuses(self, viewer, user): @@ -113,9 +112,8 @@ class ActivityStream(RedisStore): def get_statuses_for_user(self, user): # pylint: disable=no-self-use """given a user, what statuses should they see on this stream""" - return privacy_filter( + return models.Status.privacy_filter( user, - models.Status.objects.select_subclasses(), privacy_levels=["public", "unlisted", "followers"], ) @@ -139,9 +137,8 @@ class HomeStream(ActivityStream): ).distinct() def get_statuses_for_user(self, user): - return privacy_filter( + return models.Status.privacy_filter( user, - models.Status.objects.select_subclasses(), privacy_levels=["public", "unlisted", "followers"], following_only=True, ) @@ -160,11 +157,10 @@ class LocalStream(ActivityStream): def get_statuses_for_user(self, user): # all public statuses by a local user - return privacy_filter( + return models.Status.privacy_filter( user, - models.Status.objects.select_subclasses().filter(user__local=True), privacy_levels=["public"], - ) + ).filter(user__local=True) class BooksStream(ActivityStream): @@ -197,50 +193,53 @@ class BooksStream(ActivityStream): books = user.shelfbook_set.values_list( "book__parent_work__id", flat=True ).distinct() - return privacy_filter( - user, - models.Status.objects.select_subclasses() + return ( + models.Status.privacy_filter( + user, + privacy_levels=["public"], + ) .filter( Q(comment__book__parent_work__id__in=books) | Q(quotation__book__parent_work__id__in=books) | Q(review__book__parent_work__id__in=books) | Q(mention_books__parent_work__id__in=books) ) - .distinct(), - privacy_levels=["public"], + .distinct() ) def add_book_statuses(self, user, book): """add statuses about a book to a user's feed""" work = book.parent_work - statuses = privacy_filter( - user, - models.Status.objects.select_subclasses() + statuses = ( + models.Status.privacy_filter( + user, + privacy_levels=["public"], + ) .filter( Q(comment__book__parent_work=work) | Q(quotation__book__parent_work=work) | Q(review__book__parent_work=work) | Q(mention_books__parent_work=work) ) - .distinct(), - privacy_levels=["public"], + .distinct() ) self.bulk_add_objects_to_store(statuses, self.stream_id(user)) def remove_book_statuses(self, user, book): """add statuses about a book to a user's feed""" work = book.parent_work - statuses = privacy_filter( - user, - models.Status.objects.select_subclasses() + statuses = ( + models.Status.privacy_filter( + user, + privacy_levels=["public"], + ) .filter( Q(comment__book__parent_work=work) | Q(quotation__book__parent_work=work) | Q(review__book__parent_work=work) | Q(mention_books__parent_work=work) ) - .distinct(), - privacy_levels=["public"], + .distinct() ) self.bulk_remove_objects_from_store(statuses, self.stream_id(user)) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index cde181bd..1e147b5e 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -107,9 +107,7 @@ class BookWyrmModel(models.Model): raise PermissionDenied() @classmethod - def privacy_filter( - cls, viewer, privacy_levels=None, following_only=False, **filters - ): + def privacy_filter(cls, viewer, privacy_levels=None, following_only=False): """filter objects that have "user" and "privacy" fields""" queryset = cls.objects if hasattr(queryset, "select_subclasses"): diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py index 2e03c13b..bccd8c75 100644 --- a/bookwyrm/templatetags/bookwyrm_tags.py +++ b/bookwyrm/templatetags/bookwyrm_tags.py @@ -2,7 +2,7 @@ from django import template from django.db.models import Avg -from bookwyrm import models, views +from bookwyrm import models register = template.Library() @@ -11,8 +11,8 @@ register = template.Library() @register.filter(name="rating") def get_rating(book, user): """get the overall rating of a book""" - queryset = views.helpers.privacy_filter( - user, models.Review.objects.filter(book__parent_work__editions=book) + queryset = models.Review.privacy_filter(user).filter( + book__parent_work__editions=book ) return queryset.aggregate(Avg("rating"))["rating__avg"] diff --git a/bookwyrm/views/books/books.py b/bookwyrm/views/books/books.py index 298ba5a3..e495da3e 100644 --- a/bookwyrm/views/books/books.py +++ b/bookwyrm/views/books/books.py @@ -16,7 +16,7 @@ from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.connectors import connector_manager from bookwyrm.connectors.abstract_connector import get_image from bookwyrm.settings import PAGE_LENGTH -from bookwyrm.views.helpers import is_api_request, privacy_filter +from bookwyrm.views.helpers import is_api_request # pylint: disable=no-self-use @@ -48,8 +48,8 @@ class Book(View): raise Http404() # all reviews for all editions of the book - reviews = privacy_filter( - request.user, models.Review.objects.filter(book__parent_work__editions=book) + reviews = models.Review.privacy_filter(request.user).filter( + book__parent_work__editions=book ) # the reviews to show @@ -66,12 +66,9 @@ class Book(View): queryset = queryset.select_related("user").order_by("-published_date") paginated = Paginator(queryset, PAGE_LENGTH) - lists = privacy_filter( - request.user, - models.List.objects.filter( - listitem__approved=True, - listitem__book__in=book.parent_work.editions.all(), - ), + lists = models.List.privacy_filter(request.user,).filter( + listitem__approved=True, + listitem__book__in=book.parent_work.editions.all(), ) data = { "book": book, diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 7f1bc22c..8eff848c 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -13,7 +13,7 @@ from bookwyrm import activitystreams, forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.settings import PAGE_LENGTH, STREAMS from bookwyrm.suggested_users import suggested_users -from .helpers import get_user_from_username, privacy_filter +from .helpers import get_user_from_username from .helpers import is_api_request, is_bookwyrm_request @@ -56,11 +56,15 @@ class DirectMessage(View): def get(self, request, username=None): """like a feed but for dms only""" # remove fancy subclasses of status, keep just good ol' notes - queryset = models.Status.objects.filter( - review__isnull=True, - comment__isnull=True, - quotation__isnull=True, - generatednote__isnull=True, + activities = ( + models.Status.privacy_filter(request.user, privacy_levels=["direct"]) + .filter( + review__isnull=True, + comment__isnull=True, + quotation__isnull=True, + generatednote__isnull=True, + ) + .order_by("-published_date") ) user = None @@ -70,11 +74,7 @@ class DirectMessage(View): except Http404: pass if user: - queryset = queryset.filter(Q(user=user) | Q(mention_users=user)) - - activities = privacy_filter( - request.user, queryset, privacy_levels=["direct"] - ).order_by("-published_date") + activities = activities.filter(Q(user=user) | Q(mention_users=user)) paginated = Paginator(activities, PAGE_LENGTH) data = { @@ -109,9 +109,11 @@ class Status(View): status.to_activity(pure=not is_bookwyrm_request(request)) ) - visible_thread = privacy_filter( - request.user, models.Status.objects.filter(thread_id=status.thread_id) - ).values_list("id", flat=True) + visible_thread = ( + models.Status.privacy_filter(request.user) + .filter(thread_id=status.thread_id) + .values_list("id", flat=True) + ) visible_thread = list(visible_thread) ancestors = models.Status.objects.select_subclasses().raw( diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index a9d77597..b01a0e0e 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -18,7 +18,7 @@ from django.views.decorators.http import require_POST from bookwyrm import book_search, forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.settings import PAGE_LENGTH -from .helpers import is_api_request, privacy_filter +from .helpers import is_api_request from .helpers import get_user_from_username @@ -30,9 +30,10 @@ class Lists(View): """display a book list""" # hide lists with no approved books lists = ( - models.List.objects.annotate( - item_count=Count("listitem", filter=Q(listitem__approved=True)) + models.List.privacy_filter( + request.user, privacy_levels=["public", "followers"] ) + .annotate(item_count=Count("listitem", filter=Q(listitem__approved=True))) .filter(item_count__gt=0) .select_related("user") .prefetch_related("listitem_set") @@ -40,10 +41,6 @@ class Lists(View): .distinct() ) - lists = privacy_filter( - request.user, lists, privacy_levels=["public", "followers"] - ) - paginated = Paginator(lists, 12) data = { "lists": paginated.get_page(request.GET.get("page")), @@ -89,8 +86,7 @@ class UserLists(View): def get(self, request, username): """display a book list""" user = get_user_from_username(request.user, username) - lists = models.List.objects.filter(user=user) - lists = privacy_filter(request.user, lists) + lists = models.List.privacy_filter(request.user).filter(user=user) paginated = Paginator(lists, 12) data = { diff --git a/bookwyrm/views/rss_feed.py b/bookwyrm/views/rss_feed.py index 5faa1624..b924095c 100644 --- a/bookwyrm/views/rss_feed.py +++ b/bookwyrm/views/rss_feed.py @@ -4,7 +4,8 @@ from django.contrib.syndication.views import Feed from django.template.loader import get_template from django.utils.translation import gettext_lazy as _ -from .helpers import get_user_from_username, privacy_filter +from bookwyrm import models +from .helpers import get_user_from_username # pylint: disable=no-self-use, unused-argument class RssFeed(Feed): @@ -35,11 +36,10 @@ class RssFeed(Feed): def items(self, obj): """the user's activity feed""" - return privacy_filter( + return models.Status.privacy_filter( obj, - obj.status_set.select_subclasses(), privacy_levels=["public", "unlisted"], - ) + ).filter(user=obj) def item_link(self, item): """link to the status""" diff --git a/bookwyrm/views/search.py b/bookwyrm/views/search.py index d131b399..7a56ae72 100644 --- a/bookwyrm/views/search.py +++ b/bookwyrm/views/search.py @@ -13,7 +13,7 @@ from bookwyrm.connectors import connector_manager from bookwyrm.book_search import search, format_search_result from bookwyrm.settings import PAGE_LENGTH from bookwyrm.utils import regex -from .helpers import is_api_request, privacy_filter +from .helpers import is_api_request from .helpers import handle_remote_webfinger @@ -108,9 +108,8 @@ def user_search(query, viewer, *_): def list_search(query, viewer, *_): """any relevent lists?""" return ( - privacy_filter( + models.List.privacy_filter( viewer, - models.List.objects, privacy_levels=["public", "followers"], ) .annotate( diff --git a/bookwyrm/views/shelf.py b/bookwyrm/views/shelf.py index 35f660b5..37f320dc 100644 --- a/bookwyrm/views/shelf.py +++ b/bookwyrm/views/shelf.py @@ -17,7 +17,6 @@ from bookwyrm import forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.settings import PAGE_LENGTH from .helpers import is_api_request, get_user_from_username -from .helpers import privacy_filter # pylint: disable=no-self-use @@ -33,7 +32,7 @@ class Shelf(View): if is_self: shelves = user.shelf_set.all() else: - shelves = privacy_filter(request.user, user.shelf_set).all() + shelves = models.Shelf.privacy_filter(request.user).filter(user=user).all() # get the shelf and make sure the logged in user should be able to see it if shelf_identifier: @@ -58,16 +57,17 @@ class Shelf(View): if is_api_request(request): return ActivitypubResponse(shelf.to_activity(**request.GET)) - reviews = models.Review.objects.filter( + reviews = models.Review.objects + if not is_self: + reviews = models.Review.privacy_filter(request.user) + + reviews = reviews.filter( user=user, rating__isnull=False, book__id=OuterRef("id"), deleted=False, ).order_by("-published_date") - if not is_self: - reviews = privacy_filter(request.user, reviews) - books = books.annotate( rating=Subquery(reviews.values("rating")[:1]), shelved_date=F("shelfbook__shelved_date"), diff --git a/bookwyrm/views/user.py b/bookwyrm/views/user.py index fb553228..0d8d385b 100644 --- a/bookwyrm/views/user.py +++ b/bookwyrm/views/user.py @@ -12,7 +12,6 @@ from bookwyrm import models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.settings import PAGE_LENGTH from .helpers import get_user_from_username, is_api_request -from .helpers import privacy_filter # pylint: disable=no-self-use @@ -56,10 +55,10 @@ class User(View): # user's posts activities = ( - privacy_filter( + models.Status.privacy_filter( request.user, - user.status_set.select_subclasses(), ) + .filter(user=user) .select_related( "user", "reply_parent", From 68b6b1fbae10ca8d2acb756831255d8c14a20405 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 11:08:54 -0700 Subject: [PATCH 3/7] User override in child class instead of if/else for privacy_filter --- bookwyrm/models/base_model.py | 7 +------ bookwyrm/models/status.py | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index 1e147b5e..fd70fc17 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -167,12 +167,7 @@ class BookWyrmModel(models.Model): @classmethod def direct_filter(cls, queryset, viewer): """Override-able filter for "direct" privacy level""" - try: - return queryset.exclude( - ~Q(Q(user=viewer) | Q(mention_users=viewer)), privacy="direct" - ) - except FieldError: - return queryset.exclude(~Q(user=viewer), privacy="direct") + return queryset.exclude(~Q(user=viewer), privacy="direct") @receiver(models.signals.post_save) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 58488123..3e5f638f 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -207,6 +207,13 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): if isinstance(self, (GeneratedNote, ReviewRating)): raise PermissionDenied() + @classmethod + def direct_filter(cls, queryset, viewer): + """Override-able filter for "direct" privacy level""" + return queryset.exclude( + ~Q(Q(user=viewer) | Q(mention_users=viewer)), privacy="direct" + ) + class GeneratedNote(Status): """these are app-generated messages about user activity""" From 2307cb2227740f2900e172e9b148c2ba564f507f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 11:12:03 -0700 Subject: [PATCH 4/7] Filter followers only in place It's only used in one spot --- bookwyrm/activitystreams.py | 7 ++++++- bookwyrm/models/base_model.py | 14 ++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 997f3329..4896e07d 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -140,7 +140,12 @@ class HomeStream(ActivityStream): return models.Status.privacy_filter( user, privacy_levels=["public", "unlisted", "followers"], - following_only=True, + ).exclude( + ~Q( # remove everything except + Q(user__followers=user) # user following + | Q(user=user) # is self + | Q(mention_users=user) # mentions user + ), ) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index fd70fc17..6145a1d4 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -107,7 +107,7 @@ class BookWyrmModel(models.Model): raise PermissionDenied() @classmethod - def privacy_filter(cls, viewer, privacy_levels=None, following_only=False): + def privacy_filter(cls, viewer, privacy_levels=None): """filter objects that have "user" and "privacy" fields""" queryset = cls.objects if hasattr(queryset, "select_subclasses"): @@ -135,17 +135,7 @@ class BookWyrmModel(models.Model): # filter to only privided privacy levels queryset = queryset.filter(privacy__in=privacy_levels) - # only include statuses the user follows - if following_only: - queryset = queryset.exclude( - ~Q( # remove everythign except - Q(user__followers=viewer) - | Q(user=viewer) # user following - | Q(mention_users=viewer) # is self # mentions user - ), - ) - # exclude followers-only statuses the user doesn't follow - elif "followers" in privacy_levels: + if "followers" in privacy_levels: queryset = cls.followers_filter(queryset, viewer) # exclude direct messages not intended for the user From 34d6c8886174c909c87b66ba07faecb318c47a35 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 11:15:17 -0700 Subject: [PATCH 5/7] Move privacy levels filter to clearer location --- bookwyrm/models/base_model.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index 6145a1d4..06445a11 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -114,7 +114,13 @@ class BookWyrmModel(models.Model): queryset = queryset.select_subclasses() privacy_levels = privacy_levels or ["public", "unlisted", "followers", "direct"] - # if there'd a deleted field, exclude deleted items + # you can't see followers only or direct messages if you're not logged in + if viewer.is_anonymous: + privacy_levels = [ + p for p in privacy_levels if not p in ["followers", "direct"] + ] + + # if there's a deleted field, exclude deleted items try: queryset = queryset.filter(deleted=False) except FieldError: @@ -126,12 +132,6 @@ class BookWyrmModel(models.Model): Q(user__blocked_by=viewer) | Q(user__blocks=viewer) ) - # you can't see followers only or direct messages if you're not logged in - if viewer.is_anonymous: - privacy_levels = [ - p for p in privacy_levels if not p in ["followers", "direct"] - ] - # filter to only privided privacy levels queryset = queryset.filter(privacy__in=privacy_levels) From 53e576256313bdd45f4a7e43ecb3b810a075446e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 11:19:13 -0700 Subject: [PATCH 6/7] Status-specific filters in status model --- bookwyrm/models/base_model.py | 8 +------- bookwyrm/models/status.py | 8 +++++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index 06445a11..d32ec67b 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -2,7 +2,7 @@ import base64 from Crypto import Random -from django.core.exceptions import PermissionDenied, FieldError +from django.core.exceptions import PermissionDenied from django.db import models from django.db.models import Q from django.dispatch import receiver @@ -120,12 +120,6 @@ class BookWyrmModel(models.Model): p for p in privacy_levels if not p in ["followers", "direct"] ] - # if there's a deleted field, exclude deleted items - try: - queryset = queryset.filter(deleted=False) - except FieldError: - pass - # exclude blocks from both directions if not viewer.is_anonymous: queryset = queryset.exclude( diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 3e5f638f..1325aa88 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -6,6 +6,7 @@ from django.apps import apps from django.core.exceptions import PermissionDenied from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models +from django.db.models import Q from django.dispatch import receiver from django.template.loader import get_template from django.utils import timezone @@ -207,9 +208,14 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): if isinstance(self, (GeneratedNote, ReviewRating)): raise PermissionDenied() + @classmethod + def privacy_filter(cls, viewer, privacy_levels=None): + queryset = super().privacy_filter(viewer, privacy_levels=privacy_levels) + return queryset.filter(deleted=False) + @classmethod def direct_filter(cls, queryset, viewer): - """Override-able filter for "direct" privacy level""" + """Overridden filter for "direct" privacy level""" return queryset.exclude( ~Q(Q(user=viewer) | Q(mention_users=viewer)), privacy="direct" ) From 8d00ef4318a5f7500cf90cd0ae5bd30efa45fab4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 6 Oct 2021 11:23:36 -0700 Subject: [PATCH 7/7] Style cleanup --- bookwyrm/models/base_model.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index d32ec67b..b781a506 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -119,14 +119,13 @@ class BookWyrmModel(models.Model): privacy_levels = [ p for p in privacy_levels if not p in ["followers", "direct"] ] - - # exclude blocks from both directions - if not viewer.is_anonymous: + else: + # exclude blocks from both directions queryset = queryset.exclude( Q(user__blocked_by=viewer) | Q(user__blocks=viewer) ) - # filter to only privided privacy levels + # filter to only provided privacy levels queryset = queryset.filter(privacy__in=privacy_levels) if "followers" in privacy_levels: