From 4ffb7013978e6bf88db21f6685d88f7de661b583 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Fri, 3 Aug 2012 00:11:53 +0200 Subject: [PATCH 01/19] created new user-api --- openslides/application/forms.py | 7 +- openslides/application/models.py | 3 +- .../templates/application/view.html | 6 +- openslides/application/views.py | 16 +- openslides/participant/models.py | 45 +++++- openslides/utils/user/__init__.py | 141 ++++++++++++++++++ openslides/utils/user/signals.py | 15 ++ 7 files changed, 214 insertions(+), 19 deletions(-) create mode 100644 openslides/utils/user/__init__.py create mode 100644 openslides/utils/user/signals.py diff --git a/openslides/application/forms.py b/openslides/application/forms.py index 2d4bf5518..9da1f3a83 100644 --- a/openslides/application/forms.py +++ b/openslides/application/forms.py @@ -15,6 +15,7 @@ from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _, ugettext_noop from openslides.utils.forms import CssClassMixin +from openslides.utils.user import UserFormField from openslides.application.models import Application @@ -50,11 +51,7 @@ class ApplicationFormTrivialChanges(ApplicationForm): class ApplicationManagerForm(forms.ModelForm, CssClassMixin): - submitter = UserModelChoiceField( - queryset=User.objects.all().exclude(profile=None). - order_by("first_name"), - label=_("Submitter"), - ) + submitter = UserFormField() class Meta: model = Application diff --git a/openslides/application/models.py b/openslides/application/models.py index c06b4716e..e0d8b738b 100644 --- a/openslides/application/models.py +++ b/openslides/application/models.py @@ -21,6 +21,7 @@ from django.utils.translation import pgettext from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext from openslides.utils.utils import _propper_unicode +from openslides.utils.user import UserField from openslides.config.models import config from openslides.config.signals import default_config_value @@ -60,7 +61,7 @@ class Application(models.Model, SlideMixin): # genpoll ) - submitter = models.ForeignKey(User, verbose_name=_("Submitter")) + submitter = UserField(verbose_name=_("Submitter")) supporter = models.ManyToManyField(User, related_name='supporter', \ null=True, blank=True, verbose_name=_("Supporters")) number = models.PositiveSmallIntegerField(blank=True, null=True, diff --git a/openslides/application/templates/application/view.html b/openslides/application/templates/application/view.html index 0ae213ab0..dd9ad9c69 100644 --- a/openslides/application/templates/application/view.html +++ b/openslides/application/templates/application/view.html @@ -16,8 +16,8 @@ diff --git a/openslides/application/views.py b/openslides/application/views.py index f2c12645b..0158e2513 100644 --- a/openslides/application/views.py +++ b/openslides/application/views.py @@ -748,13 +748,10 @@ class ApplicationPDF(PDFView): if application.status == "pub": cell1b.append(Paragraph("__________________________________________",stylesheet['Signaturefield'])) cell1b.append(Spacer(0,0.1*cm)) - cell1b.append(Paragraph("       "+unicode(application.submitter.profile), stylesheet['Small'])) + cell1b.append(Paragraph("       "+unicode(application.submitter), stylesheet['Small'])) cell1b.append(Spacer(0,0.2*cm)) else: - try: - cell1b.append(Paragraph(unicode(application.submitter.profile), stylesheet['Normal'])) - except Profile.DoesNotExist: - pass + cell1b.append(Paragraph(unicode(application.submitter), stylesheet['Normal'])) # supporters cell2a = [] @@ -764,7 +761,7 @@ class ApplicationPDF(PDFView): cell2a.append(Paragraph("%s:" % _("Supporters"), stylesheet['Heading4'])) for supporter in application.supporters: - cell2b.append(Paragraph(".  %s" % unicode(s.profile), stylesheet['Signaturefield'])) + cell2b.append(Paragraph(".  %s" % unicode(supporter), stylesheet['Signaturefield'])) if application.status == "pub": for x in range(0,application.missing_supporters): cell2b.append(Paragraph(".  __________________________________________",stylesheet['Signaturefield'])) diff --git a/openslides/assignment/forms.py b/openslides/assignment/forms.py index 07c06fc02..c3a648355 100644 --- a/openslides/assignment/forms.py +++ b/openslides/assignment/forms.py @@ -16,7 +16,6 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop from openslides.utils.forms import CssClassMixin from openslides.utils.user import UserFormField -from openslides.participant.models import Profile from openslides.assignment.models import Assignment @@ -26,7 +25,7 @@ class AssignmentForm(forms.ModelForm, CssClassMixin): class Meta: model = Assignment - exclude = ('status', 'profile', 'elected') + exclude = ('status', 'elected') class AssignmentRunForm(forms.Form, CssClassMixin): diff --git a/openslides/assignment/models.py b/openslides/assignment/models.py index 6f7fbf169..d3bab3dca 100644 --- a/openslides/assignment/models.py +++ b/openslides/assignment/models.py @@ -23,8 +23,6 @@ from openslides.config.signals import default_config_value from openslides.projector.api import register_slidemodel from openslides.projector.projector import SlideMixin -from openslides.participant.models import Profile - from openslides.poll.models import (BasePoll, CountInvalid, CountVotesCast, BaseOption, PublishPollMixin, BaseVote) @@ -71,28 +69,27 @@ class Assignment(models.Model, SlideMixin): self.status = status self.save() - def run(self, profile, user=None): + def run(self, candidate, user=None): """ run for a vote """ - if self.is_candidate(profile): - raise NameError(_('%s is already a candidate.') % profile) + # TODO: don't make any permission checks here. + # Use other Exceptions + if self.is_candidate(candidate): + raise NameError(_('%s is already a candidate.') % candidate) if not user.has_perm("assignment.can_manage_assignment") and self.status != 'sea': raise NameError(_('The candidate list is already closed.')) - AssignmentCandidate(assignment=self, user=profile, elected=False).save() + AssignmentCandidate(assignment=self, user=candidate, elected=False).save() - def delrun(self, user): + def delrun(self, candidate): """ stop running for a vote """ - if self.status != 'sea': - # TODO: Use an OpenSlides Error - raise Exception(_('The candidate list is already closed.')) - if self.is_candidate(user): - assignment_candidats.get(user=user).delete() + if self.is_candidate(candidate): + self.assignment_candidats.get(user=candidate).delete() else: # TODO: Use an OpenSlides Error - raise Exception(_('%s is no candidate') % user) + raise Exception(_('%s is no candidate') % candidate) def is_candidate(self, user): if self.assignment_candidats.filter(user=user).exists(): diff --git a/openslides/assignment/templates/assignment/overview.html b/openslides/assignment/templates/assignment/overview.html index 85e850c18..2d9e3b8e0 100644 --- a/openslides/assignment/templates/assignment/overview.html +++ b/openslides/assignment/templates/assignment/overview.html @@ -31,7 +31,7 @@ {{ assignment }} - {{ assignment.profile.count }} / {{ assignment.posts }} + {{ assignment.candidates|length }} / {{ assignment.posts }} {{ assignment.get_status_display }} diff --git a/openslides/assignment/templates/assignment/view.html b/openslides/assignment/templates/assignment/view.html index 9a60c96db..2614b26d6 100644 --- a/openslides/assignment/templates/assignment/view.html +++ b/openslides/assignment/templates/assignment/view.html @@ -54,21 +54,18 @@
{% csrf_token %} {% if perms.assignment.can_nominate_self %}

- {% if user.profile in assignment.profile.all %} - - - - {% trans 'Withdraw self candidature' %} - - + {% if user in assignment.candidates %} + + + {% trans 'Withdraw self candidature' %} + + {% else %} - {% if user.profile %} - - - {% trans 'Self candidature' %} - - - {% endif %} + + + {% trans 'Self candidature' %} + + {% endif %}

{% endif %} diff --git a/openslides/assignment/templates/projector/Assignment.html b/openslides/assignment/templates/projector/Assignment.html index d516baa88..8627d6022 100644 --- a/openslides/assignment/templates/projector/Assignment.html +++ b/openslides/assignment/templates/projector/Assignment.html @@ -28,17 +28,17 @@ {% endblock %} {% block scrollcontent %} - {% if not assignment.profile.exists %} + {% if not assignment.candidates %}

{{ assignment.description|linebreaks }}

{% endif %} - {% if assignment.profile.exists and assignment.status != "fin" %} + {% if assignment.candidates and assignment.status != "fin" %}

