mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-09 21:02:24 +01:00
Implement anonimising deletion of users
This commit is contained in:
@ -14,5 +14,12 @@ class UserAdmin(BaseUserAdmin):
|
||||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||
(_('Activation'), {'fields': ('activation_token', 'reset_token')}),
|
||||
)
|
||||
list_display = ('username', 'email', 'name', 'date_joined', 'queue', 'is_staff')
|
||||
list_display = ('username', 'email', 'name', 'date_joined', 'last_login', 'queue', 'is_staff')
|
||||
search_fields = ('username', 'name', 'email')
|
||||
|
||||
def delete_model(self, request, user):
|
||||
user.delete()
|
||||
|
||||
def delete_queryset(self, request, users):
|
||||
for user in users.all():
|
||||
self.delete_model(request, user)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import json
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from songs.models import Song
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import json
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.utils import OperationalError
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import json
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from ...utils import get_first_queue
|
||||
|
||||
79
marietje/marietje/management/commands/old_users.py
Normal file
79
marietje/marietje/management/commands/old_users.py
Normal file
@ -0,0 +1,79 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.utils.timezone import get_default_timezone
|
||||
|
||||
_IMPORTANT_USERNAMES = ['root', 'admin', 'postmaster', 'dsprenkels', 'gmulder', 'bwesterb']
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Get the list of users that has not logged in for quite a while'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--purge',
|
||||
action='store_const',
|
||||
default=False,
|
||||
const=True,
|
||||
help='interactively purge the old users')
|
||||
parser.add_argument(
|
||||
'days_old',
|
||||
nargs='?',
|
||||
type=float,
|
||||
default=365.25,
|
||||
help='amount of days after which a user is considered old')
|
||||
|
||||
def handle(self, purge, *args, **kwargs):
|
||||
if purge:
|
||||
return self.handle_purge_users(*args, **kwargs)
|
||||
else:
|
||||
return self.handle_get_users(*args, **kwargs)
|
||||
|
||||
def handle_purge_users(self, days_old, *args, **kwargs):
|
||||
users = get_old_users(days_old).all()
|
||||
if not users:
|
||||
self.stdout.write(self.style.NOTICE("No users to be deleted"))
|
||||
return
|
||||
|
||||
self.stdout.write("{} {} {}\n".format('username'.ljust(19), 'name'.ljust(29), 'last_login'))
|
||||
for user in users:
|
||||
self.stdout.write("{} {} {}\n".format(user.username.ljust(19), user.name.ljust(29), user.last_login))
|
||||
self.stdout.write("\n")
|
||||
self.stdout.write(self.style.WARNING("I will be removing {} users, please check".format(len(users))))
|
||||
confirmation = input("Type 'YES' to confirm: ")
|
||||
|
||||
for i in range(1, 3):
|
||||
if confirmation == 'YES':
|
||||
break
|
||||
confirmation = input("Please type 'YES' to confirm (or ^C to abort): ")
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(
|
||||
'Aborting purge operation after {} prompts'.format(i + 1)))
|
||||
return
|
||||
|
||||
deleted = 0
|
||||
for i, user in enumerate(users):
|
||||
print("[{: 4.0f}% ] {}".format(100 * i / len(users), user))
|
||||
if user.username in _IMPORTANT_USERNAMES:
|
||||
self.stdout.write(self.style.WARNING("Not deleting user '{}': username looks important".format(user)))
|
||||
continue
|
||||
|
||||
user.delete()
|
||||
deleted += 1
|
||||
self.stdout.write(self.style.SUCCESS("Deleted {} users".format(deleted)))
|
||||
|
||||
def handle_get_users(self, days_old, *args, **kwargs):
|
||||
for user in get_old_users(days_old):
|
||||
self.stdout.write("{}\n".format(user))
|
||||
|
||||
|
||||
def get_old_users(days_old):
|
||||
"""Return a queryset with all users older than an amount of days"""
|
||||
User = get_user_model()
|
||||
tz = get_default_timezone()
|
||||
return User.objects.filter(is_staff=False, is_superuser=False, is_active=True).filter(
|
||||
Q(last_login__lt=datetime.now(tz) - timedelta(days_old))
|
||||
| Q(last_login=None)).order_by('username')
|
||||
@ -1,11 +1,13 @@
|
||||
from django.db import models
|
||||
from queues.models import Queue
|
||||
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import PermissionsMixin
|
||||
from django.contrib.auth.validators import ASCIIUsernameValidator, UnicodeUsernameValidator
|
||||
from django.utils import six, timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.mail import send_mail
|
||||
|
||||
from marietje.utils import get_first_queue
|
||||
|
||||
|
||||
@ -105,6 +107,23 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
verbose_name = _('user')
|
||||
verbose_name_plural = _('users')
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
"""
|
||||
We want to override the deletion behaviour for users, because we want to keep the stats
|
||||
valid. Instead of deleting the user, we will completely anonimise the user's personal
|
||||
data. The user will still have their uploads and queues associated with them, but they are
|
||||
not personal data.
|
||||
|
||||
See also: UserAdmin.delete_queryset(request, queryset)
|
||||
"""
|
||||
self.username = '_deleteduser{:d}'.format(self.id)
|
||||
self.password = make_password(None)
|
||||
self.name = '[deleted]'
|
||||
self.email = ''
|
||||
self.is_active = False
|
||||
self.study = ''
|
||||
self.save(*args, **kwargs)
|
||||
|
||||
def get_full_name(self):
|
||||
return self.name
|
||||
|
||||
|
||||
Reference in New Issue
Block a user