Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixes #15778 -- createsuperuser fails on international characters in …

…system user names. Thanks for the patch, Hynek Cernoch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16182 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 161b94ef7bbdba2f8106871be796f5d703727a3f 1 parent 688abe3
Chris Beaven SmileyChris authored
55 django/contrib/auth/management/__init__.py
View
@@ -1,14 +1,18 @@
"""
Creates permissions for all installed apps that need permissions.
"""
-
+import getpass
+import locale
+import unicodedata
from django.contrib.auth import models as auth_app
from django.db.models import get_models, signals
+from django.contrib.auth.models import User
def _get_permission_codename(action, opts):
return u'%s_%s' % (action, opts.object_name.lower())
+
def _get_all_permissions(opts):
"Returns (codename, name) for all permissions in the given opts."
perms = []
@@ -16,6 +20,7 @@ def _get_all_permissions(opts):
perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
return perms + list(opts.permissions)
+
def create_permissions(app, created_models, verbosity, **kwargs):
from django.contrib.contenttypes.models import ContentType
@@ -70,6 +75,54 @@ def create_superuser(app, created_models, verbosity, **kwargs):
call_command("createsuperuser", interactive=True)
break
+
+def get_system_username():
+ """
+ Try to determine the current system user's username.
+
+ :returns: The username as a unicode string, or an empty string if the
+ username could not be determined.
+ """
+ try:
+ return getpass.getuser().decode(locale.getdefaultlocale()[1])
+ except (ImportError, KeyError, UnicodeDecodeError):
+ # KeyError will be raised by os.getpwuid() (called by getuser())
+ # if there is no corresponding entry in the /etc/passwd file
+ # (a very restricted chroot environment, for example).
+ # UnicodeDecodeError - preventive treatment for non-latin Windows.
+ return u''
+
+
+def get_default_username(check_db=True):
+ """
+ Try to determine the current system user's username to use as a default.
+
+ :param check_db: If ``True``, requires that the username does not match an
+ existing ``auth.User`` (otherwise returns an empty string).
+ :returns: The username, or an empty string if no username can be
+ determined.
+ """
+ from django.contrib.auth.management.commands.createsuperuser import \
+ RE_VALID_USERNAME
+ default_username = get_system_username()
+ try:
+ default_username = unicodedata.normalize('NFKD', default_username)\
+ .encode('ascii', 'ignore').replace(' ', '').lower()
+ except UnicodeDecodeError:
+ return ''
+ if not RE_VALID_USERNAME.match(default_username):
+ return ''
+ # Don't return the default username if it is already taken.
+ if check_db and default_username:
+ try:
+ User.objects.get(username=default_username)
+ except User.DoesNotExist:
+ pass
+ else:
+ return ''
+ return default_username
+
+
signals.post_syncdb.connect(create_permissions,
dispatch_uid = "django.contrib.auth.management.create_permissions")
signals.post_syncdb.connect(create_superuser,
21 django/contrib/auth/management/commands/createsuperuser.py
View
@@ -7,6 +7,7 @@
import sys
from optparse import make_option
from django.contrib.auth.models import User
+from django.contrib.auth.management import get_default_username
from django.core import exceptions
from django.core.management.base import BaseCommand, CommandError
from django.utils.translation import ugettext as _
@@ -56,28 +57,10 @@ def handle(self, *args, **options):
# If not provided, create the user with an unusable password
password = None
- # Try to determine the current system user's username to use as a default.
- try:
- default_username = getpass.getuser().replace(' ', '').lower()
- except (ImportError, KeyError):
- # KeyError will be raised by os.getpwuid() (called by getuser())
- # if there is no corresponding entry in the /etc/passwd file
- # (a very restricted chroot environment, for example).
- default_username = ''
-
- # Determine whether the default username is taken, so we don't display
- # it as an option.
- if default_username:
- try:
- User.objects.get(username=default_username)
- except User.DoesNotExist:
- pass
- else:
- default_username = ''
-
# Prompt for username/email/password. Enclose this whole thing in a
# try/except to trap for a keyboard interrupt and exit gracefully.
if interactive:
+ default_username = get_default_username()
try:
# Get a username
1  django/contrib/auth/tests/__init__.py
View
@@ -8,6 +8,7 @@
UserChangeFormTest, PasswordResetFormTest)
from django.contrib.auth.tests.remote_user import (RemoteUserTest,
RemoteUserNoCreateTest, RemoteUserCustomTest)
+from django.contrib.auth.tests.management import GetDefaultUsernameTestCase
from django.contrib.auth.tests.models import ProfileTestCase
from django.contrib.auth.tests.signals import SignalTestCase
from django.contrib.auth.tests.tokens import TokenGeneratorTest
27 django/contrib/auth/tests/management.py
View
@@ -0,0 +1,27 @@
+from django.test import TestCase
+from django.contrib.auth import models, management
+
+
+class GetDefaultUsernameTestCase(TestCase):
+
+ def setUp(self):
+ self._getpass_getuser = management.get_system_username
+
+ def tearDown(self):
+ management.get_system_username = self._getpass_getuser
+
+ def test_simple(self):
+ management.get_system_username = lambda: u'joe'
+ self.assertEqual(management.get_default_username(), 'joe')
+
+ def test_existing(self):
+ models.User.objects.create(username='joe')
+ management.get_system_username = lambda: u'joe'
+ self.assertEqual(management.get_default_username(), '')
+ self.assertEqual(
+ management.get_default_username(check_db=False), 'joe')
+
+ def test_i18n(self):
+ # 'Julia' with accented 'u':
+ management.get_system_username = lambda: u'J\xfalia'
+ self.assertEqual(management.get_default_username(), 'julia')
Please sign in to comment.
Something went wrong with that request. Please try again.