diff --git a/src/players/admin.py b/src/players/admin.py index bd7f41b838..8a4d8ff616 100644 --- a/src/players/admin.py +++ b/src/players/admin.py @@ -25,6 +25,13 @@ class CustomUserChangeForm(UserChangeForm): widget=forms.TextInput(attrs={'size':'30'}), error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}, help_text = "30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") + def clean_username(self): + username = self.cleaned_data['username'] + if username.upper() == self.instance.username.upper(): + return username + elif User.objects.filter(username__iexact=username): + raise forms.ValidationError('A player with that name already exists.') + return self.cleaned_data['username'] class CustomUserCreationForm(UserCreationForm): username = forms.RegexField(label="Username", @@ -34,6 +41,13 @@ class CustomUserCreationForm(UserCreationForm): error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}, help_text = "30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") + def clean_username(self): + username = self.cleaned_data['username'] + if User.objects.filter(username__iexact=username): + raise forms.ValidationError('A player with that name already exists.') + return username + + # # The Player editor # class PlayerAttributeForm(forms.ModelForm): # "Defines how to display the atttributes" @@ -127,20 +141,30 @@ class UserAdmin(BaseUserAdmin): {'fields': ('username', 'password1', 'password2', 'email'), 'description':"These account details are shared by the admin system and the game."},),) + def is_valid(self): + raise Exception + if not super(UserAdmin, self).is_valid(): + return False + username = self.cleaned_data['username'] + if self.instance and self.instance.username.upper() == username.upper(): + return True + elif User.objects.filter(username__iexact=username): + raise ValidationError({'username' : 'A player with that name already exists.'}) + return True + def save_formset(self, request, form, formset, change): "Run all hooks on the player object" super(UserAdmin, self).save_formset(request, form, formset, change) userobj = form.instance playerobj = userobj.get_profile() + playerobj.name = userobj.username if not change: #uname, passwd, email = str(request.POST.get(u"username")), \ # str(request.POST.get(u"password1")), str(request.POST.get(u"email")) typeclass = str(request.POST.get(u"playerdb_set-0-db_typeclass_path")) - create.create_player("","","", user=userobj, typeclass=typeclass, - player_dbobj=playerobj, - create_character=False) + player_dbobj=playerobj) admin.site.register(User, UserAdmin) diff --git a/src/players/manager.py b/src/players/manager.py index d7b7e2d840..9916928f51 100644 --- a/src/players/manager.py +++ b/src/players/manager.py @@ -148,7 +148,7 @@ class PlayerManager(TypedObjectManager): def get_player_from_name(self, uname): "Get player object based on name" try: - return self.get(user__username=uname) + return self.get(user__username__iexact=uname) except self.model.DoesNotExist: return None diff --git a/src/settings_default.py b/src/settings_default.py index 1bfbb889c4..f594413111 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -82,6 +82,8 @@ HTTP_LOG_FILE = os.path.join(LOG_DIR, 'http_requests.log') # Local time zone for this installation. All choices can be found here: # http://www.postgresql.org/docs/8.0/interactive/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE TIME_ZONE = 'UTC' +# Authentication backends. This is the code used to authenticate a user. +AUTHENTICATION_BACKENDS = ('src.web.backends.CaseInsensitiveModelBackend',) # Language code for this installation. All choices can be found here: # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes LANGUAGE_CODE = 'en-us' diff --git a/src/utils/create.py b/src/utils/create.py index f009bf4245..07400fe040 100644 --- a/src/utils/create.py +++ b/src/utils/create.py @@ -432,9 +432,6 @@ def create_player(name, email, password, set any in this case. """ - # The system should already have checked so the name/email - # isn't already registered, and that the password is ok before - # getting here. global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB @@ -446,7 +443,17 @@ def create_player(name, email, password, if user: new_user = user email = user.email + + if user: + conflict_check = User.objects.filter(username__iexact=user.username) + conflict_check = len(conflict_check) > 1 else: + conflict_check = User.objects.filter(username__iexact=name) + + if conflict_check: + raise ValueError("A user with this name already exists.") + + if not user: if is_superuser: new_user = User.objects.create_superuser(name, email, password) else: diff --git a/src/web/backends.py b/src/web/backends.py new file mode 100644 index 0000000000..21c5f9a100 --- /dev/null +++ b/src/web/backends.py @@ -0,0 +1,17 @@ +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth.models import User + +class CaseInsensitiveModelBackend(ModelBackend): + """ + By default ModelBackend does case _sensitive_ username authentication, which isn't what is + generally expected. This backend supports case insensitive username authentication. + """ + def authenticate(self, username=None, password=None): + try: + user = User.objects.get(username__iexact=username) + if user.check_password(password): + return user + else: + return None + except User.DoesNotExist: + return None