Coverage for website/utils/management/commands/createsuperuser.py: 0.00%
116 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1import getpass
2import os
3import sys
5from django.contrib.auth.management import get_default_username
6from django.contrib.auth.management.commands.createsuperuser import PASSWORD_FIELD
7from django.contrib.auth.management.commands.createsuperuser import (
8 Command as OriginalCommand,
9)
10from django.contrib.auth.management.commands.createsuperuser import (
11 NotRunningInTTYException,
12)
13from django.contrib.auth.password_validation import validate_password
14from django.core import exceptions
15from django.core.management.base import CommandError
16from django.utils import timezone
17from django.utils.text import capfirst
19from members.models.membership import Membership
20from members.models.profile import Profile
23class Command(OriginalCommand):
24 # Copied from django/contrib/auth/management/commands/createsuperuser.py
25 def handle(self, *args, **options):
26 username = options[self.UserModel.USERNAME_FIELD]
27 database = options["database"]
28 user_data = {}
29 verbose_field_name = self.username_field.verbose_name
30 try:
31 self.UserModel._meta.get_field(PASSWORD_FIELD)
32 except exceptions.FieldDoesNotExist:
33 pass
34 else:
35 # If not provided, create the user with an unusable password.
36 user_data[PASSWORD_FIELD] = None
37 try:
38 if options["interactive"]:
39 # Same as user_data but without many to many fields and with
40 # foreign keys as fake model instances instead of raw IDs.
41 fake_user_data = {}
42 if hasattr(self.stdin, "isatty") and not self.stdin.isatty():
43 raise NotRunningInTTYException
44 default_username = get_default_username(database=database)
45 if username:
46 error_msg = self._validate_username(
47 username, verbose_field_name, database
48 )
49 if error_msg:
50 self.stderr.write(error_msg)
51 username = None
52 elif username == "":
53 raise CommandError(
54 f"{capfirst(verbose_field_name)} cannot be blank."
55 )
56 # Prompt for username.
57 while username is None:
58 message = self._get_input_message(
59 self.username_field, default_username
60 )
61 username = self.get_input_data(
62 self.username_field, message, default_username
63 )
64 if username:
65 error_msg = self._validate_username(
66 username, verbose_field_name, database
67 )
68 if error_msg:
69 self.stderr.write(error_msg)
70 username = None
71 continue
72 user_data[self.UserModel.USERNAME_FIELD] = username
73 fake_user_data[self.UserModel.USERNAME_FIELD] = (
74 self.username_field.remote_field.model(username)
75 if self.username_field.remote_field
76 else username
77 )
78 # Prompt for required fields.
79 for field_name in self.UserModel.REQUIRED_FIELDS:
80 field = self.UserModel._meta.get_field(field_name)
81 user_data[field_name] = options[field_name]
82 if user_data[field_name] is not None:
83 user_data[field_name] = field.clean(user_data[field_name], None)
84 while user_data[field_name] is None:
85 message = self._get_input_message(field)
86 input_value = self.get_input_data(field, message)
87 user_data[field_name] = input_value
88 if field.many_to_many and input_value:
89 if not input_value.strip():
90 user_data[field_name] = None
91 self.stderr.write("Error: This field cannot be blank.")
92 continue
93 user_data[field_name] = [
94 pk.strip() for pk in input_value.split(",")
95 ]
97 if not field.many_to_many:
98 fake_user_data[field_name] = user_data[field_name]
99 # Wrap any foreign keys in fake model instances.
100 if field.many_to_one:
101 fake_user_data[field_name] = field.remote_field.model(
102 user_data[field_name]
103 )
105 # Prompt for a password if the model has one.
106 while PASSWORD_FIELD in user_data and user_data[PASSWORD_FIELD] is None:
107 password = getpass.getpass()
108 password2 = getpass.getpass("Password (again): ")
109 if password != password2:
110 self.stderr.write("Error: Your passwords didn't match.")
111 # Don't validate passwords that don't match.
112 continue
113 if password.strip() == "":
114 self.stderr.write("Error: Blank passwords aren't allowed.")
115 # Don't validate blank passwords.
116 continue
117 try:
118 validate_password(password2, self.UserModel(**fake_user_data))
119 except exceptions.ValidationError as err:
120 self.stderr.write("\n".join(err.messages))
121 response = input(
122 "Bypass password validation and create user anyway? [y/N]: "
123 )
124 if response.lower() != "y":
125 continue
126 user_data[PASSWORD_FIELD] = password
127 else:
128 # Non-interactive mode.
129 # Use password from environment variable, if provided.
130 if (
131 PASSWORD_FIELD in user_data
132 and "DJANGO_SUPERUSER_PASSWORD" in os.environ
133 ):
134 user_data[PASSWORD_FIELD] = os.environ["DJANGO_SUPERUSER_PASSWORD"]
135 # Use username from environment variable, if not provided in
136 # options.
137 if username is None:
138 username = os.environ.get(
139 "DJANGO_SUPERUSER_" + self.UserModel.USERNAME_FIELD.upper()
140 )
141 if username is None:
142 raise CommandError(
143 f"You must use --{self.UserModel.USERNAME_FIELD} with --noinput."
144 )
145 else:
146 error_msg = self._validate_username(
147 username, verbose_field_name, database
148 )
149 if error_msg:
150 raise CommandError(error_msg)
152 user_data[self.UserModel.USERNAME_FIELD] = username
153 for field_name in self.UserModel.REQUIRED_FIELDS:
154 env_var = "DJANGO_SUPERUSER_" + field_name.upper()
155 value = options[field_name] or os.environ.get(env_var)
156 if not value:
157 raise CommandError(
158 f"You must use --{field_name} with --noinput.."
159 )
160 field = self.UserModel._meta.get_field(field_name)
161 user_data[field_name] = field.clean(value, None)
162 if field.many_to_many and isinstance(user_data[field_name], str):
163 user_data[field_name] = [
164 pk.strip() for pk in user_data[field_name].split(",")
165 ]
167 user = self.UserModel._default_manager.db_manager(
168 database
169 ).create_superuser(**user_data)
170 # Changed from django/contrib/auth/management/commands/createsuperuser.py
171 Profile.objects.create(user=user)
172 Membership.objects.create(
173 user=user, type=Membership.MEMBER, since=timezone.now()
174 )
176 if options["verbosity"] >= 1:
177 self.stdout.write("Member created successfully.")
178 except KeyboardInterrupt:
179 self.stderr.write("\nOperation cancelled.")
180 sys.exit(1)
181 except exceptions.ValidationError as e:
182 raise CommandError("; ".join(e.messages))
183 except NotRunningInTTYException:
184 self.stdout.write(
185 "Member creation skipped due to not running in a TTY. "
186 "You can run `manage.py createmember` in your project "
187 "to create one manually."
188 )