From 8a3be920c6da7bdc416e1a96bc2a05382f819a01 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 14:27:11 -0800 Subject: [PATCH 01/14] Adds test for logged out view of group --- bookwyrm/tests/views/test_group.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py index 40f601f1..f0395490 100644 --- a/bookwyrm/tests/views/test_group.py +++ b/bookwyrm/tests/views/test_group.py @@ -1,6 +1,8 @@ """ test for app action functionality """ from unittest.mock import patch +from django.contrib.auth.models import AnonymousUser +from django.http import Http404 from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory @@ -43,6 +45,8 @@ class GroupViews(TestCase): self.membership = models.GroupMember.objects.create( group=self.testgroup, user=self.local_user ) + self.anonymous_user = AnonymousUser + self.anonymous_user.is_authenticated = False models.SiteSettings.objects.create() @@ -56,6 +60,17 @@ class GroupViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) + def test_group_get_anonymous(self, _): + """there are so many views, this just makes sure it LOADS""" + self.testgroup.privacy = "followers" + self.testgroup.save() + + view = views.Group.as_view() + request = self.factory.get("") + request.user = self.anonymous_user + with self.assertRaises(Http404): + view(request, group_id=self.testgroup.id) + def test_usergroups_get(self, _): """there are so many views, this just makes sure it LOADS""" view = views.UserGroups.as_view() From 0422421d6007ead8fd6945489d7abaa9eed46748 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 14:33:30 -0800 Subject: [PATCH 02/14] Fixes bug in logged out group view --- bookwyrm/models/base_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index f62678f7..f8d3b781 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -84,6 +84,7 @@ class BookWyrmModel(models.Model): # you can see groups of which you are a member if ( hasattr(self, "memberships") + and viewer.is_authenticated and self.memberships.filter(user=viewer).exists() ): return From f62cd5fd12f04d5d3ec7ee11e194fc699cd16b01 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 14:40:11 -0800 Subject: [PATCH 03/14] Makes embed key non-optional in urls --- bookwyrm/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 87c1e160..b9fe1f20 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -339,7 +339,7 @@ urlpatterns = [ re_path(r"^save-list/(?P\d+)/?$", views.save_list, name="list-save"), re_path(r"^unsave-list/(?P\d+)/?$", views.unsave_list, name="list-unsave"), re_path( - r"^list/(?P\d+)/embed/(?P[0-9a-f]+)?$", + r"^list/(?P\d+)/embed/(?P[0-9a-f]+)/?$", views.unsafe_embed_list, name="embed-list", ), From 638ea166be528d355b68819a6872250dcd69d1b1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 14:41:45 -0800 Subject: [PATCH 04/14] More trailing slashes in urls --- bookwyrm/urls.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index b9fe1f20..bd36f3d8 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -50,7 +50,7 @@ urlpatterns = [ re_path("^api/updates/stream/(?P[a-z]+)/?$", views.get_unread_status_count), # authentication re_path(r"^login/?$", views.Login.as_view(), name="login"), - re_path(r"^login/(?Pconfirmed)?$", views.Login.as_view(), name="login"), + re_path(r"^login/(?Pconfirmed)/?$", views.Login.as_view(), name="login"), re_path(r"^register/?$", views.Register.as_view()), re_path(r"confirm-email/?$", views.ConfirmEmail.as_view(), name="confirm-email"), re_path( @@ -112,12 +112,12 @@ urlpatterns = [ name="settings-federated-server", ), re_path( - r"^settings/federation/(?P\d+)/block?$", + r"^settings/federation/(?P\d+)/block/?$", views.block_server, name="settings-federated-server-block", ), re_path( - r"^settings/federation/(?P\d+)/unblock?$", + r"^settings/federation/(?P\d+)/unblock/?$", views.unblock_server, name="settings-federated-server-unblock", ), @@ -140,7 +140,7 @@ urlpatterns = [ name="settings-invite-requests", ), re_path( - r"^settings/requests/ignore?$", + r"^settings/requests/ignore/?$", views.ignore_invite_request, name="settings-invite-requests-ignore", ), @@ -229,7 +229,7 @@ urlpatterns = [ r"^direct-messages/?$", views.DirectMessage.as_view(), name="direct-messages" ), re_path( - rf"^direct-messages/(?P{regex.USERNAME})?$", + rf"^direct-messages/(?P{regex.USERNAME})/?$", views.DirectMessage.as_view(), name="direct-messages-user", ), @@ -356,7 +356,7 @@ urlpatterns = [ name="shelf", ), re_path(r"^create-shelf/?$", views.create_shelf, name="shelf-create"), - re_path(r"^delete-shelf/(?P\d+)?$", views.delete_shelf), + re_path(r"^delete-shelf/(?P\d+)/?$", views.delete_shelf), re_path(r"^shelve/?$", views.shelve), re_path(r"^unshelve/?$", views.unshelve), # goals @@ -423,7 +423,7 @@ urlpatterns = [ re_path(rf"{BOOK_PATH}/edit/?$", views.EditBook.as_view(), name="edit-book"), re_path(rf"{BOOK_PATH}/confirm/?$", views.ConfirmEditBook.as_view()), re_path(r"^create-book/?$", views.EditBook.as_view(), name="create-book"), - re_path(r"^create-book/confirm?$", views.ConfirmEditBook.as_view()), + re_path(r"^create-book/confirm/?$", views.ConfirmEditBook.as_view()), re_path(rf"{BOOK_PATH}/editions(.json)?/?$", views.Editions.as_view()), re_path( r"^upload-cover/(?P\d+)/?$", views.upload_cover, name="upload-cover" From 14601a0c3182bde8cc3420e3bc3e95046a369497 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 14:50:28 -0800 Subject: [PATCH 05/14] Don't error out on invalid login POST Thanks, log4j exploit scanners, for catching this one --- bookwyrm/views/landing/login.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bookwyrm/views/landing/login.py b/bookwyrm/views/landing/login.py index 5c25e30e..ccee6129 100644 --- a/bookwyrm/views/landing/login.py +++ b/bookwyrm/views/landing/login.py @@ -39,7 +39,8 @@ class Login(View): return redirect("/") login_form = forms.LoginForm(request.POST) - localname = login_form.data["localname"] + localname = login_form.data.get("localname") + if "@" in localname: # looks like an email address to me try: username = models.User.objects.get(email=localname).username @@ -47,7 +48,7 @@ class Login(View): username = localname else: username = f"{localname}@{DOMAIN}" - password = login_form.data["password"] + password = login_form.data.get("password") # perform authentication user = authenticate(request, username=username, password=password) From 3f8e309680964d0b5338814fb9d7ad561ba55f0b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:04:06 -0800 Subject: [PATCH 06/14] Adds test for json requests to all books view --- bookwyrm/tests/views/shelf/test_shelf.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index ab88de0a..b5f36df2 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -60,6 +60,18 @@ class ShelfViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) + def test_shelf_page_all_books_json(self, *_): + """there is no json view here""" + view = views.Shelf.as_view() + request = self.factory.get("") + request.user = self.local_user + with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api: + is_api.return_value = True + result = view(request, self.local_user.username) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + def test_shelf_page_all_books_anonymous(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Shelf.as_view() From 21e0f4234e1047bbed6c19bfc1f6e2a3be2893a0 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:04:25 -0800 Subject: [PATCH 07/14] Don't try to create a json view of the all books page It's a fake view, a liar --- bookwyrm/views/shelf/shelf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/shelf/shelf.py b/bookwyrm/views/shelf/shelf.py index f8cffe93..34914d97 100644 --- a/bookwyrm/views/shelf/shelf.py +++ b/bookwyrm/views/shelf/shelf.py @@ -52,7 +52,7 @@ class Shelf(View): ) shelf = FakeShelf("all", _("All books"), user, books, "public") - if is_api_request(request): + if is_api_request(request) and shelf_identifier: return ActivitypubResponse(shelf.to_activity(**request.GET)) reviews = models.Review.objects From a58d600030d14ffdfe20f155ac23a3875439ae51 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:22:02 -0800 Subject: [PATCH 08/14] Adds librarything line without isbn to test data --- bookwyrm/tests/data/librarything.tsv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/data/librarything.tsv b/bookwyrm/tests/data/librarything.tsv index 68bbe48e..cf81fe96 100644 --- a/bookwyrm/tests/data/librarything.tsv +++ b/bookwyrm/tests/data/librarything.tsv @@ -1,4 +1,4 @@ Book Id Title Sort Character Primary Author Primary Author Role Secondary Author Secondary Author Roles Publication Date Review Rating Comment Private Comment Summary Media Physical Description Weight Height Thickness Length Dimensions Page Count LCCN Acquired Date Started Date Read Barcode BCID Tags Collections Languages Original Languages LC Classification ISBN ISBNs Subjects Dewey Decimal Dewey Wording Other Call Number Copies Source Entry Date From Where OCLC Work id Lending Patron Lending Status Lending Start Lending End 5498194 Marelle 1 Cortazar, Julio Gallimard (1979), Poche 1979 chef d'oeuvre 4.5 Marelle by Julio Cortázar (1979) Broché 590 p.; 7.24 inches 1.28 pounds 7.24 inches 1.26 inches 4.96 inches 7.24 x 4.96 x 1.26 inches 590 [2007-04-16] [2007-05-08] roman, espagnol, expérimental, bohème, philosophie Your library French Spanish PQ7797 .C7145 [2070291340] 2070291340, 9782070291342 Cortâazar, Julio. Rayuela 863 Literature > Spanish And Portuguese > Spanish fiction 1 Amazon.fr [2006-08-09] 57814 5015319 Le grand incendie de Londres: Récit, avec incises et bifurcations, 1985-1987 (Fiction & Cie) 1 Roubaud, Jacques Seuil (1989), Unknown Binding 1989 5 Le grand incendie de Londres: Récit, avec incises et bifurcations, 1985-1987 (Fiction & Cie) by Jacques Roubaud (1989) Broché 411 p.; 7.72 inches 0.88 pounds 7.72 inches 1.02 inches 5.43 inches 7.72 x 5.43 x 1.02 inches 411 Your library English PQ2678 .O77 [2020104725] 2020104725, 9782020104722 Autobiographical fiction|Roubaud, Jacques > Fiction 813 American And Canadian > Fiction > Literature 1 Amazon.com [2006-07-25] 478910 -5015399 Le Maître et Marguerite 1 Boulgakov, Mikhaïl Pocket (1994), Poche 1994 Le Maître et Marguerite by Mikhaïl Boulgakov (1994) Broché 579 p.; 7.09 inches 0.66 pounds 7.09 inches 1.18 inches 4.33 inches 7.09 x 4.33 x 1.18 inches 579 Your library French PG3476 .B78 [2266062328] 2266062328, 9782266062329 Allegories|Bulgakov|Good and evil > Fiction|Humanities|Jerusalem > Fiction|Jesus Christ > Fiction|Literature|Mental illness > Fiction|Moscow (Russia) > Fiction|Novel|Pilate, Pontius, 1st cent. > Fiction|Political fiction|Russia > Fiction|Russian fiction|Russian publications (Form Entry)|Soviet Union > History > 1925-1953 > Fiction|literature 891.7342 1917-1945 > 1917-1991 (USSR) > Literature > Literature of other Indo-European languages > Other Languages > Russian > Russian Fiction 1 Amazon.fr [2006-07-25] 10151 +5015399 Le Maître et Marguerite 1 Boulgakov, Mikhaïl Pocket (1994), Poche 1994 Le Maître et Marguerite by Mikhaïl Boulgakov (1994) Broché 579 p.; 7.09 inches 0.66 pounds 7.09 inches 1.18 inches 4.33 inches 7.09 x 4.33 x 1.18 inches 579 Your library French PG3476 .B78 [2266062328] Allegories|Bulgakov|Good and evil > Fiction|Humanities|Jerusalem > Fiction|Jesus Christ > Fiction|Literature|Mental illness > Fiction|Moscow (Russia) > Fiction|Novel|Pilate, Pontius, 1st cent. > Fiction|Political fiction|Russia > Fiction|Russian fiction|Russian publications (Form Entry)|Soviet Union > History > 1925-1953 > Fiction|literature 891.7342 1917-1945 > 1917-1991 (USSR) > Literature > Literature of other Indo-European languages > Other Languages > Russian > Russian Fiction 1 Amazon.fr [2006-07-25] 10151 From 5b192d1b3df6974cb02730de33332077cbabae3d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:22:20 -0800 Subject: [PATCH 09/14] Fixes error when librarything csv is missing isbn --- bookwyrm/importers/librarything_import.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/importers/librarything_import.py b/bookwyrm/importers/librarything_import.py index 1b61a6f1..37730dee 100644 --- a/bookwyrm/importers/librarything_import.py +++ b/bookwyrm/importers/librarything_import.py @@ -14,7 +14,8 @@ class LibrarythingImporter(Importer): """use the dataclass to create the formatted row of data""" remove_brackets = lambda v: re.sub(r"\[|\]", "", v) if v else None normalized = {k: remove_brackets(entry.get(v)) for k, v in mappings.items()} - isbn_13 = normalized["isbn_13"].split(", ") + isbn_13 = normalized.get("isbn_13") + isbn_13 = isbn_13.split(", ") if isbn_13 else [] normalized["isbn_13"] = isbn_13[1] if len(isbn_13) > 0 else None return normalized From 1a30546b9981057a80977adcdb315fb022091d14 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:44:47 -0800 Subject: [PATCH 10/14] Adds test for dm view with partner --- bookwyrm/tests/views/test_feed.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 5c6a4dd3..3340e616 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -36,6 +36,13 @@ class FeedViews(TestCase): local=True, localname="mouse", ) + self.another_user = models.User.objects.create_user( + "rat@local.com", + "rat@rat.rat", + "password", + local=True, + localname="rat", + ) self.book = models.Edition.objects.create( parent_work=models.Work.objects.create(title="hi"), title="Example Edition", @@ -171,6 +178,17 @@ class FeedViews(TestCase): result.render() self.assertEqual(result.status_code, 200) + def test_direct_messages_page_user(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.DirectMessage.as_view() + request = self.factory.get("") + request.user = self.local_user + result = view(request, "rat") + self.assertIsInstance(result, TemplateResponse) + result.render() + self.assertEqual(result.status_code, 200) + self.assertEqual(result.context_data["partner"], self.another_user) + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") def test_get_suggested_book(self, *_): From 14a90e805a1cd656ee370b66057376a2defa77a4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:52:35 -0800 Subject: [PATCH 11/14] Test users with domains that contain dashes --- bookwyrm/tests/views/test_user.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 5fab9386..74c9dfc6 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -80,6 +80,29 @@ class UserViews(TestCase): self.assertIsInstance(result, ActivitypubResponse) self.assertEqual(result.status_code, 200) + def test_user_page_domain(self): + """when the user domain has dashes in it""" + with patch("bookwyrm.models.user.set_remote_server"): + self.remote_user = models.User.objects.create_user( + "nutria", + "", + "nutriaword", + local=False, + remote_id="https://ex--ample.co----m/users/nutria", + inbox="https://ex--ample.co----m/users/nutria/inbox", + outbox="https://ex--ample.co----m/users/nutria/outbox", + ) + + view = views.User.as_view() + request = self.factory.get("") + request.user = self.local_user + with patch("bookwyrm.views.user.is_api_request") as is_api: + is_api.return_value = False + result = view(request, "nutria@ex--ample.co----m") + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + def test_user_page_blocked(self): """there are so many views, this just makes sure it LOADS""" view = views.User.as_view() From a8ae427aebc44460205184ca20d0b4dffc5b07bf Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:53:26 -0800 Subject: [PATCH 12/14] Updates domain regex --- bookwyrm/utils/regex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/utils/regex.py b/bookwyrm/utils/regex.py index f0c44245..f9036cda 100644 --- a/bookwyrm/utils/regex.py +++ b/bookwyrm/utils/regex.py @@ -1,6 +1,6 @@ """ defining regexes for regularly used concepts """ -DOMAIN = r"[\w_\-\.]+\.[a-z]{2,}" +DOMAIN = r"[\w_\-\.]+\.[a-z\-]{2,}" LOCALNAME = r"@?[a-zA-Z_\-\.0-9]+" STRICT_LOCALNAME = r"@[a-zA-Z_\-\.0-9]+" USERNAME = rf"{LOCALNAME}(@{DOMAIN})?" From 6745cd73ccbd840ee77e81d05fd7e86bea070636 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 15:53:35 -0800 Subject: [PATCH 13/14] Deterministic ordering for OL import test --- bookwyrm/tests/importers/test_openlibrary_import.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/importers/test_openlibrary_import.py b/bookwyrm/tests/importers/test_openlibrary_import.py index d53f5596..6a25c191 100644 --- a/bookwyrm/tests/importers/test_openlibrary_import.py +++ b/bookwyrm/tests/importers/test_openlibrary_import.py @@ -48,7 +48,9 @@ class OpenLibraryImport(TestCase): self.local_user, self.csv, False, "public" ) - import_items = models.ImportItem.objects.filter(job=import_job).all() + import_items = ( + models.ImportItem.objects.filter(job=import_job).order_by("index").all() + ) self.assertEqual(len(import_items), 4) self.assertEqual(import_items[0].index, 0) self.assertEqual(import_items[0].data["Work Id"], "OL102749W") From 5b75f3d3101290963f6bfbd368d3bd6f1a3acfa3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 28 Dec 2021 16:02:48 -0800 Subject: [PATCH 14/14] Avoid clash with existing test data user --- bookwyrm/tests/views/test_feed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 3340e616..63264b80 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -37,11 +37,11 @@ class FeedViews(TestCase): localname="mouse", ) self.another_user = models.User.objects.create_user( - "rat@local.com", - "rat@rat.rat", + "nutria@local.com", + "nutria@nutria.nutria", "password", local=True, - localname="rat", + localname="nutria", ) self.book = models.Edition.objects.create( parent_work=models.Work.objects.create(title="hi"), @@ -183,7 +183,7 @@ class FeedViews(TestCase): view = views.DirectMessage.as_view() request = self.factory.get("") request.user = self.local_user - result = view(request, "rat") + result = view(request, "nutria") self.assertIsInstance(result, TemplateResponse) result.render() self.assertEqual(result.status_code, 200)