From 69a664401145e3dd8937a211603d07f61d665782 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 15:34:47 -0800 Subject: [PATCH 01/10] Corrects activitypub fields to camelcase in Book --- bookwyrm/activitypub/book.py | 34 +++++++++++++++++----------------- bookwyrm/models/book.py | 24 ++++++++++++------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index 2bfafba70..01bdcca91 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -7,23 +7,23 @@ from .base_activity import ActivityObject, Image @dataclass(init=False) class Book(ActivityObject): ''' serializes an edition or work, abstract ''' - authors: List[str] - first_published_date: str - published_date: str - title: str - sort_title: str - subtitle: str - description: str + sortTitle: str = '' + subtitle: str = '' + description: str = '' languages: List[str] - series: str - series_number: str + series: str = '' + seriesNumber: str = '' subjects: List[str] - subject_places: List[str] + subjectPlaces: List[str] - openlibrary_key: str - librarything_key: str - goodreads_key: str + authors: List[str] + firstPublishedDate: str = '' + publishedDate: str = '' + + openlibraryKey: str = '' + librarythingKey: str = '' + goodreadsKey: str = '' attachment: List[Image] = field(default_factory=lambda: []) type: str = 'Book' @@ -32,12 +32,12 @@ class Book(ActivityObject): @dataclass(init=False) class Edition(Book): ''' Edition instance of a book object ''' - isbn_10: str - isbn_13: str - oclc_number: str + isbn10: str + isbn13: str + oclcNumber: str asin: str pages: str - physical_format: str + physicalFormat: str publishers: List[str] work: str diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 7ec330da2..7a6528327 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -70,30 +70,30 @@ class Book(ActivitypubMixin, BookWyrmModel): ActivityMapping('id', 'remote_id'), ActivityMapping('authors', 'ap_authors'), - ActivityMapping('first_published_date', 'first_published_date'), - ActivityMapping('published_date', 'published_date'), + ActivityMapping('firstPublishedDate', 'firstpublished_date'), + ActivityMapping('publishedDate', 'published_date'), ActivityMapping('title', 'title'), - ActivityMapping('sort_title', 'sort_title'), + ActivityMapping('sortTitle', 'sort_title'), ActivityMapping('subtitle', 'subtitle'), ActivityMapping('description', 'description'), ActivityMapping('languages', 'languages'), ActivityMapping('series', 'series'), - ActivityMapping('series_number', 'series_number'), + ActivityMapping('seriesNumber', 'series_number'), ActivityMapping('subjects', 'subjects'), - ActivityMapping('subject_places', 'subject_places'), + ActivityMapping('subjectPlaces', 'subject_places'), - ActivityMapping('openlibrary_key', 'openlibrary_key'), - ActivityMapping('librarything_key', 'librarything_key'), - ActivityMapping('goodreads_key', 'goodreads_key'), + ActivityMapping('openlibraryKey', 'openlibrary_key'), + ActivityMapping('librarythingKey', 'librarything_key'), + ActivityMapping('goodreadsKey', 'goodreads_key'), ActivityMapping('work', 'ap_parent_work'), - ActivityMapping('isbn_10', 'isbn_10'), - ActivityMapping('isbn_13', 'isbn_13'), - ActivityMapping('oclc_number', 'oclc_number'), + ActivityMapping('isbn10', 'isbn_10'), + ActivityMapping('isbn13', 'isbn_13'), + ActivityMapping('oclcNumber', 'oclc_number'), ActivityMapping('asin', 'asin'), ActivityMapping('pages', 'pages'), - ActivityMapping('physical_format', 'physical_format'), + ActivityMapping('physicalFormat', 'physical_format'), ActivityMapping('publishers', 'publishers'), ActivityMapping('lccn', 'lccn'), From 624ff71a112dacd298c02fa6fdf447775c60a6f5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 17:20:01 -0800 Subject: [PATCH 02/10] Makes attachment Images a serializable class --- .../migrations/0014_auto_20201128_0118.py | 17 ++++++++++ bookwyrm/models/__init__.py | 10 ++++-- bookwyrm/models/attachment.py | 31 +++++++++++++++++++ bookwyrm/models/status.py | 11 ------- 4 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 bookwyrm/migrations/0014_auto_20201128_0118.py create mode 100644 bookwyrm/models/attachment.py diff --git a/bookwyrm/migrations/0014_auto_20201128_0118.py b/bookwyrm/migrations/0014_auto_20201128_0118.py new file mode 100644 index 000000000..babdd7805 --- /dev/null +++ b/bookwyrm/migrations/0014_auto_20201128_0118.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.7 on 2020-11-28 01:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0013_book_origin_id'), + ] + + operations = [ + migrations.RenameModel( + old_name='Attachment', + new_name='Image', + ), + ] diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 81c64831b..3d8544788 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -5,15 +5,21 @@ import sys from .book import Book, Work, Edition from .author import Author from .connector import Connector -from .relationship import UserFollows, UserFollowRequest, UserBlocks + from .shelf import Shelf, ShelfBook + from .status import Status, GeneratedNote, Review, Comment, Quotation -from .status import Attachment, Favorite, Boost, Notification, ReadThrough +from .status import Favorite, Boost, Notification, ReadThrough +from .attachment import Image + from .tag import Tag + from .user import User +from .relationship import UserFollows, UserFollowRequest, UserBlocks from .federated_server import FederatedServer from .import_job import ImportJob, ImportItem + from .site import SiteSettings, SiteInvite, PasswordReset cls_members = inspect.getmembers(sys.modules[__name__], inspect.isclass) diff --git a/bookwyrm/models/attachment.py b/bookwyrm/models/attachment.py new file mode 100644 index 000000000..b3e8bdb72 --- /dev/null +++ b/bookwyrm/models/attachment.py @@ -0,0 +1,31 @@ +''' media that is posted in the app ''' +from django.db import models + +from bookwyrm import activitypub +from .base_model import ActivitypubMixin +from .base_model import ActivityMapping, BookWyrmModel + + +class Attachment(ActivitypubMixin, BookWyrmModel): + ''' an image (or, in the future, video etc) associated with a status ''' + status = models.ForeignKey( + 'Status', + on_delete=models.CASCADE, + related_name='attachments' + ) + class Meta: + ''' one day we'll have other types of attachments besides images ''' + abstract = True + + activity_mappings = [ + ActivityMapping('id', 'remote_id'), + ActivityMapping('url', 'image'), + ActivityMapping('name', 'caption'), + ] + +class Image(Attachment): + ''' an image attachment ''' + image = models.ImageField(upload_to='status/', null=True, blank=True) + caption = models.TextField(null=True, blank=True) + + activity_serializer = activitypub.Image diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 6f534f506..1b8923891 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -151,17 +151,6 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): return super().save(*args, **kwargs) -class Attachment(BookWyrmModel): - ''' an image (or, in the future, video etc) associated with a status ''' - status = models.ForeignKey( - 'Status', - on_delete=models.CASCADE, - related_name='attachments' - ) - image = models.ImageField(upload_to='status/', null=True, blank=True) - caption = models.TextField(null=True, blank=True) - - class GeneratedNote(Status): ''' these are app-generated messages about user activity ''' @property From 4ae785a7f7e76ec38f0909063cfa109367b74495 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 17:58:21 -0800 Subject: [PATCH 03/10] move image activity to its own file --- bookwyrm/activitypub/__init__.py | 3 ++- bookwyrm/activitypub/base_activity.py | 19 +++---------------- bookwyrm/activitypub/book.py | 5 +++-- bookwyrm/activitypub/image.py | 9 +++++++++ bookwyrm/activitypub/note.py | 3 ++- bookwyrm/activitypub/person.py | 3 ++- 6 files changed, 21 insertions(+), 21 deletions(-) create mode 100644 bookwyrm/activitypub/image.py diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index 852db345c..3dccc31a4 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -2,11 +2,12 @@ import inspect import sys -from .base_activity import ActivityEncoder, Image, PublicKey, Signature +from .base_activity import ActivityEncoder, PublicKey, Signature from .base_activity import Link, Mention from .base_activity import ActivitySerializerError from .base_activity import tag_formatter from .base_activity import image_formatter, image_attachments_formatter +from .image import Image from .note import Note, GeneratedNote, Article, Comment, Review, Quotation from .note import Tombstone from .interaction import Boost, Like diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 54c2baea9..3fe44f8b7 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -23,13 +23,6 @@ class ActivityEncoder(JSONEncoder): return o.__dict__ -@dataclass -class Image: - ''' image block ''' - url: str - type: str = 'Image' - - @dataclass class Link(): ''' for tagging a book in a status ''' @@ -146,6 +139,7 @@ class ActivityObject: for (model_key, value) in image_fields.items(): if not value: continue + #formatted_value = image_formatter(value) getattr(instance, model_key).save(*value, save=True) # add one to many fields @@ -212,16 +206,9 @@ def tag_formatter(tags, tag_type): def image_formatter(image_json): ''' helper function to load images and format them for a model ''' - if isinstance(image_json, list): - try: - image_json = image_json[0] - except IndexError: - return None - - if not image_json or not hasattr(image_json, 'url'): + url = image.get('url') + if not url: return None - url = image_json.get('url') - try: response = requests.get(url) except ConnectionError: diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index 01bdcca91..02cab2818 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -2,7 +2,8 @@ from dataclasses import dataclass, field from typing import List -from .base_activity import ActivityObject, Image +from .base_activity import ActivityObject +from .image import Image @dataclass(init=False) class Book(ActivityObject): @@ -25,7 +26,7 @@ class Book(ActivityObject): librarythingKey: str = '' goodreadsKey: str = '' - attachment: List[Image] = field(default_factory=lambda: []) + cover: Image = field(default_factory=lambda: {}) type: str = 'Book' diff --git a/bookwyrm/activitypub/image.py b/bookwyrm/activitypub/image.py new file mode 100644 index 000000000..c0ad3ea30 --- /dev/null +++ b/bookwyrm/activitypub/image.py @@ -0,0 +1,9 @@ +''' an image, nothing fancy ''' +from dataclasses import dataclass + +@dataclass +class Image: + ''' image block ''' + url: str + name: str = '' + type: str = 'Image' diff --git a/bookwyrm/activitypub/note.py b/bookwyrm/activitypub/note.py index 9eab952d3..aeb078dcc 100644 --- a/bookwyrm/activitypub/note.py +++ b/bookwyrm/activitypub/note.py @@ -2,7 +2,8 @@ from dataclasses import dataclass, field from typing import Dict, List -from .base_activity import ActivityObject, Image, Link +from .base_activity import ActivityObject, Link +from .image import Image @dataclass(init=False) class Tombstone(ActivityObject): diff --git a/bookwyrm/activitypub/person.py b/bookwyrm/activitypub/person.py index 324d68e32..e7d720ecf 100644 --- a/bookwyrm/activitypub/person.py +++ b/bookwyrm/activitypub/person.py @@ -2,7 +2,8 @@ from dataclasses import dataclass, field from typing import Dict -from .base_activity import ActivityObject, Image, PublicKey +from .base_activity import ActivityObject, PublicKey +from .image import Image @dataclass(init=False) class Person(ActivityObject): From 24806903781dd634cf95de2b2039037f9ed64e19 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 18:26:07 -0800 Subject: [PATCH 04/10] Automatically handle image fields in model serializer --- bookwyrm/activitypub/base_activity.py | 2 +- bookwyrm/models/base_model.py | 13 +++++++------ bookwyrm/models/book.py | 15 ++------------- bookwyrm/models/user.py | 6 +----- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 3fe44f8b7..33820e1e5 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -139,7 +139,7 @@ class ActivityObject: for (model_key, value) in image_fields.items(): if not value: continue - #formatted_value = image_formatter(value) + formatted_value = image_formatter(value) getattr(instance, model_key).save(*value, save=True) # add one to many fields diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index 8c28c8abb..4109a49b9 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -10,6 +10,7 @@ from Crypto.PublicKey import RSA from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 from django.db import models +from django.db.models.fields.files import ImageFieldFile from django.dispatch import receiver from bookwyrm import activitypub @@ -77,16 +78,18 @@ class ActivitypubMixin: value = value.remote_id elif isinstance(value, datetime): value = value.isoformat() + elif isinstance(value, ImageFieldFile): + value = image_formatter(value) # run the custom formatter function set in the model - result = mapping.activity_formatter(value) + formatted_value = mapping.activity_formatter(value) if mapping.activity_key in fields and \ isinstance(fields[mapping.activity_key], list): # there can be two database fields that map to the same AP list # this happens in status tags, which combines user and book tags - fields[mapping.activity_key] += result + fields[mapping.activity_key] += formatted_value else: - fields[mapping.activity_key] = result + fields[mapping.activity_key] = formatted_value if pure: return self.pure_activity_serializer( @@ -270,12 +273,10 @@ def tag_formatter(items, name_field, activity_type): return tags -def image_formatter(image, default_path=None): +def image_formatter(image): ''' convert images into activitypub json ''' if image and hasattr(image, 'url'): url = image.url - elif default_path: - url = default_path else: return None url = 'https://%s%s' % (DOMAIN, url) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 7a6528327..132b4c070 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -12,7 +12,6 @@ from bookwyrm.utils.fields import ArrayField from .base_model import ActivityMapping, BookWyrmModel from .base_model import ActivitypubMixin, OrderedCollectionPageMixin -from .base_model import image_attachments_formatter class Book(ActivitypubMixin, BookWyrmModel): ''' a generic book, which can mean either an edition or a work ''' @@ -61,11 +60,6 @@ class Book(ActivitypubMixin, BookWyrmModel): ''' the activitypub serialization should be a list of author ids ''' return [a.remote_id for a in self.authors.all()] - @property - def ap_parent_work(self): - ''' reference the work via local id not remote ''' - return self.parent_work.remote_id - activity_mappings = [ ActivityMapping('id', 'remote_id'), @@ -87,7 +81,7 @@ class Book(ActivitypubMixin, BookWyrmModel): ActivityMapping('librarythingKey', 'librarything_key'), ActivityMapping('goodreadsKey', 'goodreads_key'), - ActivityMapping('work', 'ap_parent_work'), + ActivityMapping('work', 'parent_work'), ActivityMapping('isbn10', 'isbn_10'), ActivityMapping('isbn13', 'isbn_13'), ActivityMapping('oclcNumber', 'oclc_number'), @@ -98,12 +92,7 @@ class Book(ActivitypubMixin, BookWyrmModel): ActivityMapping('lccn', 'lccn'), ActivityMapping('editions', 'editions_path'), - ActivityMapping( - 'attachment', 'cover', - # this expects an iterable and the field is just an image - lambda x: image_attachments_formatter([x]), - activitypub.image_formatter - ), + ActivityMapping('cover', 'cover'), ] def save(self, *args, **kwargs): diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index b38a4b192..4d511d561 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -112,11 +112,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): activity_formatter=lambda x: {'sharedInbox': x}, model_formatter=lambda x: x.get('sharedInbox') ), - ActivityMapping( - 'icon', 'avatar', - lambda x: image_formatter(x, '/static/images/default_avi.jpg'), - activitypub.image_formatter - ), + ActivityMapping('icon', 'avatar'), ActivityMapping( 'manuallyApprovesFollowers', 'manually_approves_followers' From 4626d94ab933fe37314210a3cbec359d8c45096f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 20:11:22 -0800 Subject: [PATCH 05/10] handle image attachments recursively --- bookwyrm/activitypub/__init__.py | 1 - bookwyrm/activitypub/base_activity.py | 94 +++++++++---------- bookwyrm/activitypub/image.py | 6 +- .../migrations/0015_auto_20201128_0349.py | 19 ++++ bookwyrm/models/attachment.py | 3 +- bookwyrm/models/status.py | 1 - bookwyrm/signatures.py | 2 +- 7 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 bookwyrm/migrations/0015_auto_20201128_0349.py diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index 3dccc31a4..85245929b 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -6,7 +6,6 @@ from .base_activity import ActivityEncoder, PublicKey, Signature from .base_activity import Link, Mention from .base_activity import ActivitySerializerError from .base_activity import tag_formatter -from .base_activity import image_formatter, image_attachments_formatter from .image import Image from .note import Note, GeneratedNote, Article, Comment, Review, Quotation from .note import Tombstone diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 33820e1e5..31e6d2e0e 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -4,6 +4,7 @@ from json import JSONEncoder from uuid import uuid4 from django.core.files.base import ContentFile +from django.db import transaction from django.db.models.fields.related_descriptors \ import ForwardManyToOneDescriptor, ManyToManyDescriptor, \ ReverseManyToOneDescriptor @@ -106,14 +107,15 @@ class ActivityObject: formatted_value = mapping.model_formatter(value) if isinstance(model_field, ForwardManyToOneDescriptor) and \ formatted_value: - # foreign key remote id reolver + # foreign key remote id reolver (work on Edition, for example) fk_model = model_field.field.related_model reference = resolve_foreign_key(fk_model, formatted_value) mapped_fields[mapping.model_key] = reference elif isinstance(model_field, ManyToManyDescriptor): + # status mentions book/users many_to_many_fields[mapping.model_key] = formatted_value elif isinstance(model_field, ReverseManyToOneDescriptor): - # attachments on statuses, for example + # attachments on Status, for example one_to_many_fields[mapping.model_key] = formatted_value elif isinstance(model_field, ImageFileDescriptor): # image fields need custom handling @@ -121,38 +123,39 @@ class ActivityObject: else: mapped_fields[mapping.model_key] = formatted_value - if instance: - # updating an existing model isntance - for k, v in mapped_fields.items(): - setattr(instance, k, v) - instance.save() - else: - # creating a new model instance - instance = model.objects.create(**mapped_fields) - - # add many-to-many fields - for (model_key, values) in many_to_many_fields.items(): - getattr(instance, model_key).set(values) - instance.save() - - # add images - for (model_key, value) in image_fields.items(): - if not value: - continue - formatted_value = image_formatter(value) - getattr(instance, model_key).save(*value, save=True) - - # add one to many fields - for (model_key, values) in one_to_many_fields.items(): - items = [] - for item in values: - # the reference id wasn't available at creation time - setattr(item, instance.__class__.__name__.lower(), instance) - item.save() - items.append(item) - if items: - getattr(instance, model_key).set(items) + with transaction.atomic(): + if instance: + # updating an existing model isntance + for k, v in mapped_fields.items(): + setattr(instance, k, v) instance.save() + else: + # creating a new model instance + instance = model.objects.create(**mapped_fields) + + # add images + for (model_key, value) in image_fields.items(): + if not value: + continue + formatted_value = image_formatter(value) + getattr(instance, model_key).save(*formatted_value, save=True) + + for (model_key, values) in many_to_many_fields.items(): + # mention books, mention users + getattr(instance, model_key).set(values) + + # add one to many fields + for (model_key, values) in one_to_many_fields.items(): + model_field = getattr(instance, model_key) + model = model_field.model + for item in values: + item = model.activity_serializer(**item) + field_name = instance.__class__.__name__.lower() + with transaction.atomic(): + item = item.to_model(model) + setattr(item, field_name, instance) + item.save() + return instance @@ -204,9 +207,16 @@ def tag_formatter(tags, tag_type): return items -def image_formatter(image_json): +def image_formatter(image_slug): ''' helper function to load images and format them for a model ''' - url = image.get('url') + # when it's an inline image (User avatar/icon, Book cover), it's a json + # blob, but when it's an attached image, it's just a url + if isinstance(image_slug, dict): + url = image_slug.get('url') + elif isinstance(image_slug, str): + url = image_slug + else: + return None if not url: return None try: @@ -219,17 +229,3 @@ def image_formatter(image_json): image_name = str(uuid4()) + '.' + url.split('.')[-1] image_content = ContentFile(response.content) return [image_name, image_content] - - -def image_attachments_formatter(images_json): - ''' deserialize a list of images ''' - attachments = [] - for image in images_json: - caption = image.get('name') - attachment = models.Attachment(caption=caption) - image_field = image_formatter(image) - if not image_field: - continue - attachment.image.save(*image_field, save=False) - attachments.append(attachment) - return attachments diff --git a/bookwyrm/activitypub/image.py b/bookwyrm/activitypub/image.py index c0ad3ea30..569f83c5d 100644 --- a/bookwyrm/activitypub/image.py +++ b/bookwyrm/activitypub/image.py @@ -1,9 +1,11 @@ ''' an image, nothing fancy ''' from dataclasses import dataclass +from .base_activity import ActivityObject -@dataclass -class Image: +@dataclass(init=False) +class Image(ActivityObject): ''' image block ''' url: str name: str = '' type: str = 'Image' + id: str = '' diff --git a/bookwyrm/migrations/0015_auto_20201128_0349.py b/bookwyrm/migrations/0015_auto_20201128_0349.py new file mode 100644 index 000000000..52b155186 --- /dev/null +++ b/bookwyrm/migrations/0015_auto_20201128_0349.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.7 on 2020-11-28 03:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0014_auto_20201128_0118'), + ] + + operations = [ + migrations.AlterField( + model_name='image', + name='status', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='bookwyrm.Status'), + ), + ] diff --git a/bookwyrm/models/attachment.py b/bookwyrm/models/attachment.py index b3e8bdb72..7329e65d6 100644 --- a/bookwyrm/models/attachment.py +++ b/bookwyrm/models/attachment.py @@ -11,7 +11,8 @@ class Attachment(ActivitypubMixin, BookWyrmModel): status = models.ForeignKey( 'Status', on_delete=models.CASCADE, - related_name='attachments' + related_name='attachments', + null=True ) class Meta: ''' one day we'll have other types of attachments besides images ''' diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 1b8923891..9d45379cc 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -90,7 +90,6 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): ActivityMapping( 'attachment', 'attachments', lambda x: image_attachments_formatter(x.all()), - activitypub.image_attachments_formatter ) ] diff --git a/bookwyrm/signatures.py b/bookwyrm/signatures.py index 57c181dfb..dbb88d8a2 100644 --- a/bookwyrm/signatures.py +++ b/bookwyrm/signatures.py @@ -89,7 +89,7 @@ class Signature: def verify(self, public_key, request): ''' verify rsa signature ''' - if http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE: + if False:#http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE: raise ValueError( "Request too old: %s" % (request.headers['date'],)) public_key = RSA.import_key(public_key) From 5638597112d1b1fb71508f0a1f35c9d8f1ef6fc9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Nov 2020 20:24:19 -0800 Subject: [PATCH 06/10] Fixes errors caught in tests --- bookwyrm/activitypub/base_activity.py | 6 ++++-- bookwyrm/signatures.py | 2 +- bookwyrm/tests/data/ap_quotation.json | 8 -------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 31e6d2e0e..caa4aeb80 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -135,9 +135,9 @@ class ActivityObject: # add images for (model_key, value) in image_fields.items(): - if not value: - continue formatted_value = image_formatter(value) + if not formatted_value: + continue getattr(instance, model_key).save(*formatted_value, save=True) for (model_key, values) in many_to_many_fields.items(): @@ -146,6 +146,8 @@ class ActivityObject: # add one to many fields for (model_key, values) in one_to_many_fields.items(): + if values == MISSING: + continue model_field = getattr(instance, model_key) model = model_field.model for item in values: diff --git a/bookwyrm/signatures.py b/bookwyrm/signatures.py index dbb88d8a2..57c181dfb 100644 --- a/bookwyrm/signatures.py +++ b/bookwyrm/signatures.py @@ -89,7 +89,7 @@ class Signature: def verify(self, public_key, request): ''' verify rsa signature ''' - if False:#http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE: + if http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE: raise ValueError( "Request too old: %s" % (request.headers['date'],)) public_key = RSA.import_key(public_key) diff --git a/bookwyrm/tests/data/ap_quotation.json b/bookwyrm/tests/data/ap_quotation.json index 089bc85fd..36a4112be 100644 --- a/bookwyrm/tests/data/ap_quotation.json +++ b/bookwyrm/tests/data/ap_quotation.json @@ -13,14 +13,6 @@ "sensitive": false, "content": "commentary", "type": "Quotation", - "attachment": [ - { - "type": "Document", - "mediaType": "image//images/covers/2b4e4712-5a4d-4ac1-9df4-634cc9c7aff3jpg", - "url": "https://example.com/images/covers/2b4e4712-5a4d-4ac1-9df4-634cc9c7aff3jpg", - "name": "Cover of \"This Is How You Lose the Time War\"" - } - ], "replies": { "id": "https://example.com/user/mouse/quotation/13/replies", "type": "Collection", From 78fa949237bf1621f038a107e70a738583677148 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Nov 2020 07:55:31 -0800 Subject: [PATCH 07/10] Inline form to add description to book --- bookwyrm/templates/book.html | 33 +++++++++++++++++++++++++++++++-- bookwyrm/urls.py | 1 + bookwyrm/view_actions.py | 21 +++++++++++++++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index b0064e1fd..f7456367a 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -57,6 +57,35 @@ {% include 'snippets/trimmed_text.html' with full=book|book_description %} + {% if request.user.is_authenticated and not book|book_description %} +
+ + +
+ +
+ + +
+ {% endif %} + + {% if book.parent_work.edition_set.count > 1 %}

{{ book.parent_work.edition_set.count }} editions

{% endif %} @@ -112,7 +141,7 @@
- +
@@ -135,7 +164,7 @@ -