From 54cef421e291295cac79062ceec53e145b6e397e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 28 Nov 2021 07:57:27 -0800 Subject: [PATCH 1/5] Fixes checking if image fields are already set --- bookwyrm/models/fields.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 361079906..a28ad0ea2 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -398,7 +398,11 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): if formatted is None or formatted is MISSING: return False - if not overwrite and hasattr(instance, self.name): + if ( + not overwrite + and hasattr(instance, self.name) + and getattr(instance, self.name) + ): return False getattr(instance, self.name).save(*formatted, save=save) From 7b89014e7baa35cf600559f18cf1588b77d8c44d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 28 Nov 2021 08:24:00 -0800 Subject: [PATCH 2/5] Updates image fields tests --- bookwyrm/tests/models/test_fields.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 74f4c48bd..6499e96cb 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -215,7 +215,7 @@ class ModelFields(TestCase): "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) public = "https://www.w3.org/ns/activitystreams#Public" - followers = "%s/followers" % user.remote_id + followers = f"{user.remote_id}/followers" instance = fields.PrivacyField() instance.name = "privacy_field" @@ -409,11 +409,10 @@ class ModelFields(TestCase): """loadin' a list of items from Links""" # TODO - @responses.activate @patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast") @patch("bookwyrm.suggested_users.remove_user_task.delay") - def test_image_field(self, *_): - """storing images""" + def test_image_field_to_activity(self, *_): + """serialize an image field to activitypub""" user = User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -437,10 +436,22 @@ class ModelFields(TestCase): self.assertEqual(output.name, "") self.assertEqual(output.type, "Document") + @responses.activate + def test_image_field_from_activity(self, *_): + """load an image from activitypub""" + image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + image = Image.open(image_file) + output = BytesIO() + image.save(output, format=image.format) + + instance = fields.ImageField() + responses.add( responses.GET, "http://www.example.com/image.jpg", - body=user.avatar.file.read(), + body=image.tobytes(), status=200, ) loaded_image = instance.field_from_activity("http://www.example.com/image.jpg") From a7ee8fea247935556a1f21705c1bc485d9cf4682 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 28 Nov 2021 08:49:54 -0800 Subject: [PATCH 3/5] Adds test for setting model image field --- bookwyrm/tests/models/test_fields.py | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 6499e96cb..278272d87 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -19,7 +19,7 @@ from django.utils import timezone from bookwyrm import activitypub from bookwyrm.activitypub.base_activity import ActivityObject -from bookwyrm.models import fields, User, Status +from bookwyrm.models import fields, User, Status, Edition from bookwyrm.models.base_model import BookWyrmModel from bookwyrm.models.activitypub_mixin import ActivitypubMixin from bookwyrm.settings import DOMAIN @@ -458,6 +458,33 @@ class ModelFields(TestCase): self.assertIsInstance(loaded_image, list) self.assertIsInstance(loaded_image[1], ContentFile) + @responses.activate + def test_image_field_set_field_from_activity(self, *_): + """update a model instance from an activitypub object""" + image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + image = Image.open(image_file) + output = BytesIO() + image.save(output, format=image.format) + + instance = fields.ImageField(activitypub_field="cover", name="cover") + + responses.add( + responses.GET, + "http://www.example.com/image.jpg", + body=image.tobytes(), + status=200, + ) + book = Edition.objects.create(title="hello") + + MockActivity = namedtuple("MockActivity", ("cover")) + mock_activity = MockActivity("http://www.example.com/image.jpg") + + instance.set_field_from_activity(book, mock_activity) + self.assertIsNotNone(book.cover.name) + self.assertEqual(book.cover.size, 43200) + def test_datetime_field(self, *_): """this one is pretty simple, it just has to use isoformat""" instance = fields.DateTimeField() From 3a7f070a798760301cc6c50f6e48338e29094bf7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 28 Nov 2021 08:50:29 -0800 Subject: [PATCH 4/5] Typo fix --- bookwyrm/models/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index a28ad0ea2..7d14f88f9 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -296,7 +296,7 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField): super().__init__(*args, **kwargs) def set_field_from_activity(self, instance, data, overwrite=True): - """helper function for assinging a value to the field""" + """helper function for assigning a value to the field""" if not overwrite and getattr(instance, self.name).exists(): return False From 3f09b4bc8a44db937c2cfbe02f53b78010fba801 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 28 Nov 2021 09:23:13 -0800 Subject: [PATCH 5/5] More tests --- bookwyrm/tests/models/test_fields.py | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 278272d87..8028a305e 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -485,6 +485,106 @@ class ModelFields(TestCase): self.assertIsNotNone(book.cover.name) self.assertEqual(book.cover.size, 43200) + @responses.activate + def test_image_field_set_field_from_activity_no_overwrite_no_cover(self, *_): + """update a model instance from an activitypub object""" + image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + image = Image.open(image_file) + output = BytesIO() + image.save(output, format=image.format) + + instance = fields.ImageField(activitypub_field="cover", name="cover") + + responses.add( + responses.GET, + "http://www.example.com/image.jpg", + body=image.tobytes(), + status=200, + ) + book = Edition.objects.create(title="hello") + + MockActivity = namedtuple("MockActivity", ("cover")) + mock_activity = MockActivity("http://www.example.com/image.jpg") + + instance.set_field_from_activity(book, mock_activity, overwrite=False) + self.assertIsNotNone(book.cover.name) + self.assertEqual(book.cover.size, 43200) + + @responses.activate + def test_image_field_set_field_from_activity_no_overwrite_with_cover(self, *_): + """update a model instance from an activitypub object""" + image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + image = Image.open(image_file) + output = BytesIO() + image.save(output, format=image.format) + + another_image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/logo.png" + ) + another_image = Image.open(another_image_file) + another_output = BytesIO() + another_image.save(another_output, format=another_image.format) + + instance = fields.ImageField(activitypub_field="cover", name="cover") + + responses.add( + responses.GET, + "http://www.example.com/image.jpg", + body=another_image.tobytes(), + status=200, + ) + book = Edition.objects.create(title="hello") + book.cover.save("test.jpg", ContentFile(output.getvalue())) + self.assertEqual(book.cover.size, 2136) + + MockActivity = namedtuple("MockActivity", ("cover")) + mock_activity = MockActivity("http://www.example.com/image.jpg") + + instance.set_field_from_activity(book, mock_activity, overwrite=False) + # same cover as before + self.assertEqual(book.cover.size, 2136) + + @responses.activate + def test_image_field_set_field_from_activity_with_overwrite_with_cover(self, *_): + """update a model instance from an activitypub object""" + image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + image = Image.open(image_file) + output = BytesIO() + image.save(output, format=image.format) + book = Edition.objects.create(title="hello") + book.cover.save("test.jpg", ContentFile(output.getvalue())) + self.assertEqual(book.cover.size, 2136) + + another_image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/logo.png" + ) + another_image = Image.open(another_image_file) + another_output = BytesIO() + another_image.save(another_output, format=another_image.format) + + instance = fields.ImageField(activitypub_field="cover", name="cover") + + responses.add( + responses.GET, + "http://www.example.com/image.jpg", + body=another_image.tobytes(), + status=200, + ) + + MockActivity = namedtuple("MockActivity", ("cover")) + mock_activity = MockActivity("http://www.example.com/image.jpg") + + instance.set_field_from_activity(book, mock_activity, overwrite=True) + # new cover + self.assertIsNotNone(book.cover.name) + self.assertEqual(book.cover.size, 376800) + def test_datetime_field(self, *_): """this one is pretty simple, it just has to use isoformat""" instance = fields.DateTimeField()