Merge branch 'main' into readthrough-dates

This commit is contained in:
Mouse Reeve
2021-08-27 10:25:41 -07:00
123 changed files with 3139 additions and 1768 deletions

View File

@ -7,10 +7,16 @@ from django.db import models
from django.dispatch import receiver
from model_utils import FieldTracker
from model_utils.managers import InheritanceManager
from imagekit.models import ImageSpecField
from bookwyrm import activitypub
from bookwyrm.preview_images import generate_edition_preview_image_task
from bookwyrm.settings import DOMAIN, DEFAULT_LANGUAGE, ENABLE_PREVIEW_IMAGES
from bookwyrm.settings import (
DOMAIN,
DEFAULT_LANGUAGE,
ENABLE_PREVIEW_IMAGES,
ENABLE_THUMBNAIL_GENERATION,
)
from .activitypub_mixin import OrderedCollectionPageMixin, ObjectMixin
from .base_model import BookWyrmModel
@ -97,6 +103,40 @@ class Book(BookDataModel):
objects = InheritanceManager()
field_tracker = FieldTracker(fields=["authors", "title", "subtitle", "cover"])
if ENABLE_THUMBNAIL_GENERATION:
cover_bw_book_xsmall_webp = ImageSpecField(
source="cover", id="bw:book:xsmall:webp"
)
cover_bw_book_xsmall_jpg = ImageSpecField(
source="cover", id="bw:book:xsmall:jpg"
)
cover_bw_book_small_webp = ImageSpecField(
source="cover", id="bw:book:small:webp"
)
cover_bw_book_small_jpg = ImageSpecField(source="cover", id="bw:book:small:jpg")
cover_bw_book_medium_webp = ImageSpecField(
source="cover", id="bw:book:medium:webp"
)
cover_bw_book_medium_jpg = ImageSpecField(
source="cover", id="bw:book:medium:jpg"
)
cover_bw_book_large_webp = ImageSpecField(
source="cover", id="bw:book:large:webp"
)
cover_bw_book_large_jpg = ImageSpecField(source="cover", id="bw:book:large:jpg")
cover_bw_book_xlarge_webp = ImageSpecField(
source="cover", id="bw:book:xlarge:webp"
)
cover_bw_book_xlarge_jpg = ImageSpecField(
source="cover", id="bw:book:xlarge:jpg"
)
cover_bw_book_xxlarge_webp = ImageSpecField(
source="cover", id="bw:book:xxlarge:webp"
)
cover_bw_book_xxlarge_jpg = ImageSpecField(
source="cover", id="bw:book:xxlarge:jpg"
)
@property
def author_text(self):
"""format a list of authors"""

View File

@ -66,7 +66,7 @@ class ActivitypubFieldMixin:
self.activitypub_field = activitypub_field
super().__init__(*args, **kwargs)
def set_field_from_activity(self, instance, data):
def set_field_from_activity(self, instance, data, overwrite=True):
"""helper function for assinging a value to the field. Returns if changed"""
try:
value = getattr(data, self.get_activitypub_field())
@ -79,8 +79,15 @@ class ActivitypubFieldMixin:
if formatted is None or formatted is MISSING or formatted == {}:
return False
current_value = (
getattr(instance, self.name) if hasattr(instance, self.name) else None
)
# if we're not in overwrite mode, only continue updating the field if its unset
if current_value and not overwrite:
return False
# the field is unchanged
if hasattr(instance, self.name) and getattr(instance, self.name) == formatted:
if current_value == formatted:
return False
setattr(instance, self.name, formatted)
@ -210,7 +217,10 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField):
)
# pylint: disable=invalid-name
def set_field_from_activity(self, instance, data):
def set_field_from_activity(self, instance, data, overwrite=True):
if not overwrite:
return False
original = getattr(instance, self.name)
to = data.to
cc = data.cc
@ -273,8 +283,11 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField):
self.link_only = link_only
super().__init__(*args, **kwargs)
def set_field_from_activity(self, instance, data):
def set_field_from_activity(self, instance, data, overwrite=True):
"""helper function for assinging a value to the field"""
if not overwrite and getattr(instance, self.name).exists():
return False
value = getattr(data, self.get_activitypub_field())
formatted = self.field_from_activity(value)
if formatted is None or formatted is MISSING:
@ -377,13 +390,16 @@ class ImageField(ActivitypubFieldMixin, models.ImageField):
super().__init__(*args, **kwargs)
# pylint: disable=arguments-differ
def set_field_from_activity(self, instance, data, save=True):
def set_field_from_activity(self, instance, data, save=True, overwrite=True):
"""helper function for assinging a value to the field"""
value = getattr(data, self.get_activitypub_field())
formatted = self.field_from_activity(value)
if formatted is None or formatted is MISSING:
return False
if not overwrite and hasattr(instance, self.name):
return False
getattr(instance, self.name).save(*formatted, save=save)
return True

View File

@ -235,12 +235,31 @@ class GeneratedNote(Status):
pure_type = "Note"
class Comment(Status):
"""like a review but without a rating and transient"""
ReadingStatusChoices = models.TextChoices(
"ReadingStatusChoices", ["to-read", "reading", "read"]
)
class BookStatus(Status):
"""Shared fields for comments, quotes, reviews"""
book = fields.ForeignKey(
"Edition", on_delete=models.PROTECT, activitypub_field="inReplyToBook"
)
pure_type = "Note"
reading_status = fields.CharField(
max_length=255, choices=ReadingStatusChoices.choices, null=True, blank=True
)
class Meta:
"""not a real model, sorry"""
abstract = True
class Comment(BookStatus):
"""like a review but without a rating and transient"""
# this is it's own field instead of a foreign key to the progress update
# so that the update can be deleted without impacting the status
@ -265,16 +284,12 @@ class Comment(Status):
)
activity_serializer = activitypub.Comment
pure_type = "Note"
class Quotation(Status):
class Quotation(BookStatus):
"""like a review but without a rating and transient"""
quote = fields.HtmlField()
book = fields.ForeignKey(
"Edition", on_delete=models.PROTECT, activitypub_field="inReplyToBook"
)
@property
def pure_content(self):
@ -289,16 +304,12 @@ class Quotation(Status):
)
activity_serializer = activitypub.Quotation
pure_type = "Note"
class Review(Status):
class Review(BookStatus):
"""a book review"""
name = fields.CharField(max_length=255, null=True)
book = fields.ForeignKey(
"Edition", on_delete=models.PROTECT, activitypub_field="inReplyToBook"
)
rating = fields.DecimalField(
default=None,
null=True,

View File

@ -104,6 +104,9 @@ class User(OrderedCollectionPageMixin, AbstractUser):
through_fields=("user_subject", "user_object"),
related_name="blocked_by",
)
saved_lists = models.ManyToManyField(
"List", symmetrical=False, related_name="saved_lists"
)
favorites = models.ManyToManyField(
"Status",
symmetrical=False,