From ebb82287c2cc2c8e5ebfc8437515b862b9f0b467 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 22:10:38 -0800 Subject: [PATCH] First pass at recursively resolving foreign keys --- bookwyrm/activitypub/__init__.py | 1 - bookwyrm/activitypub/base_activity.py | 59 +++++++++++++++------------ bookwyrm/models/status.py | 4 +- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index 85245929b..c97e8c49e 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -5,7 +5,6 @@ import sys from .base_activity import ActivityEncoder, PublicKey, Signature from .base_activity import Link, Mention from .base_activity import ActivitySerializerError -from .base_activity import tag_formatter from .image import Image from .note import Note, GeneratedNote, Article, Comment, Review, Quotation from .note import Tombstone diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index caa4aeb80..e4d95b0ec 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -25,12 +25,13 @@ class ActivityEncoder(JSONEncoder): @dataclass -class Link(): +class Link: ''' for tagging a book in a status ''' href: str name: str type: str = 'Link' + @dataclass class Mention(Link): ''' a subtype of Link for mentioning an actor ''' @@ -125,7 +126,7 @@ class ActivityObject: with transaction.atomic(): if instance: - # updating an existing model isntance + # updating an existing model instance for k, v in mapped_fields.items(): setattr(instance, k, v) instance.save() @@ -133,6 +134,9 @@ class ActivityObject: # creating a new model instance instance = model.objects.create(**mapped_fields) + # --- these are all fields that can't be saved until after the + # instance has an id (after it's been saved). ---------------# + # add images for (model_key, value) in image_fields.items(): formatted_value = image_formatter(value) @@ -140,9 +144,20 @@ class ActivityObject: continue getattr(instance, model_key).save(*formatted_value, save=True) + # add many to many fields for (model_key, values) in many_to_many_fields.items(): # mention books, mention users - getattr(instance, model_key).set(values) + if values == MISSING: + continue + model_field = getattr(instance, model_key) + model = model_field.model + items = [] + for link in values: + items.append( + resolve_foreign_key(model, link.get('href')) + ) + getattr(instance, model_key).set(items) + # add one to many fields for (model_key, values) in one_to_many_fields.items(): @@ -177,36 +192,30 @@ def resolve_foreign_key(model, remote_id): if hasattr(model.objects, 'select_subclasses'): result = result.select_subclasses() + # first, check for an existing copy in the database result = result.filter( remote_id=remote_id ).first() + if result: + return result - if not result: + # failing that, load the data and create the object + try: + response = requests.get( + remote_id, + headers={'Accept': 'application/json; charset=utf-8'}, + ) + except ConnectionError: + raise ActivitySerializerError( + 'Could not connect to host for remote_id in %s model: %s' % \ + (model.__name__, remote_id)) + if not response.ok: raise ActivitySerializerError( 'Could not resolve remote_id in %s model: %s' % \ (model.__name__, remote_id)) - return result - -def tag_formatter(tags, tag_type): - ''' helper function to extract foreign keys from tag activity json ''' - if not isinstance(tags, list): - return [] - items = [] - types = { - 'Book': models.Book, - 'Mention': models.User, - } - for tag in [t for t in tags if t.get('type') == tag_type]: - if not tag_type in types: - continue - remote_id = tag.get('href') - try: - item = resolve_foreign_key(types[tag_type], remote_id) - except ActivitySerializerError: - continue - items.append(item) - return items + item = model.activity_serializer(**response.json()) + return item.to_model(model) def image_formatter(image_slug): diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 9d45379cc..b55d2da61 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -80,12 +80,12 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): ActivityMapping( 'tag', 'mention_books', lambda x: tag_formatter(x, 'title', 'Book'), - lambda x: activitypub.tag_formatter(x, 'Book') + lambda x: [i for i in x if x.get('type') == 'Book'] ), ActivityMapping( 'tag', 'mention_users', lambda x: tag_formatter(x, 'username', 'Mention'), - lambda x: activitypub.tag_formatter(x, 'Mention') + lambda x: [i for i in x if x.get('type') == 'Mention'] ), ActivityMapping( 'attachment', 'attachments',