Repository: bookwyrm-social/bookwyrm

Issue:
Boosts of unrelated remote statuses load in feed
If I follow a Mastodon user, I expect to only see posts from them in my feed if they are related to local posts. This is checked correctly for regular statuses, but not for boosts


Discussion:

Resolving patch:
diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py
--- a/bookwyrm/activitypub/base_activity.py
+++ b/bookwyrm/activitypub/base_activity.py
@@ -74,6 +74,9 @@ def to_model(self, model, instance=None, save=True):
                          model.activity_serializer)
             )
 
+        if hasattr(model, 'ignore_activity') and model.ignore_activity(self):
+            return instance
+
         # check for an existing instance, if we're not updating a known obj
         instance = instance or model.find_existing(self.serialize()) or model()
 
diff --git a/bookwyrm/incoming.py b/bookwyrm/incoming.py
--- a/bookwyrm/incoming.py
+++ b/bookwyrm/incoming.py
@@ -197,26 +197,11 @@ def handle_create(activity):
         # not a type of status we are prepared to deserialize
         return
 
-    if activity.type == 'Note':
-        # keep notes if they are replies to existing statuses
-        reply = models.Status.objects.filter(
-            remote_id=activity.inReplyTo
-        ).first()
-
-        if not reply:
-            discard = True
-            # keep notes if they mention local users
-            tags = [l['href'] for l in activity.tag if l['type'] == 'Mention']
-            for tag in tags:
-                if models.User.objects.filter(
-                        remote_id=tag, local=True).exists():
-                    # we found a mention of a known use boost
-                    discard = False
-                    break
-            if discard:
-                return
-
     status = activity.to_model(model)
+    if not status:
+        # it was discarded because it's not a bookwyrm type
+        return
+
     # create a notification if this is a reply
     notified = []
     if status.reply_parent and status.reply_parent.user.local:
diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py
--- a/bookwyrm/models/status.py
+++ b/bookwyrm/models/status.py
@@ -1,7 +1,9 @@
 ''' models for storing different kinds of Activities '''
-from django.utils import timezone
+from dataclasses import MISSING
+from django.apps import apps
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.db import models
+from django.utils import timezone
 from model_utils.managers import InheritanceManager
 
 from bookwyrm import activitypub
@@ -46,6 +48,27 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
     serialize_reverse_fields = [('attachments', 'attachment')]
     deserialize_reverse_fields = [('attachments', 'attachment')]
 
+    @classmethod
+    def ignore_activity(cls, activity):
+        ''' keep notes if they are replies to existing statuses '''
+        if activity.type != 'Note':
+            return False
+        if cls.objects.filter(
+                remote_id=activity.inReplyTo).exists():
+            return False
+
+        # keep notes if they mention local users
+        if activity.tag == MISSING or activity.tag is None:
+            return True
+        tags = [l['href'] for l in activity.tag if l['type'] == 'Mention']
+        for tag in tags:
+            user_model = apps.get_model('bookwyrm.User', require_ready=True)
+            if user_model.objects.filter(
+                    remote_id=tag, local=True).exists():
+                # we found a mention of a known use boost
+                return False
+        return True
+
     @classmethod
     def replies(cls, status):
         ''' load all replies to a status. idk if there's a better way


Test patch:
diff --git a/bookwyrm/tests/test_incoming.py b/bookwyrm/tests/test_incoming.py
--- a/bookwyrm/tests/test_incoming.py
+++ b/bookwyrm/tests/test_incoming.py
@@ -410,7 +410,10 @@ def test_handle_boost(self):
             'actor': self.remote_user.remote_id,
             'object': self.status.to_activity(),
         }
-        incoming.handle_boost(activity)
+        with patch('bookwyrm.models.status.Status.ignore_activity') \
+                as discarder:
+            discarder.return_value = False
+            incoming.handle_boost(activity)
         boost = models.Boost.objects.get()
         self.assertEqual(boost.boosted_status, self.status)
         notification = models.Notification.objects.get()