undo moves

also cleans up some templates
This commit is contained in:
Hugh Rundle 2023-09-25 22:05:43 +10:00
parent 4fd5e2094a
commit b05f2e99e8
No known key found for this signature in database
GPG key ID: A7E35779918253F9
11 changed files with 80 additions and 21 deletions

View file

@ -13,14 +13,15 @@ User relationship interactions follow the standard ActivityPub spec.
- `Block`: prevent users from seeing one another's statuses, and prevents the blocked user from viewing the actor's profile - `Block`: prevent users from seeing one another's statuses, and prevents the blocked user from viewing the actor's profile
- `Update`: updates a user's profile and settings - `Update`: updates a user's profile and settings
- `Delete`: deactivates a user - `Delete`: deactivates a user
- `Undo`: reverses a `Follow` or `Block` - `Undo`: reverses a `Block` or `Follow`
### Activities ### Activities
- `Create/Status`: saves a new status in the database. - `Create/Status`: saves a new status in the database.
- `Delete/Status`: Removes a status - `Delete/Status`: Removes a status
- `Like/Status`: Creates a favorite on the status - `Like/Status`: Creates a favorite on the status
- `Announce/Status`: Boosts the status into the actor's timeline - `Announce/Status`: Boosts the status into the actor's timeline
- `Undo/*`,: Reverses a `Like` or `Announce` - `Undo/*`,: Reverses an `Announce`, `Like`, or `Move`
- `Move/User`: Moves a user from one ActivityPub id to another.
### Collections ### Collections
User's books and lists are represented by [`OrderedCollection`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) User's books and lists are represented by [`OrderedCollection`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection)

View file

@ -1,9 +1,26 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load utilities %}
{% block title %}{% trans "Updates" %}{% endblock %} {% block title %}{% trans "Updates" %}{% endblock %}
{% block content %} {% block content %}
{% if user.moved_to %}
<div class="container my-6">
<div class="notification is-info has-text-centered">
<p>
{% trans "You have have moved to" %}
<a href="{{user.moved_to}}">{% id_to_username user.moved_to %}</a>
</p>
<p> {% trans "You can undo this move to restore full functionality, but some followers may have already unfollowed this account." %}</p>
<form name="remove-alias" action="{% url 'prefs-unmove' %}" method="post">
{% csrf_token %}
<input type="hidden" name="remote_id" id="remote_id" value="{{user.moved_to}}">
<button type="submit" class="button is-small">{% trans "Undo move" %}</button>
</form>
</div>
</div>
{% else %}
<div class="columns"> <div class="columns">
{% if user.is_authenticated %} {% if user.is_authenticated %}
<div class="column is-one-third"> <div class="column is-one-third">
@ -27,6 +44,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -13,8 +13,12 @@
{% endblock %} {% endblock %}
{% block description %} {% block description %}
{% if related_user_moved_to %}
{{ related_user }} {% trans "has moved to" %} <a href="{{ related_user_moved_to }}">{% id_to_username related_user_moved_to %}</a> {{ related_user }} {% trans "has moved to" %} <a href="{{ related_user_moved_to }}">{% id_to_username related_user_moved_to %}</a>
<div class="row shrink my-2"> <div class="row shrink my-2">
{% include 'snippets/move_user_buttons.html' with group=notification.related_group %} {% include 'snippets/move_user_buttons.html' with group=notification.related_group %}
</div> </div>
{% else %}
{{ related_user }} {% trans "has undone their move" %}
{% endif %}
{% endblock %} {% endblock %}

View file

@ -13,7 +13,10 @@
<div class="box"> <div class="box">
<div class="notification is-info is-light"> <div class="notification is-info is-light">
<p> <p>
{% 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." %} {% trans "Marking another account as an alias is required if you want to move that account to this one." %}
</p>
<p>
{% trans "This is a reversable action and will not change the functionality of this account." %}
</p> </p>
</div> </div>
<form name="alias-user" action="{% url 'prefs-alias' %}" method="post"> <form name="alias-user" action="{% url 'prefs-alias' %}" method="post">

View file

@ -24,12 +24,12 @@
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Two Factor Authentication" %}</a> <a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Two Factor Authentication" %}</a>
</li> </li>
<li> <li>
{% url 'prefs-move' as url %} {% url 'prefs-alias' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Move Account" %}</a> <a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Aliases" %}</a>
</li> </li>
<li> <li>
{% url 'prefs-alias' as url %} {% url 'prefs-move' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Add alias" %}</a> <a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Move Account" %}</a>
</li> </li>
<li> <li>
{% url 'prefs-delete' as url %} {% url 'prefs-delete' as url %}

View file

