From a3df0847e1e4a7ce929e4abef8be49354da67965 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 23 Dec 2020 12:45:40 -0800 Subject: [PATCH 1/3] Fixes celery tasks expanding data not setting many to many fields --- bookwyrm/activitypub/base_activity.py | 36 ++++++++++++--------------- bookwyrm/models/book.py | 2 -- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index b9facf2f..ff057a32 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -111,15 +111,10 @@ class ActivityObject: continue model_field = getattr(model, model_field_name) - try: - # this is for one to many - related_model = model_field.field.model - related_field_name = model_field.field.name - except AttributeError: - # it's a one to one or foreign key - related_model = model_field.related.related_model - related_field_name = model_field.related.related_name - values = [values] + # creating a Work, model_field is 'editions' + # creating a User, model field is 'key_pair' + related_model = model_field.field.model + related_field_name = model_field.field.activitypub_field for item in values: set_related_field.delay( @@ -153,23 +148,24 @@ def set_related_field( with transaction.atomic(): if isinstance(data, str): - item = resolve_remote_id(model, data, save=False) - else: - # look for a match based on all the available data - item = model.find_existing(data) - if not item: - # create a new model instance - item = model.activity_serializer(**data) - item = item.to_model(model, save=False) + existing = model.find_existing_by_remote_id(data) + if existing: + data = existing.to_activity() + else: + data = get_data(data) + activity = model.activity_serializer(**data) + # this must exist because it's the object that triggered this function instance = origin_model.find_existing_by_remote_id(related_remote_id) if not instance: raise ValueError( 'Invalid related remote id: %s' % related_remote_id) - # edition.parent_work = instance, for example - setattr(item, related_field_name, instance) - item.save() + # set the origin's remote id on the activity so it will be there when + # the model instance is created + # edition.parentWork = instance, for example + setattr(activity, related_field_name, instance.remote_id) + activity.to_model(model) def resolve_remote_id(model, remote_id, refresh=False, save=True): diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 7e45eacd..1e1d8d20 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -59,9 +59,7 @@ class Book(BookDataModel): subject_places = fields.ArrayField( models.CharField(max_length=255), blank=True, null=True, default=list ) - # TODO: include an annotation about the type of authorship (ie, translator) authors = fields.ManyToManyField('Author') - # preformatted authorship string for search and easier display cover = fields.ImageField( upload_to='covers/', blank=True, null=True, alt_field='alt_text') first_published_date = fields.DateTimeField(blank=True, null=True) From 365408e86b32f1eb53abdfccd500742b1fa22d86 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 23 Dec 2020 13:33:46 -0800 Subject: [PATCH 2/3] Handle reverse serialized fields with no serialized field --- bookwyrm/activitypub/base_activity.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index ff057a32..5edf3115 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -114,7 +114,7 @@ class ActivityObject: # creating a Work, model_field is 'editions' # creating a User, model field is 'key_pair' related_model = model_field.field.model - related_field_name = model_field.field.activitypub_field + related_field_name = model_field.field.name for item in values: set_related_field.delay( @@ -137,8 +137,8 @@ class ActivityObject: @app.task @transaction.atomic def set_related_field( - model_name, origin_model_name, - related_field_name, related_remote_id, data): + model_name, origin_model_name, related_field_name, + related_remote_id, data): ''' load reverse related fields (editions, attachments) without blocking ''' model = apps.get_model('bookwyrm.%s' % model_name, require_ready=True) origin_model = apps.get_model( @@ -164,8 +164,19 @@ def set_related_field( # set the origin's remote id on the activity so it will be there when # the model instance is created # edition.parentWork = instance, for example - setattr(activity, related_field_name, instance.remote_id) - activity.to_model(model) + model_field = getattr(model, related_field_name) + if hasattr(model_field, 'activitypub_field'): + setattr( + activity, + getattr(model_field, 'activitypub_field'), + instance.remote_id + ) + item = activity.to_model(model) + + # if the related field isn't serialized (attachments on Status), then + # we have to set it post-creation + if not hasattr(model_field, 'activitypub_field'): + setattr(item, related_field_name, instance) def resolve_remote_id(model, remote_id, refresh=False, save=True): From 25d72c5d1e9d9bd1d01c1280c6bfb4d1c058a15e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 23 Dec 2020 13:38:36 -0800 Subject: [PATCH 3/3] Save attachments on incoming statuses --- bookwyrm/activitypub/base_activity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 5edf3115..7ef0920f 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -177,6 +177,7 @@ def set_related_field( # we have to set it post-creation if not hasattr(model_field, 'activitypub_field'): setattr(item, related_field_name, instance) + item.save() def resolve_remote_id(model, remote_id, refresh=False, save=True):