diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index f843641f5..997f33294 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 cde181bd4..1e147b5e0 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 2e03c13b4..bccd8c75a 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 298ba5a30..e495da3e7 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 7f1bc22c2..8eff848c3 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 a9d775971..b01a0e0e3 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 5faa16243..b924095cc 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 d131b399f..7a56ae72f 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 35f660b5f..37f320dcd 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 fb553228b..0d8d385b1 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",