From 35d30a41f3c0975d2c91bec13a4aa73a9b87e415 Mon Sep 17 00:00:00 2001 From: Dustin Steiner Date: Tue, 24 Jan 2023 13:00:18 +0000 Subject: [PATCH] feat: first version of a book series list by author --- bookwyrm/templates/book/book.html | 2 +- bookwyrm/templates/book/series.html | 35 +++++++++++++++++ bookwyrm/urls.py | 1 + bookwyrm/views/__init__.py | 1 + bookwyrm/views/books/series.py | 58 +++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/templates/book/series.html create mode 100644 bookwyrm/views/books/series.py diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 6ea051ab9..d8f9110aa 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..55cebd3c1 --- /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 %}Book {{ book.series_number }}{% else %}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 ac3a80580..6d9f34de0 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -610,6 +610,7 @@ 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 db88f1ae2..589ddb49c 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -50,6 +50,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..6085934d3 --- /dev/null +++ b/bookwyrm/views/books/series.py @@ -0,0 +1,58 @@ +""" books belonging to the same series """ +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 +from bookwyrm.settings import PAGE_LENGTH + + +# pylint: disable=no-self-use +class BookSeriesBy(View): + def get(self, request, author_id, **kwargs): + """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 closest + editions_of_work = 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(editions_of_work): + result = ( + results.filter(parent_work=work_id) + .order_by("-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=lambda book: book.series_number) + + 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) + ) + + data = { + "series_name": series_name, + "author": author, + "books": list_results, + } + + return TemplateResponse(request, "book/series.html", data)