diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py
index 5dece504b..e4f1f29b1 100644
--- a/bookwyrm/models/book.py
+++ b/bookwyrm/models/book.py
@@ -73,7 +73,10 @@ class Book(ActivitypubMixin, BookWyrmModel):
@property
def alt_text(self):
''' image alt test '''
- return '%s cover (%s)' % (self.title, self.edition_info)
+ text = '%s cover' % self.title
+ if self.edition_info:
+ text += ' (%s)' % self.edition_info
+ return text
def save(self, *args, **kwargs):
''' can't be abstract for query reasons, but you shouldn't USE it '''
diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py
index f346bc47e..672107e07 100644
--- a/bookwyrm/models/status.py
+++ b/bookwyrm/models/status.py
@@ -132,8 +132,8 @@ class Comment(Status):
@property
def pure_content(self):
''' indicate the book in question for mastodon (or w/e) users '''
- return self.content + '
(comment on "%s")' % \
- (self.book.remote_id, self.book.title)
+ return '
%s
(comment on "%s")
' % \ + (self.content, self.book.remote_id, self.book.title) activity_serializer = activitypub.Comment pure_type = 'Note' @@ -148,7 +148,7 @@ class Quotation(Status): @property def pure_content(self): ''' indicate the book in question for mastodon (or w/e) users ''' - return '"%s""%s"
-- "%s"
%s
' % ( self.quote, self.book.remote_id, self.book.title, diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index d5db9949b..ce50fc092 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -91,6 +91,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): last_active_date = models.DateTimeField(auto_now=True) manually_approves_followers = fields.BooleanField(default=False) + name_field = 'username' @property def alt_text(self): ''' alt text with username ''' diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 7c625197f..1d6eb5b8b 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -1,42 +1,206 @@ ''' testing models ''' +from io import BytesIO +import pathlib + +from PIL import Image +from django.core.files.base import ContentFile from django.test import TestCase +from django.utils import timezone from bookwyrm import models, settings class Status(TestCase): + ''' lotta types of statuses ''' def setUp(self): - user = models.User.objects.create_user( + ''' useful things for creating a status ''' + self.user = models.User.objects.create_user( 'mouse', 'mouse@mouse.mouse', 'mouseword', local=True) - book = models.Edition.objects.create(title='Example Edition') + self.book = models.Edition.objects.create(title='Test Edition') - models.Status.objects.create(user=user, content='Blah blah') - models.Comment.objects.create(user=user, content='content', book=book) - models.Quotation.objects.create( - user=user, content='content', book=book, quote='blah') - models.Review.objects.create( - user=user, content='content', book=book, rating=3) + 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) + self.book.cover.save( + 'test.jpg', + ContentFile(output.getvalue()) + ) - def test_status(self): - status = models.Status.objects.first() + def test_status_generated_fields(self): + ''' setting remote id ''' + status = models.Status.objects.create(content='bleh', user=self.user) expected_id = 'https://%s/user/mouse/status/%d' % \ (settings.DOMAIN, status.id) self.assertEqual(status.remote_id, expected_id) + self.assertEqual(status.privacy, 'public') - def test_comment(self): - comment = models.Comment.objects.first() - expected_id = 'https://%s/user/mouse/comment/%d' % \ - (settings.DOMAIN, comment.id) - self.assertEqual(comment.remote_id, expected_id) + def test_replies(self): + ''' get a list of replies ''' + parent = models.Status.objects.create(content='hi', user=self.user) + child = models.Status.objects.create( + content='hello', reply_parent=parent, user=self.user) + models.Review.objects.create( + content='hey', reply_parent=parent, user=self.user, book=self.book) + models.Status.objects.create( + content='hi hello', reply_parent=child, user=self.user) - def test_quotation(self): - quotation = models.Quotation.objects.first() - expected_id = 'https://%s/user/mouse/quotation/%d' % \ - (settings.DOMAIN, quotation.id) - self.assertEqual(quotation.remote_id, expected_id) + replies = models.Status.replies(parent) + self.assertEqual(replies.count(), 2) + self.assertEqual(replies.first(), child) + # should select subclasses + self.assertIsInstance(replies.last(), models.Review) - def test_review(self): - review = models.Review.objects.first() - expected_id = 'https://%s/user/mouse/review/%d' % \ - (settings.DOMAIN, review.id) - self.assertEqual(review.remote_id, expected_id) + def test_status_type(self): + ''' class name ''' + self.assertEqual(models.Status().status_type, 'Note') + self.assertEqual(models.Review().status_type, 'Review') + self.assertEqual(models.Quotation().status_type, 'Quotation') + self.assertEqual(models.Comment().status_type, 'Comment') + self.assertEqual(models.Boost().status_type, 'Boost') + + def test_boostable(self): + ''' can a status be boosted, based on privacy ''' + self.assertTrue(models.Status(privacy='public').boostable) + self.assertTrue(models.Status(privacy='unlisted').boostable) + self.assertFalse(models.Status(privacy='followers').boostable) + self.assertFalse(models.Status(privacy='direct').boostable) + + def test_to_replies(self): + ''' activitypub replies collection ''' + parent = models.Status.objects.create(content='hi', user=self.user) + child = models.Status.objects.create( + content='hello', reply_parent=parent, user=self.user) + models.Review.objects.create( + content='hey', reply_parent=parent, user=self.user, book=self.book) + models.Status.objects.create( + content='hi hello', reply_parent=child, user=self.user) + + replies = parent.to_replies() + self.assertEqual(replies['id'], '%s/replies' % parent.remote_id) + self.assertEqual(replies['totalItems'], 2) + + def test_status_to_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Status.objects.create( + content='test content', user=self.user) + activity = status.to_activity() + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Note') + self.assertEqual(activity['content'], 'test content') + self.assertEqual(activity['sensitive'], False) + + def test_status_to_activity_tombstone(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Status.objects.create( + content='test content', user=self.user, + deleted=True, deleted_date=timezone.now()) + activity = status.to_activity() + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Tombstone') + self.assertFalse(hasattr(activity, 'content')) + + def test_status_to_pure_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Status.objects.create( + content='test content', user=self.user) + activity = status.to_activity(pure=True) + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Note') + self.assertEqual(activity['content'], 'test content') + self.assertEqual(activity['sensitive'], False) + self.assertEqual(activity['attachment'], []) + + def test_generated_note_to_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.GeneratedNote.objects.create( + content='test content', user=self.user) + status.mention_books.set([self.book]) + status.mention_users.set([self.user]) + activity = status.to_activity() + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'GeneratedNote') + self.assertEqual(activity['content'], 'test content') + self.assertEqual(activity['sensitive'], False) + self.assertEqual(len(activity['tag']), 2) + + def test_generated_note_to_pure_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.GeneratedNote.objects.create( + content='test content', user=self.user) + status.mention_books.set([self.book]) + status.mention_users.set([self.user]) + activity = status.to_activity(pure=True) + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual( + activity['content'], + 'mouse test content "Test Edition"' % \ + self.book.remote_id) + self.assertEqual(len(activity['tag']), 2) + self.assertEqual(activity['type'], 'Note') + self.assertEqual(activity['sensitive'], False) + self.assertIsInstance(activity['attachment'], list) + self.assertEqual(activity['attachment'][0].type, 'Image') + self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ + (settings.DOMAIN, self.book.cover.url)) + self.assertEqual( + activity['attachment'][0].name, 'Test Edition cover') + + def test_comment_to_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Comment.objects.create( + content='test content', user=self.user, book=self.book) + activity = status.to_activity() + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Comment') + self.assertEqual(activity['content'], 'test content') + self.assertEqual(activity['inReplyToBook'], self.book.remote_id) + + def test_comment_to_pure_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Comment.objects.create( + content='test content', user=self.user, book=self.book) + activity = status.to_activity(pure=True) + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Note') + self.assertEqual( + activity['content'], + 'test content
' \ + '(comment on "Test Edition")
' % + self.book.remote_id) + self.assertEqual(activity['attachment'][0].type, 'Image') + self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ + (settings.DOMAIN, self.book.cover.url)) + self.assertEqual( + activity['attachment'][0].name, 'Test Edition cover') + + def test_quotation_to_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Quotation.objects.create( + quote='a sickening sense', content='test content', + user=self.user, book=self.book) + activity = status.to_activity() + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Quotation') + self.assertEqual(activity['quote'], 'a sickening sense') + self.assertEqual(activity['content'], 'test content') + self.assertEqual(activity['inReplyToBook'], self.book.remote_id) + + def test_quotation_to_pure_activity(self): + ''' subclass of the base model version with a "pure" serializer ''' + status = models.Quotation.objects.create( + quote='a sickening sense', content='test content', + user=self.user, book=self.book) + activity = status.to_activity(pure=True) + self.assertEqual(activity['id'], status.remote_id) + self.assertEqual(activity['type'], 'Note') + self.assertEqual( + activity['content'], + '"a sickening sense"
-- "Test Edition"
test content
' % self.book.remote_id) + self.assertEqual(activity['attachment'][0].type, 'Image') + self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \ + (settings.DOMAIN, self.book.cover.url)) + self.assertEqual( + activity['attachment'][0].name, 'Test Edition cover')