mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-01-05 14:58:43 +00:00
Merge branch 'main' into production
This commit is contained in:
commit
6f37a43d33
9 changed files with 80 additions and 12 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
17
bookwyrm/migrations/0058_auto_20210324_1536.py
Normal file
17
bookwyrm/migrations/0058_auto_20210324_1536.py
Normal file
|
@ -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",)},
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
{# announcements and system messages #}
|
||||
{% if not activities.number > 1 %}
|
||||
<a href="{{ request.path }}" class="hidden notification is-primary is-block" data-poll-wrapper>
|
||||
<a href="{{ request.path }}" class="transition-y hidden notification is-primary is-block" data-poll-wrapper>
|
||||
{% blocktrans %}load <span data-poll="stream/{{ tab }}">0</span> unread status(es){% endblocktrans %}
|
||||
</a>
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="{% if not request.user|notification_count %}hidden {% endif %}tag is-danger is-medium" data-poll-wrapper>
|
||||
<span class="{% if not request.user|notification_count %}hidden {% endif %}tag is-danger is-medium transition-x" data-poll-wrapper>
|
||||
<span data-poll="notifications">{{ request.user | notification_count }}</span>
|
||||
</span>
|
||||
</a>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue