From defd026ed0df5c59caa1ec653f28dce28c6f85d2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 30 Mar 2020 15:03:21 -0700 Subject: [PATCH] handle work/edition concepts in ui --- fedireads/models/book.py | 9 +++++- fedireads/templates/book.html | 6 ++-- fedireads/templates/editions.html | 18 +++++++++++ fedireads/urls.py | 1 + fedireads/view_actions.py | 9 ++++-- fedireads/views.py | 54 +++++++++++++++++++------------ 6 files changed, 69 insertions(+), 28 deletions(-) create mode 100644 fedireads/templates/editions.html diff --git a/fedireads/models/book.py b/fedireads/models/book.py index e209b6b6f..f5ea2ba3c 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -91,7 +91,7 @@ class Book(FedireadsModel): ''' constructs the absolute reference to any db object ''' base_path = 'https://%s' % DOMAIN model_name = type(self).__name__.lower() - return '%s/%s/%s' % (base_path, model_name, self.openlibrary_key) + return '%s/book/%s' % (base_path, self.openlibrary_key) def save(self, *args, **kwargs): ''' can't be abstract for query reasons, but you shouldn't USE it ''' @@ -112,6 +112,13 @@ class Work(Book): # library of congress catalog control number lccn = models.CharField(max_length=255, blank=True, null=True) + @property + def default_edition(self): + ed = Edition.objects.filter(parent_work=self, default=True).first() + if not ed: + ed = Edition.objects.filter(parent_work=self).first() + return ed + class Edition(Book): ''' an edition of a book ''' diff --git a/fedireads/templates/book.html b/fedireads/templates/book.html index d42533882..21cfbbe70 100644 --- a/fedireads/templates/book.html +++ b/fedireads/templates/book.html @@ -14,13 +14,12 @@ {% endif %}
- {% if book.parent_work %}

Edition of {{ book.parent_work.title }}

{% endif %}
{% include 'snippets/book_cover.html' with book=book size=large %}

{{ active_tab }} rating: {{ rating | stars }}

- {% if book.description %} -
{{ book.description | description }}
+ {% if book.parent_work.description %} +
{{ book.parent_work.description | description }}
{% endif %}
@@ -29,6 +28,7 @@ {% endfor %}
+

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

{% include 'snippets/shelve_button.html' %} diff --git a/fedireads/templates/editions.html b/fedireads/templates/editions.html new file mode 100644 index 000000000..ffd0c75bc --- /dev/null +++ b/fedireads/templates/editions.html @@ -0,0 +1,18 @@ +{% extends 'layout.html' %} +{% load fr_display %} +{% block content %} +
+

Editions of "{{ work.title }}"

