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 }}
+
+
+
+ {% 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)