createsuperuser.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. Misago-native rehash of Django's createsuperuser command that
  3. works with double authentication fields on user model
  4. """
  5. import sys
  6. from getpass import getpass
  7. from django.contrib.auth import get_user_model
  8. from django.contrib.auth.password_validation import validate_password
  9. from django.core.exceptions import ValidationError
  10. from django.core.management.base import BaseCommand
  11. from django.db import DEFAULT_DB_ALIAS, IntegrityError
  12. from django.utils.encoding import force_str
  13. from django.utils.six.moves import input
  14. from misago.users.validators import validate_email, validate_username
  15. UserModel = get_user_model()
  16. class NotRunningInTTYException(Exception):
  17. pass
  18. class Command(BaseCommand):
  19. help = 'Used to create a superuser.'
  20. def add_arguments(self, parser):
  21. parser.add_argument('--username', dest='username', default=None,
  22. help='Specifies the username for the superuser.')
  23. parser.add_argument('--email', dest='email', default=None,
  24. help='Specifies the username for the superuser.')
  25. parser.add_argument('--password', dest='password', default=None,
  26. help='Specifies the username for the superuser.')
  27. parser.add_argument('--noinput', action='store_false', dest='interactive',
  28. default=True,
  29. help=('Tells Misago to NOT prompt the user for input '
  30. 'of any kind. You must use --username with '
  31. '--noinput, along with an option for any other '
  32. 'required field. Superusers created with '
  33. '--noinput will not be able to log in until '
  34. 'they\'re given a valid password.'))
  35. parser.add_argument('--database', action='store', dest='database',
  36. default=DEFAULT_DB_ALIAS,
  37. help=('Specifies the database to use. '
  38. 'Default is "default".'))
  39. def execute(self, *args, **options):
  40. self.stdin = options.get('stdin', sys.stdin) # Used for testing
  41. return super(Command, self).execute(*args, **options)
  42. def handle(self, *args, **options):
  43. username = options.get('username')
  44. email = options.get('email')
  45. password = options.get('password')
  46. interactive = options.get('interactive')
  47. verbosity = int(options.get('verbosity', 1))
  48. # Validate initial inputs
  49. if username is not None:
  50. try:
  51. username = username.strip()
  52. validate_username(username)
  53. except ValidationError as e:
  54. self.stderr.write(e.messages[0])
  55. username = None
  56. if email is not None:
  57. try:
  58. email = email.strip()
  59. validate_email(email)
  60. except ValidationError as e:
  61. self.stderr.write(e.messages[0])
  62. email = None
  63. if password is not None:
  64. try:
  65. password = password.strip()
  66. validate_password(password)
  67. except ValidationError as e:
  68. self.stderr.write(e.messages[0])
  69. password = None
  70. if not interactive:
  71. if username and email and password:
  72. # Call User manager's create_superuser using our wrapper
  73. self.create_superuser(username, email, password, verbosity)
  74. else:
  75. try:
  76. if hasattr(self.stdin, 'isatty') and not self.stdin.isatty():
  77. raise NotRunningInTTYException("Not running in a TTY")
  78. # Prompt for username/password, and any other required fields.
  79. # Enclose this whole thing in a try/except to trap for a
  80. # keyboard interrupt and exit gracefully.
  81. while not username:
  82. try:
  83. message = force_str("Enter displayed username: ")
  84. raw_value = input(message).strip()
  85. validate_username(raw_value)
  86. username = raw_value
  87. except ValidationError as e:
  88. self.stderr.write(e.messages[0])
  89. while not email:
  90. try:
  91. raw_value = input("Enter E-mail address: ").strip()
  92. validate_email(raw_value)
  93. email = raw_value
  94. except ValidationError as e:
  95. self.stderr.write(e.messages[0])
  96. while not password:
  97. try:
  98. raw_value = getpass("Enter password: ").strip()
  99. validate_password(raw_value, user=UserModel(
  100. username=username,
  101. email=email
  102. ))
  103. repeat_raw_value = getpass("Repeat password: ").strip()
  104. if raw_value != repeat_raw_value:
  105. raise ValidationError(
  106. "Entered passwords are different.")
  107. password = raw_value
  108. except ValidationError as e:
  109. self.stderr.write(e.messages[0])
  110. # Call User manager's create_superuser using our wrapper
  111. self.create_superuser(username, email, password, verbosity)
  112. except KeyboardInterrupt:
  113. self.stderr.write("\nOperation cancelled.")
  114. sys.exit(1)
  115. except NotRunningInTTYException:
  116. self.stdout.write(
  117. "Superuser creation skipped due to not running in a TTY. "
  118. "You can run `manage.py createsuperuser` in your project "
  119. "to create one manually."
  120. )
  121. def create_superuser(self, username, email, password, verbosity):
  122. try:
  123. user = UserModel.objects.create_superuser(
  124. username, email, password, set_default_avatar=True)
  125. if verbosity >= 1:
  126. message = "Superuser #%(pk)s has been created successfully."
  127. self.stdout.write(message % {'pk': user.pk})
  128. except ValidationError as e:
  129. self.stderr.write(e.messages[0])
  130. except IntegrityError as e:
  131. self.stderr.write(e.messages[0])