From c7daf27baf06b24c9f4104b3114645419c917598 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 22 Apr 2021 09:06:26 -0700 Subject: [PATCH 1/6] Adds migration for last edited by field --- .../migrations/0069_auto_20210422_1604.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 bookwyrm/migrations/0069_auto_20210422_1604.py diff --git a/bookwyrm/migrations/0069_auto_20210422_1604.py b/bookwyrm/migrations/0069_auto_20210422_1604.py new file mode 100644 index 000000000..6591e7b92 --- /dev/null +++ b/bookwyrm/migrations/0069_auto_20210422_1604.py @@ -0,0 +1,34 @@ +# Generated by Django 3.1.8 on 2021-04-22 16:04 + +import bookwyrm.models.fields +from django.conf import settings +from django.db import migrations +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0068_ordering_for_list_items"), + ] + + operations = [ + migrations.AlterField( + model_name="author", + name="last_edited_by", + field=bookwyrm.models.fields.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="book", + name="last_edited_by", + field=bookwyrm.models.fields.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to=settings.AUTH_USER_MODEL, + ), + ), + ] From e9dc63e296a926e9e510b780eb9742127898ca33 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 22 Apr 2021 09:25:12 -0700 Subject: [PATCH 2/6] Only remove objects that are known --- bookwyrm/activitypub/verbs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/activitypub/verbs.py b/bookwyrm/activitypub/verbs.py index c2cbfea31..090beea5f 100644 --- a/bookwyrm/activitypub/verbs.py +++ b/bookwyrm/activitypub/verbs.py @@ -176,7 +176,8 @@ class Remove(Add): def action(self): """ find and remove the activity object """ obj = self.object.to_model(save=False, allow_create=False) - obj.delete() + if obj: + obj.delete() @dataclass(init=False) From cfa424ca59d0d52c832ad4b0011bfda1df07741a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 22 Apr 2021 09:37:24 -0700 Subject: [PATCH 3/6] Fixes nondeterministic test outcome --- bookwyrm/tests/models/test_activitypub_mixin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index 0d1acd978..e172ede96 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -155,8 +155,8 @@ class ActivitypubMixins(TestCase): recipients = ActivitypubMixin.get_recipients(mock_self) self.assertEqual(len(recipients), 2) - self.assertEqual(recipients[0], another_remote_user.inbox) - self.assertEqual(recipients[1], self.remote_user.inbox) + self.assertTrue(another_remote_user.inbox in recipients) + self.assertTrue(self.remote_user.inbox in recipients) def test_get_recipients_direct(self, _): """ determines the recipients for a user's object broadcast """ From a797b68558a9a8245a17a22ac54dba93ad6bd470 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 22 Apr 2021 10:22:37 -0700 Subject: [PATCH 4/6] Adds test that replicates follower deletion bug --- .../tests/views/inbox/test_inbox_update.py | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index fbd377388..5681ec882 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -80,14 +80,22 @@ class InboxUpdate(TestCase): def test_update_user(self): """ update an existing user """ - # we only do this with remote users - self.local_user.local = False - self.local_user.save() + models.UserFollows.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + models.UserFollows.objects.create( + user_subject=self.remote_user, + user_object=self.local_user, + ) + self.assertTrue(self.remote_user in self.local_user.followers.all()) + self.assertTrue(self.local_user in self.remote_user.followers.all()) - datafile = pathlib.Path(__file__).parent.joinpath("../../data/ap_user.json") + datafile = pathlib.Path(__file__).parent.joinpath("../../data/ap_user_rat.json") userdata = json.loads(datafile.read_bytes()) del userdata["icon"] - self.assertIsNone(self.local_user.name) + self.assertIsNone(self.remote_user.name) + self.assertFalse(self.remote_user.discoverable) views.inbox.activity_task( { "type": "Update", @@ -98,12 +106,15 @@ class InboxUpdate(TestCase): "object": userdata, } ) - user = models.User.objects.get(id=self.local_user.id) - self.assertEqual(user.name, "MOUSE?? MOUSE!!") - self.assertEqual(user.username, "mouse@example.com") - self.assertEqual(user.localname, "mouse") + user = models.User.objects.get(id=self.remote_user.id) + self.assertEqual(user.name, "RAT???") + self.assertEqual(user.username, "rat@example.com") self.assertTrue(user.discoverable) + # make sure relationships aren't disrupted + self.assertTrue(self.remote_user in self.local_user.followers.all()) + self.assertTrue(self.local_user in self.remote_user.followers.all()) + def test_update_edition(self): """ update an existing edition """ datafile = pathlib.Path(__file__).parent.joinpath("../../data/bw_edition.json") From 3ed822b9ea4339d8ab096bf6bad02d753d09878a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 22 Apr 2021 10:28:10 -0700 Subject: [PATCH 5/6] Don't erase follows on update --- bookwyrm/models/fields.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 2aefae51f..336ee4a1c 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -275,9 +275,12 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField): return [i.remote_id for i in value.all()] def field_from_activity(self, value): - items = [] if value is None or value is MISSING: - return [] + return None + if not isinstance(value, list): + # TODO + return None + items = [] for remote_id in value: try: validate_remote_id(remote_id) From c4555852625e505fc14a817e403abb42a2e750c4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 22 Apr 2021 10:30:00 -0700 Subject: [PATCH 6/6] Adds missing data file --- bookwyrm/models/fields.py | 2 +- bookwyrm/tests/data/ap_user_rat.json | 39 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/tests/data/ap_user_rat.json diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 336ee4a1c..a1b2035b1 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -278,7 +278,7 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField): if value is None or value is MISSING: return None if not isinstance(value, list): - # TODO + # If this is a link, we currently aren't doing anything with it return None items = [] for remote_id in value: diff --git a/bookwyrm/tests/data/ap_user_rat.json b/bookwyrm/tests/data/ap_user_rat.json new file mode 100644 index 000000000..0e36f1c62 --- /dev/null +++ b/bookwyrm/tests/data/ap_user_rat.json @@ -0,0 +1,39 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "https://example.com/users/rat", + "type": "Person", + "preferredUsername": "rat", + "name": "RAT???", + "inbox": "https://example.com/users/rat/inbox", + "outbox": "https://example.com/users/rat/outbox", + "followers": "https://example.com/users/rat/followers", + "following": "https://example.com/users/rat/following", + "summary": "", + "publicKey": { + "id": "https://example.com/users/rat/#main-key", + "owner": "https://example.com/users/rat", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6QisDrjOQvkRo/MqNmSYPwqtt\nCxg/8rCW+9jKbFUKvqjTeKVotEE85122v/DCvobCCdfQuYIFdVMk+dB1xJ0iPGPg\nyU79QHY22NdV9mFKA2qtXVVxb5cxpA4PlwOHM6PM/k8B+H09OUrop2aPUAYwy+vg\n+MXyz8bAXrIS1kq6fQIDAQAB\n-----END PUBLIC KEY-----" + }, + "endpoints": { + "sharedInbox": "https://example.com/inbox" + }, + "bookwyrmUser": true, + "manuallyApprovesFollowers": false, + "discoverable": true, + "devices": "https://friend.camp/users/tripofmice/collections/devices", + "tag": [], + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://example.com/images/avatars/AL-2-crop-50.png" + } +}