Merge pull request #955 from bookwyrm-social/delete-user-errors

Delete user errors
This commit is contained in:
Mouse Reeve 2021-04-17 15:29:23 -07:00 committed by GitHub
commit b53c2c2196
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 10 deletions

View file

@ -16,11 +16,10 @@ class Verb(ActivityObject):
def action(self): def action(self):
""" usually we just want to update and save """ """ usually we just want to update and save """
obj = self.object # self.object may return None if the object is invalid in an expected way
# it may return None if the object is invalid in an expected way
# ie, Question type # ie, Question type
if obj: if self.object:
obj.to_model() self.object.to_model()
@dataclass(init=False) @dataclass(init=False)
@ -43,7 +42,16 @@ class Delete(Verb):
def action(self): def action(self):
""" find and delete the activity object """ """ find and delete the activity object """
obj = self.object.to_model(save=False, allow_create=False) if not self.object:
return
if isinstance(self.object, str):
# Deleted users are passed as strings. Not wild about this fix
model = apps.get_model("bookwyrm.User")
obj = model.find_existing_by_remote_id(self.object)
else:
obj = self.object.to_model(save=False, allow_create=False)
if obj: if obj:
obj.delete() obj.delete()
# if we can't find it, we don't need to delete it because we don't have it # if we can't find it, we don't need to delete it because we don't have it
@ -58,8 +66,7 @@ class Update(Verb):
def action(self): def action(self):
""" update a model instance from the dataclass """ """ update a model instance from the dataclass """
obj = self.object if self.object:
if obj:
self.object.to_model(allow_create=False) self.object.to_model(allow_create=False)

View file

@ -241,7 +241,9 @@ class ObjectMixin(ActivitypubMixin):
return return
# is this a deletion? # is this a deletion?
if hasattr(self, "deleted") and self.deleted: if (hasattr(self, "deleted") and self.deleted) or (
hasattr(self, "is_active") and not self.is_active
):
activity = self.to_delete_activity(user) activity = self.to_delete_activity(user)
else: else:
activity = self.to_update_activity(user) activity = self.to_update_activity(user)

View file

@ -205,6 +205,9 @@ class User(OrderedCollectionPageMixin, AbstractUser):
def to_activity(self, **kwargs): def to_activity(self, **kwargs):
"""override default AP serializer to add context object """override default AP serializer to add context object
idk if this is the best way to go about this""" idk if this is the best way to go about this"""
if not self.is_active:
return self.remote_id
activity_object = super().to_activity(**kwargs) activity_object = super().to_activity(**kwargs)
activity_object["@context"] = [ activity_object["@context"] = [
"https://www.w3.org/ns/activitystreams", "https://www.w3.org/ns/activitystreams",
@ -283,6 +286,12 @@ class User(OrderedCollectionPageMixin, AbstractUser):
editable=False, editable=False,
).save(broadcast=False) ).save(broadcast=False)
def delete(self, *args, **kwargs):
""" deactivate rather than delete a user """
self.is_active = False
# skip the logic in this class's save()
super().save(*args, **kwargs)
@property @property
def local_path(self): def local_path(self):
""" this model doesn't inherit bookwyrm model, so here we are """ """ this model doesn't inherit bookwyrm model, so here we are """

View file

@ -1,4 +1,5 @@
""" testing models """ """ testing models """
import json
from unittest.mock import patch from unittest.mock import patch
from django.test import TestCase from django.test import TestCase
import responses import responses
@ -152,3 +153,17 @@ class User(TestCase):
self.assertEqual(server.server_name, DOMAIN) self.assertEqual(server.server_name, DOMAIN)
self.assertIsNone(server.application_type) self.assertIsNone(server.application_type)
self.assertIsNone(server.application_version) self.assertIsNone(server.application_version)
def test_delete_user(self):
""" deactivate a user """
self.assertTrue(self.user.is_active)
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as broadcast_mock:
self.user.delete()
self.assertEqual(broadcast_mock.call_count, 1)
activity = json.loads(broadcast_mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["object"], self.user.remote_id)
self.assertFalse(self.user.is_active)

View file

@ -49,7 +49,7 @@ class InboxActivities(TestCase):
} }
models.SiteSettings.objects.create() models.SiteSettings.objects.create()
def test_handle_delete_status(self): def test_delete_status(self):
""" remove a status """ """ remove a status """
self.assertFalse(self.status.deleted) self.assertFalse(self.status.deleted)
activity = { activity = {
@ -70,7 +70,7 @@ class InboxActivities(TestCase):
self.assertTrue(status.deleted) self.assertTrue(status.deleted)
self.assertIsInstance(status.deleted_date, datetime) self.assertIsInstance(status.deleted_date, datetime)
def test_handle_delete_status_notifications(self): def test_delete_status_notifications(self):
""" remove a status with related notifications """ """ remove a status with related notifications """
models.Notification.objects.create( models.Notification.objects.create(
related_status=self.status, related_status=self.status,
@ -104,3 +104,34 @@ class InboxActivities(TestCase):
# notifications should be truly deleted # notifications should be truly deleted
self.assertEqual(models.Notification.objects.count(), 1) self.assertEqual(models.Notification.objects.count(), 1)
self.assertEqual(models.Notification.objects.get(), notif) self.assertEqual(models.Notification.objects.get(), notif)
def test_delete_user(self):
""" delete a user """
self.assertTrue(models.User.objects.get(username="rat@example.com").is_active)
activity = {
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/test-user#delete",
"type": "Delete",
"actor": "https://example.com/users/test-user",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"object": self.remote_user.remote_id,
}
views.inbox.activity_task(activity)
self.assertFalse(models.User.objects.get(username="rat@example.com").is_active)
def test_delete_user_unknown(self):
""" don't worry about it if we don't know the user """
self.assertEqual(models.User.objects.filter(is_active=True).count(), 2)
activity = {
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/test-user#delete",
"type": "Delete",
"actor": "https://example.com/users/test-user",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"object": "https://example.com/users/test-user",
}
# nothing happens.
views.inbox.activity_task(activity)
self.assertEqual(models.User.objects.filter(is_active=True).count(), 2)