diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 2fe9cdae4..d27c7ec54 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -46,7 +46,7 @@ - ({{ book.series }}{% if book.series_number %} #{{ book.series_number }}{% endif %}) + ({{ book.series }}{% if book.series_number %} #{{ book.series_number }}{% endif %}) {% endif %}

{% endif %} diff --git a/bookwyrm/templates/book/series.html b/bookwyrm/templates/book/series.html new file mode 100644 index 000000000..dc8113813 --- /dev/null +++ b/bookwyrm/templates/book/series.html @@ -0,0 +1,35 @@ +{% extends 'layout.html' %} +{% load i18n %} +{% load book_display_tags %} + +{% block title %}{{ series_name }}{% endblock %} + +{% block content %} +
+

{{ series_name }}

+
+ {% trans "Series by" %} +
+ +
+ {% for book in books %} + {% with book=book %} +
+
+ {% if book.series_number %}{% blocktrans with series_number=book.series_number %}Book {{ series_number }}{% endblocktrans %}{% else %}{% trans 'Unsorted Book' %}{% endif %} + {% include 'landing/small-book.html' with book=book %} +
+
+ {% endwith %} + {% endfor %} +
+
+{% endblock %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 586af137d..3fbf7dda1 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -638,6 +638,11 @@ urlpatterns = [ # books re_path(rf"{BOOK_PATH}(.json)?/?$", views.Book.as_view(), name="book"), re_path(rf"{BOOK_PATH}{regex.SLUG}/?$", views.Book.as_view(), name="book"), + re_path( + r"^series/by/(?P\d+)/?$", + views.BookSeriesBy.as_view(), + name="book-series-by", + ), re_path( rf"{BOOK_PATH}/(?Preview|comment|quote)/?$", views.Book.as_view(), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 7cfa227a5..808113099 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -55,6 +55,7 @@ from .books.books import ( add_description, resolve_book, ) +from .books.series import BookSeriesBy from .books.books import update_book_from_remote from .books.edit_book import ( EditBook, diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py new file mode 100644 index 000000000..bdc8dccab --- /dev/null +++ b/bookwyrm/views/books/series.py @@ -0,0 +1,75 @@ +""" books belonging to the same series """ +from sys import float_info +from django.views import View +from django.shortcuts import get_object_or_404 +from django.template.response import TemplateResponse + +from bookwyrm.views.helpers import is_api_request +from bookwyrm import models + + +def sort_by_series(book): + """sort books using their series number""" + try: + return float(book.series_number) + except ValueError: + return float_info.max + + +# pylint: disable=no-self-use +class BookSeriesBy(View): + """book series by author""" + + def get(self, request, author_id): + """lists all books in a series""" + series_name = request.GET.get("series_name") + + if is_api_request(request): + pass + + author = get_object_or_404(models.Author, id=author_id) + + results = models.Edition.objects.filter(authors=author, series=series_name) + + # when there are multiple editions of the same work + # pick the one with a series number or closest + work_ids = results.values_list("parent_work__id", flat=True).distinct() + + # filter out multiple editions of the same work + numbered_books = [] + dated_books = [] + unsortable_books = [] + for work_id in set(work_ids): + result = ( + results.filter(parent_work=work_id) + .order_by("series_number", "-edition_rank") + .first() + ) + if result.series_number: + numbered_books.append(result) + elif result.first_published_date or result.published_date: + dated_books.append(result) + else: + unsortable_books.append(result) + + list_results = ( + sorted(numbered_books, key=sort_by_series) + + sorted( + dated_books, + key=lambda book: book.first_published_date + if book.first_published_date + else book.published_date, + ) + + sorted( + unsortable_books, + key=lambda book: book.sort_title if book.sort_title else book.title, + ) + ) + + data = { + "series_name": series_name, + "author": author, + "books": list_results, + } + + return TemplateResponse(request, "book/series.html", data)