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
This commit is contained in:
Chris Beaven 2011-05-09 01:10:40 +00:00
parent 688abe3b8d
commit 161b94ef7b
4 changed files with 84 additions and 20 deletions

View File

@ -1,14 +1,18 @@
""" """
Creates permissions for all installed apps that need permissions. 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.contrib.auth import models as auth_app
from django.db.models import get_models, signals from django.db.models import get_models, signals
from django.contrib.auth.models import User
def _get_permission_codename(action, opts): def _get_permission_codename(action, opts):
return u'%s_%s' % (action, opts.object_name.lower()) return u'%s_%s' % (action, opts.object_name.lower())
def _get_all_permissions(opts): def _get_all_permissions(opts):
"Returns (codename, name) for all permissions in the given opts." "Returns (codename, name) for all permissions in the given opts."
perms = [] 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))) perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
return perms + list(opts.permissions) return perms + list(opts.permissions)
def create_permissions(app, created_models, verbosity, **kwargs): def create_permissions(app, created_models, verbosity, **kwargs):
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -70,6 +75,54 @@ def create_superuser(app, created_models, verbosity, **kwargs):
call_command("createsuperuser", interactive=True) call_command("createsuperuser", interactive=True)
break 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, signals.post_syncdb.connect(create_permissions,
dispatch_uid = "django.contrib.auth.management.create_permissions") dispatch_uid = "django.contrib.auth.management.create_permissions")
signals.post_syncdb.connect(create_superuser, signals.post_syncdb.connect(create_superuser,

View File

@ -7,6 +7,7 @@ import re
import sys import sys
from optparse import make_option from optparse import make_option
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.management import get_default_username
from django.core import exceptions from django.core import exceptions
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@ -56,28 +57,10 @@ class Command(BaseCommand):
# If not provided, create the user with an unusable password # If not provided, create the user with an unusable password
password = None 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 # Prompt for username/email/password. Enclose this whole thing in a
# try/except to trap for a keyboard interrupt and exit gracefully. # try/except to trap for a keyboard interrupt and exit gracefully.
if interactive: if interactive:
default_username = get_default_username()
try: try:
# Get a username # Get a username

View File

@ -8,6 +8,7 @@ from django.contrib.auth.tests.forms import (UserCreationFormTest,
UserChangeFormTest, PasswordResetFormTest) UserChangeFormTest, PasswordResetFormTest)
from django.contrib.auth.tests.remote_user import (RemoteUserTest, from django.contrib.auth.tests.remote_user import (RemoteUserTest,
RemoteUserNoCreateTest, RemoteUserCustomTest) RemoteUserNoCreateTest, RemoteUserCustomTest)
from django.contrib.auth.tests.management import GetDefaultUsernameTestCase
from django.contrib.auth.tests.models import ProfileTestCase from django.contrib.auth.tests.models import ProfileTestCase
from django.contrib.auth.tests.signals import SignalTestCase from django.contrib.auth.tests.signals import SignalTestCase
from django.contrib.auth.tests.tokens import TokenGeneratorTest from django.contrib.auth.tests.tokens import TokenGeneratorTest

View File

@ -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')