Merge branch 'main' into bookwyrm-groups

There are database migrations in main ahead of this branch so they need to be merged in to the branch before we can merge back into main.
This commit is contained in:
Hugh Rundle
2021-10-17 06:22:04 +11:00
90 changed files with 2446 additions and 92814 deletions

View File

@ -70,7 +70,7 @@ from .search import Search
from .shelf import Shelf
from .shelf import create_shelf, delete_shelf
from .shelf import shelve, unshelve
from .status import CreateStatus, DeleteStatus, DeleteAndRedraft, update_progress
from .status import CreateStatus, EditStatus, DeleteStatus, update_progress
from .status import edit_readthrough
from .updates import get_notification_count, get_unread_status_count
from .user import User, Followers, Following, hide_suggestions

View File

@ -51,7 +51,7 @@ class Import(View):
elif source == "Storygraph":
importer = StorygraphImporter()
else:
# Default : GoodReads
# Default : Goodreads
importer = GoodreadsImporter()
try:

View File

@ -68,16 +68,30 @@ class Shelf(View):
deleted=False,
).order_by("-published_date")
reading = models.ReadThrough.objects
reading = reading.filter(user=user, book__id=OuterRef("id")).order_by(
"start_date"
)
books = books.annotate(
rating=Subquery(reviews.values("rating")[:1]),
shelved_date=F("shelfbook__shelved_date"),
start_date=Subquery(reading.values("start_date")[:1]),
finish_date=Subquery(reading.values("finish_date")[:1]),
author=Subquery(
models.Book.objects.filter(id=OuterRef("id")).values("authors__name")[
:1
]
),
).prefetch_related("authors")
books = sort_books(books, request.GET.get("sort"))
paginated = Paginator(
books.order_by("-shelfbook__updated_date"),
books,
PAGE_LENGTH,
)
page = paginated.get_page(request.GET.get("page"))
data = {
"user": user,
@ -87,6 +101,7 @@ class Shelf(View):
"books": page,
"edit_form": forms.ShelfForm(instance=shelf if shelf_identifier else None),
"create_form": forms.ShelfForm(),
"sort": request.GET.get("sort"),
"page_range": paginated.get_elided_page_range(
page.number, on_each_side=2, on_ends=1
),
@ -207,3 +222,23 @@ def unshelve(request):
shelf_book.delete()
return redirect(request.headers.get("Referer", "/"))
def sort_books(books, sort):
"""Books in shelf sorting"""
sort_fields = [
"title",
"author",
"shelved_date",
"start_date",
"finish_date",
"rating",
]
if sort in sort_fields:
books = books.order_by(sort)
elif sort and sort[1:] in sort_fields:
books = books.order_by(F(sort[1:]).desc(nulls_last=True))
else:
books = books.order_by("-shelved_date")
return books

View File

@ -8,6 +8,7 @@ from django.core.exceptions import ValidationError
from django.http import HttpResponse, HttpResponseBadRequest, Http404
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.http import require_POST
@ -21,23 +22,55 @@ from .helpers import handle_remote_webfinger, is_api_request
from .helpers import load_date_in_user_tz_as_utc
# pylint: disable= no-self-use
@method_decorator(login_required, name="dispatch")
class EditStatus(View):
"""the view for *posting*"""
def get(self, request, status_id): # pylint: disable=unused-argument
"""load the edit panel"""
status = get_object_or_404(
models.Status.objects.select_subclasses(), id=status_id
)
status.raise_not_editable(request.user)
status_type = "reply" if status.reply_parent else status.status_type.lower()
data = {
"type": status_type,
"book": getattr(status, "book", None),
"draft": status,
}
return TemplateResponse(request, "compose.html", data)
# pylint: disable= no-self-use
@method_decorator(login_required, name="dispatch")
class CreateStatus(View):
"""the view for *posting*"""
def get(self, request, status_type): # pylint: disable=unused-argument
"""compose view (used for delete-and-redraft)"""
"""compose view (...not used?)"""
book = get_object_or_404(models.Edition, id=request.GET.get("book"))
data = {"book": book}
return TemplateResponse(request, "compose.html", data)
def post(self, request, status_type):
"""create status of whatever type"""
def post(self, request, status_type, existing_status_id=None):
"""create status of whatever type"""
created = not existing_status_id
existing_status = None
if existing_status_id:
existing_status = get_object_or_404(
models.Status.objects.select_subclasses(), id=existing_status_id
)
existing_status.raise_not_editable(request.user)
existing_status.edited_date = timezone.now()
status_type = status_type[0].upper() + status_type[1:]
try:
form = getattr(forms, f"{status_type}Form")(request.POST)
form = getattr(forms, f"{status_type}Form")(
request.POST, instance=existing_status
)
except AttributeError:
return HttpResponseBadRequest()
if not form.is_valid():
@ -46,6 +79,11 @@ class CreateStatus(View):
return redirect(request.headers.get("Referer", "/"))
status = form.save(commit=False)
# save the plain, unformatted version of the status for future editing
status.raw_content = status.content
if hasattr(status, "quote"):
status.raw_quote = status.quote
if not status.sensitive and status.content_warning:
# the cw text field remains populated when you click "remove"
status.content_warning = None
@ -77,7 +115,7 @@ class CreateStatus(View):
if hasattr(status, "quote"):
status.quote = to_markdown(status.quote)
status.save(created=True)
status.save(created=created)
# update a readthorugh, if needed
try:
@ -106,36 +144,6 @@ class DeleteStatus(View):
return redirect(request.headers.get("Referer", "/"))
@method_decorator(login_required, name="dispatch")
class DeleteAndRedraft(View):
"""delete a status but let the user re-create it"""
def post(self, request, status_id):
"""delete and tombstone a status"""
status = get_object_or_404(
models.Status.objects.select_subclasses(), id=status_id
)
# don't let people redraft other people's statuses
status.raise_not_editable(request.user)
status_type = status.status_type.lower()
if status.reply_parent:
status_type = "reply"
data = {
"draft": status,
"type": status_type,
}
if hasattr(status, "book"):
data["book"] = status.book
elif status.mention_books:
data["book"] = status.mention_books.first()
# perform deletion
status.delete()
return TemplateResponse(request, "compose.html", data)
@login_required
@require_POST
def update_progress(request, book_id): # pylint: disable=unused-argument