From 7d1eb5207adc7898f1af4351070ca7a2076ce3d4 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Fri, 21 Jun 2013 09:51:17 +0200 Subject: [PATCH 1/2] Fixes #765. Avoids the django AbstracUser username validator Also changed added a white-space in the default username again --- openslides/participant/api.py | 35 +++++++++++-------- openslides/participant/forms.py | 29 +++++++++++++--- openslides/participant/views.py | 7 +++- tests/participant/test_umlaut_user.py | 50 +++++++++++++++++++++++++++ tests/participant/test_utils.py | 37 ++++++++++++++++++++ 5 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 tests/participant/test_umlaut_user.py create mode 100644 tests/participant/test_utils.py diff --git a/openslides/participant/api.py b/openslides/participant/api.py index 9534fb26d..621ae9b44 100644 --- a/openslides/participant/api.py +++ b/openslides/participant/api.py @@ -23,7 +23,7 @@ from openslides.participant.models import User, Group def gen_password(): """ - generates a random passwort. + Generates a random passwort. """ chars = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" size = 8 @@ -33,21 +33,28 @@ def gen_password(): def gen_username(first_name, last_name): """ - generates the username for new users. + Generates a username from a first- and lastname. """ - testname = "%s%s" % (first_name.strip(), last_name.strip()) - try: - User.objects.get(username=testname) - except User.DoesNotExist: - return testname - i = 0 + first_name = first_name.strip() + last_name = last_name.strip() + + if first_name and last_name: + base_name = " ".join((first_name, last_name)) + else: + base_name = first_name or last_name + if not base_name: + raise ValueError('Either \'first_name\' or \'last_name\' can not be ' + 'empty') + + if not User.objects.filter(username=base_name).exists(): + return base_name + + counter = 0 while True: - i += 1 - testname = "%s%s%s" % (first_name, last_name, i) - try: - User.objects.get(username=testname) - except User.DoesNotExist: - return testname + counter += 1 + test_name = "%s %d" % (base_name, counter) + if not User.objects.filter(username=test_name).exists(): + return test_name def import_users(csv_file): diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py index 68a273aa2..6f494b989 100644 --- a/openslides/participant/forms.py +++ b/openslides/participant/forms.py @@ -52,14 +52,23 @@ class UserUpdateForm(UserCreateForm): user edits himself and removes the last group containing the permission to manage participants. """ + user_name = forms.CharField() + """ + Field to save the username. + + The field username (without the underscore) from the UserModel does not + allow whitespaces and umlauts. + """ + class Meta: model = User - fields = ('username', 'title', 'first_name', 'last_name', 'gender', 'email', + fields = ('user_name', 'title', 'first_name', 'last_name', 'gender', 'email', 'groups', 'structure_level', 'committee', 'about_me', 'comment', 'is_active', 'default_password') def __init__(self, *args, **kwargs): self.request = kwargs.pop('request') + kwargs['initial']['user_name'] = kwargs['instance'].username return super(UserUpdateForm, self).__init__(*args, **kwargs) def clean(self, *args, **kwargs): @@ -145,15 +154,27 @@ class GroupForm(forms.ModelForm, CssClassMixin): return super(GroupForm, self).clean(*args, **kwargs) -class UsersettingsForm(forms.ModelForm, CssClassMixin): +class UsersettingsForm(CssClassMixin, forms.ModelForm): + user_name = forms.CharField() + """ + Field to save the username. + + The field username (without the underscore) from the UserModel does not + allow whitespaces and umlauts. + """ + language = forms.ChoiceField(choices=settings.LANGUAGES) + def __init__(self, *args, **kwargs): + kwargs['initial']['user_name'] = kwargs['instance'].username + return super(UsersettingsForm, self).__init__(*args, **kwargs) + class Meta: model = User - fields = ('username', 'title', 'first_name', 'last_name', 'gender', 'email', + fields = ('user_name', 'title', 'first_name', 'last_name', 'gender', 'email', 'committee', 'about_me') -class UserImportForm(forms.Form, CssClassMixin): +class UserImportForm(CssClassMixin, forms.Form): csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}), label=ugettext_lazy('CSV File')) diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 972a2b929..c8e19d8cd 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -132,6 +132,9 @@ class UserUpdateView(UpdateView): form_kwargs.update({'request': self.request}) return form_kwargs + def manipulate_object(self, form): + self.object.username = form.cleaned_data['user_name'] + def post_save(self, form): super(UserUpdateView, self).post_save(form) # TODO: find a better solution that makes the following lines obsolete @@ -485,7 +488,9 @@ def user_settings(request): if request.method == 'POST': form_user = UsersettingsForm(request.POST, instance=request.user) if form_user.is_valid(): - form_user.save() + user = form_user.save(commit=False) + user.username = form_user.cleaned_data['user_name'] + user.save() language = request.LANGUAGE_CODE = \ request.session['django_language'] = form_user.cleaned_data['language'] activate(language) diff --git a/tests/participant/test_umlaut_user.py b/tests/participant/test_umlaut_user.py new file mode 100644 index 000000000..f65e1314d --- /dev/null +++ b/tests/participant/test_umlaut_user.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + Test Umlaut User + ~~~~~~~~~~~~~~~~ + + :copyright: 2011–2013 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from django.test.client import Client + +from openslides.utils.test import TestCase +from openslides.config.api import config +from openslides.participant.models import User, Group + + +class TestUmlautUser(TestCase): + """ + Tests persons with umlauts in there name. + """ + + def setUp(self): + self.user = User.objects.create(username='äöü') + self.user.reset_password('äöü') + self.client = Client() + self.client.login(username='äöü', password='äöü') + + def test_login(self): + client = Client() + response = client.post('/login/', {'username': 'äöü', + 'password': 'äöüß'}) + self.assertEqual(response.status_code, 200) + + response = client.post('/login/', {'username': 'äöü', + 'password': 'äöü'}) + self.assertEqual(response.status_code, 302) + + def test_logout(self): + response = self.client.get('/logout/') + self.assertEqual(response.status_code, 302) + + def test_permission(self): + response = self.client.get('/participant/1/edit/') + self.assertEqual(response.status_code, 403) + + self.user.groups.add(Group.objects.get(pk=4)) + + response = self.client.get('/participant/1/edit/') + self.assertEqual(response.status_code, 200) diff --git a/tests/participant/test_utils.py b/tests/participant/test_utils.py new file mode 100644 index 000000000..ace52e737 --- /dev/null +++ b/tests/participant/test_utils.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + Tests for models of openslides.participant + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :copyright: 2011–2013 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from openslides.utils.test import TestCase + +from openslides.participant.models import User +from openslides.participant.api import gen_username + + +class UserGenUsername(TestCase): + """ + Tests for the function gen_username. + """ + + def test_base(self): + self.assertEqual(gen_username('foo', 'bar'), 'foo bar') + self.assertEqual(gen_username('foo ', ' bar\n'), 'foo bar') + self.assertEqual(gen_username('foobar', ''), 'foobar') + self.assertEqual(gen_username('', 'foobar'), 'foobar') + self.assertRaises(ValueError, gen_username, '', '') + + def test_used_username(self): + User.objects.create(username='user name') + self.assertEqual(gen_username('user', 'name'), 'user name 1') + + User.objects.create(username='user name 1') + self.assertEqual(gen_username('user', 'name'), 'user name 2') + + def test_umlauts(self): + self.assertEqual(gen_username('äöü', 'ßüäö'), 'äöü ßüäö') From cc6aa27167fc641419f403e8426a3cf103d7981b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Norman=20J=C3=A4ckel?= Date: Tue, 25 Jun 2013 13:56:11 +0200 Subject: [PATCH 2/2] Documentation: Whitespace in the username, fixed #782 --- docs/de/LoginLogout.rst | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/de/LoginLogout.rst b/docs/de/LoginLogout.rst index e94e597a5..5d46497cf 100644 --- a/docs/de/LoginLogout.rst +++ b/docs/de/LoginLogout.rst @@ -1,25 +1,49 @@ -An- und Abmelden – Benutzername und Passwort ändern +An- und Abmelden – Benutzername und Passwort ändern +++++++++++++++++++++++++++++++++++++++++++++++++++ An- und Abmelden ---------------- -Beim ersten Aufruf von OpenSlides erscheint die Login-Seite. Der erste Benutzername des Administrators ist ``admin``. Er hat das erste Passwort ``admin``. Über die Teilnehmerverwaltung neu angelegte Teilnehmer haben einen aus dem Vor- und Nachnamen zusammengesetzten Benutzernamen, wobei Groß- und Kleinschreibung zu beachten ist. Beispiel: Ein mit dem Vornamen ``Max`` und dem Nachnamen ``Mustermann`` angelegter Teilnehmer hat den Benutzernamen ``MaxMustermann``. Das Erstpasswort kann über die Teilnehmerverwaltung eingesehen werden. Zum Einloggen geben Sie einfach Ihren Benutzernamen und Ihr Passwort ein und klicken Sie auf ``Anmelden``. +Beim ersten Aufruf von OpenSlides erscheint die Login-Seite. Der erste +Benutzername des Administrators ist ``admin``. Er hat das erste Passwort +``admin``. Über die Teilnehmerverwaltung neu angelegte Teilnehmer haben +einen aus dem Vor- und Nachnamen zusammengesetzten Benutzernamen, wobei +Groß- und Kleinschreibung zu beachten ist und zwischen den Namen ein +Leerzeichen liegt. Beispiel: Ein mit dem Vornamen ``Max`` und dem Nachnamen +``Mustermann`` angelegter Teilnehmer hat den Benutzernamen ``Max +Mustermann``. Das Erstpasswort kann über die Teilnehmerverwaltung +eingesehen werden. Zum Einloggen geben Sie einfach Ihren Benutzernamen und +Ihr Passwort ein und klicken Sie auf ``Anmelden``. Eigene Benutzereinstellungen (insbesondere Benutzername oder Passwort) ändern ----------------------------------------------------------------------------- -Die eigenen Benutzereinstellungen wie Benutzername und Passwort können über den Link ``Benutzereinstellungen`` oben rechts geändert werden. Klicken Sie auf den Link, wählen Sie im oberen rechten Menü aus, ob Sie Ihre persönlichen Einstellungen oder Ihr Passwort ändern möchten, und ändern Sie die jeweiligen Einstellungen. Klicken Sie abschließend auf ``Speichern``. +Die eigenen Benutzereinstellungen wie Benutzername und Passwort können über +den Link ``Benutzereinstellungen`` oben rechts geändert werden. Klicken Sie +auf den Link, wählen Sie im oberen rechten Menü aus, ob Sie Ihre +persönlichen Einstellungen oder Ihr Passwort ändern möchten, und ändern Sie +die jeweiligen Einstellungen. Klicken Sie abschließend auf ``Speichern``. Fremde Benutzereinstellungen (insbesondere Benutzername oder Passwort) ändern ----------------------------------------------------------------------------- -Beim Anlegen eines Teilnehmers wird automatisch ein zufälliges Erst-Passwort gesetzt. Sie können das Erst-Passwort aus einer PDF-Datei ablesen, die Sie durch Klick auf den Link „Erst-Passwörter als PDF“ im rechten oberen Menü erreichen. +Beim Anlegen eines Teilnehmers wird automatisch ein zufälliges +Erst-Passwort gesetzt. Sie können das Erst-Passwort aus einer PDF-Datei +ablesen, die Sie durch Klick auf den Link „Erst-Passwörter als PDF“ im +rechten oberen Menü erreichen. -Benutzer mit den entsprechenden Rechten wie Mitarbeiter können alle Benutzer über den Menüpunkt „Teilnehmer/innen“ verwalten und dort auch den Benutzernamen ändern und das Passwort auf ein bestimmtes Erst-Passwort zurücksetzen. +Benutzer mit den entsprechenden Rechten wie Mitarbeiter können alle Benutzer +über den Menüpunkt „Teilnehmer/innen“ verwalten und dort auch den +Benutzernamen ändern und das Passwort auf ein bestimmtes Erst-Passwort +zurücksetzen. -Klicken Sie beim jeweiligen Teilnehmer auf das Bearbeiten-Symbol |edit| und tragen Sie unter „Erst-Passwort“ ein neues, selbstgewähltes Passwort ein. Anschließend klicken Sie auf ``Übernehmen``. In einem zweiten Schritt müssen Sie auf den Link „Auf Erst-Passwort zurücksetzen“ klicken, um das im System gespeicherte Passwort mit Ihrem neu eingegebenen zu ersetzen. Bestätigen Sie den oben auf der Seite erscheinenden Dialog mit ``Ja``. +Klicken Sie beim jeweiligen Teilnehmer auf das Bearbeiten-Symbol |edit| und +tragen Sie unter „Erst-Passwort“ ein neues, selbstgewähltes Passwort ein. +Anschließend klicken Sie auf ``Übernehmen``. In einem zweiten Schritt +müssen Sie auf den Link „Auf Erst-Passwort zurücksetzen“ klicken, um das im +System gespeicherte Passwort mit Ihrem neu eingegebenen zu ersetzen. +Bestätigen Sie den oben auf der Seite erscheinenden Dialog mit ``Ja``. .. |edit| image:: ../_images/pencil.png