diff --git a/bookwyrm/tests/views/lists/test_curate.py b/bookwyrm/tests/views/lists/test_curate.py index 98a7fc016..9be8c2a15 100644 --- a/bookwyrm/tests/views/lists/test_curate.py +++ b/bookwyrm/tests/views/lists/test_curate.py @@ -1,4 +1,5 @@ """ test for app action functionality """ +import json from unittest.mock import patch from django.contrib.auth.models import AnonymousUser @@ -66,3 +67,63 @@ class ListViews(TestCase): request.user = self.anonymous_user result = view(request, self.list.id) self.assertEqual(result.status_code, 302) + + def test_curate_approve(self): + """approve a pending item""" + view = views.Curate.as_view() + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + pending = models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=False, + order=1, + ) + + request = self.factory.post( + "", + {"item": pending.id, "approved": "true"}, + ) + request.user = self.local_user + + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: + view(request, self.list.id) + + self.assertEqual(mock.call_count, 2) + activity = json.loads(mock.call_args[1]["args"][1]) + self.assertEqual(activity["type"], "Add") + self.assertEqual(activity["actor"], self.local_user.remote_id) + self.assertEqual(activity["target"], self.list.remote_id) + + pending.refresh_from_db() + self.assertEqual(self.list.books.count(), 1) + self.assertEqual(self.list.listitem_set.first(), pending) + self.assertTrue(pending.approved) + + def test_curate_reject(self): + """approve a pending item""" + view = views.Curate.as_view() + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + pending = models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=False, + order=1, + ) + + request = self.factory.post( + "", + { + "item": pending.id, + "approved": "false", + }, + ) + request.user = self.local_user + + view(request, self.list.id) + + self.assertFalse(self.list.books.exists()) + self.assertFalse(models.ListItem.objects.exists()) diff --git a/bookwyrm/tests/views/lists/test_list.py b/bookwyrm/tests/views/lists/test_list.py index 07cdbb701..489681547 100644 --- a/bookwyrm/tests/views/lists/test_list.py +++ b/bookwyrm/tests/views/lists/test_list.py @@ -3,6 +3,7 @@ import json from unittest.mock import patch from django.contrib.auth.models import AnonymousUser +from django.core.exceptions import PermissionDenied from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory @@ -13,6 +14,7 @@ from bookwyrm.tests.validate_html import validate_html # pylint: disable=unused-argument +# pylint: disable=too-many-public-methods class ListViews(TestCase): """list view""" @@ -235,3 +237,472 @@ class ListViews(TestCase): self.assertEqual(self.list.description, "wow") self.assertEqual(self.list.privacy, "direct") self.assertEqual(self.list.curation, "curated") + + def test_delete_list(self): + """delete an entire list""" + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=True, + order=1, + ) + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book_two, + approved=False, + order=2, + ) + request = self.factory.post("") + request.user = self.local_user + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay") as redis_mock: + views.delete_list(request, self.list.id) + self.assertTrue(redis_mock.called) + activity = json.loads(mock.call_args[1]["args"][1]) + self.assertEqual(activity["type"], "Delete") + self.assertEqual(activity["actor"], self.local_user.remote_id) + self.assertEqual(activity["object"]["id"], self.list.remote_id) + self.assertEqual(activity["object"]["type"], "BookList") + + self.assertEqual(mock.call_count, 1) + self.assertFalse(models.List.objects.exists()) + self.assertFalse(models.ListItem.objects.exists()) + + def test_delete_list_permission_denied(self): + """delete an entire list""" + request = self.factory.post("") + request.user = self.rat + with self.assertRaises(PermissionDenied): + views.delete_list(request, self.list.id) + + def test_add_book(self): + """put a book on a list""" + request = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request.user = self.local_user + + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: + views.add_book(request) + self.assertEqual(mock.call_count, 1) + activity = json.loads(mock.call_args[1]["args"][1]) + self.assertEqual(activity["type"], "Add") + self.assertEqual(activity["actor"], self.local_user.remote_id) + self.assertEqual(activity["target"], self.list.remote_id) + + item = self.list.listitem_set.get() + self.assertEqual(item.book, self.book) + self.assertEqual(item.user, self.local_user) + self.assertTrue(item.approved) + + def test_add_two_books(self): + """ + Putting two books on the list. The first should have an order value of + 1 and the second should have an order value of 2. + """ + request_one = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_one.user = self.local_user + + request_two = self.factory.post( + "", + { + "book": self.book_two.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_two.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + views.add_book(request_one) + views.add_book(request_two) + + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book) + self.assertEqual(items[1].book, self.book_two) + self.assertEqual(items[0].order, 1) + self.assertEqual(items[1].order, 2) + + def test_add_three_books_and_remove_second(self): + """ + Put three books on a list and then remove the one in the middle. The + ordering of the list should adjust to not have a gap. + """ + request_one = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_one.user = self.local_user + + request_two = self.factory.post( + "", + { + "book": self.book_two.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_two.user = self.local_user + + request_three = self.factory.post( + "", + { + "book": self.book_three.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_three.user = self.local_user + + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + views.add_book(request_one) + views.add_book(request_two) + views.add_book(request_three) + + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book) + self.assertEqual(items[1].book, self.book_two) + self.assertEqual(items[2].book, self.book_three) + self.assertEqual(items[0].order, 1) + self.assertEqual(items[1].order, 2) + self.assertEqual(items[2].order, 3) + + remove_request = self.factory.post("", {"item": items[1].id}) + remove_request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + views.remove_book(remove_request, self.list.id) + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book) + self.assertEqual(items[1].book, self.book_three) + self.assertEqual(items[0].order, 1) + self.assertEqual(items[1].order, 2) + + def test_adding_book_with_a_pending_book(self): + """ + When a list contains any pending books, the pending books should have + be at the end of the list by order. If a book is added while a book is + pending, its order should precede the pending books. + """ + request = self.factory.post( + "", + { + "book": self.book_three.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=True, + order=1, + ) + models.ListItem.objects.create( + book_list=self.list, + user=self.rat, + book=self.book_two, + approved=False, + order=2, + ) + views.add_book(request) + + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book) + self.assertEqual(items[0].order, 1) + self.assertTrue(items[0].approved) + + self.assertEqual(items[1].book, self.book_three) + self.assertEqual(items[1].order, 2) + self.assertTrue(items[1].approved) + + self.assertEqual(items[2].book, self.book_two) + self.assertEqual(items[2].order, 3) + self.assertFalse(items[2].approved) + + def test_approving_one_pending_book_from_multiple(self): + """ + When a list contains any pending books, the pending books should have + be at the end of the list by order. If a pending book is approved, then + its order should be at the end of the approved books and before the + remaining pending books. + """ + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=True, + order=1, + ) + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book_two, + approved=True, + order=2, + ) + models.ListItem.objects.create( + book_list=self.list, + user=self.rat, + book=self.book_three, + approved=False, + order=3, + ) + to_be_approved = models.ListItem.objects.create( + book_list=self.list, + user=self.rat, + book=self.book_four, + approved=False, + order=4, + ) + + view = views.Curate.as_view() + request = self.factory.post( + "", + { + "item": to_be_approved.id, + "approved": "true", + }, + ) + request.user = self.local_user + + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + view(request, self.list.id) + + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book) + self.assertEqual(items[0].order, 1) + self.assertTrue(items[0].approved) + + self.assertEqual(items[1].book, self.book_two) + self.assertEqual(items[1].order, 2) + self.assertTrue(items[1].approved) + + self.assertEqual(items[2].book, self.book_four) + self.assertEqual(items[2].order, 3) + self.assertTrue(items[2].approved) + + self.assertEqual(items[3].book, self.book_three) + self.assertEqual(items[3].order, 4) + self.assertFalse(items[3].approved) + + def test_add_three_books_and_move_last_to_first(self): + """ + Put three books on the list and move the last book to the first + position. + """ + request_one = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_one.user = self.local_user + + request_two = self.factory.post( + "", + { + "book": self.book_two.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_two.user = self.local_user + + request_three = self.factory.post( + "", + { + "book": self.book_three.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request_three.user = self.local_user + + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + views.add_book(request_one) + views.add_book(request_two) + views.add_book(request_three) + + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book) + self.assertEqual(items[1].book, self.book_two) + self.assertEqual(items[2].book, self.book_three) + self.assertEqual(items[0].order, 1) + self.assertEqual(items[1].order, 2) + self.assertEqual(items[2].order, 3) + + set_position_request = self.factory.post("", {"position": 1}) + set_position_request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + views.set_book_position(set_position_request, items[2].id) + items = self.list.listitem_set.order_by("order").all() + self.assertEqual(items[0].book, self.book_three) + self.assertEqual(items[1].book, self.book) + self.assertEqual(items[2].book, self.book_two) + self.assertEqual(items[0].order, 1) + self.assertEqual(items[1].order, 2) + self.assertEqual(items[2].order, 3) + + def test_add_book_outsider(self): + """put a book on a list""" + self.list.curation = "open" + self.list.save(broadcast=False) + request = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request.user = self.rat + + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: + views.add_book(request) + self.assertEqual(mock.call_count, 1) + activity = json.loads(mock.call_args[1]["args"][1]) + self.assertEqual(activity["type"], "Add") + self.assertEqual(activity["actor"], self.rat.remote_id) + self.assertEqual(activity["target"], self.list.remote_id) + + item = self.list.listitem_set.get() + self.assertEqual(item.book, self.book) + self.assertEqual(item.user, self.rat) + self.assertTrue(item.approved) + + def test_add_book_pending(self): + """put a book on a list awaiting approval""" + self.list.curation = "curated" + self.list.save(broadcast=False) + request = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request.user = self.rat + + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: + views.add_book(request) + + self.assertEqual(mock.call_count, 1) + activity = json.loads(mock.call_args[1]["args"][1]) + + self.assertEqual(activity["type"], "Add") + self.assertEqual(activity["actor"], self.rat.remote_id) + self.assertEqual(activity["target"], self.list.remote_id) + + item = self.list.listitem_set.get() + self.assertEqual(activity["object"]["id"], item.remote_id) + + self.assertEqual(item.book, self.book) + self.assertEqual(item.user, self.rat) + self.assertFalse(item.approved) + + def test_add_book_self_curated(self): + """put a book on a list automatically approved""" + self.list.curation = "curated" + self.list.save(broadcast=False) + request = self.factory.post( + "", + { + "book": self.book.id, + "book_list": self.list.id, + "user": self.local_user, + }, + ) + request.user = self.local_user + + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock: + views.add_book(request) + self.assertEqual(mock.call_count, 1) + activity = json.loads(mock.call_args[1]["args"][1]) + self.assertEqual(activity["type"], "Add") + self.assertEqual(activity["actor"], self.local_user.remote_id) + self.assertEqual(activity["target"], self.list.remote_id) + + item = self.list.listitem_set.get() + self.assertEqual(item.book, self.book) + self.assertEqual(item.user, self.local_user) + self.assertTrue(item.approved) + + def test_remove_book(self): + """take an item off a list""" + + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + item = models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + order=1, + ) + self.assertTrue(self.list.listitem_set.exists()) + + request = self.factory.post("", {"item": item.id}) + request.user = self.local_user + + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + views.remove_book(request, self.list.id) + self.assertFalse(self.list.listitem_set.exists()) + + def test_remove_book_unauthorized(self): + """take an item off a list""" + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + item = models.ListItem.objects.create( + book_list=self.list, user=self.local_user, book=self.book, order=1 + ) + self.assertTrue(self.list.listitem_set.exists()) + request = self.factory.post("", {"item": item.id}) + request.user = self.rat + + with self.assertRaises(PermissionDenied): + views.remove_book(request, self.list.id) + self.assertTrue(self.list.listitem_set.exists()) + + def test_save_unsave_list(self): + """bookmark a list""" + self.assertFalse(self.local_user.saved_lists.exists()) + request = self.factory.post("") + request.user = self.local_user + views.save_list(request, self.list.id) + self.local_user.refresh_from_db() + self.assertEqual(self.local_user.saved_lists.first(), self.list) + + views.unsave_list(request, self.list.id) + self.local_user.refresh_from_db() + self.assertFalse(self.local_user.saved_lists.exists()) diff --git a/bookwyrm/tests/views/lists/test_list_actions.py b/bookwyrm/tests/views/lists/test_list_actions.py deleted file mode 100644 index ece305e85..000000000 --- a/bookwyrm/tests/views/lists/test_list_actions.py +++ /dev/null @@ -1,586 +0,0 @@ -""" test for app action functionality """ -import json -from unittest.mock import patch - -from django.contrib.auth.models import AnonymousUser -from django.core.exceptions import PermissionDenied -from django.test import TestCase -from django.test.client import RequestFactory - -from bookwyrm import models, views - -# pylint: disable=unused-argument -class ListActionViews(TestCase): - """tag views""" - - def setUp(self): - """we need basic test data and mocks""" - self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): - 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.rat = models.User.objects.create_user( - "rat@local.com", - "rat@rat.com", - "ratword", - local=True, - localname="rat", - remote_id="https://example.com/users/rat", - ) - - work = models.Work.objects.create(title="Work") - self.book = models.Edition.objects.create( - title="Example Edition", - remote_id="https://example.com/book/1", - parent_work=work, - ) - work_two = models.Work.objects.create(title="Labori") - self.book_two = models.Edition.objects.create( - title="Example Edition 2", - remote_id="https://example.com/book/2", - parent_work=work_two, - ) - work_three = models.Work.objects.create(title="Trabajar") - self.book_three = models.Edition.objects.create( - title="Example Edition 3", - remote_id="https://example.com/book/3", - parent_work=work_three, - ) - work_four = models.Work.objects.create(title="Travailler") - self.book_four = models.Edition.objects.create( - title="Example Edition 4", - remote_id="https://example.com/book/4", - parent_work=work_four, - ) - - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.list = models.List.objects.create( - name="Test List", user=self.local_user - ) - self.anonymous_user = AnonymousUser - self.anonymous_user.is_authenticated = False - models.SiteSettings.objects.create() - - def test_delete_list(self): - """delete an entire list""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - approved=True, - order=1, - ) - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book_two, - approved=False, - order=2, - ) - request = self.factory.post("") - request.user = self.local_user - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay") as redis_mock: - views.delete_list(request, self.list.id) - self.assertTrue(redis_mock.called) - activity = json.loads(mock.call_args[1]["args"][1]) - self.assertEqual(activity["type"], "Delete") - self.assertEqual(activity["actor"], self.local_user.remote_id) - self.assertEqual(activity["object"]["id"], self.list.remote_id) - self.assertEqual(activity["object"]["type"], "BookList") - - self.assertEqual(mock.call_count, 1) - self.assertFalse(models.List.objects.exists()) - self.assertFalse(models.ListItem.objects.exists()) - - def test_delete_list_permission_denied(self): - """delete an entire list""" - request = self.factory.post("") - request.user = self.rat - with self.assertRaises(PermissionDenied): - views.delete_list(request, self.list.id) - - def test_curate_approve(self): - """approve a pending item""" - view = views.Curate.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - pending = models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - approved=False, - order=1, - ) - - request = self.factory.post( - "", - {"item": pending.id, "approved": "true"}, - ) - request.user = self.local_user - - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: - view(request, self.list.id) - - self.assertEqual(mock.call_count, 2) - activity = json.loads(mock.call_args[1]["args"][1]) - self.assertEqual(activity["type"], "Add") - self.assertEqual(activity["actor"], self.local_user.remote_id) - self.assertEqual(activity["target"], self.list.remote_id) - - pending.refresh_from_db() - self.assertEqual(self.list.books.count(), 1) - self.assertEqual(self.list.listitem_set.first(), pending) - self.assertTrue(pending.approved) - - def test_curate_reject(self): - """approve a pending item""" - view = views.Curate.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - pending = models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - approved=False, - order=1, - ) - - request = self.factory.post( - "", - { - "item": pending.id, - "approved": "false", - }, - ) - request.user = self.local_user - - view(request, self.list.id) - - self.assertFalse(self.list.books.exists()) - self.assertFalse(models.ListItem.objects.exists()) - - def test_add_book(self): - """put a book on a list""" - request = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request.user = self.local_user - - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: - views.add_book(request) - self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[1]["args"][1]) - self.assertEqual(activity["type"], "Add") - self.assertEqual(activity["actor"], self.local_user.remote_id) - self.assertEqual(activity["target"], self.list.remote_id) - - item = self.list.listitem_set.get() - self.assertEqual(item.book, self.book) - self.assertEqual(item.user, self.local_user) - self.assertTrue(item.approved) - - def test_add_two_books(self): - """ - Putting two books on the list. The first should have an order value of - 1 and the second should have an order value of 2. - """ - request_one = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request_one.user = self.local_user - - request_two = self.factory.post( - "", - { - "book": self.book_two.id, - "list": self.list.id, - }, - ) - request_two.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - views.add_book(request_one) - views.add_book(request_two) - - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book) - self.assertEqual(items[1].book, self.book_two) - self.assertEqual(items[0].order, 1) - self.assertEqual(items[1].order, 2) - - def test_add_three_books_and_remove_second(self): - """ - Put three books on a list and then remove the one in the middle. The - ordering of the list should adjust to not have a gap. - """ - request_one = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request_one.user = self.local_user - - request_two = self.factory.post( - "", - { - "book": self.book_two.id, - "list": self.list.id, - }, - ) - request_two.user = self.local_user - - request_three = self.factory.post( - "", - { - "book": self.book_three.id, - "list": self.list.id, - }, - ) - request_three.user = self.local_user - - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - views.add_book(request_one) - views.add_book(request_two) - views.add_book(request_three) - - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book) - self.assertEqual(items[1].book, self.book_two) - self.assertEqual(items[2].book, self.book_three) - self.assertEqual(items[0].order, 1) - self.assertEqual(items[1].order, 2) - self.assertEqual(items[2].order, 3) - - remove_request = self.factory.post("", {"item": items[1].id}) - remove_request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - views.remove_book(remove_request, self.list.id) - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book) - self.assertEqual(items[1].book, self.book_three) - self.assertEqual(items[0].order, 1) - self.assertEqual(items[1].order, 2) - - def test_adding_book_with_a_pending_book(self): - """ - When a list contains any pending books, the pending books should have - be at the end of the list by order. If a book is added while a book is - pending, its order should precede the pending books. - """ - request = self.factory.post( - "", - { - "book": self.book_three.id, - "list": self.list.id, - }, - ) - request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - approved=True, - order=1, - ) - models.ListItem.objects.create( - book_list=self.list, - user=self.rat, - book=self.book_two, - approved=False, - order=2, - ) - views.add_book(request) - - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book) - self.assertEqual(items[0].order, 1) - self.assertTrue(items[0].approved) - - self.assertEqual(items[1].book, self.book_three) - self.assertEqual(items[1].order, 2) - self.assertTrue(items[1].approved) - - self.assertEqual(items[2].book, self.book_two) - self.assertEqual(items[2].order, 3) - self.assertFalse(items[2].approved) - - def test_approving_one_pending_book_from_multiple(self): - """ - When a list contains any pending books, the pending books should have - be at the end of the list by order. If a pending book is approved, then - its order should be at the end of the approved books and before the - remaining pending books. - """ - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - approved=True, - order=1, - ) - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book_two, - approved=True, - order=2, - ) - models.ListItem.objects.create( - book_list=self.list, - user=self.rat, - book=self.book_three, - approved=False, - order=3, - ) - to_be_approved = models.ListItem.objects.create( - book_list=self.list, - user=self.rat, - book=self.book_four, - approved=False, - order=4, - ) - - view = views.Curate.as_view() - request = self.factory.post( - "", - { - "item": to_be_approved.id, - "approved": "true", - }, - ) - request.user = self.local_user - - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - view(request, self.list.id) - - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book) - self.assertEqual(items[0].order, 1) - self.assertTrue(items[0].approved) - - self.assertEqual(items[1].book, self.book_two) - self.assertEqual(items[1].order, 2) - self.assertTrue(items[1].approved) - - self.assertEqual(items[2].book, self.book_four) - self.assertEqual(items[2].order, 3) - self.assertTrue(items[2].approved) - - self.assertEqual(items[3].book, self.book_three) - self.assertEqual(items[3].order, 4) - self.assertFalse(items[3].approved) - - def test_add_three_books_and_move_last_to_first(self): - """ - Put three books on the list and move the last book to the first - position. - """ - request_one = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request_one.user = self.local_user - - request_two = self.factory.post( - "", - { - "book": self.book_two.id, - "list": self.list.id, - }, - ) - request_two.user = self.local_user - - request_three = self.factory.post( - "", - { - "book": self.book_three.id, - "list": self.list.id, - }, - ) - request_three.user = self.local_user - - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - views.add_book(request_one) - views.add_book(request_two) - views.add_book(request_three) - - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book) - self.assertEqual(items[1].book, self.book_two) - self.assertEqual(items[2].book, self.book_three) - self.assertEqual(items[0].order, 1) - self.assertEqual(items[1].order, 2) - self.assertEqual(items[2].order, 3) - - set_position_request = self.factory.post("", {"position": 1}) - set_position_request.user = self.local_user - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - views.set_book_position(set_position_request, items[2].id) - items = self.list.listitem_set.order_by("order").all() - self.assertEqual(items[0].book, self.book_three) - self.assertEqual(items[1].book, self.book) - self.assertEqual(items[2].book, self.book_two) - self.assertEqual(items[0].order, 1) - self.assertEqual(items[1].order, 2) - self.assertEqual(items[2].order, 3) - - def test_add_book_outsider(self): - """put a book on a list""" - self.list.curation = "open" - self.list.save(broadcast=False) - request = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request.user = self.rat - - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: - views.add_book(request) - self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[1]["args"][1]) - self.assertEqual(activity["type"], "Add") - self.assertEqual(activity["actor"], self.rat.remote_id) - self.assertEqual(activity["target"], self.list.remote_id) - - item = self.list.listitem_set.get() - self.assertEqual(item.book, self.book) - self.assertEqual(item.user, self.rat) - self.assertTrue(item.approved) - - def test_add_book_pending(self): - """put a book on a list awaiting approval""" - self.list.curation = "curated" - self.list.save(broadcast=False) - request = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request.user = self.rat - - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: - views.add_book(request) - - self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[1]["args"][1]) - - self.assertEqual(activity["type"], "Add") - self.assertEqual(activity["actor"], self.rat.remote_id) - self.assertEqual(activity["target"], self.list.remote_id) - - item = self.list.listitem_set.get() - self.assertEqual(activity["object"]["id"], item.remote_id) - - self.assertEqual(item.book, self.book) - self.assertEqual(item.user, self.rat) - self.assertFalse(item.approved) - - def test_add_book_self_curated(self): - """put a book on a list automatically approved""" - self.list.curation = "curated" - self.list.save(broadcast=False) - request = self.factory.post( - "", - { - "book": self.book.id, - "list": self.list.id, - }, - ) - request.user = self.local_user - - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: - views.add_book(request) - self.assertEqual(mock.call_count, 1) - activity = json.loads(mock.call_args[1]["args"][1]) - self.assertEqual(activity["type"], "Add") - self.assertEqual(activity["actor"], self.local_user.remote_id) - self.assertEqual(activity["target"], self.list.remote_id) - - item = self.list.listitem_set.get() - self.assertEqual(item.book, self.book) - self.assertEqual(item.user, self.local_user) - self.assertTrue(item.approved) - - def test_remove_book(self): - """take an item off a list""" - - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - item = models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - order=1, - ) - self.assertTrue(self.list.listitem_set.exists()) - - request = self.factory.post("", {"item": item.id}) - request.user = self.local_user - - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - views.remove_book(request, self.list.id) - self.assertFalse(self.list.listitem_set.exists()) - - def test_remove_book_unauthorized(self): - """take an item off a list""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - item = models.ListItem.objects.create( - book_list=self.list, user=self.local_user, book=self.book, order=1 - ) - self.assertTrue(self.list.listitem_set.exists()) - request = self.factory.post("", {"item": item.id}) - request.user = self.rat - - with self.assertRaises(PermissionDenied): - views.remove_book(request, self.list.id) - self.assertTrue(self.list.listitem_set.exists()) - - def test_save_unsave_list(self): - """bookmark a list""" - self.assertFalse(self.local_user.saved_lists.exists()) - request = self.factory.post("") - request.user = self.local_user - views.save_list(request, self.list.id) - self.local_user.refresh_from_db() - self.assertEqual(self.local_user.saved_lists.first(), self.list) - - views.unsave_list(request, self.list.id) - self.local_user.refresh_from_db() - self.assertFalse(self.local_user.saved_lists.exists())