Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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 authored May 09, 2011
55  django/contrib/auth/management/__init__.py
... ...
@@ -1,14 +1,18 @@
1 1
 """
2 2
 Creates permissions for all installed apps that need permissions.
3 3
 """
4  
-
  4
+import getpass
  5
+import locale
  6
+import unicodedata
5 7
 from django.contrib.auth import models as auth_app
6 8
 from django.db.models import get_models, signals
  9
+from django.contrib.auth.models import User
7 10
 
8 11
 
9 12
 def _get_permission_codename(action, opts):
10 13
     return u'%s_%s' % (action, opts.object_name.lower())
11 14
 
  15
+
12 16
 def _get_all_permissions(opts):
13 17
     "Returns (codename, name) for all permissions in the given opts."
14 18
     perms = []
@@ -16,6 +20,7 @@ def _get_all_permissions(opts):
16 20
         perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
17 21
     return perms + list(opts.permissions)
18 22
 
  23
+
19 24
 def create_permissions(app, created_models, verbosity, **kwargs):
20 25
     from django.contrib.contenttypes.models import ContentType
21 26
 
@@ -70,6 +75,54 @@ def create_superuser(app, created_models, verbosity, **kwargs):
70 75
                 call_command("createsuperuser", interactive=True)
71 76
             break
72 77
 
  78
+
  79
+def get_system_username():
  80
+    """
  81
+    Try to determine the current system user's username.
  82
+
  83
+    :returns: The username as a unicode string, or an empty string if the
  84
+        username could not be determined.
  85
+    """
  86
+    try:
  87
+        return getpass.getuser().decode(locale.getdefaultlocale()[1])
  88
+    except (ImportError, KeyError, UnicodeDecodeError):
  89
+        # KeyError will be raised by os.getpwuid() (called by getuser())
  90
+        # if there is no corresponding entry in the /etc/passwd file
  91
+        # (a very restricted chroot environment, for example).
  92
+        # UnicodeDecodeError - preventive treatment for non-latin Windows.
  93
+        return u''
  94
+
  95
+
  96
+def get_default_username(check_db=True):
  97
+    """
  98
+    Try to determine the current system user's username to use as a default.
  99
+
  100
+    :param check_db: If ``True``, requires that the username does not match an
  101
+        existing ``auth.User`` (otherwise returns an empty string).
  102
+    :returns: The username, or an empty string if no username can be
  103
+        determined.
  104
+    """
  105
+    from django.contrib.auth.management.commands.createsuperuser import \
  106
+        RE_VALID_USERNAME
  107
+    default_username = get_system_username()
  108
+    try:
  109
+        default_username = unicodedata.normalize('NFKD', default_username)\
  110
+            .encode('ascii', 'ignore').replace(' ', '').lower()
  111
+    except UnicodeDecodeError:
  112
+        return ''
  113
+    if not RE_VALID_USERNAME.match(default_username):
  114
+        return ''
  115
+    # Don't return the default username if it is already taken.
  116
+    if check_db and default_username:
  117
+        try:
  118
+            User.objects.get(username=default_username)
  119
+        except User.DoesNotExist:
  120
+            pass
  121
+        else:
  122
+            return ''
  123
+    return default_username
  124
+
  125
+
73 126
 signals.post_syncdb.connect(create_permissions,
74 127
     dispatch_uid = "django.contrib.auth.management.create_permissions")
75 128
 signals.post_syncdb.connect(create_superuser,
21  django/contrib/auth/management/commands/createsuperuser.py
@@ -7,6 +7,7 @@
7 7
 import sys
8 8
 from optparse import make_option
9 9
 from django.contrib.auth.models import User
  10
+from django.contrib.auth.management import get_default_username
10 11
 from django.core import exceptions
11 12
 from django.core.management.base import BaseCommand, CommandError
12 13
 from django.utils.translation import ugettext as _
@@ -56,28 +57,10 @@ def handle(self, *args, **options):
56 57
         # If not provided, create the user with an unusable password
57 58
         password = None
58 59
 
59  
-        # Try to determine the current system user's username to use as a default.
60  
-        try:
61  
-            default_username = getpass.getuser().replace(' ', '').lower()
62  
-        except (ImportError, KeyError):
63  
-            # KeyError will be raised by os.getpwuid() (called by getuser())
64  
-            # if there is no corresponding entry in the /etc/passwd file
65  
-            # (a very restricted chroot environment, for example).
66  
-            default_username = ''
67  
-
68  
-        # Determine whether the default username is taken, so we don't display
69  
-        # it as an option.
70  
-        if default_username:
71  
-            try:
72  
-                User.objects.get(username=default_username)
73  
-            except User.DoesNotExist:
74  
-                pass
75  
-            else:
76  
-                default_username = ''
77  
-
78 60
         # Prompt for username/email/password. Enclose this whole thing in a
79 61
         # try/except to trap for a keyboard interrupt and exit gracefully.
80 62
         if interactive:
  63
+            default_username = get_default_username()
81 64
             try:
82 65
 
83 66
                 # Get a username
1  django/contrib/auth/tests/__init__.py
@@ -8,6 +8,7 @@
8 8
     UserChangeFormTest, PasswordResetFormTest)
9 9
 from django.contrib.auth.tests.remote_user import (RemoteUserTest,
10 10
     RemoteUserNoCreateTest, RemoteUserCustomTest)
  11
+from django.contrib.auth.tests.management import GetDefaultUsernameTestCase
11 12
 from django.contrib.auth.tests.models import ProfileTestCase
12 13
 from django.contrib.auth.tests.signals import SignalTestCase
13 14
 from django.contrib.auth.tests.tokens import TokenGeneratorTest
27  django/contrib/auth/tests/management.py
... ...
@@ -0,0 +1,27 @@
  1
+from django.test import TestCase
  2
+from django.contrib.auth import models, management
  3
+
  4
+
  5
+class GetDefaultUsernameTestCase(TestCase):
  6
+
  7
+    def setUp(self):
  8
+        self._getpass_getuser = management.get_system_username
  9
+
  10
+    def tearDown(self):
  11
+        management.get_system_username = self._getpass_getuser
  12
+
  13
+    def test_simple(self):
  14
+        management.get_system_username = lambda: u'joe'
  15
+        self.assertEqual(management.get_default_username(), 'joe')
  16
+
  17
+    def test_existing(self):
  18
+        models.User.objects.create(username='joe')
  19
+        management.get_system_username = lambda: u'joe'
  20
+        self.assertEqual(management.get_default_username(), '')
  21
+        self.assertEqual(
  22
+            management.get_default_username(check_db=False), 'joe')
  23
+
  24
+    def test_i18n(self):
  25
+        # 'Julia' with accented 'u':
  26
+        management.get_system_username = lambda: u'J\xfalia'
  27
+        self.assertEqual(management.get_default_username(), 'julia')

0 notes on commit 161b94e

Please sign in to comment.
Something went wrong with that request. Please try again.