diff --git a/bookwyrm/templates/discover/small-book.html b/bookwyrm/templates/discover/small-book.html
index d1676b6b1..72108c309 100644
--- a/bookwyrm/templates/discover/small-book.html
+++ b/bookwyrm/templates/discover/small-book.html
@@ -1,9 +1,7 @@
{% load bookwyrm_tags %}
{% if book %}
{% include 'snippets/book_cover.html' with book=book %}
-{% if ratings %}
-{% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %}
-{% endif %}
+{% include 'snippets/stars.html' with rating=book|rating:request.user %}
{% if book.authors %}
diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py
index d251d8e49..67354ac65 100644
--- a/bookwyrm/templatetags/bookwyrm_tags.py
+++ b/bookwyrm/templatetags/bookwyrm_tags.py
@@ -22,11 +22,8 @@ def dict_key(d, k):
@register.filter(name='rating')
def get_rating(book, user):
''' get the overall rating of a book '''
- queryset = views.helpers.get_activity_feed(
- user,
- ['public', 'followers', 'unlisted', 'direct'],
- queryset=models.Review.objects.filter(book=book),
- )
+ queryset = views.helpers.privacy_filter(
+ user, models.Review.objects.filter(book=book))
return queryset.aggregate(Avg('rating'))['rating__avg']
diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py
index 10221933c..eff083072 100644
--- a/bookwyrm/tests/views/test_helpers.py
+++ b/bookwyrm/tests/views/test_helpers.py
@@ -106,7 +106,7 @@ class ViewsHelpers(TestCase):
statuses = views.helpers.get_activity_feed(
self.local_user,
- ['public', 'unlisted', 'followers'],
+ privacy=['public', 'unlisted', 'followers'],
following_only=True,
queryset=models.Comment.objects
)
@@ -115,20 +115,21 @@ class ViewsHelpers(TestCase):
statuses = views.helpers.get_activity_feed(
self.local_user,
- ['public', 'followers'],
+ privacy=['public', 'followers'],
local_only=True
)
self.assertEqual(len(statuses), 2)
self.assertEqual(statuses[1], public_status)
self.assertEqual(statuses[0], rat_public)
- statuses = views.helpers.get_activity_feed(self.local_user, 'direct')
+ statuses = views.helpers.get_activity_feed(
+ self.local_user, privacy=['direct'])
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], direct_status)
statuses = views.helpers.get_activity_feed(
self.local_user,
- ['public', 'followers'],
+ privacy=['public', 'followers'],
)
self.assertEqual(len(statuses), 3)
self.assertEqual(statuses[2], public_status)
@@ -137,7 +138,7 @@ class ViewsHelpers(TestCase):
statuses = views.helpers.get_activity_feed(
self.local_user,
- ['public', 'unlisted', 'followers'],
+ privacy=['public', 'unlisted', 'followers'],
following_only=True
)
self.assertEqual(len(statuses), 2)
@@ -147,7 +148,7 @@ class ViewsHelpers(TestCase):
rat.followers.add(self.local_user)
statuses = views.helpers.get_activity_feed(
self.local_user,
- ['public', 'unlisted', 'followers'],
+ privacy=['public', 'unlisted', 'followers'],
following_only=True
)
self.assertEqual(len(statuses), 5)
@@ -170,18 +171,18 @@ class ViewsHelpers(TestCase):
content='blah blah', user=rat)
statuses = views.helpers.get_activity_feed(
- self.local_user, ['public'])
+ self.local_user, privacy=['public'])
self.assertEqual(len(statuses), 2)
# block relationship
rat.blocks.add(self.local_user)
statuses = views.helpers.get_activity_feed(
- self.local_user, ['public'])
+ self.local_user, privacy=['public'])
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], public_status)
statuses = views.helpers.get_activity_feed(
- rat, ['public'])
+ rat, privacy=['public'])
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], rat_public)
diff --git a/bookwyrm/views/books.py b/bookwyrm/views/books.py
index 9d1965631..e05c47264 100644
--- a/bookwyrm/views/books.py
+++ b/bookwyrm/views/books.py
@@ -45,15 +45,9 @@ class Book(View):
if not work:
return HttpResponseNotFound()
- reviews = models.Review.objects.filter(
- book__in=work.editions.all(),
- )
# all reviews for the book
- reviews = get_activity_feed(
- request.user,
- ['public', 'unlisted', 'followers', 'direct'],
- queryset=reviews
- )
+ reviews = models.Review.objects.filter(book__in=work.editions.all())
+ reviews = get_activity_feed(request.user, queryset=reviews)
# the reviews to show
paginated = Paginator(reviews.exclude(
@@ -96,9 +90,8 @@ class Book(View):
'rating': reviews.aggregate(Avg('rating'))['rating__avg'],
'tags': models.UserTag.objects.filter(book=book),
'lists': privacy_filter(
- request.user,
- book.list_set.all(),
- ['public', 'unlisted', 'followers']),
+ request.user, book.list_set.all()
+ ),
'user_tags': user_tags,
'user_shelves': user_shelves,
'other_edition_shelves': other_edition_shelves,
diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py
index c229b7c9e..3a2805b4f 100644
--- a/bookwyrm/views/feed.py
+++ b/bookwyrm/views/feed.py
@@ -11,8 +11,7 @@ from django.views import View
from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.settings import PAGE_LENGTH
-from .helpers import get_activity_feed
-from .helpers import get_user_from_username
+from .helpers import get_activity_feed, get_user_from_username
from .helpers import is_api_request, is_bookwyrm_request, object_visible_to_user
@@ -29,14 +28,13 @@ class Feed(View):
if tab == 'home':
activities = get_activity_feed(
- request.user, ['public', 'unlisted', 'followers'],
- following_only=True)
+ request.user, following_only=True)
elif tab == 'local':
activities = get_activity_feed(
- request.user, ['public', 'followers'], local_only=True)
+ request.user, privacy=['public', 'followers'], local_only=True)
else:
activities = get_activity_feed(
- request.user, ['public', 'followers'])
+ request.user, privacy=['public', 'followers'])
paginated = Paginator(activities, PAGE_LENGTH)
data = {**feed_page_data(request.user), **{
@@ -72,7 +70,7 @@ class DirectMessage(View):
queryset = queryset.filter(Q(user=user) | Q(mention_users=user))
activities = get_activity_feed(
- request.user, 'direct', queryset=queryset)
+ request.user, privacy=['direct'], queryset=queryset)
paginated = Paginator(activities, PAGE_LENGTH)
activity_page = paginated.page(page)
diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py
index fac3ab0c6..cecb65e33 100644
--- a/bookwyrm/views/helpers.py
+++ b/bookwyrm/views/helpers.py
@@ -1,6 +1,7 @@
''' helper functions used in various views '''
import re
from requests import HTTPError
+from django.core.exceptions import FieldError
from django.db.models import Q
from bookwyrm import activitypub, models
@@ -59,8 +60,11 @@ def object_visible_to_user(viewer, obj):
return False
-def privacy_filter(viewer, queryset, privacy_levels, following_only=False):
+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']
+
# exclude blocks from both directions
if not viewer.is_anonymous:
blocked = models.User.objects.filter(id__in=viewer.blocks.all()).all()
@@ -95,30 +99,56 @@ def privacy_filter(viewer, queryset, privacy_levels, following_only=False):
# exclude direct messages not intended for the user
if 'direct' in privacy_levels:
- queryset = queryset.exclude(
- ~Q(
- Q(user=viewer) | Q(mention_users=viewer)
- ), privacy='direct'
- )
+ 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 get_activity_feed(
- user, privacy, local_only=False, following_only=False,
- queryset=models.Status.objects):
+ user, privacy=None, local_only=False, following_only=False,
+ queryset=None):
''' get a filtered queryset of statuses '''
- # if we're looking at Status, we need this. We don't if it's Comment
- if hasattr(queryset, 'select_subclasses'):
- queryset = queryset.select_subclasses()
+ if queryset is None:
+ queryset = models.Status.objects.select_subclasses()
# exclude deleted
queryset = queryset.exclude(deleted=True).order_by('-published_date')
# apply privacy filters
- privacy = privacy if isinstance(privacy, list) else [privacy]
queryset = privacy_filter(
user, queryset, privacy, following_only=following_only)
+ # only show dms if we only want dms
+ if privacy == ['direct']:
+ # dms are direct statuses not related to books
+ queryset = queryset.filter(
+ review__isnull=True,
+ comment__isnull=True,
+ quotation__isnull=True,
+ generatednote__isnull=True,
+ )
+ else:
+ try:
+ queryset = queryset.exclude(
+ review__isnull=True,
+ comment__isnull=True,
+ quotation__isnull=True,
+ generatednote__isnull=True,
+ privacy='direct'
+ )
+ except FieldError:
+ # if we're looking at a subtype of Status (like Review)
+ pass
+
# filter for only local status
if local_only:
queryset = queryset.filter(user__local=True)
diff --git a/bookwyrm/views/landing.py b/bookwyrm/views/landing.py
index 3be3eb312..2774e7428 100644
--- a/bookwyrm/views/landing.py
+++ b/bookwyrm/views/landing.py
@@ -1,11 +1,10 @@
''' non-interactive pages '''
-from django.db.models import Avg, Max
+from django.db.models import Max
from django.template.response import TemplateResponse
from django.views import View
from bookwyrm import forms, models
from .feed import Feed
-from .helpers import get_activity_feed
# pylint: disable= no-self-use
@@ -34,6 +33,7 @@ class Discover(View):
''' tiled book activity page '''
books = models.Edition.objects.filter(
review__published_date__isnull=False,
+ review__deleted=False,
review__user__local=True,
review__privacy__in=['public', 'unlisted'],
).exclude(
@@ -42,18 +42,9 @@ class Discover(View):
Max('review__published_date')
).order_by('-review__published_date__max')[:6]
- ratings = {}
- for book in books:
- reviews = models.Review.objects.filter(
- book__in=book.parent_work.editions.all()
- )
- reviews = get_activity_feed(
- request.user, ['public', 'unlisted'], queryset=reviews)
- ratings[book.id] = reviews.aggregate(Avg('rating'))['rating__avg']
data = {
'title': 'Discover',
'register_form': forms.RegisterForm(),
'books': list(set(books)),
- 'ratings': ratings
}
return TemplateResponse(request, 'discover/discover.html', data)
diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py
index 7286bfb4f..e7b70a286 100644
--- a/bookwyrm/views/list.py
+++ b/bookwyrm/views/list.py
@@ -35,7 +35,8 @@ class Lists(View):
).filter(
item_count__gt=0
).distinct().all()
- lists = privacy_filter(request.user, lists, ['public', 'followers'])
+ lists = privacy_filter(
+ request.user, lists, privacy_levels=['public', 'followers'])
paginated = Paginator(lists, 12)
data = {
@@ -67,8 +68,7 @@ class UserLists(View):
page = 1
user = get_user_from_username(request.user, username)
lists = models.List.objects.filter(user=user).all()
- lists = privacy_filter(
- request.user, lists, ['public', 'followers', 'unlisted'])
+ lists = privacy_filter(request.user, lists)
paginated = Paginator(lists, 12)
data = {
diff --git a/bookwyrm/views/rss_feed.py b/bookwyrm/views/rss_feed.py
index aad227bff..d24b636ea 100644
--- a/bookwyrm/views/rss_feed.py
+++ b/bookwyrm/views/rss_feed.py
@@ -27,7 +27,10 @@ class RssFeed(Feed):
def items(self, obj):
''' the user's activity feed '''
return get_activity_feed(
- obj, ['public', 'unlisted'], queryset=obj.status_set)
+ obj,
+ privacy=['public', 'unlisted'],
+ queryset=obj.status_set.select_subclasses()
+ )
def item_link(self, item):
diff --git a/bookwyrm/views/search.py b/bookwyrm/views/search.py
index 98be166f4..8acb28363 100644
--- a/bookwyrm/views/search.py
+++ b/bookwyrm/views/search.py
@@ -44,7 +44,8 @@ class Search(View):
# any relevent lists?
list_results = privacy_filter(
- request.user, models.List.objects, ['public', 'followers']
+ request.user, models.List.objects,
+ privacy_levels=['public', 'followers']
).annotate(
similarity=Greatest(
TrigramSimilarity('name', query),
diff --git a/bookwyrm/views/user.py b/bookwyrm/views/user.py
index 7a238ce7c..a218375fd 100644
--- a/bookwyrm/views/user.py
+++ b/bookwyrm/views/user.py
@@ -71,8 +71,7 @@ class User(View):
# user's posts
activities = get_activity_feed(
request.user,
- ['public', 'unlisted', 'followers'],
- queryset=user.status_set
+ queryset=user.status_set.select_subclasses(),
)
paginated = Paginator(activities, PAGE_LENGTH)
goal = models.AnnualGoal.objects.filter(