diff --git a/bookwyrm/templates/annual_summary/layout.html b/bookwyrm/templates/annual_summary/layout.html index 99c5343db..f20a8f00c 100644 --- a/bookwyrm/templates/annual_summary/layout.html +++ b/bookwyrm/templates/annual_summary/layout.html @@ -10,12 +10,14 @@ {% endblock %} {% block content %} +{% with display_name=summary_user.display_name %} +{% if user == summary_user %}
{% with year=paginated_years|first %}
- + - {% blocktrans %}{{ year }} in the books{% endblocktrans %} + {{ year }}
{% endwith %} @@ -23,20 +25,24 @@ {% with year=paginated_years|last %} {% if year %}
- - {% blocktrans %}{{ year }} in the books{% endblocktrans %} + + {{ year }}
{% endif %} {% endwith %}
+{% endif %} -

+

📚✨ {% blocktrans %}{{ year }} in the books{% endblocktrans %} ✨📚

+

+ {% blocktrans %}{{ display_name }}’s year of reading{% endblocktrans %} +

{% if not books %}

{% blocktrans %}Sadly you didn't finish any book in {{ year }}{% endblocktrans %}

@@ -45,7 +51,7 @@

- {% blocktrans %}In {{ year }}, you read {{ books_total }} books
for a total of {{ pages_total }} pages!{% endblocktrans %} + {% blocktrans %}In {{ year }}, {{ display_name }} read {{ books_total }} books
for a total of {{ pages_total }} pages!{% endblocktrans %}

{% trans "That’s great!" %}

@@ -65,7 +71,7 @@ {% include 'snippets/book_cover.html' with book=book_pages_lowest cover_class='is-w-auto-tablet is-h-l-mobile' %}
- {% trans "Your shortest read this year" %} + {% trans "Their shortest read this year…" %}

{{ book_pages_lowest.title }} @@ -86,7 +92,7 @@ {% include 'snippets/book_cover.html' with book=book_pages_highest cover_class='is-w-auto-tablet is-h-l-mobile' %}

- {% trans "and the longest read" %} + {% trans "…and the longest" %}

{{ book_pages_highest.title }} @@ -112,10 +118,11 @@

+ {% if ratings_total > 0 %}

- {% blocktrans %}You left {{ ratings_total }} ratings,
your average rating is {{ rating_average }}{% endblocktrans %} + {% blocktrans %}{{ display_name }} left {{ ratings_total }} ratings,
their average rating is {{ rating_average }}{% endblocktrans %}

@@ -124,7 +131,7 @@
{% include 'snippets/book_cover.html' with book=book_rating_highest.book cover_class='is-w-auto-tablet is-h-l-mobile' %}
- {% trans "Your best rated review" %} + {% trans "Their best rated review" %}

{{ book_rating_highest.book.title }} @@ -137,7 +144,7 @@ {% endif %}

{% with rating=book_rating_highest.rating|floatformat %} - {% blocktrans %}Your rating: {{ rating }}{% endblocktrans%} + {% blocktrans %}Their rating: {{ rating }}{% endblocktrans%} {% endwith %}

@@ -148,11 +155,12 @@
+ {% endif %}

- {% blocktrans %}All the books you read in 2021{% endblocktrans %} + {% blocktrans %}All the books {{ display_name }} read in 2021{% endblocktrans %}

@@ -180,5 +188,6 @@ - {% endif %} +{% endif %} +{% endwith %} {% endblock %} diff --git a/bookwyrm/templates/feed/summary_card.html b/bookwyrm/templates/feed/summary_card.html index e726792e9..a5bc4643a 100644 --- a/bookwyrm/templates/feed/summary_card.html +++ b/bookwyrm/templates/feed/summary_card.html @@ -15,7 +15,7 @@

- + {% blocktrans %}Discover your stats for {{ year }}!{% endblocktrans %}

diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 7b7bc3740..30e54bc75 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -479,7 +479,11 @@ urlpatterns = [ ), # annual summary re_path( - r"^my-year-in-the-books/(?P\d{4})/?$", + r"^my-year-in-the-books/(?P\d+)/?$", + views.personal_annual_summary, + ), + re_path( + rf"{LOCAL_USER_PATH}/(?P\d+)-in-the-books/?$", views.AnnualSummary.as_view(), name="annual-summary", ), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 30195fad6..2eeda1148 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -96,4 +96,7 @@ from .status import edit_readthrough from .updates import get_notification_count, get_unread_status_count from .user import User, Followers, Following, hide_suggestions from .wellknown import * -from .annual_summary import AnnualSummary +from .annual_summary import ( + AnnualSummary, + personal_annual_summary, +) diff --git a/bookwyrm/views/annual_summary.py b/bookwyrm/views/annual_summary.py index cfdd6093f..5a98c009e 100644 --- a/bookwyrm/views/annual_summary.py +++ b/bookwyrm/views/annual_summary.py @@ -1,13 +1,17 @@ """end-of-year read books stats""" from datetime import date +from uuid import uuid4 +from django.contrib.auth.decorators import login_required from django.db.models import Case, When, Avg, Sum from django.http import Http404 -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.views import View +from django.views.decorators.http import require_POST from bookwyrm import models +from .helpers import get_user_from_username # December day of first availability @@ -16,6 +20,100 @@ FIRST_DAY = 15 LAST_DAY = 15 +# pylint: disable= no-self-use +class AnnualSummary(View): + """display a summary of the year for the current user""" + + def get(self, request, username, year): + """get response""" + + if not is_year_available(year): + raise Http404(f"The summary for {year} is unavailable") + + paginated_years = ( + int(year) - 1, + int(year) + 1 if is_year_available(int(year) + 1) else None, + ) + + user = get_user_from_username(request.user, username) + + year_key = None + if user.summary_keys and year in user.summary_keys: + year_key = user.summary_keys[year] + + # verify key + if user != request.user: + request_key = None + if "key" in request.GET: + request_key = request.GET["key"] + + if not request_key or request_key != year_key: + raise Http404(f"The summary for {year} is unavailable") + + # get data + read_book_ids_in_year = get_read_book_ids_in_year(user, year) + + if len(read_book_ids_in_year) == 0: + data = { + "summary_user": user, + "year": year, + "book_total": 0, + "books": [], + "paginated_years": paginated_years, + } + return TemplateResponse(request, "annual_summary/layout.html", data) + + read_books_in_year = get_books_from_shelfbooks(read_book_ids_in_year) + + # pages stats queries + page_stats = read_books_in_year.aggregate(Sum("pages"), Avg("pages")) + book_list_by_pages = read_books_in_year.filter(pages__gte=0).order_by("pages") + + # books with no pages + no_page_list = len(read_books_in_year.filter(pages__exact=None)) + + # rating stats queries + ratings = ( + models.Review.objects.filter(user=user) + .exclude(deleted=True) + .exclude(rating=None) + .filter(book_id__in=read_book_ids_in_year) + ) + ratings_stats = ratings.aggregate(Avg("rating")) + + data = { + "summary_user": user, + "year": year, + "books_total": len(read_books_in_year), + "books": read_books_in_year, + "pages_total": page_stats["pages__sum"], + "pages_average": round( + page_stats["pages__avg"] if page_stats["pages__avg"] else 0 + ), + "book_pages_lowest": book_list_by_pages.first(), + "book_pages_highest": book_list_by_pages.last(), + "no_page_number": no_page_list, + "ratings_total": len(ratings), + "rating_average": round( + ratings_stats["rating__avg"] if ratings_stats["rating__avg"] else 0, 2 + ), + "book_rating_highest": ratings.order_by("-rating").first(), + "best_ratings_books_ids": [ + review.book.id for review in ratings.filter(rating=5) + ], + "paginated_years": paginated_years, + } + + return TemplateResponse(request, "annual_summary/layout.html", data) + + +@login_required +def personal_annual_summary(request, year): + """redirect simple URL to URL with username""" + + return redirect("annual-summary", request.user.localname, year) + + def get_annual_summary_year(): """return the latest available annual summary year or None""" @@ -44,80 +142,6 @@ def is_year_available(year): return False -# pylint: disable= no-self-use -class AnnualSummary(View): - """display a summary of the year for the current user""" - - def get(self, request, year): - """get response""" - - if not is_year_available(year): - raise Http404(f"The summary for {year} is unavailable") - - paginated_years = ( - int(year) - 1, - int(year) + 1 if is_year_available(int(year) + 1) else None, - ) - - user = request.user - - if not user.is_authenticated: - raise Http404(f"Login or register {year} to access this page") - - read_book_ids_in_year = get_read_book_ids_in_year(user, year) - - if len(read_book_ids_in_year) == 0: - data = { - "year": year, - "book_total": 0, - "books": [], - "paginated_years": paginated_years, - } - return TemplateResponse(request, "annual_summary/layout.html", data) - - read_books_in_year = get_books_from_shelfbooks(read_book_ids_in_year) - - # pages stats queries - page_stats = read_books_in_year.aggregate(Sum("pages"), Avg("pages")) - book_list_by_pages = read_books_in_year.filter(pages__gte=0).order_by("pages") - - # books with no pages - no_page_list = len(read_books_in_year.filter(pages__exact=None)) - - # rating stats queries - ratings = ( - models.Review.objects.filter(user=user) - .exclude(deleted=True) - .exclude(rating=None) - .filter(book_id__in=read_book_ids_in_year) - ) - ratings_stats = ratings.aggregate(Avg("rating")) - - data = { - "year": year, - "books_total": len(read_books_in_year), - "books": read_books_in_year, - "pages_total": page_stats["pages__sum"], - "pages_average": round( - page_stats["pages__avg"] if page_stats["pages__avg"] else 0 - ), - "book_pages_lowest": book_list_by_pages.first(), - "book_pages_highest": book_list_by_pages.last(), - "no_page_number": no_page_list, - "ratings_total": len(ratings), - "rating_average": round( - ratings_stats["rating__avg"] if ratings_stats["rating__avg"] else 0, 2 - ), - "book_rating_highest": ratings.order_by("-rating").first(), - "best_ratings_books_ids": [ - review.book.id for review in ratings.filter(rating=5) - ], - "paginated_years": paginated_years, - } - - return TemplateResponse(request, "annual_summary/layout.html", data) - - def get_read_book_ids_in_year(user, year): """return an ordered QuerySet of the read book ids"""