mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-01-08 08:15:33 +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_DB=fedireads
|
||||||
POSTGRES_HOST=db
|
POSTGRES_HOST=db
|
||||||
|
|
||||||
# Redis as activitystreams manager
|
# Redis activity stream manager
|
||||||
|
MAX_STREAM_LENGTH=200
|
||||||
REDIS_ACTIVITY_HOST=redis_activity
|
REDIS_ACTIVITY_HOST=redis_activity
|
||||||
REDIS_ACTIVITY_PORT=6379
|
REDIS_ACTIVITY_PORT=6379
|
||||||
REDIS_ACTIVITY_PASSWORD=redispassword345
|
REDIS_ACTIVITY_PASSWORD=redispassword345
|
||||||
|
|
|
@ -248,7 +248,9 @@ def get_model_from_type(activity_type):
|
||||||
return model[0]
|
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 """
|
""" 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
|
if model: # a bonus check we can do if we already know the model
|
||||||
result = model.find_existing_by_remote_id(remote_id)
|
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()
|
return result if not get_activity else result.to_activity_dataclass()
|
||||||
|
|
||||||
item = model.activity_serializer(**data)
|
item = model.activity_serializer(**data)
|
||||||
|
if get_activity:
|
||||||
|
return item
|
||||||
|
|
||||||
# if we're refreshing, "result" will be set and we'll update it
|
# if we're refreshing, "result" will be set and we'll update it
|
||||||
return item.to_model(model=model, instance=result, save=save)
|
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")]
|
serialize_reverse_fields = [("attachments", "attachment", "id")]
|
||||||
deserialize_reverse_fields = [("attachments", "attachment")]
|
deserialize_reverse_fields = [("attachments", "attachment")]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
""" default sorting """
|
||||||
|
|
||||||
|
ordering = ("-published_date",)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
""" save and notify """
|
""" save and notify """
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
@ -118,12 +123,14 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
""" keep notes if they are replies to existing statuses """
|
""" keep notes if they are replies to existing statuses """
|
||||||
if activity.type == "Announce":
|
if activity.type == "Announce":
|
||||||
try:
|
try:
|
||||||
boosted = activitypub.resolve_remote_id(activity.object, save=False)
|
boosted = activitypub.resolve_remote_id(
|
||||||
|
activity.object, get_activity=True
|
||||||
|
)
|
||||||
except activitypub.ActivitySerializerError:
|
except activitypub.ActivitySerializerError:
|
||||||
# if we can't load the status, definitely ignore it
|
# if we can't load the status, definitely ignore it
|
||||||
return True
|
return True
|
||||||
# keep the boost if we would keep the status
|
# 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
|
# keep if it if it's a custom type
|
||||||
if activity.type != "Note":
|
if activity.type != "Note":
|
||||||
|
@ -344,7 +351,7 @@ class Boost(ActivityMixin, Status):
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
""" save and notify """
|
""" save and notify """
|
||||||
super().save(*args, **kwargs)
|
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
|
return
|
||||||
|
|
||||||
notification_model = apps.get_model("bookwyrm.Notification", require_ready=True)
|
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_PORT = env("REDIS_ACTIVITY_PORT", 6379)
|
||||||
REDIS_ACTIVITY_PASSWORD = env("REDIS_ACTIVITY_PASSWORD")
|
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"]
|
STREAMS = ["home", "local", "federated"]
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
|
|
|
@ -34,6 +34,29 @@ html {
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
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 --- */
|
/* --- STARS --- */
|
||||||
.rate-stars button.icon {
|
.rate-stars button.icon {
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
{# announcements and system messages #}
|
{# announcements and system messages #}
|
||||||
{% if not activities.number > 1 %}
|
{% 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 %}
|
{% blocktrans %}load <span data-poll="stream/{{ tab }}">0</span> unread status(es){% endblocktrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
<span class="is-sr-only">{% trans "Notifications" %}</span>
|
||||||
</span>
|
</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 data-poll="notifications">{{ request.user | notification_count }}</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -95,6 +95,23 @@ class InteractionViews(TestCase):
|
||||||
self.assertEqual(notification.related_user, self.remote_user)
|
self.assertEqual(notification.related_user, self.remote_user)
|
||||||
self.assertEqual(notification.related_status, status)
|
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, _):
|
def test_handle_boost_unlisted(self, _):
|
||||||
""" boost a status """
|
""" boost a status """
|
||||||
view = views.Boost.as_view()
|
view = views.Boost.as_view()
|
||||||
|
@ -135,23 +152,21 @@ class InteractionViews(TestCase):
|
||||||
view(request, status.id)
|
view(request, status.id)
|
||||||
self.assertEqual(models.Boost.objects.count(), 1)
|
self.assertEqual(models.Boost.objects.count(), 1)
|
||||||
|
|
||||||
def test_handle_unboost(self, broadcast_mock):
|
def test_handle_unboost(self, _):
|
||||||
""" undo a boost """
|
""" undo a boost """
|
||||||
view = views.Unboost.as_view()
|
view = views.Unboost.as_view()
|
||||||
request = self.factory.post("")
|
request = self.factory.post("")
|
||||||
request.user = self.local_user
|
request.user = self.remote_user
|
||||||
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
|
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
|
||||||
status = models.Status.objects.create(user=self.local_user, content="hi")
|
status = models.Status.objects.create(user=self.local_user, content="hi")
|
||||||
views.Boost.as_view()(request, status.id)
|
views.Boost.as_view()(request, status.id)
|
||||||
|
|
||||||
self.assertEqual(models.Boost.objects.count(), 1)
|
self.assertEqual(models.Boost.objects.count(), 1)
|
||||||
self.assertEqual(models.Notification.objects.count(), 1)
|
self.assertEqual(models.Notification.objects.count(), 1)
|
||||||
broadcast_mock.call_count = 0
|
|
||||||
with patch(
|
with patch(
|
||||||
"bookwyrm.activitystreams.ActivityStream.remove_status"
|
"bookwyrm.activitystreams.ActivityStream.remove_status"
|
||||||
) as redis_mock:
|
) as redis_mock:
|
||||||
view(request, status.id)
|
view(request, status.id)
|
||||||
self.assertEqual(broadcast_mock.call_count, 1)
|
|
||||||
self.assertTrue(redis_mock.called)
|
self.assertTrue(redis_mock.called)
|
||||||
self.assertEqual(models.Boost.objects.count(), 0)
|
self.assertEqual(models.Boost.objects.count(), 0)
|
||||||
self.assertEqual(models.Notification.objects.count(), 0)
|
self.assertEqual(models.Notification.objects.count(), 0)
|
||||||
|
|
Loading…
Reference in a new issue