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.contrib.postgres.fields import ArrayField, CICharField
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.dispatch import receiver 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 import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from model_utils import FieldTracker from model_utils import FieldTracker
@ -263,6 +263,13 @@ class User(OrderedCollectionPageMixin, AbstractUser):
is_active=True, is_active=True,
).distinct() ).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): def update_active_date(self):
"""this user is here! they are doing things!""" """this user is here! they are doing things!"""
self.last_active_date = timezone.now() self.last_active_date = timezone.now()
@ -415,10 +422,24 @@ class User(OrderedCollectionPageMixin, AbstractUser):
self.name = None self.name = None
self.favorites.set([]) self.favorites.set([])
def erase_user_statuses(self): def erase_user_statuses(self, broadcast=True):
"""Wipe the data on all the user's statuses""" """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(): 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): def deactivate(self):
"""Disable the user but allow them to reactivate""" """Disable the user but allow them to reactivate"""

View file

@ -2,6 +2,7 @@
import json import json
from unittest.mock import patch from unittest.mock import patch
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.db import IntegrityError
from django.test import TestCase from django.test import TestCase
import responses import responses
@ -265,6 +266,25 @@ class User(TestCase):
self.assertIsNone(status.content) self.assertIsNone(status.content)
self.assertIsNotNone(status.deleted_date) 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): def test_admins_no_admins(self):
"""list of admins""" """list of admins"""
result = models.User.admins() result = models.User.admins()
@ -302,3 +322,40 @@ class User(TestCase):
results = models.User.admins() results = models.User.admins()
self.assertEqual(results.count(), 1) self.assertEqual(results.count(), 1)
self.assertEqual(results.first(), self.user) 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())