diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index 201e8042..510f1f3f 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -16,7 +16,7 @@ from .response import ActivitypubResponse from .book import Edition, Work, Author from .verbs import Create, Delete, Undo, Update from .verbs import Follow, Accept, Reject, Block -from .verbs import Add, AddBook, Remove +from .verbs import Add, AddBook, AddListItem, Remove # this creates a list of all the Activity types that we can serialize, # so when an Activity comes in from outside, we can check if it's known diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 4bbb5e9f..5f35f1d7 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -65,6 +65,13 @@ class ActivityObject: def to_model(self, model, instance=None, save=True): ''' convert from an activity to a model instance ''' + if self.type != model.activity_serializer.type: + raise ActivitySerializerError( + 'Wrong activity type "%s" for activity of type "%s"' % \ + (model.activity_serializer.type, + self.type) + ) + if not isinstance(self, model.activity_serializer): raise ActivitySerializerError( 'Wrong activity type "%s" for model "%s" (expects "%s")' % \ diff --git a/bookwyrm/activitypub/verbs.py b/bookwyrm/activitypub/verbs.py index 5502ced0..190cd739 100644 --- a/bookwyrm/activitypub/verbs.py +++ b/bookwyrm/activitypub/verbs.py @@ -70,17 +70,26 @@ class Reject(Verb): @dataclass(init=False) class Add(Verb): '''Add activity ''' - target: ActivityObject + target: str + object: ActivityObject type: str = 'Add' @dataclass(init=False) -class AddBook(Verb): +class AddBook(Add): '''Add activity that's aware of the book obj ''' - target: Edition + object: Edition type: str = 'Add' +@dataclass(init=False) +class AddListItem(AddBook): + '''Add activity that's aware of the book obj ''' + notes: str = None + order: int = 0 + approved: bool = True + + @dataclass(init=False) class Remove(Verb): '''Remove activity ''' diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py index 2cbcda47..527d2f42 100644 --- a/bookwyrm/connectors/abstract_connector.py +++ b/bookwyrm/connectors/abstract_connector.py @@ -239,7 +239,8 @@ def get_image(url): 'User-Agent': settings.USER_AGENT, }, ) - except (RequestError, SSLError): + except (RequestError, SSLError) as e: + logger.exception(e) return None if not resp.ok: return None diff --git a/bookwyrm/connectors/openlibrary.py b/bookwyrm/connectors/openlibrary.py index cd196d27..a767a45a 100644 --- a/bookwyrm/connectors/openlibrary.py +++ b/bookwyrm/connectors/openlibrary.py @@ -142,7 +142,12 @@ class Connector(AbstractConnector): work = book.parent_work # we can mass download edition data from OL to avoid repeatedly querying - edition_options = self.load_edition_data(work.openlibrary_key) + try: + edition_options = self.load_edition_data(work.openlibrary_key) + except ConnectorException: + # who knows, man + return + for edition_data in edition_options.get('entries'): # does this edition have ANY interesting data? if ignore_edition(edition_data): diff --git a/bookwyrm/incoming.py b/bookwyrm/incoming.py index a88a748e..18db1069 100644 --- a/bookwyrm/incoming.py +++ b/bookwyrm/incoming.py @@ -216,9 +216,9 @@ def handle_create_list(activity): def handle_update_list(activity): ''' update a list ''' try: - book_list = models.List.objects.get(id=activity['object']['id']) + book_list = models.List.objects.get(remote_id=activity['object']['id']) except models.List.DoesNotExist: - return + book_list = None activitypub.BookList( **activity['object']).to_model(models.List, instance=book_list) @@ -319,8 +319,19 @@ def handle_add(activity): #this is janky as heck but I haven't thought of a better solution try: activitypub.AddBook(**activity).to_model(models.ShelfBook) + return except activitypub.ActivitySerializerError: - activitypub.AddBook(**activity).to_model(models.Tag) + pass + try: + activitypub.AddListItem(**activity).to_model(models.ListItem) + return + except activitypub.ActivitySerializerError: + pass + try: + activitypub.AddBook(**activity).to_model(models.UserTag) + return + except activitypub.ActivitySerializerError: + pass @app.task diff --git a/bookwyrm/migrations/0044_auto_20210207_1924.py b/bookwyrm/migrations/0044_auto_20210207_1924.py index 84b17055..7289c73d 100644 --- a/bookwyrm/migrations/0044_auto_20210207_1924.py +++ b/bookwyrm/migrations/0044_auto_20210207_1924.py @@ -10,7 +10,10 @@ def set_user(app_registry, schema_editor): shelfbook = app_registry.get_model('bookwyrm', 'ShelfBook') for item in shelfbook.objects.using(db_alias).filter(user__isnull=True): item.user = item.shelf.user - item.save(broadcast=False) + try: + item.save(broadcast=False) + except TypeError: + item.save() class Migration(migrations.Migration): diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py index db8c1af6..ef48ed95 100644 --- a/bookwyrm/models/list.py +++ b/bookwyrm/models/list.py @@ -68,7 +68,7 @@ class ListItem(CollectionItemMixin, BookWyrmModel): order = fields.IntegerField(blank=True, null=True) endorsement = models.ManyToManyField('User', related_name='endorsers') - activity_serializer = activitypub.AddBook + activity_serializer = activitypub.AddListItem object_field = 'book' collection_field = 'book_list' diff --git a/bookwyrm/tests/test_incoming.py b/bookwyrm/tests/test_incoming.py index d84fbd8d..01d0c9a3 100644 --- a/bookwyrm/tests/test_incoming.py +++ b/bookwyrm/tests/test_incoming.py @@ -308,7 +308,7 @@ class Incoming(TestCase): "@context": "https://www.w3.org/ns/activitystreams" } } - incoming.handle_create_list(activity) + incoming.handle_update_list(activity) book_list.refresh_from_db() self.assertEqual(book_list.name, 'Test List') self.assertEqual(book_list.curation, 'curated') @@ -626,7 +626,7 @@ class Incoming(TestCase): activity = { "@context": "https://www.w3.org/ns/activitystreams", - "id": "https://example.com/9e1f41ac-9ddd-4159-aede-9f43c6b9314f", + "id": "https://example.com/9e1f41ac-9ddd-4159", "type": "Block", "actor": "https://example.com/users/rat", "object": "https://example.com/user/mouse" @@ -636,6 +636,29 @@ class Incoming(TestCase): block = models.UserBlocks.objects.get() self.assertEqual(block.user_subject, self.remote_user) self.assertEqual(block.user_object, self.local_user) + self.assertEqual( + block.remote_id, 'https://example.com/9e1f41ac-9ddd-4159') self.assertFalse(models.UserFollows.objects.exists()) self.assertFalse(models.UserFollowRequest.objects.exists()) + + + def test_handle_unblock(self): + ''' unblock a user ''' + self.remote_user.blocks.add(self.local_user) + + block = models.UserBlocks.objects.get() + block.remote_id = 'https://example.com/9e1f41ac-9ddd-4159' + block.save() + + self.assertEqual(block.user_subject, self.remote_user) + self.assertEqual(block.user_object, self.local_user) + activity = {'type': 'Undo', 'object': { + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://example.com/9e1f41ac-9ddd-4159", + "type": "Block", + "actor": "https://example.com/users/rat", + "object": "https://example.com/user/mouse" + }} + incoming.handle_unblock(activity) + self.assertFalse(models.UserBlocks.objects.exists())