{% trans "Candidates" %}

    - {% for profile in assignment.profile.all|dictsort:"user.first_name" %} -
  1. {{ profile }}
  2. + {% for candidate in assignment.candidates %} +
  3. {{ candidate }}
  4. {% empty %}
  5. {% trans "No candidates available." %} @@ -122,7 +122,7 @@ - {% elif assignment.profile.exists %} + {% elif assignment.candidates %} {% trans "No ballots available." %} {% endif %}
    diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py index 350bf0e19..0b2ef82a0 100644 --- a/openslides/assignment/views.py +++ b/openslides/assignment/views.py @@ -33,7 +33,9 @@ from openslides.utils.views import FormView, DeleteView, PDFView, RedirectView from openslides.utils.user import get_user from openslides.config.models import config + from openslides.participant.models import Profile +from openslides.participant.api import user2djangouser from openslides.projector.projector import Widget @@ -169,13 +171,10 @@ def set_status(request, assignment_id=None, status=None): def run(request, assignment_id): assignment = Assignment.objects.get(pk=assignment_id) try: - assignment.run(request.user.profile, request.user) + assignment.run(user2djangouser(request.user), request.user) messages.success(request, _('You have set your candidature successfully.') ) except NameError, e: messages.error(request, e) - except Profile.DoesNotExist: - messages.error(request, - _("You can't candidate. Your user account is only for administration.")) return redirect(reverse('assignment_view', args=[assignment_id])) @@ -183,7 +182,10 @@ def run(request, assignment_id): def delrun(request, assignment_id): assignment = Assignment.objects.get(pk=assignment_id) try: - assignment.delrun(request.user.profile) + if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"): + assignment.delrun(user2djangouser(request.user)) + else: + messages.error(request, _('The candidate list is already closed.')) except Exception, e: messages.error(request, e) else: @@ -370,7 +372,7 @@ class AssignmentPDF(PDFView): cell2a.append(Paragraph("%s:" % _("Candidates"), stylesheet['Heading4'])) cell2b = [] - for candidate in assignment.profile.all(): + for candidate in assignment.candidates: cell2b.append(Paragraph(".  %s" % candidate, stylesheet['Signaturefield'])) if assignment.status == "sea": From ab33b9f05a8edb9270d5b0d1aec391118b487203 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Mon, 6 Aug 2012 14:58:52 +0200 Subject: [PATCH 14/19] fix error in application-supporters an assignment-candidates, for non admin users --- openslides/application/models.py | 2 +- openslides/assignment/templates/assignment/view.html | 2 +- openslides/assignment/views.py | 3 +++ openslides/participant/models.py | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/openslides/application/models.py b/openslides/application/models.py index 4b45a5ed8..6da30fe23 100644 --- a/openslides/application/models.py +++ b/openslides/application/models.py @@ -362,7 +362,7 @@ class Application(models.Model, SlideMixin): is_admin = False if user: try: - user.profile + user = user.profile except Profile.DoesNotExist: is_admin = True except AttributeError: diff --git a/openslides/assignment/templates/assignment/view.html b/openslides/assignment/templates/assignment/view.html index 2614b26d6..cab930676 100644 --- a/openslides/assignment/templates/assignment/view.html +++ b/openslides/assignment/templates/assignment/view.html @@ -54,7 +54,7 @@ {% csrf_token %} {% if perms.assignment.can_nominate_self %}

    - {% if user in assignment.candidates %} + {% if user_is_candidate %} {% trans 'Withdraw self candidature' %} diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py index 0b2ef82a0..6320c459b 100644 --- a/openslides/assignment/views.py +++ b/openslides/assignment/views.py @@ -97,11 +97,14 @@ def view(request, assignment_id=None): else: polls = assignment.poll_set.all() vote_results = assignment.vote_results(only_published=False) + + user = user2djangouser(request.user) return { 'assignment': assignment, 'form': form, 'vote_results': vote_results, 'polls': polls, + 'user_is_candidate': assignment.is_candidate(user) } diff --git a/openslides/participant/models.py b/openslides/participant/models.py index 919e03b95..1913da474 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -58,6 +58,9 @@ class Profile(models.Model, UserMixin): self.user.set_password(self.firstpassword) self.user.save() + def has_perm(self, perm): + return self.user.has_perm(perm) + @models.permalink def get_absolute_url(self, link='edit'): """ From b55ceddb824fe72b00a2e34e197c5cda27f9e9da Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Tue, 7 Aug 2012 10:15:39 +0200 Subject: [PATCH 15/19] append tests for the participant app --- openslides/openslides_settings.py | 1 - openslides/participant/tests.py | 87 +++++++++++++++++++++++++++++++ openslides/utils/user/api.py | 19 +++++-- 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 openslides/participant/tests.py diff --git a/openslides/openslides_settings.py b/openslides/openslides_settings.py index 6486831dd..ed2b0145e 100755 --- a/openslides/openslides_settings.py +++ b/openslides/openslides_settings.py @@ -124,7 +124,6 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', 'mptt', - 'openslides.utils', 'openslides.poll', 'openslides.projector', 'openslides.agenda', diff --git a/openslides/participant/tests.py b/openslides/participant/tests.py new file mode 100644 index 000000000..fa4026335 --- /dev/null +++ b/openslides/participant/tests.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + openslides.participant.tests + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Unit test for the participant app. + + :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from django.test import TestCase +from django.test.client import Client +from django.contrib.auth.models import User, Group +from django.db.models.query import EmptyQuerySet +from django.contrib.auth.hashers import check_password + +from openslides.utils.user import get_user, Users +from openslides.participant.api import gen_username, gen_password, user2djangouser +from openslides.participant.models import Profile, DjangoGroup, DjangoUser + + +class ParticipantTest(TestCase): + def setUp(self): + self.user1 = User(first_name=u'Max', last_name=u'Mustermann') + self.user1.username = gen_username(self.user1.first_name, self.user1.last_name) + self.user1.save() + self.participant1 = Profile.objects.create(user=self.user1, firstpassword=gen_password()) + + def test_participant_user(self): + self.assertEqual(self.user1.profile, self.participant1) + self.assertEqual(self.user1, self.participant1.user) + + def test_repr(self): + self.assertEqual(unicode(self.participant1), u'Max Mustermann') + + def test_group(self): + self.participant1.group = u'München' + self.participant1.save() + self.assertEqual(unicode(self.participant1), u'Max Mustermann (München)') + + def test_reset_password(self): + self.assertIsInstance(self.participant1.firstpassword, basestring) + self.assertEqual(len(self.participant1.firstpassword), 8) + self.user1.set_unusable_password() + self.assertFalse(self.user1.check_password(self.participant1.firstpassword)) + self.participant1.reset_password() + self.assertTrue(self.user1.check_password(self.participant1.firstpassword)) + + def test_user_api(self): + self.assertTrue(hasattr(self.participant1, 'uid')) + self.assertEqual(self.participant1.uid, 'participant:1') + self.assertEqual(get_user('participant:1'), self.participant1) + self.assertEqual(len(Users()), 1) + + +class DjangoGroupTest(TestCase): + def setUp(self): + self.group1 = Group.objects.create(name='Test Group') + self.djangogroup1 = DjangoGroup.objects.create(group=self.group1) + + def test_group_djangogroup(self): + self.assertEqual(self.djangogroup1.group, self.group1) + + def test_user_api(self): + self.assertTrue(hasattr(self.djangogroup1, 'uid')) + self.assertEqual(self.djangogroup1.uid, 'djangogroup:1') + self.assertEqual(get_user('djangogroup:1'), self.djangogroup1) + + +class DjangoUserTest(TestCase): + def setUp(self): + self.user1 = User.objects.create(username='admin') + self.djangouser1 = DjangoUser.objects.get(pk=1) + + def test_djangouser_user(self): + self.assertEqual(self.user1.pk, self.djangouser1.pk) + + def test_has_no_profile(self): + self.assertTrue(self.djangouser1.has_no_profile()) + + def test_user_api(self): + self.assertTrue(hasattr(self.djangouser1, 'uid')) + self.assertEqual(self.djangouser1.uid, 'djangouser:1') + self.assertEqual(get_user('djangouser:1'), self.djangouser1) + self.assertEqual(user2djangouser(self.user1), self.djangouser1) diff --git a/openslides/utils/user/api.py b/openslides/utils/user/api.py index 02191896d..7e418ab61 100644 --- a/openslides/utils/user/api.py +++ b/openslides/utils/user/api.py @@ -22,15 +22,26 @@ class Users(object): self.id = id def __iter__(self): - for receiver, users in receiv_users.send( - sender='users', user_prefix=self.user_prefix, id=self.id): - for user in users: - yield user + try: + return iter(self._cache) + except AttributeError: + return iter(self.iter_users()) + + def __len__(self): + return len(list(self.__iter__())) def __getitem__(self, key): user_list = list(self) return user_list[key] + def iter_users(self): + self._cache = list() + for receiver, users in receiv_users.send( + sender='users', user_prefix=self.user_prefix, id=self.id): + for user in users: + self._cache.append(user) + yield user + def generate_uid(prefix, id): if ':' in prefix: From 1719aa588d6b9666423e4030870c8a3e0aa5da2c Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Tue, 7 Aug 2012 22:43:57 +0200 Subject: [PATCH 16/19] rename some user api and participant names --- initial_data.json | 14 +-- openslides/application/forms.py | 25 +---- openslides/application/models.py | 29 +++--- openslides/application/views.py | 58 ++++++------ openslides/assignment/forms.py | 4 +- openslides/assignment/models.py | 35 ++++--- .../templates/assignment/poll_view.html | 56 ++++++------ .../assignment/templates/assignment/view.html | 10 +- openslides/assignment/views.py | 31 +++---- openslides/openslides_settings.py | 2 +- openslides/participant/api.py | 12 +-- openslides/participant/forms.py | 6 +- openslides/participant/models.py | 81 +++++++---------- openslides/participant/views.py | 91 ++++++++++--------- openslides/utils/person/__init__.py | 22 +++++ openslides/utils/person/api.py | 64 +++++++++++++ openslides/utils/{user => person}/forms.py | 34 +++---- openslides/utils/{user => person}/models.py | 40 ++++---- openslides/utils/{user => person}/signals.py | 2 +- openslides/utils/user/__init__.py | 22 ----- openslides/utils/user/api.py | 65 ------------- 21 files changed, 334 insertions(+), 369 deletions(-) create mode 100644 openslides/utils/person/__init__.py create mode 100644 openslides/utils/person/api.py rename openslides/utils/{user => person}/forms.py (66%) rename openslides/utils/{user => person}/models.py (50%) rename openslides/utils/{user => person}/signals.py (82%) delete mode 100644 openslides/utils/user/__init__.py delete mode 100644 openslides/utils/user/api.py diff --git a/initial_data.json b/initial_data.json index e7451296e..ad17d7a56 100644 --- a/initial_data.json +++ b/initial_data.json @@ -38,7 +38,7 @@ [ "can_see_participant", "participant", - "profile" + "openslidesuser" ], [ "can_see_projector", @@ -92,7 +92,7 @@ [ "can_see_participant", "participant", - "profile" + "openslidesuser" ], [ "can_see_projector", @@ -161,12 +161,12 @@ [ "can_manage_participant", "participant", - "profile" + "openslidesuser" ], [ "can_see_participant", "participant", - "profile" + "openslidesuser" ], [ "can_manage_projector", @@ -195,12 +195,12 @@ [ "can_manage_participant", "participant", - "profile" + "openslidesuser" ], [ "can_see_participant", "participant", - "profile" + "openslidesuser" ], [ "can_see_projector", @@ -210,4 +210,4 @@ ] } } -] \ No newline at end of file +] diff --git a/openslides/application/forms.py b/openslides/application/forms.py index 34a7ef9b9..963e0f531 100644 --- a/openslides/application/forms.py +++ b/openslides/application/forms.py @@ -11,32 +11,13 @@ """ from django import forms -from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _, ugettext_noop from openslides.utils.forms import CssClassMixin -from openslides.utils.user import UserFormField, MultipleUserFormField +from openslides.utils.person import PersonFormField, MultiplePersonFormField from openslides.application.models import Application -class UserModelChoiceField(forms.ModelChoiceField): - """ - Extend ModelChoiceField for users so that the choices are - listed as 'first_name last_name' instead of just 'username'. - """ - def label_from_instance(self, obj): - return obj.get_full_name() - - -class UserModelMultipleChoiceField(forms.ModelMultipleChoiceField): - """ - Extend ModelMultipleChoiceField for users so that the choices are - listed as 'first_name last_name' instead of just 'username'. - """ - def label_from_instance(self, obj): - return obj.get_full_name() - - class ApplicationForm(forms.Form, CssClassMixin): title = forms.CharField(widget=forms.TextInput(), label=_("Title")) text = forms.CharField(widget=forms.Textarea(), label=_("Text")) @@ -51,7 +32,7 @@ class ApplicationFormTrivialChanges(ApplicationForm): class ApplicationManagerForm(forms.ModelForm, CssClassMixin): - submitter = UserFormField() + submitter = PersonFormField() class Meta: model = Application @@ -60,7 +41,7 @@ class ApplicationManagerForm(forms.ModelForm, CssClassMixin): class ApplicationManagerFormSupporter(ApplicationManagerForm): # TODO: Do not show the submitter in the user-list - supporter = MultipleUserFormField(required=False, label=_("Supporters")) + supporter = MultiplePersonFormField(required=False, label=_("Supporters")) class ApplicationImportForm(forms.Form, CssClassMixin): diff --git a/openslides/application/models.py b/openslides/application/models.py index 6da30fe23..78ebd55b6 100644 --- a/openslides/application/models.py +++ b/openslides/application/models.py @@ -21,12 +21,12 @@ from django.utils.translation import pgettext from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext from openslides.utils.utils import _propper_unicode -from openslides.utils.user import UserField +from openslides.utils.person import PersonField from openslides.config.models import config from openslides.config.signals import default_config_value -from openslides.participant.models import Profile +from openslides.participant.models import OpenSlidesUser from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast, CountInvalid, BaseVote) @@ -39,7 +39,7 @@ from openslides.agenda.models import Item class ApplicationSupporter(models.Model): application = models.ForeignKey("Application") - user = UserField() + person = PersonField() class Application(models.Model, SlideMixin): @@ -66,7 +66,7 @@ class Application(models.Model, SlideMixin): # genpoll ) - submitter = UserField(verbose_name=_("Submitter")) + submitter = PersonField(verbose_name=_("Submitter")) number = models.PositiveSmallIntegerField(blank=True, null=True, unique=True) status = models.CharField(max_length=3, choices=STATUS, default='pub') @@ -163,10 +163,11 @@ class Application(models.Model, SlideMixin): @property def supporters(self): - return [object.user for object in self.applicationsupporter_set.all()] + for object in self.applicationsupporter_set.all(): + yield object.person - def is_supporter(self, user): - return self.applicationsupporter_set.filter(user=user).exists() + def is_supporter(self, person): + return self.applicationsupporter_set.filter(person=person).exists() @property def enough_supporters(self): @@ -251,20 +252,20 @@ class Application(models.Model, SlideMixin): self.save() self.writelog(_("Status reseted to: %s") % (self.get_status_display()), user) - def support(self, user): + def support(self, person): """ Add a Supporter to the list of supporters of the application. """ - if user == self.submitter: + if person == self.submitter: # TODO: Use own Exception raise NameError('Supporter can not be the submitter of a ' \ 'application.') if self.permitted is not None: # TODO: Use own Exception raise NameError('This application is already permitted.') - if not self.is_supporter(user): - ApplicationSupporter(application=self, user=user).save() - self.writelog(_("Supporter: +%s") % (user)) + if not self.is_supporter(person): + ApplicationSupporter(application=self, person=person).save() + self.writelog(_("Supporter: +%s") % (person)) def unsupport(self, user): """ @@ -362,8 +363,8 @@ class Application(models.Model, SlideMixin): is_admin = False if user: try: - user = user.profile - except Profile.DoesNotExist: + user = user.openslidesuser + except OpenSlidesUser.DoesNotExist: is_admin = True except AttributeError: # For the anonymous-user diff --git a/openslides/application/views.py b/openslides/application/views.py index 0158e2513..d531b0cab 100644 --- a/openslides/application/views.py +++ b/openslides/application/views.py @@ -42,7 +42,7 @@ from openslides.utils.template import Tab from openslides.utils.utils import (template, permission_required, del_confirm_form, gen_confirm_form) from openslides.utils.views import PDFView, RedirectView, DeleteView, FormView -from openslides.utils.user import get_user +from openslides.utils.person import get_person from openslides.config.models import config @@ -50,8 +50,8 @@ from openslides.projector.projector import Widget from openslides.poll.views import PollFormView -from openslides.participant.api import gen_username, gen_password, user2djangouser -from openslides.participant.models import Profile +from openslides.participant.api import gen_username, gen_password +from openslides.participant.models import OpenSlidesUser from openslides.agenda.models import Item @@ -124,7 +124,7 @@ def overview(request): for (i, application) in enumerate(applications): try: applications[i] = { - 'actions' : application.get_allowed_actions(user2djangouser(request.user)), + 'actions' : application.get_allowed_actions(request.user.openslidesuser), 'application' : application } except: @@ -152,7 +152,7 @@ def view(request, application_id, newest=False): else: version = application.public_version revisions = application.versions - user = user2djangouser(request.user) + user = request.user.openslidesuser actions = application.get_allowed_actions(user=user) return { @@ -183,11 +183,11 @@ def edit(request, application_id=None): if application_id is not None: application = Application.objects.get(id=application_id) if (not hasattr(application.submitter, 'user') or - not user2djangouser(request.user) == application.submitter.user) \ + not request.user.openslidesuser == application.submitter.user) \ and not is_manager: messages.error(request, _("You can not edit this application. You are not the submitter.")) return redirect(reverse('application_view', args=[application.id])) - actions = application.get_allowed_actions(user=user2djangouser(request.user)) + actions = application.get_allowed_actions(user=request.user.openslidesuser) else: application = None actions = None @@ -221,7 +221,7 @@ def edit(request, application_id=None): original_supporters = [] application = managerform.save(commit=False) elif application_id is None: - application = Application(submitter=user2djangouser(request.user)) + application = Application(submitter=request.user.openslidesuser) application.title = dataform.cleaned_data['title'] application.text = dataform.cleaned_data['text'] application.reason = dataform.cleaned_data['reason'] @@ -231,7 +231,7 @@ def edit(request, application_id=None): and dataform.cleaned_data['trivial_change'] except KeyError: trivial_change = False - application.save(user2djangouser(request.user), trivial_change=trivial_change) + application.save(request.user.openslidesuser, trivial_change=trivial_change) if is_manager: try: new_supporters = set(managerform.cleaned_data['supporter']) @@ -273,10 +273,10 @@ def edit(request, application_id=None): dataform = formclass(initial=initial, prefix="data") if is_manager: if application_id is None: - initial = {'submitter': user2djangouser(request.user).uid} + initial = {'submitter': request.user.openslidesuser.person_id} else: - initial = {'submitter': application.submitter.uid, - 'supporter': [supporter.uid for supporter in application.supporters]} + initial = {'submitter': application.submitter.person_id, + 'supporter': [supporter.person_id for supporter in application.supporters]} managerform = managerformclass(initial=initial, instance=application, prefix="manager") else: @@ -296,7 +296,7 @@ def set_number(request, application_id): set a number for an application. """ try: - Application.objects.get(pk=application_id).set_number(user=user2djangouser(request.user)) + Application.objects.get(pk=application_id).set_number(user=request.user.openslidesuser) messages.success(request, _("Application number was successfully set.")) except Application.DoesNotExist: pass @@ -312,7 +312,7 @@ def permit(request, application_id): permit an application. """ try: - Application.objects.get(pk=application_id).permit(user=user2djangouser(request.user)) + Application.objects.get(pk=application_id).permit(user=request.user.openslidesuser) messages.success(request, _("Application was successfully permitted.")) except Application.DoesNotExist: pass @@ -327,7 +327,7 @@ def notpermit(request, application_id): reject (not permit) an application. """ try: - Application.objects.get(pk=application_id).notpermit(user=user2djangouser(request.user)) + Application.objects.get(pk=application_id).notpermit(user=request.user.openslidesuser) messages.success(request, _("Application was successfully rejected.")) except Application.DoesNotExist: pass @@ -343,7 +343,7 @@ def set_status(request, application_id=None, status=None): try: if status is not None: application = Application.objects.get(pk=application_id) - application.set_status(user=user2djangouser(request.user), status=status) + application.set_status(user=request.user.openslidesuser, status=status) messages.success(request, _("Application status was set to: %s.") % application.get_status_display()) except Application.DoesNotExist: pass @@ -359,7 +359,7 @@ def reset(request, application_id): reset an application. """ try: - Application.objects.get(pk=application_id).reset(user=user2djangouser(request.user)) + Application.objects.get(pk=application_id).reset(user=request.user.openslides.user) messages.success(request, _("Application status was reset.") ) except Application.DoesNotExist: pass @@ -373,7 +373,7 @@ def support(request, application_id): support an application. """ try: - Application.objects.get(pk=application_id).support(user=user2djangouser(request.user)) + Application.objects.get(pk=application_id).support(user=request.user.openslides.user) messages.success(request, _("You have support the application successfully.") ) except Application.DoesNotExist: pass @@ -387,7 +387,7 @@ def unsupport(request, application_id): unsupport an application. """ try: - Application.objects.get(pk=application_id).unsupport(user=user2djangouser(request.user)) + Application.objects.get(pk=application_id).unsupport(user=request.user.openslidesuser) messages.success(request, _("You have unsupport the application successfully.") ) except Application.DoesNotExist: pass @@ -401,7 +401,7 @@ def gen_poll(request, application_id): gen a poll for this application. """ try: - poll = Application.objects.get(pk=application_id).gen_poll(user=user2djangouser(request.user)) + poll = Application.objects.get(pk=application_id).gen_poll(user=request.user.openslidesuser) messages.success(request, _("New vote was successfully created.") ) except Application.DoesNotExist: pass # TODO: do not call poll after this excaption @@ -418,7 +418,7 @@ def delete_poll(request, poll_id): count = application.polls.filter(id__lte=poll_id).count() if request.method == 'POST': poll.delete() - application.writelog(_("Poll deleted"), user2djangouser(request.user)) + application.writelog(_("Poll deleted"), request.user.openslidesuser) messages.success(request, _('Poll was successfully deleted.')) else: del_confirm_form(request, poll, name=_("the %s. poll") % count, delete_link=reverse('application_poll_delete', args=[poll_id])) @@ -458,7 +458,7 @@ class ApplicationDelete(DeleteView): if len(self.applications): for application in self.applications: - if not 'delete' in application.get_allowed_actions(user=user2djangouser(request.user)): + if not 'delete' in application.get_allowed_actions(user=request.user.openslidesuser): messages.error(request, _("You can not delete application %s.") % application) continue @@ -467,7 +467,7 @@ class ApplicationDelete(DeleteView): messages.success(request, _("Application %s was successfully deleted.") % title) elif self.object: - if not 'delete' in self.object.get_allowed_actions(user=user2djangouser(request.user)): + if not 'delete' in self.object.get_allowed_actions(user=request.user.openslidesuser): messages.error(request, _("You can not delete application %s.") % self.object) else: title = self.object.title @@ -508,12 +508,12 @@ class ViewPoll(PollFormView): self.application = self.poll.get_application() context['application'] = self.application context['ballot'] = self.poll.get_ballot() - context['actions'] = self.application.get_allowed_actions(user=user2djangouser(self.request.user)) + context['actions'] = self.application.get_allowed_actions(user=self.request.user.openslidesuser) return context def get_modelform_class(self): cls = super(ViewPoll, self).get_modelform_class() - user = user2djangouser(self.request.user) + user = self.request.user.openslidesuser class ViewPollFormClass(cls): def save(self, commit = True): @@ -535,7 +535,7 @@ def permit_version(request, aversion_id): aversion = AVersion.objects.get(pk=aversion_id) application = aversion.application if request.method == 'POST': - application.accept_version(aversion, user=user2djangouser(request.user)) + application.accept_version(aversion, user=request.user.openslidesuser) messages.success(request, _("Version %s accepted.") % (aversion.aid)) else: gen_confirm_form(request, _('Do you really want to permit version %s?') % aversion.aid, reverse('application_version_permit', args=[aversion.id])) @@ -547,7 +547,7 @@ def reject_version(request, aversion_id): aversion = AVersion.objects.get(pk=aversion_id) application = aversion.application if request.method == 'POST': - if application.reject_version(aversion, user=user2djangouser(request.user)): + if application.reject_version(aversion, user=request.user.openslidesuser): messages.success(request, _("Version %s rejected.") % (aversion.aid)) else: messages.error(request, _("ERROR by rejecting the version.") ) @@ -560,8 +560,8 @@ def reject_version(request, aversion_id): @template('application/import.html') def application_import(request): try: - request.user.profile - except Profile.DoesNotExist: + request.user.openslidesuser + except OpenSlidesUser.DoesNotExist: pass except AttributeError: # AnonymousUser diff --git a/openslides/assignment/forms.py b/openslides/assignment/forms.py index c3a648355..cf4dfcba2 100644 --- a/openslides/assignment/forms.py +++ b/openslides/assignment/forms.py @@ -14,7 +14,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _, ugettext_noop from openslides.utils.forms import CssClassMixin -from openslides.utils.user import UserFormField +from openslides.utils.person import PersonFormField from openslides.assignment.models import Assignment @@ -29,7 +29,7 @@ class AssignmentForm(forms.ModelForm, CssClassMixin): class AssignmentRunForm(forms.Form, CssClassMixin): - candidate = UserFormField( + candidate = PersonFormField( widget=forms.Select(attrs={'class': 'medium-input'}), label=_("Nominate a participant"), ) diff --git a/openslides/assignment/models.py b/openslides/assignment/models.py index d3bab3dca..bf288cd8e 100644 --- a/openslides/assignment/models.py +++ b/openslides/assignment/models.py @@ -15,7 +15,7 @@ from django.db import models from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _, ugettext_noop -from openslides.utils.user import UserField +from openslides.utils.person import PersonField from openslides.config.models import config from openslides.config.signals import default_config_value @@ -31,11 +31,11 @@ from openslides.agenda.models import Item class AssignmentCandidate(models.Model): assignment = models.ForeignKey("Assignment") - user = UserField(db_index=True) + person = PersonField(db_index=True) elected = models.BooleanField(default=False) def __unicode__(self): - return unicode(self.user) + return unicode(self.person) class Assignment(models.Model, SlideMixin): @@ -69,7 +69,7 @@ class Assignment(models.Model, SlideMixin): self.status = status self.save() - def run(self, candidate, user=None): + def run(self, candidate, person=None): """ run for a vote """ @@ -77,22 +77,22 @@ class Assignment(models.Model, SlideMixin): # Use other Exceptions if self.is_candidate(candidate): raise NameError(_('%s is already a candidate.') % candidate) - if not user.has_perm("assignment.can_manage_assignment") and self.status != 'sea': + if not person.has_perm("assignment.can_manage_assignment") and self.status != 'sea': raise NameError(_('The candidate list is already closed.')) - AssignmentCandidate(assignment=self, user=candidate, elected=False).save() + AssignmentCandidate(assignment=self, person=candidate, elected=False).save() def delrun(self, candidate): """ stop running for a vote """ if self.is_candidate(candidate): - self.assignment_candidats.get(user=candidate).delete() + self.assignment_candidats.get(person=candidate).delete() else: # TODO: Use an OpenSlides Error raise Exception(_('%s is no candidate') % candidate) - def is_candidate(self, user): - if self.assignment_candidats.filter(user=user).exists(): + def is_candidate(self, person): + if self.assignment_candidats.filter(person=person).exists(): return True else: return False @@ -122,23 +122,22 @@ class Assignment(models.Model, SlideMixin): if only_candidate: candidates = candidates.filter(elected=False) - return [candidate.user for candidate in candidates] - #for candidate in candidates: - # yield candidate.user + for candidate in candidates.all(): + yield candidate.person - def set_elected(self, user, value=True): - candidate = self.assignment_candidats.get(user=user) + def set_elected(self, person, value=True): + candidate = self.assignment_candidats.get(person=person) candidate.elected = value candidate.save() - def is_elected(self, user): - return user in self.elected + def is_elected(self, person): + return person in self.elected def gen_poll(self): poll = AssignmentPoll(assignment=self) poll.save() - poll.set_options([{'candidate': user} for user in self.candidates]) + poll.set_options([{'candidate': person} for person in self.candidates]) return poll @@ -228,7 +227,7 @@ class AssignmentVote(BaseVote): class AssignmentOption(BaseOption): poll = models.ForeignKey('AssignmentPoll') - candidate = UserField() + candidate = PersonField() vote_class = AssignmentVote def __unicode__(self): diff --git a/openslides/assignment/templates/assignment/poll_view.html b/openslides/assignment/templates/assignment/poll_view.html index 5176bbdbf..64ff83866 100644 --- a/openslides/assignment/templates/assignment/poll_view.html +++ b/openslides/assignment/templates/assignment/poll_view.html @@ -21,36 +21,36 @@ {% endfor %} {% for form in forms %} - - {{ form.option }} - {% for value in form %} - - {{ value.errors }} - {{ value }} - + + {{ form.option }} + {% for value in form %} + + {{ value.errors }} + {{ value }} + + {% endfor %} + + {% endfor %} + + {% trans "Invalid votes" %} + {% for value in poll.get_vote_values %} + {% if forloop.first %} + {{ pollform.votesinvalid.errors }}{{ pollform.votesinvalid }} + {% else %} + + {% endif %} + {% endfor %} + + + {% trans "Votes cast" %} + {% for value in poll.get_vote_values %} + {% if forloop.first %} + {{ pollform.votescast.errors }}{{ pollform.votescast }} + {% else %} + + {% endif %} {% endfor %} - {% endfor %} - - {% trans "Invalid votes" %} - {% for value in poll.get_vote_values %} - {% if forloop.first %} - {{ pollform.votesinvalid.errors }}{{ pollform.votesinvalid }} - {% else %} - - {% endif %} - {% endfor %} - - - {% trans "Votes cast" %} - {% for value in poll.get_vote_values %} - {% if forloop.first %} - {{ pollform.votescast.errors }}{{ pollform.votescast }} - {% else %} - - {% endif %} - {% endfor %} -

    diff --git a/openslides/assignment/templates/assignment/view.html b/openslides/assignment/templates/assignment/view.html index cab930676..fc4feb615 100644 --- a/openslides/assignment/templates/assignment/view.html +++ b/openslides/assignment/templates/assignment/view.html @@ -35,12 +35,12 @@

    {% trans "Candidates" %}

      - {% for user in assignment.candidates %} + {% for person in assignment.candidates %}
    1. - {{ user }} + {{ person }} {% if perms.assignment.can_manage_assignment %} {% if assignment.status == "sea" or assignment.status == "vot" %} - + {% endif %} {% endif %}
    2. @@ -137,7 +137,7 @@ {% if candidate in assignment.elected %} {% if perms.assignment.can_manage_assignment %} - + {% else %} @@ -145,7 +145,7 @@ {% endif %} {% else %} {% if perms.assignment.can_manage_assignment %} - + {% endif %} {% endif %} {{ candidate }} diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py index 6320c459b..324ecb79c 100644 --- a/openslides/assignment/views.py +++ b/openslides/assignment/views.py @@ -30,12 +30,11 @@ from openslides.utils.template import Tab from openslides.utils.utils import (template, permission_required, gen_confirm_form, del_confirm_form, ajax_request) from openslides.utils.views import FormView, DeleteView, PDFView, RedirectView -from openslides.utils.user import get_user +from openslides.utils.person import get_person from openslides.config.models import config -from openslides.participant.models import Profile -from openslides.participant.api import user2djangouser +from openslides.participant.models import OpenSlidesUser from openslides.projector.projector import Widget @@ -98,7 +97,7 @@ def view(request, assignment_id=None): polls = assignment.poll_set.all() vote_results = assignment.vote_results(only_published=False) - user = user2djangouser(request.user) + user = request.user.openslidesuser return { 'assignment': assignment, 'form': form, @@ -174,7 +173,7 @@ def set_status(request, assignment_id=None, status=None): def run(request, assignment_id): assignment = Assignment.objects.get(pk=assignment_id) try: - assignment.run(user2djangouser(request.user), request.user) + assignment.run(request.user.openslidesuser, request.user) messages.success(request, _('You have set your candidature successfully.') ) except NameError, e: messages.error(request, e) @@ -186,7 +185,7 @@ def delrun(request, assignment_id): assignment = Assignment.objects.get(pk=assignment_id) try: if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"): - assignment.delrun(user2djangouser(request.user)) + assignment.delrun(request.user.openslidesuser) else: messages.error(request, _('The candidate list is already closed.')) except Exception, e: @@ -199,19 +198,19 @@ def delrun(request, assignment_id): @permission_required('assignment.can_manage_assignment') def delother(request, assignment_id, user_id): assignment = Assignment.objects.get(pk=assignment_id) - user = get_user(user_id) + person = get_person(user_id) if request.method == 'POST': try: - assignment.delrun(user) + assignment.delrun(person) except Exception, e: messages.error(request, e) else: - messages.success(request, _("Candidate %s was withdrawn successfully.") % (user)) + messages.success(request, _("Candidate %s was withdrawn successfully.") % (person)) else: gen_confirm_form(request, _("Do you really want to withdraw %s from the election?") \ - % user, reverse('assignment_delother', args=[assignment_id, user_id])) + % person, reverse('assignment_delother', args=[assignment_id, user_id])) return redirect(reverse('assignment_view', args=[assignment_id])) @@ -273,15 +272,15 @@ def set_publish_status(request, poll_id): @permission_required('assignment.can_manage_assignment') def set_elected(request, assignment_id, user_id, elected=True): assignment = Assignment.objects.get(pk=assignment_id) - user = get_user(user_id) - assignment.set_elected(user, elected) + person = get_person(user_id) + assignment.set_elected(person, elected) if request.is_ajax(): if elected: - link = reverse('assignment_user_not_elected', args=[assignment.id, user.uid]) + link = reverse('assignment_user_not_elected', args=[assignment.id, person.person_id]) text = _('not elected') else: - link = reverse('assignment_user_elected', args=[assignment.id, user.uid]) + link = reverse('assignment_user_elected', args=[assignment.id, person.person_id]) text = _('elected') return ajax_request({'elected': elected, 'link': link, 'text': text}) @@ -554,8 +553,8 @@ class AssignmentPollPDF(PDFView): candidate = option.candidate cell.append(Paragraph(candidate.user.get_full_name(), stylesheet['Ballot_option_name'])) - if candidate.group: - cell.append(Paragraph("(%s)" % candidate.group, + if candidate.name_surfix: + cell.append(Paragraph("(%s)" % candidate.name_surfix, stylesheet['Ballot_option_group'])) else: cell.append(Paragraph(" ", diff --git a/openslides/openslides_settings.py b/openslides/openslides_settings.py index ed2b0145e..b3f14315f 100755 --- a/openslides/openslides_settings.py +++ b/openslides/openslides_settings.py @@ -21,7 +21,6 @@ def _fs2unicode(s): SITE_ROOT = os.path.realpath(os.path.dirname(__file__)) -AUTH_PROFILE_MODULE = 'participant.Profile' AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend', 'openslides.utils.auth.AnonymousAuth',) @@ -124,6 +123,7 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', 'mptt', + 'openslides.utils', 'openslides.poll', 'openslides.projector', 'openslides.agenda', diff --git a/openslides/participant/api.py b/openslides/participant/api.py index 77104b98b..d2919821b 100644 --- a/openslides/participant/api.py +++ b/openslides/participant/api.py @@ -15,8 +15,8 @@ import string from django.contrib.auth.models import User -from openslides.utils.user import get_user -from openslides.participant.models import Profile +from openslides.utils.person import get_person +from openslides.participant.models import OpenSlidesUser def gen_password(): @@ -47,11 +47,3 @@ def gen_username(first_name, last_name): User.objects.get(username=testname) except User.DoesNotExist: return testname - - -def user2djangouser(user): - u = get_user('djangouser:%d' % user.id) - try: - return u.profile - except Profile.DoesNotExist: - return u diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py index 610e17b2b..e597bc5aa 100644 --- a/openslides/participant/forms.py +++ b/openslides/participant/forms.py @@ -17,7 +17,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop from openslides.utils.forms import CssClassMixin, LocalizedModelMultipleChoiceField -from openslides.participant.models import Profile +from openslides.participant.models import OpenSlidesUser USER_APPLICATION_IMPORT_OPTIONS = [ @@ -62,9 +62,9 @@ class UsernameForm(forms.ModelForm, CssClassMixin): 'date_joined', 'user_permissions') -class ProfileForm(forms.ModelForm, CssClassMixin): +class OpenSlidesUserForm(forms.ModelForm, CssClassMixin): class Meta: - model = Profile + model = OpenSlidesUser class GroupForm(forms.ModelForm, CssClassMixin): diff --git a/openslides/participant/models.py b/openslides/participant/models.py index 1913da474..391dfa375 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -12,18 +12,18 @@ from django.contrib.auth.models import User, Group from django.db import models -from django.db.models import Q +from django.db.models import Q, signals from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _, ugettext_noop -from openslides.utils.user import UserMixin -from openslides.utils.user.signals import receiv_users +from openslides.utils.person import PersonMixin +from openslides.utils.person.signals import receiv_persons from openslides.config.signals import default_config_value -class Profile(models.Model, UserMixin): - user_prefix = 'participant' +class OpenSlidesUser(models.Model, PersonMixin): + person_prefix = 'openslides_user' GENDER_CHOICES = ( ('male', _('Male')), ('female', _('Female')), @@ -36,8 +36,8 @@ class Profile(models.Model, UserMixin): ) user = models.OneToOneField(User, unique=True, editable=False) - group = models.CharField(max_length=100, null=True, blank=True, - verbose_name = _("Group"), help_text=_('Shown behind the name.')) + name_surfix = models.CharField(max_length=100, null=True, blank=True, + verbose_name = _("Name Surfix"), help_text=_('Shown behind the name.')) gender = models.CharField(max_length=50, choices=GENDER_CHOICES, blank=True, verbose_name = _("Gender"), help_text=_('Only for filter the userlist.')) @@ -76,76 +76,56 @@ class Profile(models.Model, UserMixin): return ('user_delete', [str(self.user.id)]) def __unicode__(self): - if self.group: - return "%s (%s)" % (self.user.get_full_name(), self.group) + if self.name_surfix: + return "%s (%s)" % (self.user.get_full_name(), self.name_surfix) return "%s" % self.user.get_full_name() class Meta: + # Rename permissions permissions = ( ('can_see_participant', ugettext_noop("Can see participant")), ('can_manage_participant', ugettext_noop("Can manage participant")), ) -class DjangoGroup(models.Model, UserMixin): - user_prefix = 'djangogroup' +class OpenSlidesGroup(models.Model, PersonMixin): + person_prefix = 'openslides_group' group = models.OneToOneField(Group) + group_as_person = models.BooleanField(default=False) def __unicode__(self): return unicode(self.group) -class DjangoUser(User, UserMixin): - user_prefix = 'djangouser' - - def has_no_profile(self): - # TODO: Make ths with a Manager, so it does manipulate the sql query - return not hasattr(self, 'profile') - - class Meta: - proxy = True - - -class ParticipantUsers(object): - def __init__(self, user_prefix=None, id=None): - self.user_prefix = user_prefix +class OpenSlidesUsersConnecter(object): + def __init__(self, person_prefix=None, id=None): + self.person_prefix = person_prefix self.id = id def __iter__(self): - if not self.user_prefix or self.user_prefix == Profile.user_prefix: + if not self.person_prefix or self.person_prefix == OpenSlidesUser.person_prefix: if self.id: - yield Profile.objects.get(pk=self.id) + yield OpenSlidesUser.objects.get(pk=self.id) else: - for profile in Profile.objects.all(): - yield profile + for user in OpenSlidesUser.objects.all(): + yield user - if not self.user_prefix or self.user_prefix == DjangoGroup.user_prefix: + if not self.person_prefix or self.person_prefix == OpenSlidesGroup.person_prefix: if self.id: - yield DjangoGroup.objects.get(pk=self.id) + yield OpenSlidesObject.objects.get(pk=self.id) else: - for group in DjangoGroup.objects.all(): + for group in OpenSlidesGroup.objects.all(): yield group - if not self.user_prefix or self.user_prefix == DjangoUser.user_prefix: - if self.id: - yield DjangoUser.objects.get(pk=self.id) - else: - for user in DjangoUser.objects.all(): - if user.has_no_profile(): - yield user - elif self.user_prefix: - # If only users where requested, return the profile object. - yield user.profile - def __getitem__(self, key): - return Profile.objects.get(pk=key) + return OpenSlidesUser.objects.get(pk=key) -@receiver(receiv_users, dispatch_uid="participant_profile") -def receiv_users(sender, **kwargs): - return ParticipantUsers(user_prefix=kwargs['user_prefix'], id=kwargs['id']) +@receiver(receiv_persons, dispatch_uid="participant") +def receiv_persons(sender, **kwargs): + return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'], id=kwargs['id']) @receiver(default_config_value, dispatch_uid="participant_default_config") @@ -153,8 +133,15 @@ def default_config(sender, key, **kwargs): """ Default values for the participant app. """ + # TODO: Rename config-vars return { 'participant_pdf_system_url': 'http://example.com:8000', 'participant_pdf_welcometext': _('Welcome to OpenSlides!'), 'admin_password': None, }.get(key) + + +@receiver(signals.post_save, sender=User) +def user_post_save(sender, instance, signal, *args, **kwargs): + # Creates OpenSlidesUser + profile, new = OpenSlidesUser.objects.get_or_create(user=instance) diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 35ae94c4d..7797c4508 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -46,10 +46,10 @@ from openslides.utils.views import FormView, PDFView from openslides.config.models import config -from openslides.participant.models import Profile, DjangoGroup +from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup from openslides.participant.api import gen_username, gen_password from openslides.participant.forms import (UserNewForm, UserEditForm, - ProfileForm, UsersettingsForm, UserImportForm, GroupForm, + OpenSlidesUserForm, UsersettingsForm, UserImportForm, GroupForm, AdminPasswordChangeForm, ConfigForm) @@ -78,53 +78,55 @@ def get_overview(request): query = User.objects if 'gender' in sortfilter: - query = query.filter(profile__gender__iexact=sortfilter['gender'][0]) + query = query.filter(openslidesuser__gender__iexact=sortfilter['gender'][0]) if 'group' in sortfilter: - query = query.filter(profile__group__iexact=sortfilter['group'][0]) + query = query.filter(openslidesuser__group__iexact=sortfilter['name_surfix'][0]) if 'type' in sortfilter: - query = query.filter(profile__type__iexact=sortfilter['type'][0]) + query = query.filter(openslidesuser__type__iexact=sortfilter['type'][0]) if 'committee' in sortfilter: query = query. \ - filter(profile__committee__iexact=sortfilter['committee'][0]) + filter(openslidesuser__committee__iexact=sortfilter['committee'][0]) if 'status' in sortfilter: query = query.filter(is_active=sortfilter['status'][0]) if 'sort' in sortfilter: if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']: query = query.order_by(sortfilter['sort'][0]) - elif sortfilter['sort'][0] in ['group', 'type', 'committee', 'comment']: - query = query.order_by('profile__%s' % sortfilter['sort'][0]) + elif sortfilter['sort'][0] in ['name_surfix', 'type', 'committee', 'comment']: + query = query.order_by('openslidesuser__%s' % sortfilter['sort'][0]) else: query = query.order_by('last_name') if 'reverse' in sortfilter: query = query.reverse() - # list of filtered users (with profile) + # list of filtered users userlist = query.all() users = [] for user in userlist: try: - user.get_profile() - users.append(user) - except Profile.DoesNotExist: + user.openslidesuser + except OpenSlidesUser.DoesNotExist: pass - # list of all existing users (with profile) + else: + users.append(user) + # list of all existing users allusers = [] for user in User.objects.all(): try: - user.get_profile() - allusers.append(user) - except Profile.DoesNotExist: + user.openslidesuser + except OpenSlidesUser.DoesNotExist: pass + else: + allusers.append(user) # quotient of selected users and all users if len(allusers) > 0: percent = float(len(users)) * 100 / float(len(allusers)) else: percent = 0 # list of all existing groups - groups = [p['group'] for p in Profile.objects.values('group') \ - .exclude(group='').distinct()] + groups = [p['name_surfix'] for p in OpenSlidesUser.objects.values('name_surfix') \ + .exclude(name_surfix='').distinct()] # list of all existing committees - committees = [p['committee'] for p in Profile.objects.values('committee') \ + committees = [p['committee'] for p in OpenSlidesUser.objects.values('committee') \ .exclude(committee='').distinct()] return { 'users': users, @@ -142,7 +144,7 @@ def get_overview(request): @template('participant/edit.html') def edit(request, user_id=None): """ - View to create and edit users with profile. + View to create and edit users. """ if user_id is not None: user = User.objects.get(id=user_id) @@ -151,26 +153,31 @@ def edit(request, user_id=None): if request.method == 'POST': if user_id is None: - userform = UserNewForm(request.POST, prefix="user") - profileform = ProfileForm(request.POST, prefix="profile") + user_form = UserNewForm(request.POST, prefix="user") + openslides_user_form = OpenSlidesUserForm(request.POST, prefix="openslidesuser") else: - userform = UserEditForm(request.POST, instance=user, prefix="user") - profileform = ProfileForm(request.POST, instance=user.profile, - prefix="profile") + user_form = UserEditForm(request.POST, instance=user, prefix="user") + openslides_user_form = OpenSlidesUserForm(request.POST, instance=user.openslidesuser, + prefix="openslidesuser") - if userform.is_valid() and profileform.is_valid(): - user = userform.save() + if user_form.is_valid() and openslides_user_form.is_valid(): + user = user_form.save(commit=False) if user_id is None: + # TODO: call first_name and last_name though openslides_user user.username = gen_username(user.first_name, user.last_name) user.save() - profile = profileform.save(commit=False) - profile.user = user + openslides_user = user.openslidesuser + openslides_user_form = OpenSlidesUserForm(request.POST, instance=openslides_user, prefix="openslidesuser") + openslides_user_form.is_valid() + openslides_user = openslides_user_form.save(commit=False) + openslides_user.user = user if user_id is None: - if not profile.firstpassword: - profile.firstpassword = gen_password() - profile.user.set_password(profile.firstpassword) - profile.user.save() - profile.save() + if not openslides_user.firstpassword: + openslides_user.firstpassword = gen_password() + openslides_user.user.set_password(openslides_user.firstpassword) + # TODO: Try not to save the user object + openslides_user.user.save() + openslides_user.save() if user_id is None: messages.success(request, _('New participant was successfully created.')) @@ -185,15 +192,15 @@ def edit(request, user_id=None): messages.error(request, _('Please check the form for errors.')) else: if user_id is None: - userform = UserNewForm(prefix="user") - profileform = ProfileForm(prefix="profile") + user_form = UserNewForm(prefix="user") + openslides_user_form = OpenSlidesUserForm(prefix="openslidesuser") else: - userform = UserEditForm(instance=user, prefix="user") - profileform = ProfileForm(instance=user.profile, prefix="profile") - + user_form = UserEditForm(instance=user, prefix="user") + openslides_user_form = OpenSlidesUserForm(instance=user.openslidesuser, prefix="openslidesuser") + # TODO: rename template vars return { - 'userform': userform, - 'profileform': profileform, + 'userform': user_form, + 'profileform': openslides_user_form, 'edituser': user, } @@ -330,7 +337,7 @@ def group_edit(request, group_id=None): else: messages.error(request, _('Please check the form for errors.')) else: - if group and DjangoGroup.objects.filter(group=group).exists(): + if group and OpenSlidesGroup.objects.filter(group=group).exists(): initial = {'as_user': True} else: initial = {'as_user': False} diff --git a/openslides/utils/person/__init__.py b/openslides/utils/person/__init__.py new file mode 100644 index 000000000..e54e6258a --- /dev/null +++ b/openslides/utils/person/__init__.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + openslides.utils.person + ~~~~~~~~~~~~~~~~~~~~~~~ + + Person api for OpenSlides + + :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from openslides.utils.person.signals import receiv_persons +from openslides.utils.person.api import generate_person_id, get_person, Persons +from openslides.utils.person.forms import PersonFormField, MultiplePersonFormField +from openslides.utils.person.models import PersonField, PersonMixin + + +class EmtyPerson(PersonMixin): + @property + def person_id(self): + return 'emtyuser' diff --git a/openslides/utils/person/api.py b/openslides/utils/person/api.py new file mode 100644 index 000000000..59e7d7a1a --- /dev/null +++ b/openslides/utils/person/api.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + openslides.utils.person.api + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Usefull functions for the OpenSlides person api. + + :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from openslides.utils.person.signals import receiv_persons + + +class Persons(object): + """ + A Storage for a multiplicity of different Person-Objects. + """ + def __init__(self, person_prefix=None, id=None): + self.person_prefix = person_prefix + self.id = id + + def __iter__(self): + try: + return iter(self._cache) + except AttributeError: + return iter(self.iter_persons()) + + def __len__(self): + return len(list(self.__iter__())) + + def __getitem__(self, key): + return list(self)[key] + + def iter_persons(self): + self._cache = list() + for receiver, persons in receiv_persons.send( + sender='persons', person_prefix=self.person_prefix, id=self.id): + for person in persons: + self._cache.append(person) + yield person + + +def generate_person_id(prefix, id): + if ':' in prefix: + raise ValueError("':' is not allowed in a the 'person_prefix'") + return "%s:%d" % (prefix, id) + + +def split_person_id(person_id): + data = person_id.split(':', 1) + if len(data) == 2 and data[0] and data[1]: + return data + raise TypeError("Invalid person_id: '%s'" % person_id) + + +def get_person(person_id): + try: + person_prefix, id = split_person_id(person_id) + except TypeError: + from openslides.utils.person import EmtyPerson + return EmtyPerson() + return Persons(person_prefix=person_prefix, id=id)[0] diff --git a/openslides/utils/user/forms.py b/openslides/utils/person/forms.py similarity index 66% rename from openslides/utils/user/forms.py rename to openslides/utils/person/forms.py index 383754402..2330443dc 100644 --- a/openslides/utils/user/forms.py +++ b/openslides/utils/person/forms.py @@ -1,10 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ - openslides.utils.user.forms - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + openslides.utils.person.forms + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Forms and FormFields for the OpenSlides user api. + Forms and FormFields for the OpenSlides person api. :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. :license: GNU GPL, see LICENSE for more details. @@ -12,21 +12,21 @@ from django import forms -from openslides.utils.user.api import Users, get_user +from openslides.utils.person.api import Persons, get_person -class UserChoices(object): +class PersonChoices(object): def __init__(self, field): self.field = field def __iter__(self): if self.field.empty_label is not None: yield (u"", self.field.empty_label) - for user in Users(): - yield (user.uid, user) + for person in Persons(): + yield (person.person_id, person) -class UserFormField(forms.fields.ChoiceField): +class PersonFormField(forms.fields.ChoiceField): def __init__(self, required=True, initial=None, empty_label=u"---------", *args, **kwargs): if required and (initial is not None): @@ -46,32 +46,32 @@ class UserFormField(forms.fields.ChoiceField): # the property self.choices. In this case, just return self._choices. if hasattr(self, '_choices'): return self._choices - return UserChoices(self) + return PersonChoices(self) choices = property(_get_choices, forms.fields.ChoiceField._set_choices) def to_python(self, value): - return get_user(value) + return get_person(value) def valid_value(self, value): - return super(UserFormField, self).valid_value(value.uid) + return super(PersonFormField, self).valid_value(value.person_id) -class MultipleUserFormField(UserFormField): +class MultiplePersonFormField(PersonFormField): widget = forms.widgets.SelectMultiple def __init__(self, *args, **kwargs): - super(MultipleUserFormField, self).__init__(empty_label=None, + super(MultiplePersonFormField, self).__init__(empty_label=None, *args, **kwargs) def to_python(self, value): if hasattr(value, '__iter__'): - return [super(MultipleUserFormField, self).to_python(v) + return [super(MultiplePersonFormField, self).to_python(v) for v in value] - return super(MultipleUserFormField, self).to_python(value) + return super(MultiplePersonFormField, self).to_python(value) def valid_value(self, value): if hasattr(value, '__iter__'): - return [super(MultipleUserFormField, self).valid_value(v) + return [super(MultiplePersonFormField, self).valid_value(v) for v in value] - return super(MultipleUserFormField, self).valid_value(value) + return super(MultiplePersonFormField, self).valid_value(value) diff --git a/openslides/utils/user/models.py b/openslides/utils/person/models.py similarity index 50% rename from openslides/utils/user/models.py rename to openslides/utils/person/models.py index c826be061..3df620dfd 100644 --- a/openslides/utils/user/models.py +++ b/openslides/utils/person/models.py @@ -1,25 +1,25 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ - openslides.utils.user.models - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + openslides.utils.person.models + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Models and ModelFields for the OpenSlides user api. + Models and ModelFields for the OpenSlides person api. :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. :license: GNU GPL, see LICENSE for more details. """ from django.db import models -from openslides.utils.user.forms import UserFormField -from openslides.utils.user.api import get_user, generate_uid +from openslides.utils.person.forms import PersonFormField +from openslides.utils.person.api import get_person, generate_person_id -class UserField(models.fields.Field): +class PersonField(models.fields.Field): __metaclass__ = models.SubfieldBase def __init__(self, *args, **kwargs): - super(UserField, self).__init__(max_length=255, *args, **kwargs) + super(PersonField, self).__init__(max_length=255, *args, **kwargs) # TODO: Validate the uid def get_internal_type(self): @@ -29,36 +29,36 @@ class UserField(models.fields.Field): """ Convert string value to a User Object. """ - if hasattr(value, 'uid'): - user = value + if hasattr(value, 'person_id'): + person = value else: - user = get_user(value) + person = get_person(value) - user.prepare_database_save = ( - lambda unused: UserField().get_prep_value(user)) - return user + person.prepare_database_save = ( + lambda unused: PersonField().get_prep_value(person)) + return person def get_prep_value(self, value): - return value.uid + return value.person_id def value_to_string(self, obj): value = self._get_val_from_obj(obj) return self.get_prep_value(value) def formfield(self, **kwargs): - defaults = {'form_class': UserFormField} + defaults = {'form_class': PersonFormField} defaults.update(kwargs) - return super(UserField, self).formfield(**defaults) + return super(PersonField, self).formfield(**defaults) -class UserMixin(object): +class PersonMixin(object): @property - def uid(self): + def person_id(self): try: - return generate_uid(self.user_prefix, self.pk) + return generate_person_id(self.person_prefix, self.pk) except AttributeError: raise AttributeError("%s has to have a attribute 'user_prefix'" % self) def __repr__(self): - return 'User: %s' % self.uid + return 'Person: %s' % self.person_id diff --git a/openslides/utils/user/signals.py b/openslides/utils/person/signals.py similarity index 82% rename from openslides/utils/user/signals.py rename to openslides/utils/person/signals.py index 5779db7ab..5d8dba88b 100644 --- a/openslides/utils/user/signals.py +++ b/openslides/utils/person/signals.py @@ -12,4 +12,4 @@ from django.dispatch import Signal -receiv_users = Signal(providing_args=['user_prefix', 'id']) +receiv_persons = Signal(providing_args=['person_prefix', 'id']) diff --git a/openslides/utils/user/__init__.py b/openslides/utils/user/__init__.py deleted file mode 100644 index 87b167d8c..000000000 --- a/openslides/utils/user/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - openslides.utils.user - ~~~~~~~~~~~~~~~~~~~~~ - - User api for OpenSlides - - :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. - :license: GNU GPL, see LICENSE for more details. -""" - -from openslides.utils.user.signals import receiv_users -from openslides.utils.user.api import generate_uid, split_uid, get_user, Users -from openslides.utils.user.forms import UserFormField, MultipleUserFormField -from openslides.utils.user.models import UserField, UserMixin - - -class EmtyUser(UserMixin): - @property - def uid(self): - return 'emtyuser' diff --git a/openslides/utils/user/api.py b/openslides/utils/user/api.py deleted file mode 100644 index 7e418ab61..000000000 --- a/openslides/utils/user/api.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - openslides.utils.user.api - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Usefull functions for the OpenSlides user api. - - :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. - :license: GNU GPL, see LICENSE for more details. -""" - -from openslides.utils.user.signals import receiv_users - - -class Users(object): - """ - A Storage for a multiplicity of different User-Objects. - """ - def __init__(self, user_prefix=None, id=None): - self.user_prefix = user_prefix - self.id = id - - def __iter__(self): - try: - return iter(self._cache) - except AttributeError: - return iter(self.iter_users()) - - def __len__(self): - return len(list(self.__iter__())) - - def __getitem__(self, key): - user_list = list(self) - return user_list[key] - - def iter_users(self): - self._cache = list() - for receiver, users in receiv_users.send( - sender='users', user_prefix=self.user_prefix, id=self.id): - for user in users: - self._cache.append(user) - yield user - - -def generate_uid(prefix, id): - if ':' in prefix: - raise ValueError("':' is not allowed in a the 'user_prefix'") - return "%s:%d" % (prefix, id) - - -def split_uid(uid): - data = uid.split(':', 1) - if len(data) == 2 and data[0] and data[1]: - return data - raise TypeError("Invalid uid: '%s'" % uid) - - -def get_user(uid): - try: - user_prefix, id = split_uid(uid) - except TypeError: - from openslides.utils.user import EmtyUser - return EmtyUser() - return Users(user_prefix=user_prefix, id=id)[0] From f22362df9db518056a9752678adfebb79690bdaa Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Wed, 8 Aug 2012 10:07:36 +0200 Subject: [PATCH 17/19] made participant-test run again --- openslides/participant/models.py | 8 ++-- openslides/participant/tests.py | 81 +++++++++++++------------------- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/openslides/participant/models.py b/openslides/participant/models.py index 391dfa375..b330084cf 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -51,11 +51,13 @@ class OpenSlidesUser(models.Model, PersonMixin): firstpassword = models.CharField(max_length=100, null=True, blank=True, verbose_name = _("First Password")) - def reset_password(self): + def reset_password(self, password=None): """ Reset the password for the user to his default-password. """ - self.user.set_password(self.firstpassword) + if password is None: + password = self.firstpassword + self.user.set_password(password) self.user.save() def has_perm(self, perm): @@ -114,7 +116,7 @@ class OpenSlidesUsersConnecter(object): if not self.person_prefix or self.person_prefix == OpenSlidesGroup.person_prefix: if self.id: - yield OpenSlidesObject.objects.get(pk=self.id) + yield OpenSlidesGroup.objects.get(pk=self.id) else: for group in OpenSlidesGroup.objects.all(): yield group diff --git a/openslides/participant/tests.py b/openslides/participant/tests.py index fa4026335..c7dbadf46 100644 --- a/openslides/participant/tests.py +++ b/openslides/participant/tests.py @@ -16,72 +16,57 @@ from django.contrib.auth.models import User, Group from django.db.models.query import EmptyQuerySet from django.contrib.auth.hashers import check_password -from openslides.utils.user import get_user, Users -from openslides.participant.api import gen_username, gen_password, user2djangouser -from openslides.participant.models import Profile, DjangoGroup, DjangoUser +from openslides.utils.person import get_person, Persons +from openslides.participant.api import gen_username, gen_password +from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup -class ParticipantTest(TestCase): +class OpenSlidesUserTest(TestCase): def setUp(self): self.user1 = User(first_name=u'Max', last_name=u'Mustermann') self.user1.username = gen_username(self.user1.first_name, self.user1.last_name) self.user1.save() - self.participant1 = Profile.objects.create(user=self.user1, firstpassword=gen_password()) + self.openslidesuser1 = self.user1.openslidesuser + self.openslidesuser1.firstpassword = gen_password() + self.openslidesuser1.save() + self.user1 = self.openslidesuser1.user def test_participant_user(self): - self.assertEqual(self.user1.profile, self.participant1) - self.assertEqual(self.user1, self.participant1.user) + self.assertEqual(self.user1.openslidesuser, self.openslidesuser1) + self.assertEqual(self.user1, self.openslidesuser1.user) def test_repr(self): - self.assertEqual(unicode(self.participant1), u'Max Mustermann') + self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann') - def test_group(self): - self.participant1.group = u'München' - self.participant1.save() - self.assertEqual(unicode(self.participant1), u'Max Mustermann (München)') + def test_name_surfix(self): + self.openslidesuser1.name_surfix = u'München' + self.openslidesuser1.save() + self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann (München)') def test_reset_password(self): - self.assertIsInstance(self.participant1.firstpassword, basestring) - self.assertEqual(len(self.participant1.firstpassword), 8) + self.assertIsInstance(self.openslidesuser1.firstpassword, basestring) + self.assertEqual(len(self.openslidesuser1.firstpassword), 8) self.user1.set_unusable_password() - self.assertFalse(self.user1.check_password(self.participant1.firstpassword)) - self.participant1.reset_password() - self.assertTrue(self.user1.check_password(self.participant1.firstpassword)) + self.assertFalse(self.user1.check_password(self.openslidesuser1.firstpassword)) + self.openslidesuser1.reset_password() + self.assertTrue(self.user1.check_password(self.openslidesuser1.firstpassword)) - def test_user_api(self): - self.assertTrue(hasattr(self.participant1, 'uid')) - self.assertEqual(self.participant1.uid, 'participant:1') - self.assertEqual(get_user('participant:1'), self.participant1) - self.assertEqual(len(Users()), 1) + def test_person_api(self): + self.assertTrue(hasattr(self.openslidesuser1, 'person_id')) + self.assertEqual(self.openslidesuser1.person_id, 'openslides_user:1') + self.assertEqual(get_person('openslides_user:1'), self.openslidesuser1) + self.assertEqual(len(Persons()), 1) -class DjangoGroupTest(TestCase): +class OpenSlidesGroupTest(TestCase): def setUp(self): self.group1 = Group.objects.create(name='Test Group') - self.djangogroup1 = DjangoGroup.objects.create(group=self.group1) + self.openslidesgroup1 = OpenSlidesGroup.objects.create(group=self.group1) - def test_group_djangogroup(self): - self.assertEqual(self.djangogroup1.group, self.group1) + def test_group_openslidesgroup(self): + self.assertEqual(self.openslidesgroup1.group, self.group1) - def test_user_api(self): - self.assertTrue(hasattr(self.djangogroup1, 'uid')) - self.assertEqual(self.djangogroup1.uid, 'djangogroup:1') - self.assertEqual(get_user('djangogroup:1'), self.djangogroup1) - - -class DjangoUserTest(TestCase): - def setUp(self): - self.user1 = User.objects.create(username='admin') - self.djangouser1 = DjangoUser.objects.get(pk=1) - - def test_djangouser_user(self): - self.assertEqual(self.user1.pk, self.djangouser1.pk) - - def test_has_no_profile(self): - self.assertTrue(self.djangouser1.has_no_profile()) - - def test_user_api(self): - self.assertTrue(hasattr(self.djangouser1, 'uid')) - self.assertEqual(self.djangouser1.uid, 'djangouser:1') - self.assertEqual(get_user('djangouser:1'), self.djangouser1) - self.assertEqual(user2djangouser(self.user1), self.djangouser1) + def test_person_api(self): + self.assertTrue(hasattr(self.openslidesgroup1, 'person_id')) + self.assertEqual(self.openslidesgroup1.person_id, 'openslides_group:1') + self.assertEqual(get_person('openslides_group:1'), self.openslidesgroup1) From d1ab2f2e8577f530fc4e619b9c6e9b48237955f3 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Wed, 8 Aug 2012 10:34:23 +0200 Subject: [PATCH 18/19] some pep8 corections for the participant app --- openslides/participant/forms.py | 49 +++++++-------- openslides/participant/models.py | 43 +++++++------ openslides/participant/views.py | 105 ++++++++++++++++--------------- 3 files changed, 103 insertions(+), 94 deletions(-) diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py index e597bc5aa..f39db40fb 100644 --- a/openslides/participant/forms.py +++ b/openslides/participant/forms.py @@ -15,7 +15,8 @@ from django.contrib.auth.forms import AdminPasswordChangeForm from django.contrib.auth.models import User, Group, Permission from django.utils.translation import ugettext_lazy as _, ugettext_noop -from openslides.utils.forms import CssClassMixin, LocalizedModelMultipleChoiceField +from openslides.utils.forms import ( + CssClassMixin, LocalizedModelMultipleChoiceField) from openslides.participant.models import OpenSlidesUser @@ -23,43 +24,43 @@ from openslides.participant.models import OpenSlidesUser USER_APPLICATION_IMPORT_OPTIONS = [ ('REASSIGN', _('Keep applications, try to reassign submitter')), ('INREVIEW', _('Keep applications, set status to "needs review"')), - ('DISCARD' , _('Discard applications')) + ('DISCARD', _('Discard applications')) ] class UserNewForm(forms.ModelForm, CssClassMixin): first_name = forms.CharField(label=_("First name")) last_name = forms.CharField(label=_("Last name")) - groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(), - label=_("User groups"), required=False) - is_active = forms.BooleanField(label=_("Active"), required=False, - initial=True) + groups = forms.ModelMultipleChoiceField( + queryset=Group.objects.all(), label=_("User groups"), required=False) + is_active = forms.BooleanField( + label=_("Active"), required=False, initial=True) class Meta: model = User exclude = ('username', 'password', 'is_staff', 'is_superuser', - 'last_login', 'date_joined', 'user_permissions') + 'last_login', 'date_joined', 'user_permissions') class UserEditForm(forms.ModelForm, CssClassMixin): first_name = forms.CharField(label=_("First name")) last_name = forms.CharField(label=_("Last name")) - groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(), - label=_("User groups"), required=False) + groups = forms.ModelMultipleChoiceField( + queryset=Group.objects.all(), label=_("User groups"), required=False) is_active = forms.BooleanField(label=_("Active"), required=False) class Meta: model = User exclude = ('password', 'is_staff', 'is_superuser', 'last_login', - 'date_joined', 'user_permissions') + 'date_joined', 'user_permissions') class UsernameForm(forms.ModelForm, CssClassMixin): class Meta: model = User exclude = ('first_name', 'last_name', 'email', 'is_active', - 'is_superuser', 'groups', 'password', 'is_staff', 'last_login', - 'date_joined', 'user_permissions') + 'is_superuser', 'groups', 'password', 'is_staff', + 'last_login', 'date_joined', 'user_permissions') class OpenSlidesUserForm(forms.ModelForm, CssClassMixin): @@ -68,8 +69,8 @@ class OpenSlidesUserForm(forms.ModelForm, CssClassMixin): class GroupForm(forms.ModelForm, CssClassMixin): - as_user = forms.BooleanField(initial=False, required=False, - label=_("Treat Group as User"), + as_user = forms.BooleanField( + initial=False, required=False, label=_("Treat Group as User"), help_text=_("The Group will appear on any place, other user does.")) permissions = LocalizedModelMultipleChoiceField( queryset=Permission.objects.all(), label=_("Persmissions")) @@ -77,8 +78,8 @@ class GroupForm(forms.ModelForm, CssClassMixin): def __init__(self, *args, **kwargs): super(GroupForm, self).__init__(*args, **kwargs) if kwargs.get('instance', None) is not None: - self.fields['permissions'].initial = \ - [p.pk for p in kwargs['instance'].permissions.all()] + self.fields['permissions'].initial = ( + [p.pk for p in kwargs['instance'].permissions.all()]) class Meta: model = Group @@ -92,13 +93,11 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin): class UserImportForm(forms.Form, CssClassMixin): - csvfile = forms.FileField(widget=forms.FileInput(attrs={'size':'50'}), - label=_("CSV File")) + csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}), + label=_("CSV File")) application_handling = forms.ChoiceField( - required=True, - choices=USER_APPLICATION_IMPORT_OPTIONS, - label=_("For existing applications"), - ) + required=True, choices=USER_APPLICATION_IMPORT_OPTIONS, + label=_("For existing applications")) class ConfigForm(forms.Form, CssClassMixin): @@ -106,11 +105,9 @@ class ConfigForm(forms.Form, CssClassMixin): widget=forms.TextInput(), required=False, label=_("System URL"), - help_text=_("Printed in PDF of first time passwords only."), - ) + help_text=_("Printed in PDF of first time passwords only.")) participant_pdf_welcometext = forms.CharField( widget=forms.Textarea(), required=False, label=_("Welcome text"), - help_text=_("Printed in PDF of first time passwords only."), - ) + help_text=_("Printed in PDF of first time passwords only.")) diff --git a/openslides/participant/models.py b/openslides/participant/models.py index b330084cf..f7685994e 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -36,20 +36,24 @@ class OpenSlidesUser(models.Model, PersonMixin): ) user = models.OneToOneField(User, unique=True, editable=False) - name_surfix = models.CharField(max_length=100, null=True, blank=True, - verbose_name = _("Name Surfix"), help_text=_('Shown behind the name.')) - gender = models.CharField(max_length=50, choices=GENDER_CHOICES, blank=True, - verbose_name = _("Gender"), + name_surfix = models.CharField( + max_length=100, null=True, blank=True, verbose_name=_("Name Surfix"), + help_text=_('Shown behind the name.')) + gender = models.CharField( + max_length=50, choices=GENDER_CHOICES, blank=True, + verbose_name=_("Gender"), help_text=_('Only for filter the userlist.')) + type = models.CharField( + max_length=100, choices=TYPE_CHOICE, blank=True, + verbose_name=_("Typ"), help_text=_('Only for filter the userlist.')) + committee = models.CharField( + max_length=100, null=True, blank=True, verbose_name=_("Committee"), help_text=_('Only for filter the userlist.')) - type = models.CharField(max_length=100, choices=TYPE_CHOICE, blank=True, - verbose_name = _("Typ"), help_text=_('Only for filter the userlist.')) - committee = models.CharField(max_length=100, null=True, blank=True, - verbose_name = _("Committee"), - help_text=_('Only for filter the userlist.')) - comment = models.TextField(null=True, blank=True, - verbose_name = _('Comment'), help_text=_('Only for notes.')) - firstpassword = models.CharField(max_length=100, null=True, blank=True, - verbose_name = _("First Password")) + comment = models.TextField( + null=True, blank=True, verbose_name=_('Comment'), + help_text=_('Only for notes.')) + firstpassword = models.CharField( + max_length=100, null=True, blank=True, + verbose_name=_("First Password")) def reset_password(self, password=None): """ @@ -82,12 +86,12 @@ class OpenSlidesUser(models.Model, PersonMixin): return "%s (%s)" % (self.user.get_full_name(), self.name_surfix) return "%s" % self.user.get_full_name() - class Meta: # Rename permissions permissions = ( ('can_see_participant', ugettext_noop("Can see participant")), - ('can_manage_participant', ugettext_noop("Can manage participant")), + ('can_manage_participant', + ugettext_noop("Can manage participant")), ) @@ -107,14 +111,16 @@ class OpenSlidesUsersConnecter(object): self.id = id def __iter__(self): - if not self.person_prefix or self.person_prefix == OpenSlidesUser.person_prefix: + if (not self.person_prefix or + self.person_prefix == OpenSlidesUser.person_prefix): if self.id: yield OpenSlidesUser.objects.get(pk=self.id) else: for user in OpenSlidesUser.objects.all(): yield user - if not self.person_prefix or self.person_prefix == OpenSlidesGroup.person_prefix: + if (not self.person_prefix or + self.person_prefix == OpenSlidesGroup.person_prefix): if self.id: yield OpenSlidesGroup.objects.get(pk=self.id) else: @@ -127,7 +133,8 @@ class OpenSlidesUsersConnecter(object): @receiver(receiv_persons, dispatch_uid="participant") def receiv_persons(sender, **kwargs): - return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'], id=kwargs['id']) + return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'], + id=kwargs['id']) @receiver(default_config_value, dispatch_uid="participant_default_config") diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 7797c4508..728965c55 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -18,13 +18,14 @@ from urllib import urlencode try: from urlparse import parse_qs -except ImportError: # python <= 2.5 grab it from cgi +except ImportError: # python <= 2.5 grab it from cgi from cgi import parse_qs from reportlab.lib import colors from reportlab.lib.units import cm -from reportlab.platypus import (SimpleDocTemplate, PageBreak, Paragraph, - LongTable, Spacer, Table, TableStyle) +from reportlab.platypus import ( + SimpleDocTemplate, PageBreak, Paragraph, LongTable, Spacer, Table, + TableStyle) from django.db import transaction from django.contrib import messages @@ -39,18 +40,18 @@ from django.utils.translation import ugettext as _, ungettext, ugettext_lazy from openslides.utils import csv_ext from openslides.utils.pdf import stylesheet from openslides.utils.template import Tab -from openslides.utils.utils import (template, permission_required, - gen_confirm_form, ajax_request, decodedict, encodedict, - delete_default_permissions, html_strong) +from openslides.utils.utils import ( + template, permission_required, gen_confirm_form, ajax_request, decodedict, + encodedict, delete_default_permissions, html_strong) from openslides.utils.views import FormView, PDFView from openslides.config.models import config from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup from openslides.participant.api import gen_username, gen_password -from openslides.participant.forms import (UserNewForm, UserEditForm, - OpenSlidesUserForm, UsersettingsForm, UserImportForm, GroupForm, - AdminPasswordChangeForm, ConfigForm) +from openslides.participant.forms import ( + UserNewForm, UserEditForm, OpenSlidesUserForm, UsersettingsForm, + UserImportForm, GroupForm, AdminPasswordChangeForm, ConfigForm) @permission_required('participant.can_see_participant') @@ -78,21 +79,26 @@ def get_overview(request): query = User.objects if 'gender' in sortfilter: - query = query.filter(openslidesuser__gender__iexact=sortfilter['gender'][0]) + query = query.filter( + openslidesuser__gender__iexact=sortfilter['gender'][0]) if 'group' in sortfilter: - query = query.filter(openslidesuser__group__iexact=sortfilter['name_surfix'][0]) + query = query.filter( + openslidesuser__group__iexact=sortfilter['name_surfix'][0]) if 'type' in sortfilter: - query = query.filter(openslidesuser__type__iexact=sortfilter['type'][0]) + query = query.filter( + openslidesuser__type__iexact=sortfilter['type'][0]) if 'committee' in sortfilter: - query = query. \ - filter(openslidesuser__committee__iexact=sortfilter['committee'][0]) + query = query.filter( + openslidesuser__committee__iexact=sortfilter['committee'][0]) if 'status' in sortfilter: query = query.filter(is_active=sortfilter['status'][0]) if 'sort' in sortfilter: if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']: query = query.order_by(sortfilter['sort'][0]) - elif sortfilter['sort'][0] in ['name_surfix', 'type', 'committee', 'comment']: - query = query.order_by('openslidesuser__%s' % sortfilter['sort'][0]) + elif (sortfilter['sort'][0] in + ['name_surfix', 'type', 'committee', 'comment']): + query = query.order_by( + 'openslidesuser__%s' % sortfilter['sort'][0]) else: query = query.order_by('last_name') if 'reverse' in sortfilter: @@ -123,10 +129,10 @@ def get_overview(request): else: percent = 0 # list of all existing groups - groups = [p['name_surfix'] for p in OpenSlidesUser.objects.values('name_surfix') \ + groups = [p['name_surfix'] for p in OpenSlidesUser.objects.values('name_surfix') .exclude(name_surfix='').distinct()] # list of all existing committees - committees = [p['committee'] for p in OpenSlidesUser.objects.values('committee') \ + committees = [p['committee'] for p in OpenSlidesUser.objects.values('committee') .exclude(committee='').distinct()] return { 'users': users, @@ -303,7 +309,7 @@ def group_edit(request, group_id=None): _('Group name "%s" is reserved for internal use.') % group_name) return { - 'form' : form, + 'form': form, 'group': group } @@ -317,7 +323,6 @@ def group_edit(request, group_id=None): elif not form.cleaned_data['as_user'] and django_group: django_group.delete() - if anonymous_group is not None and \ anonymous_group.id == group.id: # prevent name changes - @@ -373,7 +378,7 @@ def user_settings(request): Edit own user account. """ if request.method == 'POST': - form_user = UsersettingsForm(request.POST,instance=request.user) + form_user = UsersettingsForm(request.POST, instance=request.user) if form_user.is_valid(): form_user.save() messages.success(request, _('User settings successfully saved.')) @@ -633,7 +638,7 @@ class ParticipantsListPDF(PDFView): document_title = ugettext_lazy('List of Participants') def append_to_pdf(self, story): - data= [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'), + data = [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'), _('Committee')]] sort = 'last_name' counter = 0 @@ -641,27 +646,27 @@ class ParticipantsListPDF(PDFView): try: counter += 1 user.get_profile() - data.append([counter, + data.append([ + counter, Paragraph(user.last_name, stylesheet['Tablecell']), Paragraph(user.first_name, stylesheet['Tablecell']), Paragraph(user.profile.group, stylesheet['Tablecell']), Paragraph(user.profile.get_type_display(), stylesheet['Tablecell']), - Paragraph(user.profile.committee, stylesheet['Tablecell']), - ]) + Paragraph(user.profile.committee, stylesheet['Tablecell']) + ]) except Profile.DoesNotExist: counter -= 1 pass t = LongTable(data, style=[ - ('VALIGN',(0,0),(-1,-1), 'TOP'), - ('LINEABOVE',(0,0),(-1,0),2,colors.black), - ('LINEABOVE',(0,1),(-1,1),1,colors.black), - ('LINEBELOW',(0,-1),(-1,-1),2,colors.black), + ('VALIGN', (0, 0), (-1, -1), 'TOP'), + ('LINEABOVE', (0, 0), (-1, 0), 2, colors.black), + ('LINEABOVE', (0, 1), (-1, 1), 1, colors.black), + ('LINEBELOW', (0, -1), (-1, -1), 2, colors.black), ('ROWBACKGROUNDS', (0, 1), (-1, -1), - (colors.white, (.9, .9, .9))), - ]) - t._argW[0]=0.75*cm + (colors.white, (.9, .9, .9)))]) + t._argW[0] = 0.75 * cm story.append(t) @@ -681,48 +686,48 @@ class ParticipantsPasswordsPDF(PDFView): pdf_document.build(story) def append_to_pdf(self, story): - data= [] + data = [] participant_pdf_system_url = config["participant_pdf_system_url"] participant_pdf_welcometext = config["participant_pdf_welcometext"] for user in User.objects.all().order_by('last_name'): try: user.get_profile() cell = [] - cell.append(Spacer(0,0.8*cm)) + cell.append(Spacer(0, 0.8 * cm)) cell.append(Paragraph(_("Account for OpenSlides"), - stylesheet['Ballot_title'])) + stylesheet['Ballot_title'])) cell.append(Paragraph(_("for %s") % (user.profile), - stylesheet['Ballot_subtitle'])) - cell.append(Spacer(0,0.5*cm)) + stylesheet['Ballot_subtitle'])) + cell.append(Spacer(0, 0.5 * cm)) cell.append(Paragraph(_("User: %s") % (user.username), - stylesheet['Monotype'])) + stylesheet['Monotype'])) cell.append(Paragraph(_("Password: %s") % (user.profile.firstpassword), stylesheet['Monotype'])) - cell.append(Spacer(0,0.5*cm)) + cell.append(Spacer(0, 0.5 * cm)) cell.append(Paragraph(_("URL: %s") % (participant_pdf_system_url), stylesheet['Ballot_option'])) - cell.append(Spacer(0,0.5*cm)) + cell.append(Spacer(0, 0.5 * cm)) cell2 = [] - cell2.append(Spacer(0,0.8*cm)) + cell2.append(Spacer(0, 0.8 * cm)) if participant_pdf_welcometext is not None: cell2.append(Paragraph( - participant_pdf_welcometext.replace('\r\n','
      '), + participant_pdf_welcometext.replace('\r\n', '
      '), stylesheet['Ballot_subtitle'])) - data.append([cell,cell2]) - except Profile.DoesNotExist: + data.append([cell, cell2]) + except OpenSlidesUser.DoesNotExist: pass # add empty table line if no participants available if data == []: - data.append(['','']) + data.append(['', '']) # build table - t=Table(data, 10.5*cm, 7.42*cm) + t = Table(data, 10.5 * cm, 7.42 * cm) t.setStyle(TableStyle([ - ('LINEBELOW', (0,0), (-1,0), 0.25, colors.grey), - ('LINEBELOW', (0,1), (-1,1), 0.25, colors.grey), - ('LINEBELOW', (0,1), (-1,-1), 0.25, colors.grey), - ('VALIGN', (0,0), (-1,-1), 'TOP'), + ('LINEBELOW', (0, 0), (-1, 0), 0.25, colors.grey), + ('LINEBELOW', (0, 1), (-1, 1), 0.25, colors.grey), + ('LINEBELOW', (0, 1), (-1, -1), 0.25, colors.grey), + ('VALIGN', (0, 0), (-1, -1), 'TOP'), ])) story.append(t) From 75443808af63fb2dc555f7c5a68d47a5b399e397 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Wed, 8 Aug 2012 10:52:13 +0200 Subject: [PATCH 19/19] fix some errors in participant --- openslides/assignment/views.py | 2 +- .../participant/templates/participant/overview.html | 8 ++++---- openslides/participant/views.py | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py index 324ecb79c..96a37bb14 100644 --- a/openslides/assignment/views.py +++ b/openslides/assignment/views.py @@ -412,7 +412,7 @@ class AssignmentPDF(PDFView): # Add result rows - elected_candidates = assignment.elected.all() + elected_candidates = list(assignment.elected) for candidate, poll_list in vote_results.iteritems(): row = [] diff --git a/openslides/participant/templates/participant/overview.html b/openslides/participant/templates/participant/overview.html index dadbb48df..f068dd69c 100644 --- a/openslides/participant/templates/participant/overview.html +++ b/openslides/participant/templates/participant/overview.html @@ -77,11 +77,11 @@ {{ user.first_name }} {{ user.last_name }} - {{ user.profile.group }} - {{ user.profile.get_type_display }} - {{ user.profile.committee }} + {{ user.openslidesuser.name_surfix }} + {{ user.openslidesuser.get_type_display }} + {{ user.openslidesuser.committee }} {% if perms.participant.can_manage_participant %} - {{ user.profile.comment|first_line }} + {{ user.openslidesuser.comment|first_line }} {% if user.last_login > user.date_joined %} {{ user.last_login }} {% endif %} diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 728965c55..3fd5f6a55 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -83,7 +83,7 @@ def get_overview(request): openslidesuser__gender__iexact=sortfilter['gender'][0]) if 'group' in sortfilter: query = query.filter( - openslidesuser__group__iexact=sortfilter['name_surfix'][0]) + openslidesuser__name_surfix__iexact=sortfilter['group'][0]) if 'type' in sortfilter: query = query.filter( openslidesuser__type__iexact=sortfilter['type'][0]) @@ -315,11 +315,11 @@ def group_edit(request, group_id=None): group = form.save() try: - django_group = DjangoGroup.objects.get(group=group) - except DjangoGroup.DoesNotExist: + openslides_group = OpenSlidesGroup.objects.get(group=group) + except OpenSlidesGroup.DoesNotExist: django_group = None if form.cleaned_data['as_user'] and django_group is None: - DjangoGroup(group=group).save() + OpenSlidesGroup(group=group).save() elif not form.cleaned_data['as_user'] and django_group: django_group.delete()