+
+ {% for book in editions %} +
+ + {% include 'snippets/book_cover.html' with book=book %} + + {% include 'snippets/shelve_button.html' with book=book %} +
+ {% endfor %} +
+
+{% endblock %} + diff --git a/fedireads/urls.py b/fedireads/urls.py index aa9ba3625..a22ba7ddb 100644 --- a/fedireads/urls.py +++ b/fedireads/urls.py @@ -60,6 +60,7 @@ urlpatterns = [ re_path(r'%s(.json)?/?$' % book_path, views.book_page), re_path(r'%s/(?Pfriends|local|federated)?$' % book_path, views.book_page), re_path(r'%s/edit/?$' % book_path, views.edit_book_page), + re_path(r'^editions/(?P\d+)/?$', views.editions_page), re_path(r'^author/(?P[\w\-]+)/?$', views.author_page), re_path(r'^tag/(?P.+)/?$', views.tag_page), diff --git a/fedireads/view_actions.py b/fedireads/view_actions.py index 509e4bfec..f2945c7ec 100644 --- a/fedireads/view_actions.py +++ b/fedireads/view_actions.py @@ -135,7 +135,10 @@ def upload_cover(request, book_id): @login_required def shelve(request): ''' put a on a user's shelf ''' - book = models.Book.objects.get(id=request.POST['book']) + book = models.Book.objects.select_subclasses().get(id=request.POST['book']) + if isinstance(book, models.Work): + book = book.default_edition + desired_shelf = models.Shelf.objects.filter( identifier=request.POST['shelf'], user=request.user @@ -144,8 +147,8 @@ def shelve(request): if request.POST.get('reshelve', True): try: current_shelf = models.Shelf.objects.get( - user=request.user, - book=book + shelf__user=request.user, + edition=book ) outgoing.handle_unshelve(request.user, book, current_shelf) except models.Shelf.DoesNotExist: diff --git a/fedireads/views.py b/fedireads/views.py index c18d1c583..3fcb51df6 100644 --- a/fedireads/views.py +++ b/fedireads/views.py @@ -52,15 +52,18 @@ def home_tab(request, tab): size = sum(len(s['books']) for s in shelves) # books new to the instance, for discovery if size < 6: + recent_books = models.Work.objects.order_by( + '-created_date' + )[:6 - size] + recent_books = [b.default_edition for b in recent_books] shelves.append({ 'name': 'Recently added', 'identifier': None, - 'books': models.Edition.objects.order_by( - '-created_date' - )[:6 - size], + 'books': recent_books, 'count': 6 - size, }) + # allows us to check if a user has shelved a book user_books = models.Edition.objects.filter(shelves__user=request.user).all() @@ -107,18 +110,21 @@ def home_tab(request, tab): def books_page(request): ''' discover books ''' - recent_books = models.Book.objects - if request.user.is_authenticated: - recent_books = recent_books.filter( - ~Q(shelfbook__shelf__user=request.user) - ) + recent_books = models.Work.objects recent_books = recent_books.order_by('-created_date')[:50] + recent_books = [b.default_edition for b in recent_books] + if request.user.is_authenticated: + recent_books = models.Edition.objects.filter( + ~Q(shelfbook__shelf__user=request.user), + id__in=[b.id for b in recent_books], + ) data = { 'books': recent_books, } return TemplateResponse(request, 'books.html', data) + @login_required def import_page(request): ''' import history from goodreads ''' @@ -322,16 +328,11 @@ def book_page(request, book_identifier, tab='friends'): return JsonResponse(activitypub.get_book(book)) if isinstance(book, models.Work): - book = models.Edition.objects.filter( - parent_work=book, - default=True - ).first() - if not book: - book = models.Edition.objects.filter( - parent_work=book, - ).first() + book = book.default_edition - book_reviews = models.Review.objects.filter(book=book) + work = book.parent_work + + book_reviews = models.Review.objects.filter(book__in=work.edition_set.all()) if request.user.is_authenticated: user_reviews = book_reviews.filter( @@ -360,7 +361,7 @@ def book_page(request, book_identifier, tab='friends'): # TODO: books can be on multiple shelves shelf = models.Shelf.objects.filter( user=request.user, - book=book + edition=book ).first() except models.Shelf.DoesNotExist: shelf = None @@ -422,6 +423,17 @@ def edit_book_page(request, book_identifier): return TemplateResponse(request, 'edit_book.html', data) +def editions_page(request, work_id): + ''' list of editions of a book ''' + work = models.Work.objects.get(id=work_id) + editions = models.Edition.objects.filter(parent_work=work).all() + data = { + 'editions': editions, + 'work': work, + } + return TemplateResponse(request, 'editions.html', data) + + def author_page(request, author_identifier): ''' landing page for an author ''' try: @@ -429,10 +441,10 @@ def author_page(request, author_identifier): except ValueError: return HttpResponseNotFound() - books = models.Book.objects.filter(authors=author) + books = models.Work.objects.filter(authors=author) data = { 'author': author, - 'books': books, + 'books': [b.default_edition for b in books], } return TemplateResponse(request, 'author.html', data) @@ -440,7 +452,7 @@ def author_page(request, author_identifier): def tag_page(request, tag_id): ''' books related to a tag ''' tag_obj = models.Tag.objects.filter(identifier=tag_id).first() - books = models.Book.objects.filter(tag__identifier=tag_id).distinct() + books = models.Edition.objects.filter(tag__identifier=tag_id).distinct() data = { 'books': books, 'tag': tag_obj,