-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
retire_user.py
100 lines (83 loc) · 4.02 KB
/
retire_user.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# lint-amnesty, pylint: disable=missing-module-docstring
import logging
from django.contrib.auth import get_user_model # lint-amnesty, pylint: disable=unused-import
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from social_django.models import UserSocialAuth
from common.djangoapps.student.models import AccountRecovery, Registration, get_retired_email_by_email
from openedx.core.djangolib.oauth2_retirement_utils import retire_dot_oauth2_models
from ...models import UserRetirementStatus
logger = logging.getLogger(__name__)
class Command(BaseCommand):
"""
Manually move a user into the retirement queue, so that they can be
picked up by the user retirement pipeline. This should only be done in
the case that a user has tried and is unable to delete their account
via the UI.
Most of this code has been lifted from openedx/core/djangoapps/user_api/accounts/views
As this is a fairly sensitive operation, we want to make sure that human
error is accounted for. In order to make sure that something like a typo
during command invocation does not result in the retirement of a
different user, you must supply both the username and email address linked
to the user account.
"""
def add_arguments(self, parser):
parser.add_argument(
'--username',
required=True,
type=str,
help='Username to be retired'
)
parser.add_argument(
'--user_email',
required=True,
type=str,
help='User email address.'
)
def handle(self, *args, **options):
"""
Execute the command.
"""
username = options['username']
user_email = options['user_email']
try:
user = User.objects.get(username=username, email=user_email)
except:
error_message = (
'Could not find a user with specified username and email '
'address. Make sure you have everything correct before '
'trying again'
)
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from
user_model = get_user_model()
try:
with transaction.atomic():
# Add user to retirement queue.
UserRetirementStatus.create_retirement(user)
# Unlink LMS social auth accounts
UserSocialAuth.objects.filter(user_id=user.id).delete()
# Change LMS password & email
user.email = get_retired_email_by_email(user.email)
user.set_unusable_password()
user.save()
# TODO: Unlink social accounts & change password on each IDA.
# Remove the activation keys sent by email to the user for account activation.
Registration.objects.filter(user=user).delete()
# Delete OAuth tokens associated with the user.
retire_dot_oauth2_models(user)
AccountRecovery.retire_recovery_email(user.id)
except KeyError:
error_message = f'Username not specified {user}'
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from
except user_model.DoesNotExist:
error_message = f'The user "{user.username}" does not exist.'
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from
except Exception as exc: # pylint: disable=broad-except
error_message = f'500 error deactivating account {exc}'
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from
logger.info("User succesfully moved to the retirment pipeline")