diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index a7439722..9f46e12a 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -10,6 +10,7 @@ from .note import Note, GeneratedNote, Article, Comment, Review, Quotation from .note import Tombstone from .interaction import Boost, Like from .ordered_collection import OrderedCollection, OrderedCollectionPage +from .ordered_collection import BookList from .person import Person, PublicKey from .response import ActivitypubResponse from .book import Edition, Work, Author diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 7ef0920f..3ebf2fab 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -130,6 +130,7 @@ class ActivityObject: def serialize(self): ''' convert to dictionary with context attr ''' data = self.__dict__ + data = {k:v for (k, v) in data.items() if v is not None} data['@context'] = 'https://www.w3.org/ns/activitystreams' return data diff --git a/bookwyrm/activitypub/ordered_collection.py b/bookwyrm/activitypub/ordered_collection.py index 335723f4..94254644 100644 --- a/bookwyrm/activitypub/ordered_collection.py +++ b/bookwyrm/activitypub/ordered_collection.py @@ -12,13 +12,20 @@ class OrderedCollection(ActivityObject): first: str last: str = None name: str = None - summary: str = None owner: str = None to: List[str] = field(default_factory=lambda: []) cc: List[str] = field(default_factory=lambda: []) type: str = 'OrderedCollection' +@dataclass(init=False) +class BookList(OrderedCollection): + ''' structure of an ordered collection activity ''' + summary: str = None + curation: str = 'closed' + type: str = 'List' + + @dataclass(init=False) class OrderedCollectionPage(ActivityObject): ''' structure of an ordered collection activity ''' diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index 889eb5f4..b652ae9f 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -140,20 +140,7 @@ class ActivitypubMixin: def to_activity(self): ''' convert from a model to an activity ''' - activity = {} - for field in self.activity_fields: - field.set_activity_from_field(activity, self) - - if hasattr(self, 'serialize_reverse_fields'): - # for example, editions of a work - for model_field_name, activity_field_name, sort_field in \ - self.serialize_reverse_fields: - related_field = getattr(self, model_field_name) - activity[activity_field_name] = \ - unfurl_related_field(related_field, sort_field) - - if not activity.get('id'): - activity['id'] = self.get_remote_id() + activity = generate_activity(self) return self.activity_serializer(**activity).serialize() @@ -225,7 +212,7 @@ class OrderedCollectionPageMixin(ActivitypubMixin): def to_ordered_collection(self, queryset, \ - remote_id=None, page=False, **kwargs): + remote_id=None, page=False, collection_only=False, **kwargs): ''' an ordered collection of whatevers ''' if not queryset.ordered: raise RuntimeError('queryset must be ordered') @@ -234,18 +221,24 @@ class OrderedCollectionPageMixin(ActivitypubMixin): if page: return to_ordered_collection_page( queryset, remote_id, **kwargs) - name = self.name if hasattr(self, 'name') else None - owner = self.user.remote_id if hasattr(self, 'user') else '' + + if collection_only or not hasattr(self, 'activity_serializer'): + serializer = activitypub.OrderedCollection + activity = {} + else: + serializer = self.activity_serializer + # a dict from the model fields + activity = generate_activity(self) + if remote_id: + activity['id'] = remote_id paginated = Paginator(queryset, PAGE_LENGTH) - return activitypub.OrderedCollection( - id=remote_id, - totalItems=paginated.count, - name=name, - owner=owner, - first='%s?page=1' % remote_id, - last='%s?page=%d' % (remote_id, paginated.num_pages) - ).serialize() + # add computed fields specific to orderd collections + activity['totalItems'] = paginated.count + activity['first'] = '%s?page=1' % remote_id + activity['last'] = '%s?page=%d' % (remote_id, paginated.num_pages) + + return serializer(**activity).serialize() # pylint: disable=unused-argument @@ -287,3 +280,22 @@ class OrderedCollectionMixin(OrderedCollectionPageMixin): def to_activity(self, **kwargs): ''' an ordered collection of the specified model queryset ''' return self.to_ordered_collection(self.collection_queryset, **kwargs) + + +def generate_activity(obj): + ''' go through the fields on an object ''' + activity = {} + for field in obj.activity_fields: + field.set_activity_from_field(activity, obj) + + if hasattr(obj, 'serialize_reverse_fields'): + # for example, editions of a work + for model_field_name, activity_field_name, sort_field in \ + obj.serialize_reverse_fields: + related_field = getattr(obj, model_field_name) + activity[activity_field_name] = \ + unfurl_related_field(related_field, sort_field) + + if not activity.get('id'): + activity['id'] = obj.get_remote_id() + return activity diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index c6571ff4..bc10156b 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -213,7 +213,10 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): setattr(instance, self.name, 'followers') def set_activity_from_field(self, activity, instance): - mentions = [u.remote_id for u in instance.mention_users.all()] + # explicitly to anyone mentioned (statuses only) + mentions = [] + if hasattr(instance, 'mention_users'): + mentions = [u.remote_id for u in instance.mention_users.all()] # this is a link to the followers list followers = instance.user.__class__._meta.get_field('followers')\ .field_to_activity(instance.user.followers) diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py index 801a3f2a..b567929b 100644 --- a/bookwyrm/models/list.py +++ b/bookwyrm/models/list.py @@ -33,6 +33,7 @@ class List(OrderedCollectionMixin, BookWyrmModel): through='ListItem', through_fields=('book_list', 'book'), ) + activity_serializer = activitypub.BookList def get_remote_id(self): ''' don't want the user to be in there in this case ''' diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index dad65974..093dd773 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -94,6 +94,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): return self.to_ordered_collection( self.replies(self), remote_id='%s/replies' % self.remote_id, + collection_only=True, **kwargs )