Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • bde/nk20-scripts
1 result
Show changes
Commits on Source (1)
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
import getpass
from time import sleep
from django.conf import settings
from django.contrib.auth.models import User
from django.core.mail import mail_admins
from django.core.management.base import BaseCommand
from django.db import transaction
from django.db.models import Q
from django.test import override_settings
from note.models import Alias, Transaction
class Command(BaseCommand):
"""
This script is used to force delete a user.
THIS IS ONLY ATTENDED TO BE USED TO DELETE FAKE ACCOUNTS THAT
WERE VALIDATED BY ERRORS. Please use data anonymization if you
want to block the account of a user.
"""
def add_arguments(self, parser):
parser.add_argument('user', type=str, nargs='+', help="User id to delete.")
parser.add_argument('--force', '-f', action='store_true',
help="Force the script to have low verbosity.")
parser.add_argument('--doit', '-d', action='store_true',
help="Don't ask for a final confirmation and commit modification. "
"This option should really be used carefully.")
def handle(self, *args, **kwargs):
force = kwargs['force']
if not force:
self.stdout.write(self.style.WARNING("This is a dangerous script. "
"Please use --force to indicate that you known what you are doing. "
"Nothing will be deleted yet."))
sleep(5)
# We need to know who to blame.
qs = User.objects.filter(note__alias__normalized_name=Alias.normalize(getpass.getuser()))
if not qs.exists():
self.stderr.write(self.style.ERROR("I don't know who you are. Please add your linux id as an alias of "
"your own account."))
exit(2)
executor = qs.get()
deleted_users = []
deleted = []
# Don't send mails during the process
with override_settings(EMAIL_BACKEND='django.core.mail.backends.dummy.EmailBackend'):
for user_id in kwargs['user']:
if user_id.isnumeric():
qs = User.objects.filter(pk=int(user_id))
if not qs.exists():
self.stderr.write(self.style.WARNING(f"User {user_id} was not found. Ignoring..."))
continue
user = qs.get()
else:
qs = Alias.objects.filter(normalized_name=Alias.normalize(user_id), note__noteuser__isnull=False)
if not qs.exists():
self.stderr.write(self.style.WARNING(f"User {user_id} was not found. Ignoring..."))
continue
user = qs.get().note.user
with transaction.atomic():
local_deleted = []
# Unlock note to enable modifications
if force and not user.note.is_active:
user.note.is_active = True
user.note.save()
# Deleting transactions
transactions = Transaction.objects.filter(Q(source=user.note) | Q(destination=user.note)).all()
local_deleted += list(transactions)
if kwargs['verbosity'] >= 1:
for tr in transactions:
self.stdout.write(f"Removing {tr}...")
if force:
transactions.delete()
# Deleting memberships
memberships = user.memberships.all()
local_deleted += list(memberships)
if kwargs['verbosity'] >= 1:
for membership in memberships:
self.stdout.write(f"Removing {membership}...")
if force:
memberships.delete()
# Deleting aliases
alias_set = user.note.alias.all()
local_deleted += list(alias_set)
if kwargs['verbosity'] >= 1:
for alias in alias_set:
self.stdout.write(f"Removing alias {alias}...")
if force:
alias_set.delete()
if 'activity' in settings.INSTALLED_APPS:
from activity.models import Guest, Entry
# Deleting activity entries
entries = Entry.objects.filter(Q(note=user.note) | Q(guest__inviter=user.note)).all()
local_deleted += list(entries)
if kwargs['verbosity'] >= 1:
for entry in entries:
self.stdout.write(f"Removing {entry}...")
if force:
entries.delete()
# Deleting invited guests
guests = Guest.objects.filter(inviter=user.note).all()
local_deleted += list(guests)
if kwargs['verbosity'] >= 1:
for guest in guests:
self.stdout.write(f"Removing guest {guest}...")
if force:
guests.delete()
if 'treasury' in settings.INSTALLED_APPS:
from treasury.models import SogeCredit
# Deleting soge credit
credits = SogeCredit.objects.filter(user=user).all()
local_deleted += list(credits)
if kwargs['verbosity'] >= 1:
for credit in credits:
self.stdout.write(f"Removing {credit}...")
if force:
credits.delete()
# Deleting note
local_deleted.append(user.note)
if force:
user.note.delete()
if 'logs' in settings.INSTALLED_APPS:
from logs.models import Changelog
# Replace log executors by the runner of the script
Changelog.objects.filter(user=user).update(user=executor)
# Deleting profile
local_deleted.append(user.profile)
if force:
user.profile.delete()
# Finally deleting user
if force:
user.delete()
local_deleted.append(user)
# This script should really not be used.
if not kwargs['doit'] and not input('You are about to delete real user data. '
'Are you really sure that it is what you want? [y/N] ')\
.lower().startswith('y'):
self.stdout.write(self.style.ERROR("Aborted."))
exit(1)
if kwargs['verbosity'] >= 1:
self.stdout.write(self.style.SUCCESS(f"User {user} deleted."))
deleted_users.append(user)
deleted += local_deleted
if deleted_users:
message = f"Les utilisateurs {deleted_users} ont été supprimés par {executor}.\n\n"
message += "Ont été supprimés en conséquence les objets suivants :\n\n"
for obj in deleted:
message += f"{repr(obj)} (pk: {obj.pk})\n"
mail_admins("Utilisateurs supprimés", message)