mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-06-03 05:49:35 +00:00
Erase user data and statuses on account deletion
This commit is contained in:
parent
95ba38524b
commit
93a7dd9cf3
|
@ -1,6 +1,7 @@
|
||||||
""" database schema for user data """
|
""" database schema for user data """
|
||||||
import re
|
import re
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
|
@ -394,10 +395,31 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||||
"""We don't actually delete the database entry"""
|
"""We don't actually delete the database entry"""
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.is_active = False
|
self.is_active = False
|
||||||
self.avatar = ""
|
self.allow_reactivation = False
|
||||||
|
|
||||||
|
self.erase_user_data()
|
||||||
|
self.erase_user_statuses()
|
||||||
|
|
||||||
# skip the logic in this class's save()
|
# skip the logic in this class's save()
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def erase_user_data(self):
|
||||||
|
"""Wipe a user's custom data"""
|
||||||
|
# mangle email address
|
||||||
|
self.email = f"{uuid4()}@deleted.user"
|
||||||
|
|
||||||
|
# erase data fields
|
||||||
|
self.avatar = ""
|
||||||
|
self.preview_image = ""
|
||||||
|
self.summary = None
|
||||||
|
self.name = None
|
||||||
|
self.favorites.set([])
|
||||||
|
|
||||||
|
def erase_user_statuses(self):
|
||||||
|
"""Wipe the data on all the user's statuses"""
|
||||||
|
for status in self.status_set.all():
|
||||||
|
status.delete()
|
||||||
|
|
||||||
def deactivate(self):
|
def deactivate(self):
|
||||||
"""Disable the user but allow them to reactivate"""
|
"""Disable the user but allow them to reactivate"""
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
|
|
@ -26,6 +26,7 @@ class User(TestCase):
|
||||||
local=True,
|
local=True,
|
||||||
localname="mouse",
|
localname="mouse",
|
||||||
name="hi",
|
name="hi",
|
||||||
|
summary="a summary",
|
||||||
bookwyrm_user=False,
|
bookwyrm_user=False,
|
||||||
)
|
)
|
||||||
self.another_user = models.User.objects.create_user(
|
self.another_user = models.User.objects.create_user(
|
||||||
|
@ -218,19 +219,52 @@ class User(TestCase):
|
||||||
|
|
||||||
@patch("bookwyrm.suggested_users.remove_user_task.delay")
|
@patch("bookwyrm.suggested_users.remove_user_task.delay")
|
||||||
def test_delete_user(self, _):
|
def test_delete_user(self, _):
|
||||||
"""deactivate a user"""
|
"""permanently delete a user"""
|
||||||
self.assertTrue(self.user.is_active)
|
self.assertTrue(self.user.is_active)
|
||||||
|
self.assertEqual(self.user.name, "hi")
|
||||||
|
self.assertEqual(self.user.summary, "a summary")
|
||||||
|
self.assertEqual(self.user.email, "mouse@mouse.mouse")
|
||||||
with patch(
|
with patch(
|
||||||
"bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"
|
"bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"
|
||||||
) as broadcast_mock:
|
) as broadcast_mock, patch(
|
||||||
|
"bookwyrm.models.user.User.erase_user_statuses"
|
||||||
|
) as erase_statuses_mock:
|
||||||
self.user.delete()
|
self.user.delete()
|
||||||
|
|
||||||
|
self.assertEqual(erase_statuses_mock.call_count, 1)
|
||||||
|
|
||||||
|
# make sure the deletion is broadcast
|
||||||
self.assertEqual(broadcast_mock.call_count, 1)
|
self.assertEqual(broadcast_mock.call_count, 1)
|
||||||
activity = json.loads(broadcast_mock.call_args[1]["args"][1])
|
activity = json.loads(broadcast_mock.call_args[1]["args"][1])
|
||||||
self.assertEqual(activity["type"], "Delete")
|
self.assertEqual(activity["type"], "Delete")
|
||||||
self.assertEqual(activity["object"], self.user.remote_id)
|
self.assertEqual(activity["object"], self.user.remote_id)
|
||||||
|
|
||||||
|
self.user.refresh_from_db()
|
||||||
|
|
||||||
|
# the user's account data should be deleted
|
||||||
|
self.assertIsNone(self.user.name)
|
||||||
|
self.assertIsNone(self.user.summary)
|
||||||
|
self.assertNotEqual(self.user.email, "mouse@mouse.mouse")
|
||||||
self.assertFalse(self.user.is_active)
|
self.assertFalse(self.user.is_active)
|
||||||
|
|
||||||
|
@patch("bookwyrm.suggested_users.remove_user_task.delay")
|
||||||
|
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
|
||||||
|
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||||
|
@patch("bookwyrm.activitystreams.remove_status_task.delay")
|
||||||
|
def test_delete_user_erase_statuses(self, *_):
|
||||||
|
"""erase user statuses when user is deleted"""
|
||||||
|
status = models.Status.objects.create(user=self.user, content="hello")
|
||||||
|
self.assertFalse(status.deleted)
|
||||||
|
self.assertIsNotNone(status.content)
|
||||||
|
self.assertIsNone(status.deleted_date)
|
||||||
|
|
||||||
|
self.user.delete()
|
||||||
|
status.refresh_from_db()
|
||||||
|
|
||||||
|
self.assertTrue(status.deleted)
|
||||||
|
self.assertIsNone(status.content)
|
||||||
|
self.assertIsNotNone(status.deleted_date)
|
||||||
|
|
||||||
def test_admins_no_admins(self):
|
def test_admins_no_admins(self):
|
||||||
"""list of admins"""
|
"""list of admins"""
|
||||||
result = models.User.admins()
|
result = models.User.admins()
|
||||||
|
|
Loading…
Reference in a new issue