serialize book and author models

This commit is contained in:
Mouse Reeve 2020-11-30 14:40:26 -08:00
parent 3966c84e08
commit 77aead722d
3 changed files with 49 additions and 88 deletions

View file

@ -4,29 +4,29 @@ from django.utils import timezone
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
from bookwyrm.utils.fields import ArrayField
from .base_model import ActivitypubMixin, ActivityMapping, BookWyrmModel from .base_model import ActivitypubMixin, BookWyrmModel
from . import fields
class Author(ActivitypubMixin, BookWyrmModel): class Author(ActivitypubMixin, BookWyrmModel):
''' basic biographic info ''' ''' basic biographic info '''
origin_id = models.CharField(max_length=255, null=True) origin_id = models.CharField(max_length=255, null=True)
''' copy of an author from OL ''' ''' copy of an author from OL '''
openlibrary_key = models.CharField(max_length=255, blank=True, null=True) openlibrary_key = fields.CharField(max_length=255, blank=True, null=True)
sync = models.BooleanField(default=True) sync = models.BooleanField(default=True)
last_sync_date = models.DateTimeField(default=timezone.now) last_sync_date = models.DateTimeField(default=timezone.now)
wikipedia_link = models.CharField(max_length=255, blank=True, null=True) wikipedia_link = fields.CharField(max_length=255, blank=True, null=True)
# idk probably other keys would be useful here? # idk probably other keys would be useful here?
born = models.DateTimeField(blank=True, null=True) born = fields.DateTimeField(blank=True, null=True)
died = models.DateTimeField(blank=True, null=True) died = fields.DateTimeField(blank=True, null=True)
name = models.CharField(max_length=255) name = fields.CharField(max_length=255)
last_name = models.CharField(max_length=255, blank=True, null=True) last_name = models.CharField(max_length=255, blank=True, null=True)
first_name = models.CharField(max_length=255, blank=True, null=True) first_name = models.CharField(max_length=255, blank=True, null=True)
aliases = ArrayField( aliases = fields.ArrayField(
models.CharField(max_length=255), blank=True, default=list models.CharField(max_length=255), blank=True, default=list
) )
bio = models.TextField(null=True, blank=True) bio = fields.TextField(null=True, blank=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
''' can't be abstract for query reasons, but you shouldn't USE it ''' ''' can't be abstract for query reasons, but you shouldn't USE it '''
@ -52,14 +52,4 @@ class Author(ActivitypubMixin, BookWyrmModel):
return self.first_name + ' ' + self.last_name return self.first_name + ' ' + self.last_name
return self.last_name or self.first_name return self.last_name or self.first_name
activity_mappings = [
ActivityMapping('id', 'remote_id'),
ActivityMapping('name', 'name'),
ActivityMapping('born', 'born'),
ActivityMapping('died', 'died'),
ActivityMapping('aliases', 'aliases'),
ActivityMapping('bio', 'bio'),
ActivityMapping('openlibraryKey', 'openlibrary_key'),
ActivityMapping('wikipediaLink', 'wikipedia_link'),
]
activity_serializer = activitypub.Author activity_serializer = activitypub.Author

View file

@ -7,18 +7,18 @@ from model_utils.managers import InheritanceManager
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
from bookwyrm.utils.fields import ArrayField
from .base_model import ActivityMapping, BookWyrmModel from .base_model import BookWyrmModel
from .base_model import ActivitypubMixin, OrderedCollectionPageMixin from .base_model import ActivitypubMixin, OrderedCollectionPageMixin
from . import fields
class Book(ActivitypubMixin, BookWyrmModel): class Book(ActivitypubMixin, BookWyrmModel):
''' a generic book, which can mean either an edition or a work ''' ''' a generic book, which can mean either an edition or a work '''
origin_id = models.CharField(max_length=255, null=True, blank=True) origin_id = models.CharField(max_length=255, null=True, blank=True)
# these identifiers apply to both works and editions # these identifiers apply to both works and editions
openlibrary_key = models.CharField(max_length=255, blank=True, null=True) openlibrary_key = fields.CharField(max_length=255, blank=True, null=True)
librarything_key = models.CharField(max_length=255, blank=True, null=True) librarything_key = fields.CharField(max_length=255, blank=True, null=True)
goodreads_key = models.CharField(max_length=255, blank=True, null=True) goodreads_key = fields.CharField(max_length=255, blank=True, null=True)
# info about where the data comes from and where/if to sync # info about where the data comes from and where/if to sync
sync = models.BooleanField(default=True) sync = models.BooleanField(default=True)
@ -30,66 +30,31 @@ class Book(ActivitypubMixin, BookWyrmModel):
# TODO: edit history # TODO: edit history
# book/work metadata # book/work metadata
title = models.CharField(max_length=255) title = fields.CharField(max_length=255)
sort_title = models.CharField(max_length=255, blank=True, null=True) sort_title = fields.CharField(max_length=255, blank=True, null=True)
subtitle = models.CharField(max_length=255, blank=True, null=True) subtitle = fields.CharField(max_length=255, blank=True, null=True)
description = models.TextField(blank=True, null=True) description = fields.TextField(blank=True, null=True)
languages = ArrayField( languages = fields.ArrayField(
models.CharField(max_length=255), blank=True, default=list models.CharField(max_length=255), blank=True, default=list
) )
series = models.CharField(max_length=255, blank=True, null=True) series = fields.CharField(max_length=255, blank=True, null=True)
series_number = models.CharField(max_length=255, blank=True, null=True) series_number = fields.CharField(max_length=255, blank=True, null=True)
subjects = ArrayField( subjects = fields.ArrayField(
models.CharField(max_length=255), blank=True, null=True, default=list models.CharField(max_length=255), blank=True, null=True, default=list
) )
subject_places = ArrayField( subject_places = fields.ArrayField(
models.CharField(max_length=255), blank=True, null=True, default=list models.CharField(max_length=255), blank=True, null=True, default=list
) )
# TODO: include an annotation about the type of authorship (ie, translator) # TODO: include an annotation about the type of authorship (ie, translator)
authors = models.ManyToManyField('Author') authors = fields.ManyToManyField('Author')
# preformatted authorship string for search and easier display # preformatted authorship string for search and easier display
author_text = models.CharField(max_length=255, blank=True, null=True) author_text = models.CharField(max_length=255, blank=True, null=True)
cover = models.ImageField(upload_to='covers/', blank=True, null=True) cover = fields.ImageField(upload_to='covers/', blank=True, null=True)
first_published_date = models.DateTimeField(blank=True, null=True) first_published_date = fields.DateTimeField(blank=True, null=True)
published_date = models.DateTimeField(blank=True, null=True) published_date = fields.DateTimeField(blank=True, null=True)
objects = InheritanceManager() objects = InheritanceManager()
activity_mappings = [
ActivityMapping('id', 'remote_id'),
ActivityMapping('authors', 'authors'),
ActivityMapping('firstPublishedDate', 'firstpublished_date'),
ActivityMapping('publishedDate', 'published_date'),
ActivityMapping('title', 'title'),
ActivityMapping('sortTitle', 'sort_title'),
ActivityMapping('subtitle', 'subtitle'),
ActivityMapping('description', 'description'),
ActivityMapping('languages', 'languages'),
ActivityMapping('series', 'series'),
ActivityMapping('seriesNumber', 'series_number'),
ActivityMapping('subjects', 'subjects'),
ActivityMapping('subjectPlaces', 'subject_places'),
ActivityMapping('openlibraryKey', 'openlibrary_key'),
ActivityMapping('librarythingKey', 'librarything_key'),
ActivityMapping('goodreadsKey', 'goodreads_key'),
ActivityMapping('work', 'parent_work'),
ActivityMapping('isbn10', 'isbn_10'),
ActivityMapping('isbn13', 'isbn_13'),
ActivityMapping('oclcNumber', 'oclc_number'),
ActivityMapping('asin', 'asin'),
ActivityMapping('pages', 'pages'),
ActivityMapping('physicalFormat', 'physical_format'),
ActivityMapping('publishers', 'publishers'),
ActivityMapping('lccn', 'lccn'),
ActivityMapping('editions', 'editions'),
ActivityMapping('defaultEdition', 'default_edition'),
ActivityMapping('cover', 'cover'),
]
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
''' can't be abstract for query reasons, but you shouldn't USE it ''' ''' can't be abstract for query reasons, but you shouldn't USE it '''
if not isinstance(self, Edition) and not isinstance(self, Work): if not isinstance(self, Edition) and not isinstance(self, Work):
@ -118,9 +83,9 @@ class Book(ActivitypubMixin, BookWyrmModel):
class Work(OrderedCollectionPageMixin, Book): class Work(OrderedCollectionPageMixin, Book):
''' a work (an abstract concept of a book that manifests in an edition) ''' ''' a work (an abstract concept of a book that manifests in an edition) '''
# library of congress catalog control number # library of congress catalog control number
lccn = models.CharField(max_length=255, blank=True, null=True) lccn = fields.CharField(max_length=255, blank=True, null=True)
# this has to be nullable but should never be null # this has to be nullable but should never be null
default_edition = models.ForeignKey( default_edition = fields.ForeignKey(
'Edition', 'Edition',
on_delete=models.PROTECT, on_delete=models.PROTECT,
null=True null=True
@ -131,18 +96,19 @@ class Work(OrderedCollectionPageMixin, Book):
return self.default_edition or self.editions.first() return self.default_edition or self.editions.first()
activity_serializer = activitypub.Work activity_serializer = activitypub.Work
serialize_reverse_fields = ['editions']
class Edition(Book): class Edition(Book):
''' an edition of a book ''' ''' an edition of a book '''
# these identifiers only apply to editions, not works # these identifiers only apply to editions, not works
isbn_10 = models.CharField(max_length=255, blank=True, null=True) isbn_10 = fields.CharField(max_length=255, blank=True, null=True)
isbn_13 = models.CharField(max_length=255, blank=True, null=True) isbn_13 = fields.CharField(max_length=255, blank=True, null=True)
oclc_number = models.CharField(max_length=255, blank=True, null=True) oclc_number = fields.CharField(max_length=255, blank=True, null=True)
asin = models.CharField(max_length=255, blank=True, null=True) asin = fields.CharField(max_length=255, blank=True, null=True)
pages = models.IntegerField(blank=True, null=True) pages = fields.IntegerField(blank=True, null=True)
physical_format = models.CharField(max_length=255, blank=True, null=True) physical_format = fields.CharField(max_length=255, blank=True, null=True)
publishers = ArrayField( publishers = fields.ArrayField(
models.CharField(max_length=255), blank=True, default=list models.CharField(max_length=255), blank=True, default=list
) )
shelves = models.ManyToManyField( shelves = models.ManyToManyField(
@ -151,8 +117,9 @@ class Edition(Book):
through='ShelfBook', through='ShelfBook',
through_fields=('book', 'shelf') through_fields=('book', 'shelf')
) )
parent_work = models.ForeignKey( parent_work = fields.ForeignKey(
'Work', on_delete=models.PROTECT, null=True, related_name='editions') 'Work', on_delete=models.PROTECT, null=True,
related_name='editions', activitypub_field='work')
activity_serializer = activitypub.Edition activity_serializer = activitypub.Edition
name_field = 'title' name_field = 'title'
@ -167,7 +134,6 @@ class Edition(Book):
return super().save(*args, **kwargs) return super().save(*args, **kwargs)
def isbn_10_to_13(isbn_10): def isbn_10_to_13(isbn_10):
''' convert an isbn 10 into an isbn 13 ''' ''' convert an isbn 10 into an isbn 13 '''
isbn_10 = re.sub(r'[^0-9X]', '', isbn_10) isbn_10 = re.sub(r'[^0-9X]', '', isbn_10)

View file

@ -3,6 +3,7 @@ import re
from uuid import uuid4 from uuid import uuid4
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.contrib.postgres.fields import ArrayField as DjangoArrayField
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.db import models from django.db import models
@ -97,8 +98,6 @@ class ForeignKey(ActivitypubFieldMixin, models.ForeignKey):
class OneToOneField(ActivitypubFieldMixin, models.OneToOneField): class OneToOneField(ActivitypubFieldMixin, models.OneToOneField):
''' activitypub-aware foreign key field ''' ''' activitypub-aware foreign key field '''
def to_activity(self, value): def to_activity(self, value):
print('HIIIII')
print(value)
if not value: if not value:
return None return None
return value.to_activity() return value.to_activity()
@ -116,7 +115,7 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField):
def to_activity(self, value): def to_activity(self, value):
if self.link_only: if self.link_only:
return '%s/followers' % value.instance.remote_id return '%s/followers' % value.instance.remote_id
return [i.remote_id for i in value] return [i.remote_id for i in value.all()]
def from_activity(self, activity_data): def from_activity(self, activity_data):
if self.link_only: if self.link_only:
@ -185,8 +184,14 @@ class ImageField(ActivitypubFieldMixin, models.ImageField):
class DateTimeField(ActivitypubFieldMixin, models.DateTimeField): class DateTimeField(ActivitypubFieldMixin, models.DateTimeField):
''' activitypub-aware datetime field ''' ''' activitypub-aware datetime field '''
def to_activity(self, value): def to_activity(self, value):
if not value:
return None
return value.isoformat() return value.isoformat()
class ArrayField(ActivitypubFieldMixin, DjangoArrayField):
''' activitypub-aware array field '''
def to_activity(self, value):
return [str(i) for i in value]
class CharField(ActivitypubFieldMixin, models.CharField): class CharField(ActivitypubFieldMixin, models.CharField):
''' activitypub-aware char field ''' ''' activitypub-aware char field '''