mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-01-23 23:48:07 +00:00
Merge branch 'main' into page-range
This commit is contained in:
commit
248eab22ed
22 changed files with 109 additions and 40 deletions
2
.github/workflows/black.yml
vendored
2
.github/workflows/black.yml
vendored
|
@ -13,3 +13,5 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
- uses: psf/black@22.12.0
|
- uses: psf/black@22.12.0
|
||||||
|
with:
|
||||||
|
version: 22.12.0
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
""" functionality outline for a book data connector """
|
""" functionality outline for a book data connector """
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from urllib.parse import quote_plus
|
||||||
import imghdr
|
import imghdr
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
@ -48,7 +49,7 @@ class AbstractMinimalConnector(ABC):
|
||||||
return f"{self.isbn_search_url}{normalized_query}"
|
return f"{self.isbn_search_url}{normalized_query}"
|
||||||
# NOTE: previously, we tried searching isbn and if that produces no results,
|
# NOTE: previously, we tried searching isbn and if that produces no results,
|
||||||
# searched as free text. This, instead, only searches isbn if it's isbn-y
|
# searched as free text. This, instead, only searches isbn if it's isbn-y
|
||||||
return f"{self.search_url}{query}"
|
return f"{self.search_url}{quote_plus(query)}"
|
||||||
|
|
||||||
def process_search_response(self, query, data, min_confidence):
|
def process_search_response(self, query, data, min_confidence):
|
||||||
"""Format the search results based on the formt of the query"""
|
"""Format the search results based on the formt of the query"""
|
||||||
|
|
|
@ -52,7 +52,7 @@ class AnnualGoal(BookWyrmModel):
|
||||||
user=self.user,
|
user=self.user,
|
||||||
book__in=book_ids,
|
book__in=book_ids,
|
||||||
)
|
)
|
||||||
return {r.book.id: r.rating for r in reviews}
|
return {r.book_id: r.rating for r in reviews}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def progress(self):
|
def progress(self):
|
||||||
|
|
|
@ -32,7 +32,7 @@ class ReadThrough(BookWyrmModel):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""update user active time"""
|
"""update user active time"""
|
||||||
cache.delete(f"latest_read_through-{self.user.id}-{self.book.id}")
|
cache.delete(f"latest_read_through-{self.user_id}-{self.book_id}")
|
||||||
self.user.update_active_date()
|
self.user.update_active_date()
|
||||||
# an active readthrough must have an unset finish date
|
# an active readthrough must have an unset finish date
|
||||||
if self.finish_date or self.stopped_date:
|
if self.finish_date or self.stopped_date:
|
||||||
|
|
|
@ -107,7 +107,7 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
|
||||||
# remove all caches related to all editions of this book
|
# remove all caches related to all editions of this book
|
||||||
cache.delete_many(
|
cache.delete_many(
|
||||||
[
|
[
|
||||||
f"book-on-shelf-{book.id}-{self.shelf.id}"
|
f"book-on-shelf-{book.id}-{self.shelf_id}"
|
||||||
for book in self.book.parent_work.editions.all()
|
for book in self.book.parent_work.editions.all()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -117,7 +117,7 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
|
||||||
if self.id and self.user.local:
|
if self.id and self.user.local:
|
||||||
cache.delete_many(
|
cache.delete_many(
|
||||||
[
|
[
|
||||||
f"book-on-shelf-{book}-{self.shelf.id}"
|
f"book-on-shelf-{book}-{self.shelf_id}"
|
||||||
for book in self.book.parent_work.editions.values_list(
|
for book in self.book.parent_work.editions.values_list(
|
||||||
"id", flat=True
|
"id", flat=True
|
||||||
)
|
)
|
||||||
|
|
|
@ -80,7 +80,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""save and notify"""
|
"""save and notify"""
|
||||||
if self.reply_parent:
|
if self.reply_parent:
|
||||||
self.thread_id = self.reply_parent.thread_id or self.reply_parent.id
|
self.thread_id = self.reply_parent.thread_id or self.reply_parent_id
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
8
bookwyrm/static/css/vendor/shepherd.scss
vendored
8
bookwyrm/static/css/vendor/shepherd.scss
vendored
|
@ -6,16 +6,16 @@
|
||||||
@use 'bulma/bulma.sass';
|
@use 'bulma/bulma.sass';
|
||||||
|
|
||||||
.shepherd-button {
|
.shepherd-button {
|
||||||
@extend .button.mr-2;
|
@extend .button, .mr-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shepherd-button.shepherd-button-secondary {
|
.shepherd-button.shepherd-button-secondary {
|
||||||
@extend .button.is-light;
|
@extend .button, .is-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shepherd-footer {
|
.shepherd-footer {
|
||||||
@extend .message-body;
|
@extend .message-body;
|
||||||
@extend .is-info.is-light;
|
@extend .is-info, .is-light;
|
||||||
border-color: $info-light;
|
border-color: $info-light;
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
.shepherd-text {
|
.shepherd-text {
|
||||||
@extend .message-body;
|
@extend .message-body;
|
||||||
@extend .is-info.is-light;
|
@extend .is-info, .is-light;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,10 +215,10 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% with work=book.parent_work %}
|
{% with work=book.parent_work editions_count=book.parent_work.editions.count %}
|
||||||
<p>
|
<p>
|
||||||
<a href="{{ work.local_path }}/editions" id="tour-other-editions-link">
|
<a href="{{ work.local_path }}/editions" id="tour-other-editions-link">
|
||||||
{% blocktrans trimmed count counter=work.editions.count with count=work.editions.count|intcomma %}
|
{% blocktrans trimmed count counter=editions_count with count=editions_count|intcomma %}
|
||||||
{{ count }} edition
|
{{ count }} edition
|
||||||
{% plural %}
|
{% plural %}
|
||||||
{{ count }} editions
|
{{ count }} editions
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<nav class="navbar" aria-label="main navigation">
|
<nav class="navbar" aria-label="main navigation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{% with notification_count=request.user.unread_notification_count has_unread_mentions=request.user.has_unread_mentions %}
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item" href="/">
|
<a class="navbar-item" href="/">
|
||||||
<img class="image logo" src="{% if site.logo_small %}{% get_media_prefix %}{{ site.logo_small }}{% else %}{% static "images/logo-small.png" %}{% endif %}" alt="{% blocktrans with site_name=site.name %}{{ site_name }} home page{% endblocktrans %}">
|
<img class="image logo" src="{% if site.logo_small %}{% get_media_prefix %}{{ site.logo_small }}{% else %}{% static "images/logo-small.png" %}{% endif %}" alt="{% blocktrans with site_name=site.name %}{{ site_name }} home page{% endblocktrans %}">
|
||||||
|
@ -67,9 +68,8 @@
|
||||||
>
|
>
|
||||||
<i class="icon-dots-three-vertical" aria-hidden="true"></i>
|
<i class="icon-dots-three-vertical" aria-hidden="true"></i>
|
||||||
|
|
||||||
{% with request.user.unread_notification_count as notification_count %}
|
|
||||||
<strong
|
<strong
|
||||||
class="{% if not notification_count %}is-hidden {% elif request.user.has_unread_mentions %}is-danger {% else %}is-primary {% endif %} tag is-small px-1"
|
class="{% if not notification_count %}is-hidden {% elif has_unread_mentions %}is-danger {% else %}is-primary {% endif %} tag is-small px-1"
|
||||||
data-poll-wrapper
|
data-poll-wrapper
|
||||||
>
|
>
|
||||||
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
||||||
|
@ -77,7 +77,6 @@
|
||||||
{{ notification_count }}
|
{{ notification_count }}
|
||||||
</strong>
|
</strong>
|
||||||
</strong>
|
</strong>
|
||||||
{% endwith %}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -108,14 +107,12 @@
|
||||||
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{% with request.user.unread_notification_count as notification_count %}
|
|
||||||
<span
|
<span
|
||||||
class="{% if not notification_count %}is-hidden {% elif request.user.has_unread_mentions %}is-danger {% endif %}tag is-medium transition-x"
|
class="{% if not notification_count %}is-hidden {% elif has_unread_mentions %}is-danger {% endif %}tag is-medium transition-x"
|
||||||
data-poll-wrapper
|
data-poll-wrapper
|
||||||
>
|
>
|
||||||
<span data-poll="notifications">{{ notification_count }}</span>
|
<span data-poll="notifications">{{ notification_count }}</span>
|
||||||
</span>
|
</span>
|
||||||
{% endwith %}
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -154,6 +151,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,14 @@
|
||||||
|
|
||||||
{% block panel %}
|
{% block panel %}
|
||||||
|
|
||||||
|
<div class="notification">
|
||||||
|
<p>
|
||||||
|
{% trans "You can set up monitoring to check if Celery is running by querying:" %}
|
||||||
|
{% url "settings-celery-ping" as url %}
|
||||||
|
<a href="{{ url }}" target="_blank" rel="nofollow noopener noreferrer">{{ url }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if queues %}
|
{% if queues %}
|
||||||
<section class="block content">
|
<section class="block content">
|
||||||
<h2>{% trans "Queues" %}</h2>
|
<h2>{% trans "Queues" %}</h2>
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not user.is_active and user.deactivation_reason == "pending" %}
|
||||||
|
<form name="activate" method="post" action="{% url 'settings-activate-user' user.id %}" class="mr-1">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="button is-success is-light">{% trans "Activate user" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
{% if user.is_active or user.deactivation_reason == "pending" %}
|
{% if user.is_active or user.deactivation_reason == "pending" %}
|
||||||
<form name="suspend" method="post" action="{% url 'settings-report-suspend' user.id %}" class="mr-1">
|
<form name="suspend" method="post" action="{% url 'settings-report-suspend' user.id %}" class="mr-1">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
|
@ -19,9 +19,9 @@ uuid: a unique identifier used to make html "id" attributes unique and clarify j
|
||||||
{# Supplemental fields #}
|
{# Supplemental fields #}
|
||||||
<div>
|
<div>
|
||||||
{% active_shelf book as active_shelf %}
|
{% active_shelf book as active_shelf %}
|
||||||
{% if active_shelf.shelf.identifier == 'reading' and book.latest_readthrough %}
|
{% if active_shelf.shelf.identifier == 'reading' %}
|
||||||
|
|
||||||
{% with readthrough=book.latest_readthrough %}
|
{% with readthrough=book.latest_readthrough %}
|
||||||
|
{% if readthrough %}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<input type="hidden" name="id" value="{{ readthrough.id }}"/>
|
<input type="hidden" name="id" value="{{ readthrough.id }}"/>
|
||||||
<label class="label" for="progress_{{ uuid }}">{% trans "Progress:" %}</label>
|
<label class="label" for="progress_{{ uuid }}">{% trans "Progress:" %}</label>
|
||||||
|
@ -66,6 +66,7 @@ uuid: a unique identifier used to make html "id" attributes unique and clarify j
|
||||||
<p class="help">{% blocktrans with pages=book.pages %}of {{ pages }} pages{% endblocktrans %}</p>
|
<p class="help">{% blocktrans with pages=book.pages %}of {{ pages }} pages{% endblocktrans %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
{# Three day cache #}
|
{# Three day cache #}
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
{% cache 259200 generated_note_header LANGUAGE_CODE status.id %}
|
{% cache 259200 generated_note_header LANGUAGE_CODE status.id %}
|
||||||
{% if status.content == 'wants to read' %}
|
{% if status.content == 'wants to read' or status.content == '<p>wants to read</p>' %}
|
||||||
{% include 'snippets/status/headers/to_read.html' with book=status.mention_books.first %}
|
{% include 'snippets/status/headers/to_read.html' with book=status.mention_books.first %}
|
||||||
{% elif status.content == 'finished reading' %}
|
{% elif status.content == 'finished reading' or status.content == '<p>finished reading</p>' %}
|
||||||
{% include 'snippets/status/headers/read.html' with book=status.mention_books.first %}
|
{% include 'snippets/status/headers/read.html' with book=status.mention_books.first %}
|
||||||
{% elif status.content == 'started reading' %}
|
{% elif status.content == 'started reading' or status.content == '<p>started reading</p>' %}
|
||||||
{% include 'snippets/status/headers/reading.html' with book=status.mention_books.first %}
|
{% include 'snippets/status/headers/reading.html' with book=status.mention_books.first %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ status.content }}
|
{{ status.content }}
|
||||||
|
|
|
@ -145,6 +145,11 @@ urlpatterns = [
|
||||||
views.UserAdmin.as_view(),
|
views.UserAdmin.as_view(),
|
||||||
name="settings-user",
|
name="settings-user",
|
||||||
),
|
),
|
||||||
|
re_path(
|
||||||
|
r"^settings/users/(?P<user>\d+)/activate/?$",
|
||||||
|
views.ActivateUserAdmin.as_view(),
|
||||||
|
name="settings-activate-user",
|
||||||
|
),
|
||||||
re_path(
|
re_path(
|
||||||
r"^settings/federation/(?P<status>(federated|blocked))?/?$",
|
r"^settings/federation/(?P<status>(federated|blocked))?/?$",
|
||||||
views.Federation.as_view(),
|
views.Federation.as_view(),
|
||||||
|
@ -329,6 +334,9 @@ urlpatterns = [
|
||||||
re_path(
|
re_path(
|
||||||
r"^settings/celery/?$", views.CeleryStatus.as_view(), name="settings-celery"
|
r"^settings/celery/?$", views.CeleryStatus.as_view(), name="settings-celery"
|
||||||
),
|
),
|
||||||
|
re_path(
|
||||||
|
r"^settings/celery/ping/?$", views.celery_ping, name="settings-celery-ping"
|
||||||
|
),
|
||||||
re_path(
|
re_path(
|
||||||
r"^settings/email-config/?$",
|
r"^settings/email-config/?$",
|
||||||
views.EmailConfig.as_view(),
|
views.EmailConfig.as_view(),
|
||||||
|
|
|
@ -4,7 +4,7 @@ from .admin.announcements import Announcements, Announcement
|
||||||
from .admin.announcements import EditAnnouncement, delete_announcement
|
from .admin.announcements import EditAnnouncement, delete_announcement
|
||||||
from .admin.automod import AutoMod, automod_delete, run_automod
|
from .admin.automod import AutoMod, automod_delete, run_automod
|
||||||
from .admin.automod import schedule_automod_task, unschedule_automod_task
|
from .admin.automod import schedule_automod_task, unschedule_automod_task
|
||||||
from .admin.celery_status import CeleryStatus
|
from .admin.celery_status import CeleryStatus, celery_ping
|
||||||
from .admin.dashboard import Dashboard
|
from .admin.dashboard import Dashboard
|
||||||
from .admin.federation import Federation, FederatedServer
|
from .admin.federation import Federation, FederatedServer
|
||||||
from .admin.federation import AddFederatedServer, ImportServerBlocklist
|
from .admin.federation import AddFederatedServer, ImportServerBlocklist
|
||||||
|
@ -31,7 +31,7 @@ from .admin.reports import (
|
||||||
)
|
)
|
||||||
from .admin.site import Site, Registration, RegistrationLimited
|
from .admin.site import Site, Registration, RegistrationLimited
|
||||||
from .admin.themes import Themes, delete_theme
|
from .admin.themes import Themes, delete_theme
|
||||||
from .admin.user_admin import UserAdmin, UserAdminList
|
from .admin.user_admin import UserAdmin, UserAdminList, ActivateUserAdmin
|
||||||
|
|
||||||
# user preferences
|
# user preferences
|
||||||
from .preferences.change_password import ChangePassword
|
from .preferences.change_password import ChangePassword
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
""" celery status """
|
""" celery status """
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.http import HttpResponse
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
from django.views.decorators.http import require_GET
|
||||||
import redis
|
import redis
|
||||||
|
|
||||||
from celerywyrm import settings
|
from celerywyrm import settings
|
||||||
|
@ -50,3 +52,18 @@ class CeleryStatus(View):
|
||||||
"errors": errors,
|
"errors": errors,
|
||||||
}
|
}
|
||||||
return TemplateResponse(request, "settings/celery.html", data)
|
return TemplateResponse(request, "settings/celery.html", data)
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def celery_ping(request):
|
||||||
|
"""Just tells you if Celery is on or not"""
|
||||||
|
try:
|
||||||
|
ping = celery.control.inspect().ping()
|
||||||
|
if ping:
|
||||||
|
return HttpResponse()
|
||||||
|
# pylint: disable=broad-except
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return HttpResponse(status=500)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
""" manage user """
|
""" manage user """
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
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.template.response import TemplateResponse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
@ -95,3 +95,19 @@ class UserAdmin(View):
|
||||||
form.save(request)
|
form.save(request)
|
||||||
data = {"user": user, "group_form": form}
|
data = {"user": user, "group_form": form}
|
||||||
return TemplateResponse(request, "settings/users/user.html", data)
|
return TemplateResponse(request, "settings/users/user.html", data)
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(login_required, name="dispatch")
|
||||||
|
@method_decorator(
|
||||||
|
permission_required("bookwyrm.moderate_user", raise_exception=True),
|
||||||
|
name="dispatch",
|
||||||
|
)
|
||||||
|
class ActivateUserAdmin(View):
|
||||||
|
"""activate a user manually"""
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def post(self, request, user):
|
||||||
|
"""activate user"""
|
||||||
|
user = get_object_or_404(models.User, id=user)
|
||||||
|
user.reactivate()
|
||||||
|
return redirect("settings-user", user.id)
|
||||||
|
|
|
@ -68,7 +68,7 @@ class AnnualSummary(View):
|
||||||
book_list_by_pages = read_books_in_year.filter(pages__gte=0).order_by("pages")
|
book_list_by_pages = read_books_in_year.filter(pages__gte=0).order_by("pages")
|
||||||
|
|
||||||
# books with no pages
|
# books with no pages
|
||||||
no_page_list = len(read_books_in_year.filter(pages__exact=None))
|
no_page_list = read_books_in_year.filter(pages__exact=None).count()
|
||||||
|
|
||||||
# rating stats queries
|
# rating stats queries
|
||||||
ratings = (
|
ratings = (
|
||||||
|
@ -95,13 +95,13 @@ class AnnualSummary(View):
|
||||||
"book_pages_lowest": book_list_by_pages.first(),
|
"book_pages_lowest": book_list_by_pages.first(),
|
||||||
"book_pages_highest": book_list_by_pages.last(),
|
"book_pages_highest": book_list_by_pages.last(),
|
||||||
"no_page_number": no_page_list,
|
"no_page_number": no_page_list,
|
||||||
"ratings_total": len(ratings),
|
"ratings_total": ratings.count(),
|
||||||
"rating_average": round(
|
"rating_average": round(
|
||||||
ratings_stats["rating__avg"] if ratings_stats["rating__avg"] else 0, 2
|
ratings_stats["rating__avg"] if ratings_stats["rating__avg"] else 0, 2
|
||||||
),
|
),
|
||||||
"book_rating_highest": ratings.order_by("-rating").first(),
|
"book_rating_highest": ratings.order_by("-rating").first(),
|
||||||
"best_ratings_books_ids": [
|
"best_ratings_books_ids": [
|
||||||
review.book.id for review in ratings.filter(rating=5)
|
review.book_id for review in ratings.filter(rating=5)
|
||||||
],
|
],
|
||||||
"paginated_years": paginated_years,
|
"paginated_years": paginated_years,
|
||||||
"goal_status": goal_status,
|
"goal_status": goal_status,
|
||||||
|
|
|
@ -237,16 +237,24 @@ def feed_page_data(user):
|
||||||
def get_suggested_books(user, max_books=5):
|
def get_suggested_books(user, max_books=5):
|
||||||
"""helper to get a user's recent books"""
|
"""helper to get a user's recent books"""
|
||||||
book_count = 0
|
book_count = 0
|
||||||
preset_shelves = [("reading", max_books), ("read", 2), ("to-read", max_books)]
|
preset_shelves = {"reading": max_books, "read": 2, "to-read": max_books}
|
||||||
suggested_books = []
|
suggested_books = []
|
||||||
for (preset, shelf_max) in preset_shelves:
|
|
||||||
|
user_shelves = {
|
||||||
|
shelf.identifier: shelf
|
||||||
|
for shelf in user.shelf_set.filter(
|
||||||
|
identifier__in=preset_shelves.keys()
|
||||||
|
).exclude(books__isnull=True)
|
||||||
|
}
|
||||||
|
|
||||||
|
for preset, shelf_max in preset_shelves.items():
|
||||||
limit = (
|
limit = (
|
||||||
shelf_max
|
shelf_max
|
||||||
if shelf_max < (max_books - book_count)
|
if shelf_max < (max_books - book_count)
|
||||||
else max_books - book_count
|
else max_books - book_count
|
||||||
)
|
)
|
||||||
shelf = user.shelf_set.get(identifier=preset)
|
shelf = user_shelves.get(preset, None)
|
||||||
if not shelf.books.exists():
|
if not shelf:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
shelf_preview = {
|
shelf_preview = {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
black==22.3.0
|
black==22.12.0
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: 0.0.1\n"
|
"Project-Id-Version: 0.0.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-01-26 16:43+0000\n"
|
"POT-Creation-Date: 2023-01-30 08:21+0000\n"
|
||||||
"PO-Revision-Date: 2021-02-28 17:19-0800\n"
|
"PO-Revision-Date: 2021-02-28 17:19-0800\n"
|
||||||
"Last-Translator: Mouse Reeve <mousereeve@riseup.net>\n"
|
"Last-Translator: Mouse Reeve <mousereeve@riseup.net>\n"
|
||||||
"Language-Team: English <LL@li.org>\n"
|
"Language-Team: English <LL@li.org>\n"
|
||||||
|
@ -851,7 +851,7 @@ msgstr ""
|
||||||
#: bookwyrm/templates/settings/registration.html:96
|
#: bookwyrm/templates/settings/registration.html:96
|
||||||
#: bookwyrm/templates/settings/registration_limited.html:76
|
#: bookwyrm/templates/settings/registration_limited.html:76
|
||||||
#: bookwyrm/templates/settings/site.html:144
|
#: 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/shelf/form.html:25
|
||||||
#: bookwyrm/templates/snippets/reading_modals/layout.html:18
|
#: bookwyrm/templates/snippets/reading_modals/layout.html:18
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
|
@ -5448,7 +5448,7 @@ msgid "Remove theme"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bookwyrm/templates/settings/users/delete_user_form.html:5
|
#: 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"
|
msgid "Permanently delete user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -5570,14 +5570,18 @@ msgid "User Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bookwyrm/templates/settings/users/user_moderation_actions.html:21
|
#: 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"
|
msgid "Suspend user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bookwyrm/templates/settings/users/user_moderation_actions.html:26
|
#: bookwyrm/templates/settings/users/user_moderation_actions.html:32
|
||||||
msgid "Un-suspend user"
|
msgid "Un-suspend user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bookwyrm/templates/settings/users/user_moderation_actions.html:48
|
#: bookwyrm/templates/settings/users/user_moderation_actions.html:54
|
||||||
msgid "Access level:"
|
msgid "Access level:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ aiohttp==3.8.3
|
||||||
bleach==5.0.1
|
bleach==5.0.1
|
||||||
celery==5.2.7
|
celery==5.2.7
|
||||||
colorthief==0.2.1
|
colorthief==0.2.1
|
||||||
Django==3.2.16
|
Django==3.2.17
|
||||||
django-celery-beat==2.4.0
|
django-celery-beat==2.4.0
|
||||||
django-compressor==4.3.1
|
django-compressor==4.3.1
|
||||||
django-imagekit==4.1.0
|
django-imagekit==4.1.0
|
||||||
|
|
Loading…
Reference in a new issue