From 048339c7a2f54e5141c72f871ddaef42b4c84e82 Mon Sep 17 00:00:00 2001 From: Eliot Berriot <contact@eliotberriot.com> Date: Tue, 30 Apr 2019 14:46:05 +0200 Subject: [PATCH] Fix #809: Added admin options to disable login for users, ensure related content is deleted when deleting a user account --- api/funkwhale_api/users/admin.py | 17 ++++++++++- api/funkwhale_api/users/models.py | 7 +++++ api/tests/users/test_models.py | 10 +++++++ changes/changelog.d/809.enhancement | 1 + .../views/admin/moderation/AccountsDetail.vue | 29 +++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 changes/changelog.d/809.enhancement diff --git a/api/funkwhale_api/users/admin.py b/api/funkwhale_api/users/admin.py index 303f4f9c..c11c33bb 100644 --- a/api/funkwhale_api/users/admin.py +++ b/api/funkwhale_api/users/admin.py @@ -33,6 +33,20 @@ class MyUserCreationForm(UserCreationForm): raise forms.ValidationError(self.error_messages["duplicate_username"]) +def disable(modeladmin, request, queryset): + queryset.exclude(pk=request.user.pk).update(is_active=False) + + +disable.short_description = "Disable login" + + +def enable(modeladmin, request, queryset): + queryset.update(is_active=True) + + +enable.short_description = "Enable login" + + @admin.register(models.User) class UserAdmin(AuthUserAdmin): form = MyUserChangeForm @@ -40,6 +54,7 @@ class UserAdmin(AuthUserAdmin): list_display = [ "username", "email", + "is_active", "date_joined", "last_login", "is_staff", @@ -53,7 +68,7 @@ class UserAdmin(AuthUserAdmin): "permission_library", "permission_moderation", ] - + actions = [disable, enable] fieldsets = ( (None, {"fields": ("username", "password", "privacy_level")}), ( diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py index 8ef06c87..3748dd63 100644 --- a/api/funkwhale_api/users/models.py +++ b/api/funkwhale_api/users/models.py @@ -388,3 +388,10 @@ def warm_user_avatar(sender, instance, **kwargs): instance_or_queryset=instance, rendition_key_set="square", image_attr="avatar" ) num_created, failed_to_create = user_avatar_warmer.warm() + + +@receiver(models.signals.pre_delete, sender=User) +def delete_actor(sender, instance, **kwargs): + if not instance.actor: + return + instance.actor.delete() diff --git a/api/tests/users/test_models.py b/api/tests/users/test_models.py index 4b2f71bc..1b185e55 100644 --- a/api/tests/users/test_models.py +++ b/api/tests/users/test_models.py @@ -219,3 +219,13 @@ def test_user_get_quota_status(factories, preferences, mocker): "errored": 3, "finished": 4, } + + +def test_deleting_users_deletes_associated_actor(factories): + actor = factories["federation.Actor"]() + user = factories["users.User"](actor=actor) + + user.delete() + + with pytest.raises(actor.DoesNotExist): + actor.refresh_from_db() diff --git a/changes/changelog.d/809.enhancement b/changes/changelog.d/809.enhancement new file mode 100644 index 00000000..92a4e57b --- /dev/null +++ b/changes/changelog.d/809.enhancement @@ -0,0 +1 @@ +Added admin options to disable login for users, ensure related content is deleted when deleting a user account (#809) diff --git a/front/src/views/admin/moderation/AccountsDetail.vue b/front/src/views/admin/moderation/AccountsDetail.vue index d863af52..09b5bb82 100644 --- a/front/src/views/admin/moderation/AccountsDetail.vue +++ b/front/src/views/admin/moderation/AccountsDetail.vue @@ -27,6 +27,35 @@ </div> </div> </h2> + <div class="header-buttons"> + <div class="ui icon buttons"> + <a + v-if="object.user && $store.state.auth.profile && $store.state.auth.profile.is_superuser" + class="ui labeled icon button" + :href="$store.getters['instance/absoluteUrl'](`/api/admin/users/user/${object.user.id}`)" + target="_blank" rel="noopener noreferrer"> + <i class="wrench icon"></i> + <translate translate-context="Content/Moderation/Link/Verb">View in Django's admin</translate> + </a> + <a + v-else-if="$store.state.auth.profile && $store.state.auth.profile.is_superuser" + class="ui labeled icon button" + :href="$store.getters['instance/absoluteUrl'](`/api/admin/federation/actor/${object.id}`)" + target="_blank" rel="noopener noreferrer"> + <i class="wrench icon"></i> + <translate translate-context="Content/Moderation/Link/Verb">View in Django's admin</translate> + </a> + <div class="ui floating dropdown icon button" v-dropdown> + <i class="dropdown icon"></i> + <div class="menu"> + <a class="basic item" :href="object.url || object.fid" target="_blank" rel="noopener noreferrer"> + <i class="external icon"></i> + <translate translate-context="Content/Moderation/Link/Verb">Open remote profile</translate> + </a> + </div> + </div> + </div> + </div> </div> </div> <div class="ui column"> -- GitLab