diff --git a/.env.example b/.env.example index d2b43e171..e8302af42 100644 --- a/.env.example +++ b/.env.example @@ -23,7 +23,8 @@ POSTGRES_USER=fedireads POSTGRES_DB=fedireads POSTGRES_HOST=db -# Redis as activitystreams manager +# Redis activity stream manager +MAX_STREAM_LENGTH=200 REDIS_ACTIVITY_HOST=redis_activity REDIS_ACTIVITY_PORT=6379 REDIS_ACTIVITY_PASSWORD=redispassword345 diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 74f491022..768eb2084 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -248,7 +248,9 @@ def get_model_from_type(activity_type): return model[0] -def resolve_remote_id(remote_id, model=None, refresh=False, save=True): +def resolve_remote_id( + remote_id, model=None, refresh=False, save=True, get_activity=False +): """ take a remote_id and return an instance, creating if necessary """ if model: # a bonus check we can do if we already know the model result = model.find_existing_by_remote_id(remote_id) @@ -272,5 +274,8 @@ def resolve_remote_id(remote_id, model=None, refresh=False, save=True): return result if not get_activity else result.to_activity_dataclass() item = model.activity_serializer(**data) + if get_activity: + return item + # if we're refreshing, "result" will be set and we'll update it return item.to_model(model=model, instance=result, save=save) diff --git a/bookwyrm/migrations/0058_auto_20210324_1536.py b/bookwyrm/migrations/0058_auto_20210324_1536.py new file mode 100644 index 000000000..0fa8c90b6 --- /dev/null +++ b/bookwyrm/migrations/0058_auto_20210324_1536.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.6 on 2021-03-24 15:36 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0057_user_discoverable"), + ] + + operations = [ + migrations.AlterModelOptions( + name="status", + options={"ordering": ("-published_date",)}, + ), + ] diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 1690ec37d..8038e3ee5 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -58,6 +58,11 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): serialize_reverse_fields = [("attachments", "attachment", "id")] deserialize_reverse_fields = [("attachments", "attachment")] + class Meta: + """ default sorting """ + + ordering = ("-published_date",) + def save(self, *args, **kwargs): """ save and notify """ super().save(*args, **kwargs) @@ -118,12 +123,14 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): """ keep notes if they are replies to existing statuses """ if activity.type == "Announce": try: - boosted = activitypub.resolve_remote_id(activity.object, save=False) + boosted = activitypub.resolve_remote_id( + activity.object, get_activity=True + ) except activitypub.ActivitySerializerError: # if we can't load the status, definitely ignore it return True # keep the boost if we would keep the status - return cls.ignore_activity(boosted.to_activity_dataclass()) + return cls.ignore_activity(boosted) # keep if it if it's a custom type if activity.type != "Note": @@ -344,7 +351,7 @@ class Boost(ActivityMixin, Status): def save(self, *args, **kwargs): """ save and notify """ super().save(*args, **kwargs) - if not self.boosted_status.user.local: + if not self.boosted_status.user.local or self.boosted_status.user == self.user: return notification_model = apps.get_model("bookwyrm.Notification", require_ready=True) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 0f010da27..1aa7c3bea 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -97,7 +97,7 @@ REDIS_ACTIVITY_HOST = env("REDIS_ACTIVITY_HOST", "localhost") REDIS_ACTIVITY_PORT = env("REDIS_ACTIVITY_PORT", 6379) REDIS_ACTIVITY_PASSWORD = env("REDIS_ACTIVITY_PASSWORD") -MAX_STREAM_LENGTH = env("MAX_STREAM_LENGTH", 200) +MAX_STREAM_LENGTH = int(env("MAX_STREAM_LENGTH", 200)) STREAMS = ["home", "local", "federated"] # Database diff --git a/bookwyrm/static/css/format.css b/bookwyrm/static/css/format.css index c68eb40d2..6a1167b26 100644 --- a/bookwyrm/static/css/format.css +++ b/bookwyrm/static/css/format.css @@ -34,6 +34,29 @@ html { .hidden { display: none !important; } +.hidden.transition-y, .hidden.transition-x { + display: block !important; + visibility: hidden !important; + height: 0; + width: 0; + margin: 0; + padding: 0; +} +.transition-y { + transition-property: height, margin-top, margin-bottom, padding-top, padding-bottom; + transition-duration: 0.5s; + transition-timing-function: ease; +} +.transition-x { + transition-property: width, margin-left, margin-right, padding-left, padding-right; + transition-duration: 0.5s; + transition-timing-function: ease; +} +@media (prefers-reduced-motion: reduce) { + .transition-x, .transition-y { + transition-duration: 0.001ms !important; + } +} /* --- STARS --- */ .rate-stars button.icon { diff --git a/bookwyrm/templates/feed/feed.html b/bookwyrm/templates/feed/feed.html index 379bf9272..bc35d3b90 100644 --- a/bookwyrm/templates/feed/feed.html +++ b/bookwyrm/templates/feed/feed.html @@ -28,7 +28,7 @@ {# announcements and system messages #} {% if not activities.number > 1 %} - diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index d08b18202..4f6573582 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -139,7 +139,7 @@ {% trans "Notifications" %} - + {{ request.user | notification_count }} diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index 40152c0fb..297eeb73d 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -95,6 +95,23 @@ class InteractionViews(TestCase): self.assertEqual(notification.related_user, self.remote_user) self.assertEqual(notification.related_status, status) + def test_handle_self_boost(self, _): + """ boost your own status """ + view = views.Boost.as_view() + request = self.factory.post("") + request.user = self.local_user + with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + status = models.Status.objects.create(user=self.local_user, content="hi") + + view(request, status.id) + + boost = models.Boost.objects.get() + self.assertEqual(boost.boosted_status, status) + self.assertEqual(boost.user, self.local_user) + self.assertEqual(boost.privacy, "public") + + self.assertFalse(models.Notification.objects.exists()) + def test_handle_boost_unlisted(self, _): """ boost a status """ view = views.Boost.as_view() @@ -135,23 +152,21 @@ class InteractionViews(TestCase): view(request, status.id) self.assertEqual(models.Boost.objects.count(), 1) - def test_handle_unboost(self, broadcast_mock): + def test_handle_unboost(self, _): """ undo a boost """ view = views.Unboost.as_view() request = self.factory.post("") - request.user = self.local_user + request.user = self.remote_user with patch("bookwyrm.activitystreams.ActivityStream.add_status"): status = models.Status.objects.create(user=self.local_user, content="hi") views.Boost.as_view()(request, status.id) self.assertEqual(models.Boost.objects.count(), 1) self.assertEqual(models.Notification.objects.count(), 1) - broadcast_mock.call_count = 0 with patch( "bookwyrm.activitystreams.ActivityStream.remove_status" ) as redis_mock: view(request, status.id) - self.assertEqual(broadcast_mock.call_count, 1) self.assertTrue(redis_mock.called) self.assertEqual(models.Boost.objects.count(), 0) self.assertEqual(models.Notification.objects.count(), 0)