diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index d934681e0..2c2e5a72d 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -6,6 +6,7 @@ import operator import logging from uuid import uuid4 import requests +from requests.exceptions import HTTPError, SSLError from Crypto.PublicKey import RSA from Crypto.Signature import pkcs1_15 @@ -440,7 +441,7 @@ def broadcast_task(sender_id, activity, recipients): for recipient in recipients: try: sign_and_send(sender, activity, recipient) - except requests.exceptions.HTTPError as e: + except (HTTPError, SSLError) as e: logger.exception(e) diff --git a/bookwyrm/templates/discover/large-book.html b/bookwyrm/templates/discover/large-book.html index 401411a11..7881a33ab 100644 --- a/bookwyrm/templates/discover/large-book.html +++ b/bookwyrm/templates/discover/large-book.html @@ -3,7 +3,7 @@
{% include 'snippets/book_cover.html' with book=book size="large" %} - {% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %} + {% include 'snippets/stars.html' with rating=book|rating:request.user %}

{{ book.title }}

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 %}

{{ book.title }}

{% 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(