Use dataclasses to define activitypub (de)serialization (#177)
* Use dataclasses to define activitypub (de)serialization
This commit is contained in:
parent
2c0a07a330
commit
8bbf1fe252
46 changed files with 1449 additions and 1228 deletions
|
@ -1,15 +1,16 @@
|
|||
''' database schema for books and shelves '''
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.http import http_date
|
||||
from model_utils.managers import InheritanceManager
|
||||
|
||||
from fedireads import activitypub
|
||||
from fedireads.settings import DOMAIN
|
||||
from fedireads.utils.fields import ArrayField
|
||||
from .base_model import FedireadsModel
|
||||
|
||||
from fedireads.connectors.settings import CONNECTORS
|
||||
|
||||
from .base_model import ActivityMapping, ActivitypubMixin, FedireadsModel
|
||||
|
||||
|
||||
ConnectorFiles = models.TextChoices('ConnectorFiles', CONNECTORS)
|
||||
class Connector(FedireadsModel):
|
||||
|
@ -45,7 +46,7 @@ class Connector(FedireadsModel):
|
|||
]
|
||||
|
||||
|
||||
class Book(FedireadsModel):
|
||||
class Book(ActivitypubMixin, FedireadsModel):
|
||||
''' a generic book, which can mean either an edition or a work '''
|
||||
# these identifiers apply to both works and editions
|
||||
openlibrary_key = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
@ -86,6 +87,52 @@ class Book(FedireadsModel):
|
|||
published_date = models.DateTimeField(blank=True, null=True)
|
||||
objects = InheritanceManager()
|
||||
|
||||
@property
|
||||
def ap_authors(self):
|
||||
return [a.remote_id for a in self.authors.all()]
|
||||
|
||||
activity_mappings = [
|
||||
ActivityMapping('id', 'remote_id'),
|
||||
|
||||
ActivityMapping('authors', 'ap_authors'),
|
||||
ActivityMapping(
|
||||
'first_published_date',
|
||||
'first_published_date',
|
||||
activity_formatter=lambda d: http_date(d.timestamp()) if d else None
|
||||
),
|
||||
ActivityMapping(
|
||||
'published_date',
|
||||
'published_date',
|
||||
activity_formatter=lambda d: http_date(d.timestamp()) if d else None
|
||||
),
|
||||
|
||||
ActivityMapping('title', 'title'),
|
||||
ActivityMapping('sort_title', 'sort_title'),
|
||||
ActivityMapping('subtitle', 'subtitle'),
|
||||
ActivityMapping('description', 'description'),
|
||||
ActivityMapping('languages', 'languages'),
|
||||
ActivityMapping('series', 'series'),
|
||||
ActivityMapping('series_number', 'series_number'),
|
||||
ActivityMapping('subjects', 'subjects'),
|
||||
ActivityMapping('subject_places', 'subject_places'),
|
||||
|
||||
ActivityMapping('openlibrary_key', 'openlibrary_key'),
|
||||
ActivityMapping('librarything_key', 'librarything_key'),
|
||||
ActivityMapping('goodreads_key', 'goodreads_key'),
|
||||
|
||||
ActivityMapping('work', 'parent_work'),
|
||||
ActivityMapping('isbn_10', 'isbn_10'),
|
||||
ActivityMapping('isbn_13', 'isbn_13'),
|
||||
ActivityMapping('oclc_number', 'oclc_number'),
|
||||
ActivityMapping('asin', 'asin'),
|
||||
ActivityMapping('pages', 'pages'),
|
||||
ActivityMapping('physical_format', 'physical_format'),
|
||||
ActivityMapping('publishers', 'publishers'),
|
||||
|
||||
ActivityMapping('lccn', 'lccn'),
|
||||
ActivityMapping('editions', 'editions_path'),
|
||||
]
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
''' can't be abstract for query reasons, but you shouldn't USE it '''
|
||||
if not isinstance(self, Edition) and not isinstance(self, Work):
|
||||
|
@ -106,7 +153,6 @@ class Book(FedireadsModel):
|
|||
the remote canonical copy '''
|
||||
return 'https://%s/book/%d' % (DOMAIN, self.id)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "<{} key={!r} title={!r}>".format(
|
||||
self.__class__,
|
||||
|
@ -114,16 +160,17 @@ class Book(FedireadsModel):
|
|||
self.title,
|
||||
)
|
||||
|
||||
@property
|
||||
def activitypub_serialize(self):
|
||||
return activitypub.get_book(self)
|
||||
|
||||
|
||||
class Work(Book):
|
||||
''' a work (an abstract concept of a book that manifests in an edition) '''
|
||||
# library of congress catalog control number
|
||||
lccn = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
@property
|
||||
def editions_path(self):
|
||||
return self.remote_id + '/editions'
|
||||
|
||||
|
||||
@property
|
||||
def default_edition(self):
|
||||
ed = Edition.objects.filter(parent_work=self, default=True).first()
|
||||
|
@ -131,6 +178,8 @@ class Work(Book):
|
|||
ed = Edition.objects.filter(parent_work=self).first()
|
||||
return ed
|
||||
|
||||
activity_serializer = activitypub.Work
|
||||
|
||||
|
||||
class Edition(Book):
|
||||
''' an edition of a book '''
|
||||
|
@ -155,8 +204,10 @@ class Edition(Book):
|
|||
)
|
||||
parent_work = models.ForeignKey('Work', on_delete=models.PROTECT, null=True)
|
||||
|
||||
activity_serializer = activitypub.Edition
|
||||
|
||||
class Author(FedireadsModel):
|
||||
|
||||
class Author(ActivitypubMixin, FedireadsModel):
|
||||
''' copy of an author from OL '''
|
||||
openlibrary_key = models.CharField(max_length=255, blank=True, null=True)
|
||||
sync = models.BooleanField(default=True)
|
||||
|
@ -181,17 +232,25 @@ class Author(FedireadsModel):
|
|||
the remote canonical copy (ditto here for author)'''
|
||||
return 'https://%s/book/%d' % (DOMAIN, self.id)
|
||||
|
||||
@property
|
||||
def activitypub_serialize(self):
|
||||
return activitypub.get_author(self)
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
''' Helper to return a displayable name'''
|
||||
if self.name:
|
||||
return name
|
||||
return self.name
|
||||
# don't want to return a spurious space if all of these are None
|
||||
elif self.first_name and self.last_name:
|
||||
if self.first_name and self.last_name:
|
||||
return self.first_name + ' ' + self.last_name
|
||||
else:
|
||||
return self.last_name or self.first_name
|
||||
return self.last_name or self.first_name
|
||||
|
||||
activity_mappings = [
|
||||
ActivityMapping('id', 'remote_id'),
|
||||
ActivityMapping('url', 'remote_id'),
|
||||
ActivityMapping('name', 'display_name'),
|
||||
ActivityMapping('born', 'born'),
|
||||
ActivityMapping('died', 'died'),
|
||||
ActivityMapping('aliases', 'aliases'),
|
||||
ActivityMapping('bio', 'bio'),
|
||||
ActivityMapping('openlibrary_key', 'openlibrary_key'),
|
||||
ActivityMapping('wikipedia_link', 'wikipedia_link'),
|
||||
]
|
||||
activity_serializer = activitypub.Author
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue