diff --git a/bookwyrm/templates/book.html b/bookwyrm/templates/book.html index 35c8dd5f..f792408c 100644 --- a/bookwyrm/templates/book.html +++ b/bookwyrm/templates/book.html @@ -223,7 +223,7 @@ -
+
{% for review in reviews %}
{% include 'snippets/status.html' with status=review hide_book=True depth=1 %} @@ -231,25 +231,28 @@ {% endfor %}
- {% for rating in ratings %} -
-
-
{% include 'snippets/avatar.html' with user=rating.user %}
-
-
- {% include 'snippets/username.html' with user=rating.user %} -
-
-
rated it
- {% include 'snippets/stars.html' with rating=rating.rating %} -
-
- {{ rating.published_date | naturaltime }} + {% for rating in ratings %} +
+
+
{% include 'snippets/avatar.html' with user=rating.user %}
+
+
+ {% include 'snippets/username.html' with user=rating.user %} +
+
+
rated it
+ {% include 'snippets/stars.html' with rating=rating.rating %} +
+
+ {% endfor %}
- {% endfor %} +
+ {% include 'snippets/pagination.html' with page=reviews path=book.local_path anchor="#reviews" %}
diff --git a/bookwyrm/templates/direct_messages.html b/bookwyrm/templates/direct_messages.html index 6a20b111..666f5290 100644 --- a/bookwyrm/templates/direct_messages.html +++ b/bookwyrm/templates/direct_messages.html @@ -13,25 +13,7 @@
{% endfor %} - + {% include 'snippets/pagination.html' with page=activities path="direct-messages" %}
{% endblock %} diff --git a/bookwyrm/templates/edit_book.html b/bookwyrm/templates/edit_book.html index b0e262dd..27d1d5be 100644 --- a/bookwyrm/templates/edit_book.html +++ b/bookwyrm/templates/edit_book.html @@ -27,7 +27,7 @@
{% endif %} -
+ {% csrf_token %}
diff --git a/bookwyrm/templates/feed.html b/bookwyrm/templates/feed.html index f02219bc..db66a72d 100644 --- a/bookwyrm/templates/feed.html +++ b/bookwyrm/templates/feed.html @@ -94,25 +94,7 @@
{% endfor %} - + {% include 'snippets/pagination.html' with page=activities path='/'|add:tab anchor="#feed" %}
{% endblock %} diff --git a/bookwyrm/templates/snippets/pagination.html b/bookwyrm/templates/snippets/pagination.html new file mode 100644 index 00000000..1855dfed --- /dev/null +++ b/bookwyrm/templates/snippets/pagination.html @@ -0,0 +1,19 @@ + diff --git a/bookwyrm/templates/user.html b/bookwyrm/templates/user.html index 2d3fac1e..dd5ca94c 100644 --- a/bookwyrm/templates/user.html +++ b/bookwyrm/templates/user.html @@ -45,7 +45,7 @@

User Activity

{% for activity in activities %} -
+
{% include 'snippets/status.html' with status=activity %}
{% endfor %} @@ -55,25 +55,7 @@
{% endif %} - + {% include 'snippets/pagination.html' with page=activities path=user.local_path anchor="#feed" %} {% endblock %} diff --git a/bookwyrm/tests/views/test_book.py b/bookwyrm/tests/views/test_book.py new file mode 100644 index 00000000..a9475772 --- /dev/null +++ b/bookwyrm/tests/views/test_book.py @@ -0,0 +1,127 @@ +''' test for app action functionality ''' +from unittest.mock import patch +from django.contrib.auth.models import Group, Permission +from django.contrib.contenttypes.models import ContentType +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import forms, models, views +from bookwyrm.activitypub import ActivitypubResponse + + +class InteractionViews(TestCase): + ''' viewing and creating statuses ''' + def setUp(self): + ''' we need basic test data and mocks ''' + self.factory = RequestFactory() + self.local_user = models.User.objects.create_user( + 'mouse@local.com', 'mouse@mouse.com', 'mouseword', + local=True, localname='mouse', + remote_id='https://example.com/users/mouse', + ) + self.group = Group.objects.create(name='editor') + self.group.permissions.add( + Permission.objects.create( + name='edit_book', + codename='edit_book', + content_type=ContentType.objects.get_for_model(models.User)).id + ) + self.work = models.Work.objects.create(title='Test Work') + self.book = models.Edition.objects.create( + title='Example Edition', + remote_id='https://example.com/book/1', + parent_work=self.work + ) + + + def test_book_page(self): + ''' there are so many views, this just makes sure it LOADS ''' + view = views.Book.as_view() + request = self.factory.get('') + request.user = self.local_user + with patch('bookwyrm.views.books.is_api_request') as is_api: + is_api.return_value = False + result = view(request, self.book.id) + self.assertIsInstance(result, TemplateResponse) + self.assertEqual(result.template_name, 'book.html') + self.assertEqual(result.status_code, 200) + + request = self.factory.get('') + with patch('bookwyrm.views.books.is_api_request') as is_api: + is_api.return_value = True + result = view(request, self.book.id) + self.assertIsInstance(result, ActivitypubResponse) + self.assertEqual(result.status_code, 200) + + + def test_edit_book_page(self): + ''' there are so many views, this just makes sure it LOADS ''' + view = views.EditBook.as_view() + request = self.factory.get('') + request.user = self.local_user + request.user.is_superuser = True + result = view(request, self.book.id) + self.assertIsInstance(result, TemplateResponse) + self.assertEqual(result.template_name, 'edit_book.html') + self.assertEqual(result.status_code, 200) + + + def test_edit_book(self): + ''' lets a user edit a book ''' + view = views.EditBook.as_view() + self.local_user.groups.add(self.group) + form = forms.EditionForm(instance=self.book) + form.data['title'] = 'New Title' + form.data['last_edited_by'] = self.local_user.id + request = self.factory.post('', form.data) + request.user = self.local_user + with patch('bookwyrm.broadcast.broadcast_task.delay'): + view(request, self.book.id) + self.book.refresh_from_db() + self.assertEqual(self.book.title, 'New Title') + + + def test_switch_edition(self): + ''' updates user's relationships to a book ''' + work = models.Work.objects.create(title='test work') + edition1 = models.Edition.objects.create( + title='first ed', parent_work=work) + edition2 = models.Edition.objects.create( + title='second ed', parent_work=work) + shelf = models.Shelf.objects.create( + name='Test Shelf', user=self.local_user) + shelf.books.add(edition1) + models.ReadThrough.objects.create( + user=self.local_user, book=edition1) + + self.assertEqual(models.ShelfBook.objects.get().book, edition1) + self.assertEqual(models.ReadThrough.objects.get().book, edition1) + request = self.factory.post('', { + 'edition': edition2.id + }) + request.user = self.local_user + with patch('bookwyrm.broadcast.broadcast_task.delay'): + views.switch_edition(request) + + self.assertEqual(models.ShelfBook.objects.get().book, edition2) + self.assertEqual(models.ReadThrough.objects.get().book, edition2) + + + def test_editions_page(self): + ''' there are so many views, this just makes sure it LOADS ''' + view = views.Editions.as_view() + request = self.factory.get('') + with patch('bookwyrm.views.books.is_api_request') as is_api: + is_api.return_value = False + result = view(request, self.work.id) + self.assertIsInstance(result, TemplateResponse) + self.assertEqual(result.template_name, 'editions.html') + self.assertEqual(result.status_code, 200) + + request = self.factory.get('') + with patch('bookwyrm.views.books.is_api_request') as is_api: + is_api.return_value = True + result = view(request, self.work.id) + self.assertIsInstance(result, ActivitypubResponse) + self.assertEqual(result.status_code, 200) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index dfd2ff81..186a0d94 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -88,10 +88,16 @@ urlpatterns = [ re_path(r'^unboost/(?P\d+)/?$', views.Unboost.as_view()), # books - re_path(r'%s(.json)?/?$' % book_path, vviews.book_page), - re_path(r'%s/edit/?$' % book_path, vviews.edit_book_page), + re_path(r'%s(.json)?/?$' % book_path, views.Book.as_view()), + re_path(r'%s/edit/?$' % book_path, views.EditBook.as_view()), + re_path(r'%s/editions(.json)?/?$' % book_path, views.Editions.as_view()), + re_path(r'^upload-cover/(?P\d+)/?$', views.upload_cover), + re_path(r'^add-description/(?P\d+)/?$', views.add_description), + re_path(r'^resolve-book/?$', views.resolve_book), + re_path(r'^switch-edition/?$', views.switch_edition), + re_path(r'^author/(?P[\w\-]+)/edit/?$', vviews.edit_author_page), - re_path(r'%s/editions(.json)?/?$' % book_path, vviews.editions_page), + re_path(r'^tag/?$', actions.tag), re_path(r'^untag/?$', actions.untag), @@ -105,15 +111,8 @@ urlpatterns = [ re_path(r'^search/?$', vviews.search), - # internal action endpoints - - re_path(r'^resolve-book/?$', actions.resolve_book), - re_path(r'^edit-book/(?P\d+)/?$', actions.edit_book), - re_path(r'^upload-cover/(?P\d+)/?$', actions.upload_cover), - re_path(r'^add-description/(?P\d+)/?$', actions.add_description), re_path(r'^edit-author/(?P\d+)/?$', actions.edit_author), - re_path(r'^switch-edition/?$', actions.switch_edition), re_path(r'^edit-readthrough/?$', actions.edit_readthrough), re_path(r'^delete-readthrough/?$', actions.delete_readthrough), re_path(r'^create-readthrough/?$', actions.create_readthrough), diff --git a/bookwyrm/view_actions.py b/bookwyrm/view_actions.py index 1a6edd7f..f2456491 100644 --- a/bookwyrm/view_actions.py +++ b/bookwyrm/view_actions.py @@ -3,7 +3,6 @@ import dateutil.parser from dateutil.parser import ParserError from django.contrib.auth.decorators import login_required, permission_required -from django.db import transaction from django.http import HttpResponseBadRequest, HttpResponseNotFound from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse @@ -11,108 +10,9 @@ from django.utils import timezone from django.views.decorators.http import require_POST from bookwyrm import forms, models, outgoing -from bookwyrm.connectors import connector_manager from bookwyrm.broadcast import broadcast from bookwyrm.vviews import get_user_from_username, get_edition - -@require_POST -def resolve_book(request): - ''' figure out the local path to a book from a remote_id ''' - remote_id = request.POST.get('remote_id') - connector = connector_manager.get_or_create_connector(remote_id) - book = connector.get_or_create_book(remote_id) - - return redirect('/book/%d' % book.id) - - -@login_required -@permission_required('bookwyrm.edit_book', raise_exception=True) -@require_POST -def edit_book(request, book_id): - ''' edit a book cool ''' - book = get_object_or_404(models.Edition, id=book_id) - - form = forms.EditionForm(request.POST, request.FILES, instance=book) - if not form.is_valid(): - data = { - 'title': 'Edit Book', - 'book': book, - 'form': form - } - return TemplateResponse(request, 'edit_book.html', data) - book = form.save() - - broadcast(request.user, book.to_update_activity(request.user)) - return redirect('/book/%s' % book.id) - - -@login_required -@require_POST -@transaction.atomic -def switch_edition(request): - ''' switch your copy of a book to a different edition ''' - edition_id = request.POST.get('edition') - new_edition = get_object_or_404(models.Edition, id=edition_id) - shelfbooks = models.ShelfBook.objects.filter( - book__parent_work=new_edition.parent_work, - shelf__user=request.user - ) - for shelfbook in shelfbooks.all(): - broadcast(request.user, shelfbook.to_remove_activity(request.user)) - - shelfbook.book = new_edition - shelfbook.save() - - broadcast(request.user, shelfbook.to_add_activity(request.user)) - - readthroughs = models.ReadThrough.objects.filter( - book__parent_work=new_edition.parent_work, - user=request.user - ) - for readthrough in readthroughs.all(): - readthrough.book = new_edition - readthrough.save() - - return redirect('/book/%d' % new_edition.id) - - -@login_required -@require_POST -def upload_cover(request, book_id): - ''' upload a new cover ''' - book = get_object_or_404(models.Edition, id=book_id) - - form = forms.CoverForm(request.POST, request.FILES, instance=book) - if not form.is_valid(): - return redirect('/book/%d' % book.id) - - book.cover = form.files['cover'] - book.save() - - broadcast(request.user, book.to_update_activity(request.user)) - return redirect('/book/%s' % book.id) - - -@login_required -@require_POST -@permission_required('bookwyrm.edit_book', raise_exception=True) -def add_description(request, book_id): - ''' upload a new cover ''' - if not request.method == 'POST': - return redirect('/') - - book = get_object_or_404(models.Edition, id=book_id) - - description = request.POST.get('description') - - book.description = description - book.save() - - broadcast(request.user, book.to_update_activity(request.user)) - return redirect('/book/%s' % book.id) - - @login_required @permission_required('bookwyrm.edit_book', raise_exception=True) @require_POST @@ -378,33 +278,6 @@ def untag(request): return redirect('/book/%s' % book_id) -@login_required -@require_POST -def unfavorite(request, status_id): - ''' like a status ''' - status = models.Status.objects.get(id=status_id) - outgoing.handle_unfavorite(request.user, status) - return redirect(request.headers.get('Referer', '/')) - - -@login_required -@require_POST -def boost(request, status_id): - ''' boost a status ''' - status = models.Status.objects.get(id=status_id) - outgoing.handle_boost(request.user, status) - return redirect(request.headers.get('Referer', '/')) - - -@login_required -@require_POST -def unboost(request, status_id): - ''' boost a status ''' - status = models.Status.objects.get(id=status_id) - outgoing.handle_unboost(request.user, status) - return redirect(request.headers.get('Referer', '/')) - - @login_required @require_POST def follow(request): diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 2611184b..52f4f36f 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -9,3 +9,5 @@ from .import_data import Import, ImportStatus from .user import User, EditUser, Followers, Following from .status import Status, Replies, CreateStatus, DeleteStatus from .interaction import Favorite, Unfavorite, Boost, Unboost +from .books import Book, EditBook, Editions +from .books import upload_cover, add_description, switch_edition, resolve_book diff --git a/bookwyrm/views/direct_message.py b/bookwyrm/views/direct_message.py index feb0c19a..1f6c4f19 100644 --- a/bookwyrm/views/direct_message.py +++ b/bookwyrm/views/direct_message.py @@ -18,19 +18,9 @@ class DirectMessage(View): activities = get_activity_feed(request.user, 'direct') paginated = Paginator(activities, PAGE_LENGTH) activity_page = paginated.page(page) - - prev_page = next_page = None - if activity_page.has_next(): - next_page = '/direct-message/?page=%d#feed' % \ - activity_page.next_page_number() - if activity_page.has_previous(): - prev_page = '/direct-messages/?page=%d#feed' % \ - activity_page.previous_page_number() data = { 'title': 'Direct Messages', 'user': request.user, - 'activities': activity_page.object_list, - 'next': next_page, - 'prev': prev_page, + 'activities': activity_page, } return TemplateResponse(request, 'direct_messages.html', data) diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index 3c3afcce..13f990fb 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -137,3 +137,13 @@ def handle_remote_webfinger(query): except KeyError: return None return user + + +def get_edition(book_id): + ''' look up a book in the db and return an edition ''' + book = models.Book.objects.select_subclasses().get(id=book_id) + if isinstance(book, models.Work): + book = book.get_default_edition() + return book + + diff --git a/bookwyrm/views/interaction.py b/bookwyrm/views/interaction.py index 2c5de375..a6732c52 100644 --- a/bookwyrm/views/interaction.py +++ b/bookwyrm/views/interaction.py @@ -105,7 +105,6 @@ class Boost(View): return redirect(request.headers.get('Referer', '/')) - @method_decorator(login_required, name='dispatch') class Unboost(View): ''' boost a status ''' diff --git a/bookwyrm/views/landing.py b/bookwyrm/views/landing.py index 389ab2ec..7917c5b4 100644 --- a/bookwyrm/views/landing.py +++ b/bookwyrm/views/landing.py @@ -86,23 +86,12 @@ class Feed(View): activities = get_activity_feed( request.user, ['public', 'followers']) paginated = Paginator(activities, PAGE_LENGTH) - activity_page = paginated.page(page) - - prev_page = next_page = None - if activity_page.has_next(): - next_page = '/%s/?page=%d#feed' % \ - (tab, activity_page.next_page_number()) - if activity_page.has_previous(): - prev_page = '/%s/?page=%d#feed' % \ - (tab, activity_page.previous_page_number()) data = { 'title': 'Updates Feed', 'user': request.user, 'suggested_books': suggested_books, - 'activities': activity_page.object_list, + 'activities': paginated.page(page), 'tab': tab, - 'next': next_page, - 'prev': prev_page, } return TemplateResponse(request, 'feed.html', data) diff --git a/bookwyrm/views/user.py b/bookwyrm/views/user.py index 35d06fd0..9a22c47c 100644 --- a/bookwyrm/views/user.py +++ b/bookwyrm/views/user.py @@ -70,24 +70,13 @@ class User(View): queryset=models.Status.objects.filter(user=user) ) paginated = Paginator(activities, PAGE_LENGTH) - activity_page = paginated.page(page) - - prev_page = next_page = None - if activity_page.has_next(): - next_page = '/user/%s/?page=%d' % \ - (username, activity_page.next_page_number()) - if activity_page.has_previous(): - prev_page = '/user/%s/?page=%d' % \ - (username, activity_page.previous_page_number()) data = { 'title': user.name, 'user': user, 'is_self': is_self, 'shelves': shelf_preview, 'shelf_count': shelves.count(), - 'activities': activity_page.object_list, - 'next': next_page, - 'prev': prev_page, + 'activities': paginated.page(page), } return TemplateResponse(request, 'user.html', data) diff --git a/bookwyrm/vviews.py b/bookwyrm/vviews.py index 2c7137e6..befdca2d 100644 --- a/bookwyrm/vviews.py +++ b/bookwyrm/vviews.py @@ -3,8 +3,7 @@ import re from django.contrib.auth.decorators import login_required, permission_required from django.contrib.postgres.search import TrigramSimilarity -from django.core.paginator import Paginator -from django.db.models import Avg, Q +from django.db.models import Q from django.db.models.functions import Greatest from django.http import HttpResponseNotFound, JsonResponse from django.shortcuts import get_object_or_404 @@ -16,10 +15,8 @@ from bookwyrm import outgoing from bookwyrm import forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.connectors import connector_manager -from bookwyrm.settings import PAGE_LENGTH from bookwyrm.utils import regex - def get_edition(book_id): ''' look up a book in the db and return an edition ''' book = models.Book.objects.select_subclasses().get(id=book_id) @@ -27,6 +24,8 @@ def get_edition(book_id): book = book.get_default_edition() return book + + def get_user_from_username(username): ''' helper function to resolve a localname or a username to a user ''' # raises DoesNotExist if user is now found @@ -41,14 +40,6 @@ def is_api_request(request): return 'json' in request.headers.get('Accept') or \ request.path[-5:] == '.json' -def is_bookworm_request(request): - ''' check if the request is coming from another bookworm instance ''' - user_agent = request.headers.get('User-Agent') - if user_agent is None or \ - re.search(regex.bookwyrm_user_agent, user_agent) is None: - return False - - return True def server_error_page(request): ''' 500 errors ''' @@ -62,64 +53,6 @@ def not_found_page(request, _): request, 'notfound.html', {'title': 'Not found'}, status=404) -def get_activity_feed( - user, privacy, local_only=False, following_only=False, - queryset=models.Status.objects): - ''' get a filtered queryset of statuses ''' - privacy = privacy if isinstance(privacy, list) else [privacy] - # if we're looking at Status, we need this. We don't if it's Comment - if hasattr(queryset, 'select_subclasses'): - queryset = queryset.select_subclasses() - - # exclude deleted - queryset = queryset.exclude(deleted=True).order_by('-published_date') - - # you can't see followers only or direct messages if you're not logged in - if user.is_anonymous: - privacy = [p for p in privacy if not p in ['followers', 'direct']] - - # filter to only privided privacy levels - queryset = queryset.filter(privacy__in=privacy) - - # only include statuses the user follows - if following_only: - queryset = queryset.exclude( - ~Q(# remove everythign except - Q(user__in=user.following.all()) | # user follwoing - Q(user=user) |# is self - Q(mention_users=user)# mentions user - ), - ) - # exclude followers-only statuses the user doesn't follow - elif 'followers' in privacy: - queryset = queryset.exclude( - ~Q(# user isn't following and it isn't their own status - Q(user__in=user.following.all()) | Q(user=user) - ), - privacy='followers' # and the status is followers only - ) - - # exclude direct messages not intended for the user - if 'direct' in privacy: - queryset = queryset.exclude( - ~Q( - Q(user=user) | Q(mention_users=user) - ), privacy='direct' - ) - - # filter for only local status - if local_only: - queryset = queryset.filter(user__local=True) - - # remove statuses that have boosts in the same queryset - try: - queryset = queryset.filter(~Q(boosters__in=queryset)) - except ValueError: - pass - - return queryset - - @require_GET def search(request): ''' that search bar up top ''' @@ -157,111 +90,6 @@ def search(request): return TemplateResponse(request, 'search_results.html', data) -@require_GET -def book_page(request, book_id): - ''' info about a book ''' - try: - page = int(request.GET.get('page', 1)) - except ValueError: - page = 1 - - try: - book = models.Book.objects.select_subclasses().get(id=book_id) - except models.Book.DoesNotExist: - return HttpResponseNotFound() - - if is_api_request(request): - return ActivitypubResponse(book.to_activity()) - - if isinstance(book, models.Work): - book = book.get_default_edition() - if not book: - return HttpResponseNotFound() - - work = book.parent_work - if not work: - return HttpResponseNotFound() - - reviews = models.Review.objects.filter( - book__in=work.editions.all(), - ) - # all reviews for the book - reviews = get_activity_feed( - request.user, - ['public', 'unlisted', 'followers', 'direct'], - queryset=reviews - ) - - # the reviews to show - paginated = Paginator(reviews.exclude( - Q(content__isnull=True) | Q(content='') - ), PAGE_LENGTH) - reviews_page = paginated.page(page) - - prev_page = next_page = None - if reviews_page.has_next(): - next_page = '/book/%d/?page=%d' % \ - (book_id, reviews_page.next_page_number()) - if reviews_page.has_previous(): - prev_page = '/book/%s/?page=%d' % \ - (book_id, reviews_page.previous_page_number()) - - user_tags = readthroughs = user_shelves = other_edition_shelves = [] - if request.user.is_authenticated: - user_tags = models.UserTag.objects.filter( - book=book, user=request.user - ).values_list('tag__identifier', flat=True) - - readthroughs = models.ReadThrough.objects.filter( - user=request.user, - book=book, - ).order_by('start_date') - - user_shelves = models.ShelfBook.objects.filter( - added_by=request.user, book=book - ) - - other_edition_shelves = models.ShelfBook.objects.filter( - ~Q(book=book), - added_by=request.user, - book__parent_work=book.parent_work, - ) - - data = { - 'title': book.title, - 'book': book, - 'reviews': reviews_page, - 'review_count': reviews.count(), - 'ratings': reviews.filter(Q(content__isnull=True) | Q(content='')), - 'rating': reviews.aggregate(Avg('rating'))['rating__avg'], - 'tags': models.UserTag.objects.filter(book=book), - 'user_tags': user_tags, - 'user_shelves': user_shelves, - 'other_edition_shelves': other_edition_shelves, - 'readthroughs': readthroughs, - 'path': '/book/%s' % book_id, - 'next': next_page, - 'prev': prev_page, - } - return TemplateResponse(request, 'book.html', data) - - -@login_required -@permission_required('bookwyrm.edit_book', raise_exception=True) -@require_GET -def edit_book_page(request, book_id): - ''' info about a book ''' - book = get_edition(book_id) - if not book.description: - book.description = book.parent_work.description - data = { - 'title': 'Edit Book', - 'book': book, - 'form': forms.EditionForm(instance=book) - } - return TemplateResponse(request, 'edit_book.html', data) - - @login_required @permission_required('bookwyrm.edit_book', raise_exception=True) @require_GET @@ -276,22 +104,6 @@ def edit_author_page(request, author_id): return TemplateResponse(request, 'edit_author.html', data) -@require_GET -def editions_page(request, book_id): - ''' list of editions of a book ''' - work = get_object_or_404(models.Work, id=book_id) - - if is_api_request(request): - return ActivitypubResponse(work.to_edition_list(**request.GET)) - - data = { - 'title': 'Editions of %s' % work.title, - 'editions': work.editions.order_by('-edition_rank').all(), - 'work': work, - } - return TemplateResponse(request, 'editions.html', data) - - @require_GET def author_page(request, author_id): ''' landing page for an author '''