From e7ba6a31418f127e502451836f07d4292a294931 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Tue, 29 Aug 2023 21:07:41 +1000 Subject: [PATCH 01/12] initial work to add 'Move' activity --- bookwyrm/activitypub/__init__.py | 1 + bookwyrm/activitypub/verbs.py | 25 ++++++++++ bookwyrm/models/move.py | 50 +++++++++++++++++++ bookwyrm/models/notification.py | 16 +++++- bookwyrm/templates/notifications/item.html | 2 + .../templates/notifications/items/move.html | 28 +++++++++++ 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/models/move.py create mode 100644 bookwyrm/templates/notifications/items/move.html diff --git a/bookwyrm/activitypub/__init__.py b/bookwyrm/activitypub/__init__.py index 05ca444766..e2bd4261d9 100644 --- a/bookwyrm/activitypub/__init__.py +++ b/bookwyrm/activitypub/__init__.py @@ -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 diff --git a/bookwyrm/activitypub/verbs.py b/bookwyrm/activitypub/verbs.py index 4b7514b5ab..3432da4d56 100644 --- a/bookwyrm/activitypub/verbs.py +++ b/bookwyrm/activitypub/verbs.py @@ -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) \ No newline at end of file diff --git a/bookwyrm/models/move.py b/bookwyrm/models/move.py new file mode 100644 index 0000000000..cb597e84a5 --- /dev/null +++ b/bookwyrm/models/move.py @@ -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? \ No newline at end of file diff --git a/bookwyrm/models/notification.py b/bookwyrm/models/notification.py index 522038f9ab..48baacfaf8 100644 --- a/bookwyrm/models/notification.py +++ b/bookwyrm/models/notification.py @@ -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) @@ -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, + ) \ No newline at end of file diff --git a/bookwyrm/templates/notifications/item.html b/bookwyrm/templates/notifications/item.html index b53abe3d10..b2020839af 100644 --- a/bookwyrm/templates/notifications/item.html +++ b/bookwyrm/templates/notifications/item.html @@ -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 %} diff --git a/bookwyrm/templates/notifications/items/move.html b/bookwyrm/templates/notifications/items/move.html new file mode 100644 index 0000000000..ffa23829f2 --- /dev/null +++ b/bookwyrm/templates/notifications/items/move.html @@ -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 %} + +{% endblock %} + +{% block description %} + + {% blocktrans trimmed with object_name=notification.related_object.name object_path=notification.related_object.local_path %} + {{ related_user }} + moved {{ object_name }} + "{{ object_name }}" + {% endblocktrans %} + + + +{% endblock %} From 5b051631ecf296844b70c669d1cab055d32a7f7b Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 18 Sep 2023 21:21:04 +1000 Subject: [PATCH 02/12] Move MVP * update User model to allow for moved_to and also_known_as values * allow users to add aliases (also_known_as) in UI * allow users to move account to another one (moved_to) * redirect webfinger to the new account after a move * present notification to followers inviting to follow at new account Note: unlike Mastodon we're not running any unfollow/autofollow action here: users can decide for themselves This makes undoing moves easier. TODO There is still a bug with incoming Moves, at least from Mastodon. This seems to be something to do with Update activities (rather than Move, strictly). --- bookwyrm/activitypub/person.py | 2 + bookwyrm/activitypub/verbs.py | 21 ++- bookwyrm/forms/edit_user.py | 16 +++ bookwyrm/models/__init__.py | 2 + bookwyrm/models/move.py | 89 +++++++++--- bookwyrm/models/notification.py | 21 +-- bookwyrm/models/user.py | 13 ++ bookwyrm/templates/notifications/item.html | 2 +- .../templates/notifications/items/layout.html | 4 + .../templates/notifications/items/move.html | 28 ---- .../notifications/items/move_user.html | 20 +++ .../templates/preferences/alias_user.html | 56 ++++++++ bookwyrm/templates/preferences/layout.html | 8 ++ bookwyrm/templates/preferences/move_user.html | 41 ++++++ .../templates/settings/users/user_admin.html | 15 +- .../templates/settings/users/user_info.html | 12 +- .../templates/snippets/move_user_buttons.html | 13 ++ bookwyrm/templates/user/layout.html | 133 ++++++++++-------- bookwyrm/templates/user/moved.html | 27 ++++ bookwyrm/templatetags/utilities.py | 19 +++ bookwyrm/urls.py | 5 + bookwyrm/views/__init__.py | 1 + bookwyrm/views/preferences/move_user.py | 98 +++++++++++++ bookwyrm/views/wellknown.py | 3 +- 24 files changed, 516 insertions(+), 133 deletions(-) delete mode 100644 bookwyrm/templates/notifications/items/move.html create mode 100644 bookwyrm/templates/notifications/items/move_user.html create mode 100644 bookwyrm/templates/preferences/alias_user.html create mode 100644 bookwyrm/templates/preferences/move_user.html create mode 100644 bookwyrm/templates/snippets/move_user_buttons.html create mode 100644 bookwyrm/templates/user/moved.html create mode 100644 bookwyrm/views/preferences/move_user.py diff --git a/bookwyrm/activitypub/person.py b/bookwyrm/activitypub/person.py index 61c15a5794..85cf444099 100644 --- a/bookwyrm/activitypub/person.py +++ b/bookwyrm/activitypub/person.py @@ -40,4 +40,6 @@ class Person(ActivityObject): manuallyApprovesFollowers: str = False discoverable: str = False hideFollows: str = False + movedTo: str = None + alsoKnownAs: dict[str] = None type: str = "Person" diff --git a/bookwyrm/activitypub/verbs.py b/bookwyrm/activitypub/verbs.py index 3432da4d56..0b04d9ebaf 100644 --- a/bookwyrm/activitypub/verbs.py +++ b/bookwyrm/activitypub/verbs.py @@ -75,6 +75,9 @@ def action(self, allow_external_connections=True): """update a model instance from the dataclass""" if not self.object: return + # BUG: THIS IS THROWING A DUPLIATE USERNAME ERROR WHEN WE GET AN "UPDATE" AFTER/BEFORE A "MOVE" + # FROM MASTODON - BUT ONLY SINCE WE ADDED MOVEUSER + # is it something to do with the updated User model? self.object.to_model( allow_create=False, allow_external_connections=allow_external_connections ) @@ -232,27 +235,23 @@ 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 + origin: str = None + target: str = None 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! + object_is_user = resolve_remote_id(remote_id=self.object, model="User") if object_is_user: - self.to_model(object_is_user=True allow_external_connections=allow_external_connections) + model = apps.get_model("bookwyrm.MoveUser") + self.to_model(model=model) else: - self.to_model(object_is_user=False allow_external_connections=allow_external_connections) \ No newline at end of file + return diff --git a/bookwyrm/forms/edit_user.py b/bookwyrm/forms/edit_user.py index ce7bb6d075..9024972c33 100644 --- a/bookwyrm/forms/edit_user.py +++ b/bookwyrm/forms/edit_user.py @@ -70,6 +70,22 @@ class Meta: fields = ["password"] +class MoveUserForm(CustomForm): + target = forms.CharField(widget=forms.TextInput) + + class Meta: + model = models.User + fields = ["password"] + + +class AliasUserForm(CustomForm): + username = forms.CharField(widget=forms.TextInput) + + class Meta: + model = models.User + fields = ["password"] + + class ChangePasswordForm(CustomForm): current_password = forms.CharField(widget=forms.PasswordInput) confirm_password = forms.CharField(widget=forms.PasswordInput) diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 7b779190b6..9edb89286c 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -27,6 +27,8 @@ from .import_job import ImportJob, ImportItem +from .move import MoveUser, MoveUserNotification + from .site import SiteSettings, Theme, SiteInvite from .site import PasswordReset, InviteRequest from .announcement import Announcement diff --git a/bookwyrm/models/move.py b/bookwyrm/models/move.py index cb597e84a5..5c8044ce35 100644 --- a/bookwyrm/models/move.py +++ b/bookwyrm/models/move.py @@ -1,4 +1,5 @@ """ move an object including migrating a user account """ +from django.core.exceptions import PermissionDenied from django.db import models from bookwyrm import activitypub @@ -6,6 +7,7 @@ from .base_model import BookWyrmModel from . import fields from .status import Status +from bookwyrm.models import User class Move(ActivityMixin, BookWyrmModel): @@ -15,20 +17,21 @@ class Move(ActivityMixin, BookWyrmModel): "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, + object = fields.CharField( + max_length=255, + blank=False, + null=False, + deduplication_field=True, 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 + max_length=255, + blank=True, + null=True, + deduplication_field=True, + default="", + activitypub_field="origin", ) activity_serializer = activitypub.Move @@ -37,14 +40,66 @@ class Move(ActivityMixin, BookWyrmModel): @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? + # TODO pass + +class MoveUser(Move): + """migrating an activitypub user account""" + + target = fields.ForeignKey( + "User", + on_delete=models.PROTECT, + related_name="move_target", + activitypub_field="target", + ) + + # pylint: disable=unused-argument + @classmethod + def ignore_activity(cls, activity, allow_external_connections=True): + """don't bother with incoming moves of unknown users""" + return not User.objects.filter(remote_id=activity.origin).exists() + def save(self, *args, **kwargs): - """update user active time""" - self.user.update_active_date() - super().save(*args, **kwargs) + """update user info and broadcast it""" - # 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? \ No newline at end of file + notify_followers = False + if self.user in self.target.also_known_as.all(): + + self.user.also_known_as.add(self.target.id) + self.user.update_active_date() + self.user.moved_to = self.target.remote_id + self.user.save(update_fields=["moved_to"]) + + if self.user.local: + kwargs[ + "broadcast" + ] = True # Only broadcast if we are initiating the Move + notify_followers = True + + super().save(*args, **kwargs) + + if notify_followers: + for follower in self.user.followers.all(): + MoveUserNotification.objects.create(user=follower, target=self.user) + + else: + raise PermissionDenied() + + +class MoveUserNotification(models.Model): + """notify followers that the user has moved""" + + created_date = models.DateTimeField(auto_now_add=True) + + user = models.ForeignKey( + "User", on_delete=models.CASCADE, related_name="moved_user_notifications" + ) # user we are notifying + + target = models.ForeignKey( + "User", on_delete=models.CASCADE, related_name="moved_user_notification_target" + ) # new account of user who moved + + def save(self, *args, **kwargs): + """send notification""" + super().save(*args, **kwargs) diff --git a/bookwyrm/models/notification.py b/bookwyrm/models/notification.py index 48baacfaf8..9026b23df3 100644 --- a/bookwyrm/models/notification.py +++ b/bookwyrm/models/notification.py @@ -2,7 +2,14 @@ from django.db import models, transaction from django.dispatch import receiver from .base_model import BookWyrmModel -from . import Boost, Favorite, GroupMemberInvitation, ImportJob, LinkDomain +from . import ( + Boost, + Favorite, + GroupMemberInvitation, + ImportJob, + LinkDomain, + MoveUserNotification, +) from . import ListItem, Report, Status, User, UserFollowRequest @@ -330,13 +337,11 @@ def notify_user_on_follow(sender, instance, created, *args, **kwargs): read=False, ) -@receiver(models.signals.post_save, sender=Move) + +@receiver(models.signals.post_save, sender=MoveUserNotification) # pylint: disable=unused-argument def notify_on_move(sender, instance, *args, **kwargs): - """someone moved something""" + """someone migrated their account""" Notification.notify( - instance.status.user, - instance.user, - related_object=instance.object, - notification_type=Notification.MOVE, - ) \ No newline at end of file + instance.user, instance.target, notification_type=Notification.MOVE + ) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 6e0912aece..6c87af18c7 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -140,6 +140,17 @@ class User(OrderedCollectionPageMixin, AbstractUser): theme = models.ForeignKey("Theme", null=True, blank=True, on_delete=models.SET_NULL) hide_follows = fields.BooleanField(default=False) + # migration fields + + moved_to = fields.RemoteIdField( + null=True, unique=False, activitypub_field="movedTo" + ) + also_known_as = fields.ManyToManyField( + "self", + symmetrical=True, + activitypub_field="alsoKnownAs", + ) + # options to turn features on and off show_goal = models.BooleanField(default=True) show_suggested_users = models.BooleanField(default=True) @@ -314,6 +325,8 @@ def to_activity(self, **kwargs): "schema": "http://schema.org#", "PropertyValue": "schema:PropertyValue", "value": "schema:value", + "alsoKnownAs": {"@id": "as:alsoKnownAs", "@type": "@id"}, + "movedTo": {"@id": "as:movedTo", "@type": "@id"}, }, ] return activity_object diff --git a/bookwyrm/templates/notifications/item.html b/bookwyrm/templates/notifications/item.html index b2020839af..6c9b295f75 100644 --- a/bookwyrm/templates/notifications/item.html +++ b/bookwyrm/templates/notifications/item.html @@ -36,5 +36,5 @@ {% elif notification.notification_type == 'GROUP_DESCRIPTION' %} {% include 'notifications/items/update.html' %} {% elif notification.notification_type == 'MOVE' %} - {% include 'notifications/items/move.html' %} + {% include 'notifications/items/move_user.html' %} {% endif %} diff --git a/bookwyrm/templates/notifications/items/layout.html b/bookwyrm/templates/notifications/items/layout.html index 8acbb9fec7..41353abcf3 100644 --- a/bookwyrm/templates/notifications/items/layout.html +++ b/bookwyrm/templates/notifications/items/layout.html @@ -39,6 +39,8 @@ {% with related_user=related_users.0.display_name %} {% with related_user_link=related_users.0.local_path %} + {% with related_user_moved_to=related_users.0.moved_to %} + {% with related_user_username=related_users.0.username %} {% with second_user=related_users.1.display_name %} {% with second_user_link=related_users.1.local_path %} {% with other_user_count=related_user_count|add:"-1" %} @@ -50,6 +52,8 @@ {% endwith %} {% endwith %} {% endwith %} + {% endwith %} + {% endwith %} {% if related_status %} diff --git a/bookwyrm/templates/notifications/items/move.html b/bookwyrm/templates/notifications/items/move.html deleted file mode 100644 index ffa23829f2..0000000000 --- a/bookwyrm/templates/notifications/items/move.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends 'notifications/items/layout.html' %} - -{% load i18n %} -{% load utilities %} - -{% block primary_link %}{% spaceless %} - {{ notification.related_object.local_path }} -{% endspaceless %}{% endblock %} - -{% block icon %} - -{% endblock %} - -{% block description %} - - {% blocktrans trimmed with object_name=notification.related_object.name object_path=notification.related_object.local_path %} - {{ related_user }} - moved {{ object_name }} - "{{ object_name }}" - {% endblocktrans %} - - - -{% endblock %} diff --git a/bookwyrm/templates/notifications/items/move_user.html b/bookwyrm/templates/notifications/items/move_user.html new file mode 100644 index 0000000000..39d3af83b3 --- /dev/null +++ b/bookwyrm/templates/notifications/items/move_user.html @@ -0,0 +1,20 @@ +{% extends 'notifications/items/layout.html' %} + +{% load i18n %} +{% load utilities %} +{% load user_page_tags %} + +{% block primary_link %}{% spaceless %} + {{ notification.related_object.local_path }} +{% endspaceless %}{% endblock %} + +{% block icon %} + +{% endblock %} + +{% block description %} + {{ related_user }} {% trans "has moved to" %} {% id_to_username related_user_moved_to %} +
+ {% include 'snippets/move_user_buttons.html' with group=notification.related_group %} +
+{% endblock %} diff --git a/bookwyrm/templates/preferences/alias_user.html b/bookwyrm/templates/preferences/alias_user.html new file mode 100644 index 0000000000..493bf83de9 --- /dev/null +++ b/bookwyrm/templates/preferences/alias_user.html @@ -0,0 +1,56 @@ +{% extends 'preferences/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Move Account" %}{% endblock %} + +{% block header %} +{% trans "Create Alias" %} +{% endblock %} + +{% block panel %} +
+

{% trans "Add another account as an alias" %}

+
+
+

+ {% trans "Marking another account as an alias is required if you want to move that account to this one. This is a reversable action and will not change this account." %} +

+
+
+ {% csrf_token %} +
+ + + {% include 'snippets/form_errors.html' with errors_list=form.password.errors id="desc_password" %} +
+
+ + + {% include 'snippets/form_errors.html' with errors_list=form.username.errors id="desc_username" %} +
+ +
+
+ {% if user.also_known_as.all.0 %} +
+

{% trans "Aliases" %}

+
+ + {% for alias in user.also_known_as.all %} + + + + + {% endfor %} +
{{ alias.username }} +
+ {% csrf_token %} + + +
+
+
+
+ {% endif %} +
+{% endblock %} diff --git a/bookwyrm/templates/preferences/layout.html b/bookwyrm/templates/preferences/layout.html index ca63ec93de..2ef09a2452 100644 --- a/bookwyrm/templates/preferences/layout.html +++ b/bookwyrm/templates/preferences/layout.html @@ -23,6 +23,14 @@ {% url 'prefs-2fa' as url %} {% trans "Two Factor Authentication" %} +
  • + {% url 'prefs-move' as url %} + {% trans "Move Account" %} +
  • +
  • + {% url 'prefs-alias' as url %} + {% trans "Add alias" %} +
  • {% url 'prefs-delete' as url %} {% trans "Delete Account" %} diff --git a/bookwyrm/templates/preferences/move_user.html b/bookwyrm/templates/preferences/move_user.html new file mode 100644 index 0000000000..95fa4811ff --- /dev/null +++ b/bookwyrm/templates/preferences/move_user.html @@ -0,0 +1,41 @@ +{% extends 'preferences/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Move Account" %}{% endblock %} + +{% block header %} +{% trans "Move Account" %} +{% endblock %} + +{% block panel %} +
    +

    {% trans "Migrate account to another server" %}

    +
    +
    +

    + {% trans "Moving your account will notify all your followers and redirect them to the new account." %} +

    +

    + {{ user.username }} {% trans "will be marked as moved and will not be discoverable." %} +

    +
    +
    +

    {% trans "Remember to add this user as an alias of the target account before you try to move." %}

    +
    +
    + {% csrf_token %} +
    + + + {% include 'snippets/form_errors.html' with errors_list=form.password.errors id="desc_password" %} +
    +
    + + + {% include 'snippets/form_errors.html' with errors_list=form.target.errors id="desc_target" %} +
    + +
    +
    +
    +{% endblock %} diff --git a/bookwyrm/templates/settings/users/user_admin.html b/bookwyrm/templates/settings/users/user_admin.html index 9bc5805b1e..a1d93ddd0e 100644 --- a/bookwyrm/templates/settings/users/user_admin.html +++ b/bookwyrm/templates/settings/users/user_admin.html @@ -75,10 +75,17 @@ {{ user.last_active_date }} {% if user.is_active %} - - {% trans "Active" %} + {% if user.moved_to %} + + {% trans "Moved" %} + {% else %} + + {% trans "Active" %} + {% endif %} {% elif user.deactivation_reason == "moderator_deletion" or user.deactivation_reason == "self_deletion" %}
  • - {% url 'prefs-move' as url %} - {% trans "Move Account" %} + {% url 'prefs-alias' as url %} + {% trans "Aliases" %}
  • - {% url 'prefs-alias' as url %} - {% trans "Add alias" %} + {% url 'prefs-move' as url %} + {% trans "Move Account" %}
  • {% url 'prefs-delete' as url %} diff --git a/bookwyrm/templates/preferences/move_user.html b/bookwyrm/templates/preferences/move_user.html index 444e5aa5e7..aa1b9f12d3 100644 --- a/bookwyrm/templates/preferences/move_user.html +++ b/bookwyrm/templates/preferences/move_user.html @@ -13,10 +13,10 @@

    {% trans "Migrate account to another server" %}

    - {% trans "Moving your account will notify all your followers and redirect them to the new account." %} + {% trans "Moving your account will notify all your followers and direct them to follow the new account." %}

    - {{ user.username }} {% trans "will be marked as moved and will not be discoverable." %} + {{ user.username }} {% trans "will be marked as moved and will not be discoverable or usable unless you undo the move." %}

    diff --git a/bookwyrm/templates/shelf/shelf.html b/bookwyrm/templates/shelf/shelf.html index 7d0035ed3b..a2410ef955 100644 --- a/bookwyrm/templates/shelf/shelf.html +++ b/bookwyrm/templates/shelf/shelf.html @@ -18,7 +18,22 @@

    {% include 'user/books_header.html' %}

    - +{% if user.moved_to %} +
    +
    +

    + {% trans "You have have moved to" %} + {% id_to_username user.moved_to %} +

    +

    {% trans "You can undo this move to restore full functionality, but some followers may have already unfollowed this account." %}

    + + {% csrf_token %} + + + +
    +
    +{% else %} @@ -167,11 +168,15 @@
    - {# almost every view needs to know the user shelves #} - {% with request.user.shelf_set.all as user_shelves %} - {% block content %} - {% endblock %} - {% endwith %} + {% if request.user.moved_to %} + {% include "moved.html" %} + {% else %} + {# almost every view needs to know the user shelves #} + {% with request.user.shelf_set.all as user_shelves %} + {% block content %} + {% endblock %} + {% endwith %} + {% endif %}
    diff --git a/bookwyrm/templates/moved.html b/bookwyrm/templates/moved.html new file mode 100644 index 0000000000..fe651fd135 --- /dev/null +++ b/bookwyrm/templates/moved.html @@ -0,0 +1,48 @@ +{% load i18n %} +{% load static %} +{% load utilities %} + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +

    {{ request.user.display_name }}

    +

    {{request.user.username}}

    +
    +
    + +
    +

    + {% blocktrans %} + You have moved your account to + {% endblocktrans %} + {% id_to_username request.user.moved_to %} +

    + {% blocktrans %} +

    You can undo the move to restore full functionality, but some followers may have already unfollowed this account.

    + {% endblocktrans %} +
    +
    +
    +
    +
    + + {% csrf_token %} + + + +
    + {% csrf_token %} + +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/bookwyrm/templates/notifications/items/move_user.html b/bookwyrm/templates/notifications/items/move_user.html index 04163bc12f..ba83ffa9c9 100644 --- a/bookwyrm/templates/notifications/items/move_user.html +++ b/bookwyrm/templates/notifications/items/move_user.html @@ -14,11 +14,15 @@ {% block description %} {% if related_user_moved_to %} - {{ related_user }} {% trans "has moved to" %} {% id_to_username related_user_moved_to %} + {% blocktrans %} + {{ related_user }} has moved to + {% endblocktrans %}{% id_to_username related_user_moved_to %}
    {% include 'snippets/move_user_buttons.html' with group=notification.related_group %}
    {% else %} - {{ related_user }} {% trans "has undone their move" %} + {% blocktrans %} + {{ related_user }} has undone their move + {% endblocktrans %} {% endif %} {% endblock %} diff --git a/bookwyrm/templates/preferences/move_user.html b/bookwyrm/templates/preferences/move_user.html index aa1b9f12d3..47b370e82d 100644 --- a/bookwyrm/templates/preferences/move_user.html +++ b/bookwyrm/templates/preferences/move_user.html @@ -16,7 +16,9 @@

    {% trans "Migrate account to another server" %}

    {% trans "Moving your account will notify all your followers and direct them to follow the new account." %}

    - {{ user.username }} {% trans "will be marked as moved and will not be discoverable or usable unless you undo the move." %} + {% blocktrans %} + {{ user }} will be marked as moved and will not be discoverable or usable unless you undo the move. + {% endblocktrans %}

    From 4d35fd45df803714a41f5fa95779f31b5b16e068 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Fri, 27 Oct 2023 22:22:58 +1100 Subject: [PATCH 11/12] template and migration fixes --- ...924_0821.py => 0182_auto_20231027_1122.py} | 33 +------------------ bookwyrm/templates/layout.html | 8 ++++- bookwyrm/templates/moved.html | 4 +-- .../notifications/items/move_user.html | 5 +-- 4 files changed, 13 insertions(+), 37 deletions(-) rename bookwyrm/migrations/{0182_auto_20230924_0821.py => 0182_auto_20231027_1122.py} (79%) diff --git a/bookwyrm/migrations/0182_auto_20230924_0821.py b/bookwyrm/migrations/0182_auto_20231027_1122.py similarity index 79% rename from bookwyrm/migrations/0182_auto_20230924_0821.py rename to bookwyrm/migrations/0182_auto_20231027_1122.py index 24f25b3926..ab57907a93 100644 --- a/bookwyrm/migrations/0182_auto_20230924_0821.py +++ b/bookwyrm/migrations/0182_auto_20231027_1122.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.20 on 2023-09-24 08:21 +# Generated by Django 3.2.20 on 2023-10-27 11:22 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields @@ -57,37 +57,6 @@ class Migration(migrations.Migration): max_length=255, ), ), - migrations.CreateModel( - name="MoveUserNotification", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("created_date", models.DateTimeField(auto_now_add=True)), - ( - "target", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="moved_user_notification_target", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="moved_user_notifications", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), migrations.CreateModel( name="Move", fields=[ diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 9b726d4ca1..36288911cf 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -26,11 +26,11 @@