Created mixin for ordered collection items

This commit is contained in:
Mouse Reeve 2021-02-04 12:25:07 -08:00
parent 12e0e6a1f0
commit feb8190d8f
4 changed files with 76 additions and 72 deletions

View file

@ -16,6 +16,7 @@ from django.db.models import Q
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.http import http_date from django.utils.http import http_date
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import PAGE_LENGTH, USER_AGENT from bookwyrm.settings import PAGE_LENGTH, USER_AGENT
from bookwyrm.signatures import make_signature, make_digest from bookwyrm.signatures import make_signature, make_digest
@ -55,6 +56,10 @@ class ActivitypubMixin:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def delete(self, *args, **kwargs):
''' broadcast suitable delete activities '''
@classmethod @classmethod
def find_existing_by_remote_id(cls, remote_id): def find_existing_by_remote_id(cls, remote_id):
''' look up a remote id in the db ''' ''' look up a remote id in the db '''
@ -293,6 +298,34 @@ class OrderedCollectionMixin(OrderedCollectionPageMixin):
return self.to_ordered_collection(self.collection_queryset, **kwargs) return self.to_ordered_collection(self.collection_queryset, **kwargs)
class CollectionItemMixin(ActivitypubMixin):
''' for items that are part of an (Ordered)Collection '''
activity_serializer = activitypub.Add
object_field = collection_field = None
def to_add_activity(self):
''' AP for shelving a book'''
object_field = getattr(self, self.object_field)
collection_field = getattr(self, self.collection_field)
return activitypub.Add(
id='%s#add' % self.remote_id,
actor=self.user.remote_id,
object=object_field.to_activity(),
target=collection_field.remote_id
).serialize()
def to_remove_activity(self):
''' AP for un-shelving a book'''
object_field = getattr(self, self.object_field)
collection_field = getattr(self, self.collection_field)
return activitypub.Remove(
id='%s#remove' % self.remote_id,
actor=self.user.remote_id,
object=object_field.to_activity(),
target=collection_field.remote_id
).serialize()
def generate_activity(obj): def generate_activity(obj):
''' go through the fields on an object ''' ''' go through the fields on an object '''
activity = {} activity = {}
@ -371,15 +404,35 @@ def sign_and_send(sender, data, destination):
def execute_after_save(sender, instance, created, *args, **kwargs): def execute_after_save(sender, instance, created, *args, **kwargs):
''' broadcast when a model instance is created or updated ''' ''' broadcast when a model instance is created or updated '''
# user content like statuses, lists, and shelves, have a "user" field # user content like statuses, lists, and shelves, have a "user" field
if created: user = instance.user if hasattr(instance, 'user') else None
if not hasattr(instance, 'user'): if user and not user.local:
# book data and users don't need to broadcast on creation
return
# we don't want to broadcast when we save remote activities # we don't want to broadcast when we save remote activities
if not instance.user.local:
return
activity = instance.to_create_activity(instance.user)
instance.broadcast(activity, instance.user)
return return
if created:
if not user:
# book data and users don't need to broadcast on creation
return
# ordered collection items get "Add"ed
if hasattr(instance, 'to_add_activity'):
activity = instance.to_add_activity()
else:
# everything else gets "Create"d
activity = instance.to_create_activity(user)
else:
# now, handle updates # now, handle updates
if not user:
# users don't have associated users, they ARE users
if sender.__class__ == 'User':
user = instance
# book data trakcs last editor
elif hasattr(instance, 'last_edited_by'):
user = instance.last_edited_by
# again, if we don't know the user or they're remote, don't bother
if not user or not user.local:
return
activity = instance.to_update_activity(user)
if activity and user and user.local:
instance.broadcast(activity, user)

View file

@ -3,7 +3,7 @@ from django.db import models
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
from .activitypub_mixin import ActivitypubMixin, OrderedCollectionMixin from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
from . import fields from . import fields
@ -49,13 +49,13 @@ class List(OrderedCollectionMixin, BookWyrmModel):
ordering = ('-updated_date',) ordering = ('-updated_date',)
class ListItem(ActivitypubMixin, BookWyrmModel): class ListItem(CollectionItemMixin, BookWyrmModel):
''' ok ''' ''' ok '''
book = fields.ForeignKey( book = fields.ForeignKey(
'Edition', on_delete=models.PROTECT, activitypub_field='object') 'Edition', on_delete=models.PROTECT, activitypub_field='object')
book_list = fields.ForeignKey( book_list = fields.ForeignKey(
'List', on_delete=models.CASCADE, activitypub_field='target') 'List', on_delete=models.CASCADE, activitypub_field='target')
added_by = fields.ForeignKey( user = fields.ForeignKey(
'User', 'User',
on_delete=models.PROTECT, on_delete=models.PROTECT,
activitypub_field='actor' activitypub_field='actor'
@ -66,24 +66,8 @@ class ListItem(ActivitypubMixin, BookWyrmModel):
endorsement = models.ManyToManyField('User', related_name='endorsers') endorsement = models.ManyToManyField('User', related_name='endorsers')
activity_serializer = activitypub.AddBook activity_serializer = activitypub.AddBook
object_field = 'book'
def to_add_activity(self, user): collection_field = 'book_list'
''' AP for shelving a book'''
return activitypub.Add(
id='%s#add' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.book_list.remote_id,
).serialize()
def to_remove_activity(self, user):
''' AP for un-shelving a book'''
return activitypub.Remove(
id='%s#remove' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.book_list.remote_id
).serialize()
class Meta: class Meta:
''' an opinionated constraint! you can't put a book on a list twice ''' ''' an opinionated constraint! you can't put a book on a list twice '''

View file

@ -3,7 +3,7 @@ import re
from django.db import models from django.db import models
from bookwyrm import activitypub from bookwyrm import activitypub
from .activitypub_mixin import ActivitypubMixin, OrderedCollectionMixin from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
from . import fields from . import fields
@ -49,13 +49,13 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel):
unique_together = ('user', 'identifier') unique_together = ('user', 'identifier')
class ShelfBook(ActivitypubMixin, BookWyrmModel): class ShelfBook(CollectionItemMixin, BookWyrmModel):
''' many to many join table for books and shelves ''' ''' many to many join table for books and shelves '''
book = fields.ForeignKey( book = fields.ForeignKey(
'Edition', on_delete=models.PROTECT, activitypub_field='object') 'Edition', on_delete=models.PROTECT, activitypub_field='object')
shelf = fields.ForeignKey( shelf = fields.ForeignKey(
'Shelf', on_delete=models.PROTECT, activitypub_field='target') 'Shelf', on_delete=models.PROTECT, activitypub_field='target')
added_by = fields.ForeignKey( user = fields.ForeignKey(
'User', 'User',
blank=True, blank=True,
null=True, null=True,
@ -64,24 +64,8 @@ class ShelfBook(ActivitypubMixin, BookWyrmModel):
) )
activity_serializer = activitypub.AddBook activity_serializer = activitypub.AddBook
object_field = 'book'
def to_add_activity(self, user): collection_field = 'shelf'
''' AP for shelving a book'''
return activitypub.Add(
id='%s#add' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.shelf.remote_id,
).serialize()
def to_remove_activity(self, user):
''' AP for un-shelving a book'''
return activitypub.Remove(
id='%s#remove' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.shelf.to_activity()
).serialize()
class Meta: class Meta:

View file

@ -5,7 +5,7 @@ from django.db import models
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
from .activitypub_mixin import OrderedCollectionMixin from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
from . import fields from . import fields
@ -41,7 +41,7 @@ class Tag(OrderedCollectionMixin, BookWyrmModel):
super().save(*args, **kwargs) super().save(*args, **kwargs)
class UserTag(BookWyrmModel): class UserTag(CollectionItemMixin, BookWyrmModel):
''' an instance of a tag on a book by a user ''' ''' an instance of a tag on a book by a user '''
user = fields.ForeignKey( user = fields.ForeignKey(
'User', on_delete=models.PROTECT, activitypub_field='actor') 'User', on_delete=models.PROTECT, activitypub_field='actor')
@ -51,25 +51,8 @@ class UserTag(BookWyrmModel):
'Tag', on_delete=models.PROTECT, activitypub_field='target') 'Tag', on_delete=models.PROTECT, activitypub_field='target')
activity_serializer = activitypub.AddBook activity_serializer = activitypub.AddBook
object_field = 'book'
def to_add_activity(self, user): collection_field = 'tag'
''' AP for shelving a book'''
return activitypub.Add(
id='%s#add' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.remote_id,
).serialize()
def to_remove_activity(self, user):
''' AP for un-shelving a book'''
return activitypub.Remove(
id='%s#remove' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.remote_id,
).serialize()
class Meta: class Meta:
''' unqiueness constraint ''' ''' unqiueness constraint '''