diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 34f90103b..747167f08 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -42,7 +42,13 @@ class ActivitypubFieldMixin: def set_field_from_activity(self, instance, data): ''' helper function for assinging a value to the field ''' - value = getattr(data, self.get_activitypub_field()) + try: + value = getattr(data, self.get_activitypub_field()) + except AttributeError: + # masssively hack-y workaround for boosts + if self.get_activitypub_field() != 'attributedTo': + raise + value = getattr(data, 'actor') formatted = self.field_from_activity(value) if formatted is None or formatted is MISSING: return diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 0bf897dc1..f0cd3c1d2 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -218,6 +218,18 @@ class Boost(Status): activitypub_field='object', ) + def __init__(self, *args, **kwargs): + ''' the user field is "actor" here instead of "attributedTo" ''' + super().__init__(*args, **kwargs) + + reserve_fields = ['user', 'boosted_status'] + self.simple_fields = [f for f in self.simple_fields if \ + f.name in reserve_fields] + self.activity_fields = self.simple_fields + self.many_to_many_fields = [] + self.image_fields = [] + self.deserialize_reverse_fields = [] + activity_serializer = activitypub.Boost # This constraint can't work as it would cross tables. diff --git a/bookwyrm/tests/test_incoming.py b/bookwyrm/tests/test_incoming.py index 06aeac88f..34375321c 100644 --- a/bookwyrm/tests/test_incoming.py +++ b/bookwyrm/tests/test_incoming.py @@ -256,7 +256,9 @@ class Incoming(TestCase): models.Edition.objects.create( title='Test Book', remote_id='https://example.com/book/1') activity = {'object': status_data, 'type': 'Create'} + incoming.handle_create(activity) + status = models.Quotation.objects.get() self.assertEqual( status.remote_id, 'https://example.com/user/mouse/quotation/13') @@ -397,3 +399,36 @@ class Incoming(TestCase): incoming.handle_unfavorite(activity) self.assertEqual(models.Favorite.objects.count(), 0) + + + def test_handle_boost(self): + ''' boost a status ''' + self.assertEqual(models.Notification.objects.count(), 0) + activity = { + 'type': 'Announce', + 'id': '%s/boost' % self.status.remote_id, + 'actor': self.remote_user.remote_id, + 'object': self.status.to_activity(), + } + incoming.handle_boost(activity) + boost = models.Boost.objects.get() + self.assertEqual(boost.boosted_status, self.status) + notification = models.Notification.objects.get() + self.assertEqual(notification.user, self.local_user) + self.assertEqual(notification.related_status, self.status) + + + def test_handle_unboost(self): + ''' undo a boost ''' + activity = { + 'type': 'Undo', + 'object': { + 'type': 'Announce', + 'id': '%s/boost' % self.status.remote_id, + 'actor': self.local_user.remote_id, + 'object': self.status.to_activity(), + } + } + models.Boost.objects.create( + boosted_status=self.status, user=self.remote_user) + incoming.handle_unboost(activity)