Merge branch 'main' into inventaire
This commit is contained in:
@@ -13,7 +13,7 @@ from . import fields
|
||||
|
||||
|
||||
class BookDataModel(ObjectMixin, BookWyrmModel):
|
||||
""" fields shared between editable book data (books, works, authors) """
|
||||
"""fields shared between editable book data (books, works, authors)"""
|
||||
|
||||
origin_id = models.CharField(max_length=255, null=True, blank=True)
|
||||
openlibrary_key = fields.CharField(
|
||||
@@ -32,15 +32,19 @@ class BookDataModel(ObjectMixin, BookWyrmModel):
|
||||
max_length=255, blank=True, null=True, deduplication_field=True
|
||||
)
|
||||
|
||||
last_edited_by = models.ForeignKey("User", on_delete=models.PROTECT, null=True)
|
||||
last_edited_by = fields.ForeignKey(
|
||||
"User",
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
""" can't initialize this model, that wouldn't make sense """
|
||||
"""can't initialize this model, that wouldn't make sense"""
|
||||
|
||||
abstract = True
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
""" ensure that the remote_id is within this instance """
|
||||
"""ensure that the remote_id is within this instance"""
|
||||
if self.id:
|
||||
self.remote_id = self.get_remote_id()
|
||||
else:
|
||||
@@ -49,24 +53,24 @@ class BookDataModel(ObjectMixin, BookWyrmModel):
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def broadcast(self, activity, sender, software="bookwyrm"):
|
||||
""" only send book data updates to other bookwyrm instances """
|
||||
"""only send book data updates to other bookwyrm instances"""
|
||||
super().broadcast(activity, sender, software=software)
|
||||
|
||||
|
||||
class Book(BookDataModel):
|
||||
""" a generic book, which can mean either an edition or a work """
|
||||
"""a generic book, which can mean either an edition or a work"""
|
||||
|
||||
connector = models.ForeignKey("Connector", on_delete=models.PROTECT, null=True)
|
||||
|
||||
# book/work metadata
|
||||
title = fields.CharField(max_length=255)
|
||||
title = fields.TextField(max_length=255)
|
||||
sort_title = fields.CharField(max_length=255, blank=True, null=True)
|
||||
subtitle = fields.CharField(max_length=255, blank=True, null=True)
|
||||
subtitle = fields.TextField(max_length=255, blank=True, null=True)
|
||||
description = fields.HtmlField(blank=True, null=True)
|
||||
languages = fields.ArrayField(
|
||||
models.CharField(max_length=255), blank=True, default=list
|
||||
)
|
||||
series = fields.CharField(max_length=255, blank=True, null=True)
|
||||
series = fields.TextField(max_length=255, blank=True, null=True)
|
||||
series_number = fields.CharField(max_length=255, blank=True, null=True)
|
||||
subjects = fields.ArrayField(
|
||||
models.CharField(max_length=255), blank=True, null=True, default=list
|
||||
@@ -85,17 +89,17 @@ class Book(BookDataModel):
|
||||
|
||||
@property
|
||||
def author_text(self):
|
||||
""" format a list of authors """
|
||||
"""format a list of authors"""
|
||||
return ", ".join(a.name for a in self.authors.all())
|
||||
|
||||
@property
|
||||
def latest_readthrough(self):
|
||||
""" most recent readthrough activity """
|
||||
"""most recent readthrough activity"""
|
||||
return self.readthrough_set.order_by("-updated_date").first()
|
||||
|
||||
@property
|
||||
def edition_info(self):
|
||||
""" properties of this edition, as a string """
|
||||
"""properties of this edition, as a string"""
|
||||
items = [
|
||||
self.physical_format if hasattr(self, "physical_format") else None,
|
||||
self.languages[0] + " language"
|
||||
@@ -108,20 +112,20 @@ class Book(BookDataModel):
|
||||
|
||||
@property
|
||||
def alt_text(self):
|
||||
""" image alt test """
|
||||
"""image alt test"""
|
||||
text = "%s" % self.title
|
||||
if self.edition_info:
|
||||
text += " (%s)" % self.edition_info
|
||||
return text
|
||||
|
||||
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):
|
||||
raise ValueError("Books should be added as Editions or Works")
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def get_remote_id(self):
|
||||
""" editions and works both use "book" instead of model_name """
|
||||
"""editions and works both use "book" instead of model_name"""
|
||||
return "https://%s/book/%d" % (DOMAIN, self.id)
|
||||
|
||||
def __repr__(self):
|
||||
@@ -133,7 +137,7 @@ class Book(BookDataModel):
|
||||
|
||||
|
||||
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
|
||||
lccn = fields.CharField(
|
||||
@@ -145,19 +149,19 @@ class Work(OrderedCollectionPageMixin, Book):
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
""" set some fields on the edition object """
|
||||
"""set some fields on the edition object"""
|
||||
# set rank
|
||||
for edition in self.editions.all():
|
||||
edition.save()
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def get_default_edition(self):
|
||||
""" in case the default edition is not set """
|
||||
"""in case the default edition is not set"""
|
||||
return self.default_edition or self.editions.order_by("-edition_rank").first()
|
||||
|
||||
@transaction.atomic()
|
||||
def reset_default_edition(self):
|
||||
""" sets a new default edition based on computed rank """
|
||||
"""sets a new default edition based on computed rank"""
|
||||
self.default_edition = None
|
||||
# editions are re-ranked implicitly
|
||||
self.save()
|
||||
@@ -165,11 +169,11 @@ class Work(OrderedCollectionPageMixin, Book):
|
||||
self.save()
|
||||
|
||||
def to_edition_list(self, **kwargs):
|
||||
""" an ordered collection of editions """
|
||||
"""an ordered collection of editions"""
|
||||
return self.to_ordered_collection(
|
||||
self.editions.order_by("-edition_rank").all(),
|
||||
remote_id="%s/editions" % self.remote_id,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
activity_serializer = activitypub.Work
|
||||
@@ -178,7 +182,7 @@ class Work(OrderedCollectionPageMixin, Book):
|
||||
|
||||
|
||||
class Edition(Book):
|
||||
""" an edition of a book """
|
||||
"""an edition of a book"""
|
||||
|
||||
# these identifiers only apply to editions, not works
|
||||
isbn_10 = fields.CharField(
|
||||
@@ -217,7 +221,7 @@ class Edition(Book):
|
||||
name_field = "title"
|
||||
|
||||
def get_rank(self, ignore_default=False):
|
||||
""" calculate how complete the data is on this edition """
|
||||
"""calculate how complete the data is on this edition"""
|
||||
if (
|
||||
not ignore_default
|
||||
and self.parent_work
|
||||
@@ -237,7 +241,7 @@ class Edition(Book):
|
||||
return rank
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
""" set some fields on the edition object """
|
||||
"""set some fields on the edition object"""
|
||||
# calculate isbn 10/13
|
||||
if self.isbn_13 and self.isbn_13[:3] == "978" and not self.isbn_10:
|
||||
self.isbn_10 = isbn_13_to_10(self.isbn_13)
|
||||
@@ -251,7 +255,7 @@ class Edition(Book):
|
||||
|
||||
|
||||
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)
|
||||
# drop the last character of the isbn 10 number (the original checkdigit)
|
||||
converted = isbn_10[:9]
|
||||
@@ -273,7 +277,7 @@ def isbn_10_to_13(isbn_10):
|
||||
|
||||
|
||||
def isbn_13_to_10(isbn_13):
|
||||
""" convert isbn 13 to 10, if possible """
|
||||
"""convert isbn 13 to 10, if possible"""
|
||||
if isbn_13[:3] != "978":
|
||||
return None
|
||||
|
||||
|
Reference in New Issue
Block a user