diff --git a/bookwyrm/connectors/bookwyrm_connector.py b/bookwyrm/connectors/bookwyrm_connector.py
index 96d94e8e..a9517ca0 100644
--- a/bookwyrm/connectors/bookwyrm_connector.py
+++ b/bookwyrm/connectors/bookwyrm_connector.py
@@ -52,11 +52,13 @@ class Connector(AbstractConnector):
def get_edition_from_work_data(self, data):
- return data['editions'][0]
+ ''' we're served a list of edition urls '''
+ path = data['editions'][0]
+ return get_data(path)
def get_work_from_edition_date(self, data):
- return data['work']
+ return get_data(data['work'])
def get_authors_from_data(self, data):
diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py
index 3bec4662..e32846fe 100644
--- a/bookwyrm/models/book.py
+++ b/bookwyrm/models/book.py
@@ -135,7 +135,7 @@ class Work(Book):
@property
def editions_path(self):
''' it'd be nice to serialize the edition instead but, recursion '''
- return self.remote_id + '/editions'
+ return [e.remote_id for e in self.edition_set.all()]
@property
@@ -174,6 +174,49 @@ class Edition(Book):
activity_serializer = activitypub.Edition
+ def save(self, *args, **kwargs):
+ ''' 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)
+ if self.isbn_10 and not self.isbn_13:
+ self.isbn_13 = isbn_10_to_13(self.isbn_10)
+
+ super().save(*args, **kwargs)
+
+
+def isbn_10_to_13(isbn_10):
+ ''' convert an isbn 10 into an isbn 13 '''
+ # drop the last character of the isbn 10 number (the original checkdigit)
+ converted = isbn_10[:9]
+ # add "978" to the front
+ converted = '978' + converted
+ # add a check digit to the end
+ # multiply the odd digits by 1 and the even digits by 3 and sum them
+ checksum = sum(int(i) for i in converted[::2]) + \
+ sum(int(i) * 3 for i in converted[1::2])
+ # add the checksum mod 10 to the end
+ checkdigit = checksum % 10
+ if checkdigit != 0:
+ checkdigit = 10 - checkdigit
+ return converted + str(checkdigit)
+
+
+def isbn_13_to_10(isbn_13):
+ ''' convert isbn 13 to 10, if possible '''
+ if isbn_13[:3] != '978':
+ return None
+
+ # remove '978' and old checkdigit
+ converted = isbn_13[3:-1]
+ # calculate checkdigit
+ # multiple each digit by 10,9,8.. successively and sum them
+ checksum = sum(int(d) * (10 - idx) for (idx, d) in enumerate(converted))
+ checkdigit = checksum % 11
+ checkdigit = 11 - checkdigit
+ if checkdigit == 10:
+ checkdigit = 'X'
+ return converted + str(checkdigit)
+
class Author(ActivitypubMixin, BookWyrmModel):
''' copy of an author from OL '''
diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py
index 9eb00e04..085cfea6 100644
--- a/bookwyrm/models/import_job.py
+++ b/bookwyrm/models/import_job.py
@@ -80,7 +80,10 @@ class ImportItem(models.Model):
)
search_result = books_manager.first_search_result(search_term)
if search_result:
- return books_manager.get_or_create_book(search_result.key)
+ try:
+ return books_manager.get_or_create_book(search_result.key)
+ except ConnectorException:
+ pass
@property
def isbn(self):
diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html
index 5e9696fa..c5d529ed 100644
--- a/bookwyrm/templates/book.html
+++ b/bookwyrm/templates/book.html
@@ -55,6 +55,14 @@
{% endif %}
+ {% for readthrough in readthroughs %}
+
+ {{ readthrough.start_date }}
+ {{ readthrough.finish_date }}
+ {{ readthrough.pages_read }}
+
+ {% endfor %}
+
{% if request.user.is_authenticated %}
{% include 'snippets/create_status.html' with book=book hide_cover=True %}
diff --git a/bookwyrm/tests/connectors/test_fedireads_connector.py b/bookwyrm/tests/connectors/test_fedireads_connector.py
index 6645a936..5f475fdb 100644
--- a/bookwyrm/tests/connectors/test_fedireads_connector.py
+++ b/bookwyrm/tests/connectors/test_fedireads_connector.py
@@ -34,16 +34,6 @@ class BookWyrmConnector(TestCase):
self.assertEqual(self.connector.is_work_data(self.edition_data), False)
- def test_get_edition_from_work_data(self):
- edition = self.connector.get_edition_from_work_data(self.work_data)
- self.assertEqual(edition['url'], 'https://example.com/book/122')
-
-
- def test_get_work_from_edition_data(self):
- work = self.connector.get_work_from_edition_date(self.edition_data)
- self.assertEqual(work['url'], 'https://example.com/book/121')
-
-
def test_format_search_result(self):
datafile = pathlib.Path(__file__).parent.joinpath('../data/fr_search.json')
search_data = json.loads(datafile.read_bytes())
diff --git a/bookwyrm/tests/models/test_book_model.py b/bookwyrm/tests/models/test_book_model.py
index 2cd980f8..78567a92 100644
--- a/bookwyrm/tests/models/test_book_model.py
+++ b/bookwyrm/tests/models/test_book_model.py
@@ -2,6 +2,7 @@
from django.test import TestCase
from bookwyrm import models, settings
+from bookwyrm.models.book import isbn_10_to_13, isbn_13_to_10
class Book(TestCase):
@@ -48,6 +49,16 @@ class Book(TestCase):
self.assertEqual(self.work.default_edition, self.second_edition)
+ def test_isbn_10_to_13(self):
+ isbn_10 = '178816167X'
+ isbn_13 = isbn_10_to_13(isbn_10)
+ self.assertEqual(isbn_13, '9781788161671')
+
+ def test_isbn_13_to_10(self):
+ isbn_13 = '9781788161671'
+ isbn_10 = isbn_13_to_10(isbn_13)
+ self.assertEqual(isbn_10, '178816167X')
+
class Shelf(TestCase):
def setUp(self):
diff --git a/bookwyrm/views.py b/bookwyrm/views.py
index 2422cd27..9bf02959 100644
--- a/bookwyrm/views.py
+++ b/bookwyrm/views.py
@@ -112,26 +112,34 @@ def home_tab(request, tab):
def get_activity_feed(user, filter_level, model=models.Status):
''' get a filtered queryset of statuses '''
# status updates for your follow network
- following = models.User.objects.filter(
- Q(followers=user) | Q(id=user.id)
- )
+ if user.is_anonymous:
+ user = None
+ if user:
+ following = models.User.objects.filter(
+ Q(followers=user) | Q(id=user.id)
+ )
+ else:
+ following = []
activities = model
if hasattr(model, 'objects'):
- activities = model.objects.filter(deleted=False)
+ activities = model.objects
- activities = activities.order_by(
- '-created_date'
+ activities = activities.filter(
+ deleted=False
+ ).order_by(
+ '-published_date'
)
+
if hasattr(activities, 'select_subclasses'):
activities = activities.select_subclasses()
- # TODO: privacy relationshup between request.user and user
if filter_level in ['friends', 'home']:
# people you follow and direct mentions
activities = activities.filter(
- Q(user__in=following, privacy__in=['public', 'unlisted', 'followers']) | \
- Q(mention_users=user) | Q(user=user)
+ Q(user__in=following, privacy__in=[
+ 'public', 'unlisted', 'followers'
+ ]) | Q(mention_users=user) | Q(user=user)
)
elif filter_level == 'self':
activities = activities.filter(user=user, privacy='public')
@@ -470,14 +478,21 @@ def book_page(request, book_id):
reviews = models.Review.objects.filter(
book__in=work.edition_set.all(),
- ).order_by('-published_date')
+ )
+ reviews = get_activity_feed(request.user, 'federated', model=reviews)
user_tags = []
+ readthroughs = []
if request.user.is_authenticated:
user_tags = models.Tag.objects.filter(
book=book, user=request.user
).values_list('identifier', flat=True)
+ readthroughs = models.ReadThrough.objects.filter(
+ user=request.user
+ ).order_by('start_date')
+
+
rating = reviews.aggregate(Avg('rating'))
tags = models.Tag.objects.filter(
book=book
@@ -492,6 +507,7 @@ def book_page(request, book_id):
'rating': rating['rating__avg'],
'tags': tags,
'user_tags': user_tags,
+ 'readthroughs': readthroughs,
'review_form': forms.ReviewForm(),
'quotation_form': forms.QuotationForm(),
'comment_form': forms.CommentForm(),