Adds migration and more tests

This commit is contained in:
Mouse Reeve 2023-11-05 08:51:42 -08:00
parent 5e42afd85a
commit 61caeed5a3
3 changed files with 106 additions and 3 deletions

View file

@ -0,0 +1,25 @@
# Generated by Django 3.2.20 on 2023-11-05 16:07
from django.db import migrations
from bookwyrm.models import User
def erase_deleted_user_data(apps, schema_editor):
"""Retroactively clear user data"""
for user in User.get_permanently_deleted_users():
user.erase_user_data()
user.save(broadcast=False)
user.erase_user_statuses(broadcast=False)
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0182_auto_20231027_1122"),
]
operations = [
migrations.RunPython(
erase_deleted_user_data, reverse_code=migrations.RunPython.noop
)
]

View file

@ -8,7 +8,7 @@ from django.contrib.auth.models import AbstractUser
from django.contrib.postgres.fields import ArrayField, CICharField
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.dispatch import receiver
from django.db import models, transaction
from django.db import models, transaction, IntegrityError
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from model_utils import FieldTracker
@ -263,6 +263,13 @@ class User(OrderedCollectionPageMixin, AbstractUser):
is_active=True,
).distinct()
@classmethod
def get_permanently_deleted_users(cls):
return cls.objects.filter(
is_active=False,
deactivation_reason__in=["self_deletion", "moderator_deletion"],
).distinct()
def update_active_date(self):
"""this user is here! they are doing things!"""
self.last_active_date = timezone.now()
@ -415,10 +422,24 @@ class User(OrderedCollectionPageMixin, AbstractUser):
self.name = None
self.favorites.set([])
def erase_user_statuses(self):
def erase_user_statuses(self, broadcast=True):
"""Wipe the data on all the user's statuses"""
# safety valve: make sure the user is deleted
if not self.is_permanently_deleted:
raise IntegrityError(
"Attempted to delete statuses for improperly deleted user"
)
for status in self.status_set.all():
status.delete()
status.delete(broadcast=broadcast)
@property
def is_permanently_deleted(self):
"""is this user inactive, or really truly deleted?"""
return not self.is_active and self.deactivation_reason in [
"self_deletion",
"moderator_deletion",
]
def deactivate(self):
"""Disable the user but allow them to reactivate"""

View file

@ -2,6 +2,7 @@
import json
from unittest.mock import patch
from django.contrib.auth.models import Group
from django.db import IntegrityError
from django.test import TestCase
import responses
@ -265,6 +266,25 @@ class User(TestCase):
self.assertIsNone(status.content)
self.assertIsNotNone(status.deleted_date)
@patch("bookwyrm.suggested_users.remove_user_task.delay")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
@patch("bookwyrm.activitystreams.add_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.deactivate()
with self.assertRaises(IntegrityError):
self.user.erase_user_statuses()
status.refresh_from_db()
self.assertFalse(status.deleted)
self.assertIsNotNone(status.content)
self.assertIsNone(status.deleted_date)
def test_admins_no_admins(self):
"""list of admins"""
result = models.User.admins()
@ -302,3 +322,40 @@ class User(TestCase):
results = models.User.admins()
self.assertEqual(results.count(), 1)
self.assertEqual(results.first(), self.user)
def test_get_permanently_deleted_users(self):
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
active_user = models.User.objects.create_user(
f"activeuser@{DOMAIN}",
"activeuser@activeuser.activeuser",
"activeuserword",
local=True,
localname="active",
)
deleted_user = models.User.objects.create_user(
f"deleteduser@{DOMAIN}",
"deleteduser@deleteduser.deleteduser",
"deleteduserword",
local=True,
localname="deleted",
is_active=False,
deactivation_reason="self_deletion",
)
inactive_user = models.User.objects.create_user(
f"inactiveuser@{DOMAIN}",
"inactiveuser@inactiveuser.inactiveuser",
"inactiveuserword",
local=True,
localname="inactive",
is_active=False,
deactivation_reason="self_deactivation",
)
deleted_users = models.User.get_permanently_deleted_users()
self.assertTrue(deleted_users.filter(localname="deleted").exists())
self.assertFalse(deleted_users.filter(localname="active").exists())
self.assertFalse(deleted_users.filter(localname="inactive").exists())