From 35d30a41f3c0975d2c91bec13a4aa73a9b87e415 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Tue, 24 Jan 2023 13:00:18 +0000
Subject: [PATCH 01/11] 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)
From cd13e6f523fc38e703631b21570fb9cc79bb163a Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Tue, 24 Jan 2023 13:14:06 +0000
Subject: [PATCH 02/11] style: run linter
---
bookwyrm/urls.py | 6 ++-
bookwyrm/views/books/series.py | 83 +++++++++++++++++-----------------
2 files changed, 47 insertions(+), 42 deletions(-)
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py
index 6d9f34de0..c4d6b9b45 100644
--- a/bookwyrm/urls.py
+++ b/bookwyrm/urls.py
@@ -610,7 +610,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(
+ 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/books/series.py b/bookwyrm/views/books/series.py
index 6085934d3..f573aac57 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -10,49 +10,50 @@ 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")
+ 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)
- )
+ if is_api_request(request):
+ pass
- # when there are multiple editions of the same work, pick the closest
- editions_of_work = results.values_list("parent_work__id", flat=True).distinct()
+ author = get_object_or_404(models.Author, id=author_id)
- # 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)
- )
+ results = models.Edition.objects.filter(authors=author, series=series_name)
- data = {
- "series_name": series_name,
- "author": author,
- "books": list_results,
- }
+ # when there are multiple editions of the same work, pick the closest
+ editions_of_work = results.values_list("parent_work__id", flat=True).distinct()
- return TemplateResponse(request, "book/series.html", data)
+ # 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)
From eb4672ff18697ef1602cd21b2ccc40e33ce225d9 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Thu, 26 Jan 2023 06:49:55 +0000
Subject: [PATCH 03/11] style: format
---
bookwyrm/views/books/series.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index f573aac57..14a2a82c5 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -5,12 +5,13 @@ 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):
+ """book series by author"""
+
+ def get(self, request, author_id):
"""lists all books in a series"""
series_name = request.GET.get("series_name")
From f2902e8de5e17757076dc497d4c5727da56d48c9 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Sat, 28 Jan 2023 08:38:57 +0000
Subject: [PATCH 04/11] fix: sort series number as int
---
bookwyrm/views/books/series.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index 14a2a82c5..98e3841d3 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -41,7 +41,7 @@ class BookSeriesBy(View):
unsortable_books.append(result)
list_results = (
- sorted(numbered_books, key=lambda book: book.series_number)
+ sorted(numbered_books, key=lambda book: int(book.series_number))
+ sorted(
dated_books,
key=lambda book: book.first_published_date
From 4b64b707533f4f5de3a1c88abc6a634c0f0ff9a3 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Sun, 29 Jan 2023 09:35:02 +0000
Subject: [PATCH 05/11] fix: sort series by float
---
bookwyrm/views/books/series.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index 98e3841d3..3017ba5b6 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -41,7 +41,7 @@ class BookSeriesBy(View):
unsortable_books.append(result)
list_results = (
- sorted(numbered_books, key=lambda book: int(book.series_number))
+ sorted(numbered_books, key=lambda book: float(book.series_number))
+ sorted(
dated_books,
key=lambda book: book.first_published_date
From 0628ccad414c731eb58a8908e8e3c66533f908c3 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Sun, 29 Jan 2023 11:43:30 +0000
Subject: [PATCH 06/11] chore: sort editions with series number before edition
rank
---
bookwyrm/views/books/series.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index 3017ba5b6..6e295a4e9 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -21,17 +21,17 @@ class BookSeriesBy(View):
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()
-
+
+ # 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(editions_of_work):
+ for work_id in set(work_ids):
result = (
- results.filter(parent_work=work_id).order_by("-edition_rank").first()
+ results.filter(parent_work=work_id).order_by("series_number", "-edition_rank").first()
)
if result.series_number:
numbered_books.append(result)
@@ -48,7 +48,7 @@ class BookSeriesBy(View):
if book.first_published_date
else book.published_date,
)
- + sorted(unsortable_books, key=lambda book: book.sort_title)
+ + sorted(unsortable_books, key=lambda book: book.sort_title if book.sort_title else book.title)
)
data = {
From 59a8098517fadd7d7f88ccde6370aa68f8984204 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Mon, 30 Jan 2023 08:26:59 +0000
Subject: [PATCH 07/11] chore: add translations
---
bookwyrm/templates/book/series.html | 2 +-
locale/en_US/LC_MESSAGES/django.po | 15 ++++++++++++++-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/bookwyrm/templates/book/series.html b/bookwyrm/templates/book/series.html
index 55cebd3c1..dc8113813 100644
--- a/bookwyrm/templates/book/series.html
+++ b/bookwyrm/templates/book/series.html
@@ -24,7 +24,7 @@
{% with book=book %}
- {% if book.series_number %}Book {{ book.series_number }}{% else %}Unsorted Book{% endif %}
+ {% 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 %}
diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po
index 9ba4bfe40..2806208d0 100644
--- a/locale/en_US/LC_MESSAGES/django.po
+++ b/locale/en_US/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-26 16:43+0000\n"
+"POT-Creation-Date: 2023-01-30 08:25+0000\n"
"PO-Revision-Date: 2021-02-28 17:19-0800\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: English \n"
@@ -1471,6 +1471,19 @@ msgstr ""
msgid "rated it"
msgstr ""
+#: bookwyrm/templates/book/series.html:11
+msgid "Series by"
+msgstr ""
+
+#: bookwyrm/templates/book/series.html:27
+#, python-format
+msgid "Book %(series_number)s"
+msgstr ""
+
+#: bookwyrm/templates/book/series.html:27
+msgid "Unsorted Book"
+msgstr ""
+
#: bookwyrm/templates/book/sync_modal.html:15
#, python-format
msgid "Loading data will connect to %(source_name)s and check for any metadata about this book which aren't present here. Existing metadata will not be overwritten."
From e0505722e10ca4ab5089347e916bde39a66ee515 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Mon, 30 Jan 2023 14:45:30 +0000
Subject: [PATCH 08/11] chore: formatting
---
bookwyrm/views/books/series.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index 6e295a4e9..23ec924a5 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -21,17 +21,19 @@ class BookSeriesBy(View):
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()
+ results.filter(parent_work=work_id)
+ .order_by("series_number", "-edition_rank")
+ .first()
)
if result.series_number:
numbered_books.append(result)
@@ -48,7 +50,10 @@ class BookSeriesBy(View):
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)
+ + sorted(
+ unsortable_books,
+ key=lambda book: book.sort_title if book.sort_title else book.title,
+ )
)
data = {
From d0ac65b93140c56cb9011248dfc597cbf9e18f20 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Tue, 31 Jan 2023 10:05:03 +0000
Subject: [PATCH 09/11] chore: reset translation files
---
locale/en_US/LC_MESSAGES/django.po | 27 +++++++++------------------
1 file changed, 9 insertions(+), 18 deletions(-)
diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po
index 2806208d0..5f3c62895 100644
--- a/locale/en_US/LC_MESSAGES/django.po
+++ b/locale/en_US/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-30 08:25+0000\n"
+"POT-Creation-Date: 2023-01-30 08:21+0000\n"
"PO-Revision-Date: 2021-02-28 17:19-0800\n"
"Last-Translator: Mouse Reeve \n"
"Language-Team: English \n"
@@ -851,7 +851,7 @@ msgstr ""
#: bookwyrm/templates/settings/registration.html:96
#: bookwyrm/templates/settings/registration_limited.html:76
#: bookwyrm/templates/settings/site.html:144
-#: bookwyrm/templates/settings/users/user_moderation_actions.html:69
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:75
#: bookwyrm/templates/shelf/form.html:25
#: bookwyrm/templates/snippets/reading_modals/layout.html:18
msgid "Save"
@@ -1471,19 +1471,6 @@ msgstr ""
msgid "rated it"
msgstr ""
-#: bookwyrm/templates/book/series.html:11
-msgid "Series by"
-msgstr ""
-
-#: bookwyrm/templates/book/series.html:27
-#, python-format
-msgid "Book %(series_number)s"
-msgstr ""
-
-#: bookwyrm/templates/book/series.html:27
-msgid "Unsorted Book"
-msgstr ""
-
#: bookwyrm/templates/book/sync_modal.html:15
#, python-format
msgid "Loading data will connect to %(source_name)s and check for any metadata about this book which aren't present here. Existing metadata will not be overwritten."
@@ -5461,7 +5448,7 @@ msgid "Remove theme"
msgstr ""
#: bookwyrm/templates/settings/users/delete_user_form.html:5
-#: bookwyrm/templates/settings/users/user_moderation_actions.html:32
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:38
msgid "Permanently delete user"
msgstr ""
@@ -5583,14 +5570,18 @@ msgid "User Actions"
msgstr ""
#: bookwyrm/templates/settings/users/user_moderation_actions.html:21
+msgid "Activate user"
+msgstr ""
+
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:27
msgid "Suspend user"
msgstr ""
-#: bookwyrm/templates/settings/users/user_moderation_actions.html:26
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:32
msgid "Un-suspend user"
msgstr ""
-#: bookwyrm/templates/settings/users/user_moderation_actions.html:48
+#: bookwyrm/templates/settings/users/user_moderation_actions.html:54
msgid "Access level:"
msgstr ""
From 90f996ac903864ad67d851d1c55dd18e484d28eb Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Tue, 31 Jan 2023 10:16:44 +0000
Subject: [PATCH 10/11] chore: multi line comment for linter
---
bookwyrm/views/books/series.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index 23ec924a5..ad9b08667 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -22,7 +22,8 @@ class BookSeriesBy(View):
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
+ # 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
From d1f85e43176ac811c6575e7598380b724fcc2221 Mon Sep 17 00:00:00 2001
From: Dustin Steiner
Date: Tue, 7 Feb 2023 12:05:16 +0000
Subject: [PATCH 11/11] fix: books can have non-decimal series numbers
---
bookwyrm/views/books/series.py | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py
index ad9b08667..bdc8dccab 100644
--- a/bookwyrm/views/books/series.py
+++ b/bookwyrm/views/books/series.py
@@ -1,4 +1,5 @@
""" 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
@@ -7,6 +8,14 @@ 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"""
@@ -44,7 +53,7 @@ class BookSeriesBy(View):
unsortable_books.append(result)
list_results = (
- sorted(numbered_books, key=lambda book: float(book.series_number))
+ sorted(numbered_books, key=sort_by_series)
+ sorted(
dated_books,
key=lambda book: book.first_published_date