diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 7cdfd92a..01e86411 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -358,15 +358,15 @@ urlpatterns = [ re_path(r"^list/saved/?$", views.SavedLists.as_view(), name="saved-lists"), re_path(r"^list/(?P\d+)(.json)?/?$", views.List.as_view(), name="list"), re_path(r"^list/delete/(?P\d+)/?$", views.delete_list, name="delete-list"), - re_path(r"^list/add-book/?$", views.list.add_book, name="list-add-book"), + re_path(r"^list/add-book/?$", views.add_book, name="list-add-book"), re_path( r"^list/(?P\d+)/remove/?$", - views.list.remove_book, + views.remove_book, name="list-remove-book", ), re_path( r"^list-item/(?P\d+)/set-position$", - views.list.set_book_position, + views.set_book_position, name="list-set-book-position", ), re_path( diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 3f57c274..da9098dc 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -61,6 +61,20 @@ from .imports.manually_review import ( delete_import_item, ) +# lists +from .list.curate import Curate +from .list.lists import Lists, SavedLists, UserLists +from .list.list import ( + List, + save_list, + unsave_list, + delete_list, + unsafe_embed_list, + add_book, + remove_book, + set_book_position, +) + # misc views from .author import Author, EditAuthor, update_author_from_remote from .directory import Directory @@ -90,8 +104,6 @@ from .group import ( from .inbox import Inbox from .interaction import Favorite, Unfavorite, Boost, Unboost from .isbn import Isbn -from .list import Lists, SavedLists, List, Curate, UserLists -from .list import save_list, unsave_list, delete_list, unsafe_embed_list from .notifications import Notifications from .outbox import Outbox from .reading import ReadThrough, delete_readthrough, delete_progressupdate diff --git a/bookwyrm/views/list/curate.py b/bookwyrm/views/list/curate.py new file mode 100644 index 00000000..924f3770 --- /dev/null +++ b/bookwyrm/views/list/curate.py @@ -0,0 +1,55 @@ +""" book list views""" +from django.contrib.auth.decorators import login_required +from django.db.models import Max +from django.shortcuts import get_object_or_404, redirect +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.views import View + +from bookwyrm import forms, models +from bookwyrm.views.list.list import increment_order_in_reverse +from bookwyrm.views.list.list import normalize_book_list_ordering + + +# pylint: disable=no-self-use +@method_decorator(login_required, name="dispatch") +class Curate(View): + """approve or discard list suggestsions""" + + def get(self, request, list_id): + """display a pending list""" + book_list = get_object_or_404(models.List, id=list_id) + book_list.raise_not_editable(request.user) + + data = { + "list": book_list, + "pending": book_list.listitem_set.filter(approved=False), + "list_form": forms.ListForm(instance=book_list), + } + return TemplateResponse(request, "lists/curate.html", data) + + def post(self, request, list_id): + """edit a book_list""" + book_list = get_object_or_404(models.List, id=list_id) + book_list.raise_not_editable(request.user) + + suggestion = get_object_or_404(models.ListItem, id=request.POST.get("item")) + approved = request.POST.get("approved") == "true" + if approved: + # update the book and set it to be the last in the order of approved books, + # before any pending books + suggestion.approved = True + order_max = ( + book_list.listitem_set.filter(approved=True).aggregate(Max("order"))[ + "order__max" + ] + or 0 + ) + 1 + suggestion.order = order_max + increment_order_in_reverse(book_list.id, order_max) + suggestion.save() + else: + deleted_order = suggestion.order + suggestion.delete(broadcast=False) + normalize_book_list_ordering(book_list.id, start=deleted_order) + return redirect("list-curate", book_list.id) diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list/list.py similarity index 76% rename from bookwyrm/views/list.py rename to bookwyrm/views/list/list.py index 804234ac..296b7e9f 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list/list.py @@ -18,81 +18,11 @@ from django.views.decorators.clickjacking import xframe_options_exempt from bookwyrm import book_search, forms, models from bookwyrm.activitypub import ActivitypubResponse -from bookwyrm.lists_stream import ListsStream from bookwyrm.settings import PAGE_LENGTH -from .helpers import is_api_request -from .helpers import get_user_from_username +from bookwyrm.views.helpers import is_api_request # pylint: disable=no-self-use -class Lists(View): - """book list page""" - - def get(self, request): - """display a book list""" - lists = ListsStream().get_list_stream(request.user) - paginated = Paginator(lists, 12) - data = { - "lists": paginated.get_page(request.GET.get("page")), - "list_form": forms.ListForm(), - "path": "/list", - } - return TemplateResponse(request, "lists/lists.html", data) - - @method_decorator(login_required, name="dispatch") - # pylint: disable=unused-argument - def post(self, request): - """create a book_list""" - form = forms.ListForm(request.POST) - if not form.is_valid(): - return redirect("lists") - book_list = form.save() - # list should not have a group if it is not group curated - if not book_list.curation == "group": - book_list.group = None - book_list.save(broadcast=False) - - return redirect(book_list.local_path) - - -@method_decorator(login_required, name="dispatch") -class SavedLists(View): - """saved book list page""" - - def get(self, request): - """display book lists""" - # hide lists with no approved books - lists = request.user.saved_lists.order_by("-updated_date") - - paginated = Paginator(lists, 12) - data = { - "lists": paginated.get_page(request.GET.get("page")), - "list_form": forms.ListForm(), - "path": "/list", - } - return TemplateResponse(request, "lists/lists.html", data) - - -@method_decorator(login_required, name="dispatch") -class UserLists(View): - """a user's book list page""" - - def get(self, request, username): - """display a book list""" - user = get_user_from_username(request.user, username) - lists = models.List.privacy_filter(request.user).filter(user=user) - paginated = Paginator(lists, 12) - - data = { - "user": user, - "is_self": request.user.id == user.id, - "lists": paginated.get_page(request.GET.get("page")), - "list_form": forms.ListForm(), - "path": user.local_path + "/lists", - } - return TemplateResponse(request, "user/lists.html", data) - - class List(View): """book list page""" @@ -254,49 +184,6 @@ class EmbedList(View): return TemplateResponse(request, "lists/embed-list.html", data) -@method_decorator(login_required, name="dispatch") -class Curate(View): - """approve or discard list suggestsions""" - - def get(self, request, list_id): - """display a pending list""" - book_list = get_object_or_404(models.List, id=list_id) - book_list.raise_not_editable(request.user) - - data = { - "list": book_list, - "pending": book_list.listitem_set.filter(approved=False), - "list_form": forms.ListForm(instance=book_list), - } - return TemplateResponse(request, "lists/curate.html", data) - - def post(self, request, list_id): - """edit a book_list""" - book_list = get_object_or_404(models.List, id=list_id) - book_list.raise_not_editable(request.user) - - suggestion = get_object_or_404(models.ListItem, id=request.POST.get("item")) - approved = request.POST.get("approved") == "true" - if approved: - # update the book and set it to be the last in the order of approved books, - # before any pending books - suggestion.approved = True - order_max = ( - book_list.listitem_set.filter(approved=True).aggregate(Max("order"))[ - "order__max" - ] - or 0 - ) + 1 - suggestion.order = order_max - increment_order_in_reverse(book_list.id, order_max) - suggestion.save() - else: - deleted_order = suggestion.order - suggestion.delete(broadcast=False) - normalize_book_list_ordering(book_list.id, start=deleted_order) - return redirect("list-curate", book_list.id) - - @require_POST @login_required def save_list(request, list_id): diff --git a/bookwyrm/views/list/lists.py b/bookwyrm/views/list/lists.py new file mode 100644 index 00000000..635ad4bc --- /dev/null +++ b/bookwyrm/views/list/lists.py @@ -0,0 +1,80 @@ +""" book list views""" +from django.contrib.auth.decorators import login_required +from django.core.paginator import Paginator +from django.shortcuts import redirect +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.views import View + +from bookwyrm import forms, models +from bookwyrm.lists_stream import ListsStream +from bookwyrm.views.helpers import get_user_from_username + + +# pylint: disable=no-self-use +class Lists(View): + """book list page""" + + def get(self, request): + """display a book list""" + lists = ListsStream().get_list_stream(request.user) + paginated = Paginator(lists, 12) + data = { + "lists": paginated.get_page(request.GET.get("page")), + "list_form": forms.ListForm(), + "path": "/list", + } + return TemplateResponse(request, "lists/lists.html", data) + + @method_decorator(login_required, name="dispatch") + # pylint: disable=unused-argument + def post(self, request): + """create a book_list""" + form = forms.ListForm(request.POST) + if not form.is_valid(): + return redirect("lists") + book_list = form.save() + # list should not have a group if it is not group curated + if not book_list.curation == "group": + book_list.group = None + book_list.save(broadcast=False) + + return redirect(book_list.local_path) + + +@method_decorator(login_required, name="dispatch") +class SavedLists(View): + """saved book list page""" + + def get(self, request): + """display book lists""" + # hide lists with no approved books + lists = request.user.saved_lists.order_by("-updated_date") + + paginated = Paginator(lists, 12) + data = { + "lists": paginated.get_page(request.GET.get("page")), + "list_form": forms.ListForm(), + "path": "/list", + } + return TemplateResponse(request, "lists/lists.html", data) + + +@method_decorator(login_required, name="dispatch") +class UserLists(View): + """a user's book list page""" + + def get(self, request, username): + """display a book list""" + user = get_user_from_username(request.user, username) + lists = models.List.privacy_filter(request.user).filter(user=user) + paginated = Paginator(lists, 12) + + data = { + "user": user, + "is_self": request.user.id == user.id, + "lists": paginated.get_page(request.GET.get("page")), + "list_form": forms.ListForm(), + "path": user.local_path + "/lists", + } + return TemplateResponse(request, "user/lists.html", data)