@ -13,10 +13,10 @@
<div class="box"> <div class="box">
<div class="notification is-danger is-light"> <div class="notification is-danger is-light">
<p> <p>
{% 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." %}
</p> </p>
<p> <p>
<strong>{{ user.username }}</strong> {% trans "will be marked as moved and will not be discoverable." %} <strong>{{ user.username }}</strong> {% trans "will be marked as moved and will not be discoverable or usable unless you undo the move." %}
</p> </p>
</div> </div>
<div class="notification is-info is-light"> <div class="notification is-info is-light">

View file

@ -18,7 +18,22 @@
{% include 'user/books_header.html' %} {% include 'user/books_header.html' %}
</h1> </h1>
</header> </header>
{% if user.moved_to %}
<div class="container my-6">
<div class="notification is-info has-text-centered">
<p>
{% trans "You have have moved to" %}
<a href="{{user.moved_to}}">{% id_to_username user.moved_to %}</a>
</p>
<p> {% trans "You can undo this move to restore full functionality, but some followers may have already unfollowed this account." %}</p>
<form name="remove-alias" action="{% url 'prefs-unmove' %}" method="post">
{% csrf_token %}
<input type="hidden" name="remote_id" id="remote_id" value="{{user.moved_to}}">
<button type="submit" class="button is-small">{% trans "Undo move" %}</button>
</form>
</div>
</div>
{% else %}
<nav class="breadcrumb subtitle" aria-label="breadcrumbs"> <nav class="breadcrumb subtitle" aria-label="breadcrumbs">
<ul> <ul>
<li><a href="{% url 'user-feed' user|username %}">{% trans "User profile" %}</a></li> <li><a href="{% url 'user-feed' user|username %}">{% trans "User profile" %}</a></li>
@ -215,6 +230,7 @@
<div> <div>
{% include 'snippets/pagination.html' with page=books path=request.path %} {% include 'snippets/pagination.html' with page=books path=request.path %}
</div> </div>
{% endif %}
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}

View file

@ -117,8 +117,11 @@ def get_isni(existing, author, autoescape=True):
@register.simple_tag(takes_context=False) @register.simple_tag(takes_context=False)
def id_to_username(user_id): def id_to_username(user_id):
"""given an arbitrary user id, return the username""" """given an arbitrary user id, return the username"""
if user_id:
url = urlparse(user_id) url = urlparse(user_id)
domain = url.netloc domain = url.netloc
parts = url.path.split("/") parts = url.path.split("/")
name = parts[-1] name = parts[-1]
return f"{name}@{domain}" return f"{name}@{domain}"
else:
return None

View file

@ -598,6 +598,7 @@ urlpatterns = [
re_path( re_path(
r"^preferences/remove-alias/?$", views.remove_alias, name="prefs-remove-alias" r"^preferences/remove-alias/?$", views.remove_alias, name="prefs-remove-alias"
), ),
re_path(r"^preferences/unmove/?$", views.unmove, name="prefs-unmove"),
re_path(r"^preferences/delete/?$", views.DeleteUser.as_view(), name="prefs-delete"), re_path(r"^preferences/delete/?$", views.DeleteUser.as_view(), name="prefs-delete"),
re_path( re_path(
r"^preferences/deactivate/?$", r"^preferences/deactivate/?$",

View file

@ -37,7 +37,7 @@ from .admin.user_admin import UserAdmin, UserAdminList, ActivateUserAdmin
from .preferences.change_password import ChangePassword from .preferences.change_password import ChangePassword
from .preferences.edit_user import EditUser from .preferences.edit_user import EditUser
from .preferences.export import Export from .preferences.export import Export
from .preferences.move_user import MoveUser, AliasUser, remove_alias from .preferences.move_user import MoveUser, AliasUser, remove_alias, unmove
from .preferences.delete_user import DeleteUser, DeactivateUser, ReactivateUser from .preferences.delete_user import DeleteUser, DeactivateUser, ReactivateUser
from .preferences.block import Block, unblock from .preferences.block import Block, unblock
from .preferences.two_factor_auth import ( from .preferences.two_factor_auth import (

View file

@ -2,7 +2,7 @@
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views import View from django.views import View
@ -96,3 +96,16 @@ def remove_alias(request):
request.user.also_known_as.remove(request.POST["alias"]) request.user.also_known_as.remove(request.POST["alias"])
return redirect("prefs-alias") return redirect("prefs-alias")
@require_POST
@login_required
def unmove(request):
"""undo a user move"""
target = get_object_or_404(models.User, remote_id=request.POST["remote_id"])
move = get_object_or_404(models.MoveUser, target=target, user=request.user)
move.delete()
request.user.moved_to = None
request.user.save(update_fields=["moved_to"], broadcast=True)
return redirect("prefs-alias")