Skip to content

Commit

Permalink
initial work to add 'Move' activity
Browse files Browse the repository at this point in the history
  • Loading branch information
hughrun committed Aug 29, 2023
1 parent e5f8e4b commit e7ba6a3
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 1 deletion.
1 change: 1 addition & 0 deletions bookwyrm/activitypub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .verbs import Follow, Accept, Reject, Block
from .verbs import Add, Remove
from .verbs import Announce, Like
from .verbs import Move

# this creates a list of all the Activity types that we can serialize,
# so when an Activity comes in from outside, we can check if it's known
Expand Down
25 changes: 25 additions & 0 deletions bookwyrm/activitypub/verbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,28 @@ class Announce(Verb):
def action(self, allow_external_connections=True):
"""boost"""
self.to_model(allow_external_connections=allow_external_connections)

@dataclass(init=False)
class Move(Verb):
"""a user moving an object"""

# note the spec example for target and origin is an object but
# Mastodon uses a URI string and TBH this makes more sense
# Is there a way we can account for either format?

object: str
type: str = "Move"
target: str
origin: str

def action(self, allow_external_connections=True):
"""move"""

# we need to work out whether the object is a user or something else.

object_is_user = True # TODO!

if object_is_user:
self.to_model(object_is_user=True allow_external_connections=allow_external_connections)
else:
self.to_model(object_is_user=False allow_external_connections=allow_external_connections)
50 changes: 50 additions & 0 deletions bookwyrm/models/move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
""" move an object including migrating a user account """
from django.db import models

from bookwyrm import activitypub
from .activitypub_mixin import ActivityMixin
from .base_model import BookWyrmModel
from . import fields
from .status import Status


class Move(ActivityMixin, BookWyrmModel):
"""migrating an activitypub user account"""

user = fields.ForeignKey(
"User", on_delete=models.PROTECT, activitypub_field="actor"
)

# TODO: can we just use the abstract class here?
activitypub_object = fields.ForeignKey(
"BookWyrmModel", on_delete=models.PROTECT,
activitypub_field="object",
blank=True,
null=True
)

target = fields.CharField(
max_length=255, blank=True, null=True, deduplication_field=True
)

origin = fields.CharField(
max_length=255, blank=True, null=True, deduplication_field=True
)

activity_serializer = activitypub.Move

# pylint: disable=unused-argument
@classmethod
def ignore_activity(cls, activity, allow_external_connections=True):
"""don't bother with incoming moves of unknown objects"""
# TODO how do we check this for any conceivable object?
pass

def save(self, *args, **kwargs):
"""update user active time"""
self.user.update_active_date()
super().save(*args, **kwargs)

# Ok what else? We can trigger a notification for followers of a user who sends a `Move` for themselves
# What about when a book is merged (i.e. moved from one id into another)? We could use that to send out a message
# to other Bookwyrm instances to update their remote_id for the book, but ...how do we trigger any action?
16 changes: 15 additions & 1 deletion bookwyrm/models/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ class Notification(BookWyrmModel):
GROUP_NAME = "GROUP_NAME"
GROUP_DESCRIPTION = "GROUP_DESCRIPTION"

# Migrations
MOVE = "MOVE"

# pylint: disable=line-too-long
NotificationType = models.TextChoices(
# there has got be a better way to do this
"NotificationType",
f"{FAVORITE} {REPLY} {MENTION} {TAG} {FOLLOW} {FOLLOW_REQUEST} {BOOST} {IMPORT} {ADD} {REPORT} {LINK_DOMAIN} {INVITE} {ACCEPT} {JOIN} {LEAVE} {REMOVE} {GROUP_PRIVACY} {GROUP_NAME} {GROUP_DESCRIPTION}",
f"{FAVORITE} {REPLY} {MENTION} {TAG} {FOLLOW} {FOLLOW_REQUEST} {BOOST} {IMPORT} {ADD} {REPORT} {LINK_DOMAIN} {INVITE} {ACCEPT} {JOIN} {LEAVE} {REMOVE} {GROUP_PRIVACY} {GROUP_NAME} {GROUP_DESCRIPTION} {MOVE}",
)

user = models.ForeignKey("User", on_delete=models.CASCADE)
Expand Down Expand Up @@ -326,3 +329,14 @@ def notify_user_on_follow(sender, instance, created, *args, **kwargs):
notification_type=Notification.FOLLOW,
read=False,
)

@receiver(models.signals.post_save, sender=Move)
# pylint: disable=unused-argument
def notify_on_move(sender, instance, *args, **kwargs):
"""someone moved something"""
Notification.notify(
instance.status.user,
instance.user,
related_object=instance.object,
notification_type=Notification.MOVE,
)
2 changes: 2 additions & 0 deletions bookwyrm/templates/notifications/item.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@
{% include 'notifications/items/update.html' %}
{% elif notification.notification_type == 'GROUP_DESCRIPTION' %}
{% include 'notifications/items/update.html' %}
{% elif notification.notification_type == 'MOVE' %}
{% include 'notifications/items/move.html' %}
{% endif %}
28 changes: 28 additions & 0 deletions bookwyrm/templates/notifications/items/move.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{% extends 'notifications/items/layout.html' %}

{% load i18n %}
{% load utilities %}

{% block primary_link %}{% spaceless %}
{{ notification.related_object.local_path }}
{% endspaceless %}{% endblock %}

{% block icon %}
<span class="icon icon-local"></span>
{% endblock %}

{% block description %}
<!--
TODO: a user has a 'name' but not everything does, notably a book.
On the other hand, maybe we don't need to notify anyone if a book
is moved, just update the remote_id?
-->
{% blocktrans trimmed with object_name=notification.related_object.name object_path=notification.related_object.local_path %}
<a href="{{ related_user_link }}">{{ related_user }}</a>
moved {{ object_name }}
"<a href="{{ object_path }}">{{ object_name }}</a>"
{% endblocktrans %}

<!-- TODO maybe put a brief context message here for migrated user accounts? -->

{% endblock %}

0 comments on commit e7ba6a3

Please sign in to comment.