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

1import getpass 

2import os 

3import sys 

4 

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 

18 

19from members.models.membership import Membership 

20from members.models.profile import Profile 

21 

22 

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 ] 

96 

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 ) 

104 

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) 

151 

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 ] 

166 

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 ) 

175 

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 )