diff --git a/initial_data.json b/initial_data.json
index ad17d7a56..5f7c8e30c 100644
--- a/initial_data.json
+++ b/initial_data.json
@@ -1,6 +1,6 @@
[
{
- "pk": 2,
+ "pk": 1,
"model": "auth.group",
"fields": {
"name": "Beobachter",
@@ -38,7 +38,7 @@
[
"can_see_participant",
"participant",
- "openslidesuser"
+ "user"
],
[
"can_see_projector",
@@ -49,7 +49,7 @@
}
},
{
- "pk": 3,
+ "pk": 2,
"model": "auth.group",
"fields": {
"name": "Delegierter",
@@ -92,7 +92,7 @@
[
"can_see_participant",
"participant",
- "openslidesuser"
+ "user"
],
[
"can_see_projector",
@@ -103,7 +103,7 @@
}
},
{
- "pk": 4,
+ "pk": 3,
"model": "auth.group",
"fields": {
"name": "Versammlungsleitung",
@@ -161,12 +161,12 @@
[
"can_manage_participant",
"participant",
- "openslidesuser"
+ "user"
],
[
"can_see_participant",
"participant",
- "openslidesuser"
+ "user"
],
[
"can_manage_projector",
@@ -182,7 +182,7 @@
}
},
{
- "pk": 5,
+ "pk": 4,
"model": "auth.group",
"fields": {
"name": "Teilnehmerverwaltung",
@@ -195,12 +195,12 @@
[
"can_manage_participant",
"participant",
- "openslidesuser"
+ "user"
],
[
"can_see_participant",
"participant",
- "openslidesuser"
+ "user"
],
[
"can_see_projector",
diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py
index 9e5f69ac3..24a21f1c8 100644
--- a/openslides/agenda/views.py
+++ b/openslides/agenda/views.py
@@ -167,69 +167,24 @@ class ItemDelete(DeleteView):
model = Item
url = 'item_overview'
- def pre_post_redirect(self, request, *args, **kwargs):
- self.object = self.get_object()
+ def get_answer_options(self):
+ if self.object.children.exists():
+ return [('all', _("Yes, with all child items."))] + self.answer_options
+ else:
+ return self.answer_options
- if 'all' in request.POST:
+ def pre_post_redirect(self, request, *args, **kwargs):
+ if self.get_answer() == 'all':
self.object.delete(with_children=True)
messages.success(request,
_("Item %s and his children were successfully deleted.") \
% html_strong(self.object))
- else:
+ elif self.get_answer() == 'yes':
self.object.delete(with_children=False)
messages.success(request,
_("Item %s was successfully deleted.") \
% html_strong(self.object))
- def gen_confirm_form(self, request, message, url, singleitem=False):
- if singleitem:
- messages.warning(
- request,
- """
- %s
-
- """
- % (message, url, csrf(request)['csrf_token'], _("Yes"),
- _("No"))
- )
- else:
- messages.warning(
- request,
- """
- %s
-
- """
- % (message, url, csrf(request)['csrf_token'], _("Yes"),
- _("Yes, with all child items."), _("No"))
- )
-
- def confirm_form(self, request, object, item=None):
- if item is None:
- item = object
- if item.get_children():
- self.gen_confirm_form(
- request,
- _('Do you really want to delete %s?') % html_strong(item),
- item.get_absolute_url('delete'),
- False,
- )
- else:
- self.gen_confirm_form(
- request,
- _('Do you really want to delete %s?') % html_strong(item),
- item.get_absolute_url('delete'),
- True,
- )
-
class AgendaPDF(PDFView):
"""
diff --git a/openslides/application/models.py b/openslides/application/models.py
index 78ebd55b6..82d1099c8 100644
--- a/openslides/application/models.py
+++ b/openslides/application/models.py
@@ -12,7 +12,6 @@
from datetime import datetime
-from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Max
@@ -26,8 +25,6 @@ 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 OpenSlidesUser
-
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
CountInvalid, BaseVote)
@@ -360,15 +357,6 @@ class Application(models.Model, SlideMixin):
Return a list of all the allowed status.
"""
actions = []
- is_admin = False
- if user:
- try:
- user = user.openslidesuser
- except OpenSlidesUser.DoesNotExist:
- is_admin = True
- except AttributeError:
- # For the anonymous-user
- pass
# check if user allowed to withdraw an application
if ((self.status == "pub"
@@ -405,11 +393,10 @@ class Application(models.Model, SlideMixin):
# Check if the user can delete the application (admin, manager, owner)
# reworked as requiered in #100
- if is_admin \
- or (user.has_perm("application.can_manage_application") \
- and (self.status == "pub" or self.number is None)) \
- or (self.submitter == user \
- and (self.status == "pub" or self.number is None)):
+ if (user.has_perm("applicatoin.can_delete_all_applications") or
+ (user.has_perm("application.can_manage_application") and
+ self.number is None) or
+ (self.submitter == user and self.number is None)):
actions.append("delete")
#For the rest, all actions need the manage permission
@@ -543,6 +530,7 @@ class Application(models.Model, SlideMixin):
('can_create_application', ugettext_noop("Can create application")),
('can_support_application', ugettext_noop("Can support application")),
('can_manage_application', ugettext_noop("Can manage application")),
+ ('can_delete_all_applications', ugettext_noop("Can delete all applications")),
)
diff --git a/openslides/application/tests.py b/openslides/application/tests.py
index 2f5e65e09..bd3ecb73a 100644
--- a/openslides/application/tests.py
+++ b/openslides/application/tests.py
@@ -12,15 +12,17 @@
from django.test import TestCase
from django.test.client import Client
-from django.contrib.auth.models import User
+from openslides.participant.models import User
from openslides.application.models import Application, AVersion
class ApplicationTest(TestCase):
def setUp(self):
- self.admin = User.objects.create_user('testadmin', '', 'default')
- self.anonym = User.objects.create_user('testanoym', '', 'default')
- self.app1 = Application(submitter=self.admin.openslidesuser)
+ self.admin = User(username='testadmin')
+ self.admin.save()
+ self.anonym = User(username='testanoym')
+ self.anonym.save()
+ self.app1 = Application(submitter=self.admin)
self.app1.save()
def refresh(self):
diff --git a/openslides/application/views.py b/openslides/application/views.py
index d531b0cab..1163d6ea2 100644
--- a/openslides/application/views.py
+++ b/openslides/application/views.py
@@ -51,7 +51,7 @@ from openslides.projector.projector import Widget
from openslides.poll.views import PollFormView
from openslides.participant.api import gen_username, gen_password
-from openslides.participant.models import OpenSlidesUser
+from openslides.participant.models import User
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(request.user.openslidesuser),
+ 'actions' : application.get_allowed_actions(request.user),
'application' : application
}
except:
@@ -152,8 +152,7 @@ def view(request, application_id, newest=False):
else:
version = application.public_version
revisions = application.versions
- user = request.user.openslidesuser
- actions = application.get_allowed_actions(user=user)
+ actions = application.get_allowed_actions(user=request.user)
return {
'application': application,
@@ -183,11 +182,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 request.user.openslidesuser == application.submitter.user) \
+ not request.user == 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=request.user.openslidesuser)
+ actions = application.get_allowed_actions(user=request.user)
else:
application = None
actions = None
@@ -221,7 +220,7 @@ def edit(request, application_id=None):
original_supporters = []
application = managerform.save(commit=False)
elif application_id is None:
- application = Application(submitter=request.user.openslidesuser)
+ application = Application(submitter=request.user)
application.title = dataform.cleaned_data['title']
application.text = dataform.cleaned_data['text']
application.reason = dataform.cleaned_data['reason']
@@ -231,7 +230,7 @@ def edit(request, application_id=None):
and dataform.cleaned_data['trivial_change']
except KeyError:
trivial_change = False
- application.save(request.user.openslidesuser, trivial_change=trivial_change)
+ application.save(request.user, trivial_change=trivial_change)
if is_manager:
try:
new_supporters = set(managerform.cleaned_data['supporter'])
@@ -273,7 +272,7 @@ def edit(request, application_id=None):
dataform = formclass(initial=initial, prefix="data")
if is_manager:
if application_id is None:
- initial = {'submitter': request.user.openslidesuser.person_id}
+ initial = {'submitter': request.user.person_id}
else:
initial = {'submitter': application.submitter.person_id,
'supporter': [supporter.person_id for supporter in application.supporters]}
@@ -296,7 +295,7 @@ def set_number(request, application_id):
set a number for an application.
"""
try:
- Application.objects.get(pk=application_id).set_number(user=request.user.openslidesuser)
+ Application.objects.get(pk=application_id).set_number(user=request.user)
messages.success(request, _("Application number was successfully set."))
except Application.DoesNotExist:
pass
@@ -312,7 +311,7 @@ def permit(request, application_id):
permit an application.
"""
try:
- Application.objects.get(pk=application_id).permit(user=request.user.openslidesuser)
+ Application.objects.get(pk=application_id).permit(user=request.user)
messages.success(request, _("Application was successfully permitted."))
except Application.DoesNotExist:
pass
@@ -327,7 +326,7 @@ def notpermit(request, application_id):
reject (not permit) an application.
"""
try:
- Application.objects.get(pk=application_id).notpermit(user=request.user.openslidesuser)
+ Application.objects.get(pk=application_id).notpermit(user=request.user)
messages.success(request, _("Application was successfully rejected."))
except Application.DoesNotExist:
pass
@@ -343,7 +342,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=request.user.openslidesuser, status=status)
+ application.set_status(user=request.user, status=status)
messages.success(request, _("Application status was set to: %s.") % application.get_status_display())
except Application.DoesNotExist:
pass
@@ -387,7 +386,7 @@ def unsupport(request, application_id):
unsupport an application.
"""
try:
- Application.objects.get(pk=application_id).unsupport(user=request.user.openslidesuser)
+ Application.objects.get(pk=application_id).unsupport(user=request.user)
messages.success(request, _("You have unsupport the application successfully.") )
except Application.DoesNotExist:
pass
@@ -401,7 +400,7 @@ def gen_poll(request, application_id):
gen a poll for this application.
"""
try:
- poll = Application.objects.get(pk=application_id).gen_poll(user=request.user.openslidesuser)
+ poll = Application.objects.get(pk=application_id).gen_poll(user=request.user)
messages.success(request, _("New vote was successfully created.") )
except Application.DoesNotExist:
pass # TODO: do not call poll after this excaption
@@ -418,7 +417,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"), request.user.openslidesuser)
+ application.writelog(_("Poll deleted"), request.user)
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 +457,7 @@ class ApplicationDelete(DeleteView):
if len(self.applications):
for application in self.applications:
- if not 'delete' in application.get_allowed_actions(user=request.user.openslidesuser):
+ if not 'delete' in application.get_allowed_actions(user=request.user):
messages.error(request, _("You can not delete application %s.") % application)
continue
@@ -467,7 +466,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=request.user.openslidesuser):
+ if not 'delete' in self.object.get_allowed_actions(user=request.user):
messages.error(request, _("You can not delete application %s.") % self.object)
else:
title = self.object.title
@@ -508,12 +507,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=self.request.user.openslidesuser)
+ context['actions'] = self.application.get_allowed_actions(user=self.request.user)
return context
def get_modelform_class(self):
cls = super(ViewPoll, self).get_modelform_class()
- user = self.request.user.openslidesuser
+ user = self.request.user
class ViewPollFormClass(cls):
def save(self, commit = True):
@@ -535,7 +534,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=request.user.openslidesuser)
+ application.accept_version(aversion, user=request.user)
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 +546,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=request.user.openslidesuser):
+ if application.reject_version(aversion, user=request.user):
messages.success(request, _("Version %s rejected.") % (aversion.aid))
else:
messages.error(request, _("ERROR by rejecting the version.") )
@@ -559,17 +558,6 @@ def reject_version(request, aversion_id):
@permission_required('application.can_manage_application')
@template('application/import.html')
def application_import(request):
- try:
- request.user.openslidesuser
- except OpenSlidesUser.DoesNotExist:
- pass
- except AttributeError:
- # AnonymousUser
- pass
- else:
- messages.error(request, _('The import function is available for the admin (without user profile) only.'))
- return redirect(reverse('application_overview'))
-
if request.method == 'POST':
form = ApplicationImportForm(request.POST, request.FILES)
if form.is_valid():
diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py
index 96a37bb14..56dc26448 100644
--- a/openslides/assignment/views.py
+++ b/openslides/assignment/views.py
@@ -34,7 +34,7 @@ from openslides.utils.person import get_person
from openslides.config.models import config
-from openslides.participant.models import OpenSlidesUser
+from openslides.participant.models import User
from openslides.projector.projector import Widget
@@ -97,13 +97,12 @@ def view(request, assignment_id=None):
polls = assignment.poll_set.all()
vote_results = assignment.vote_results(only_published=False)
- user = request.user.openslidesuser
return {
'assignment': assignment,
'form': form,
'vote_results': vote_results,
'polls': polls,
- 'user_is_candidate': assignment.is_candidate(user)
+ 'user_is_candidate': assignment.is_candidate(request.user)
}
@@ -173,7 +172,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(request.user.openslidesuser, request.user)
+ assignment.run(request.user, request.user)
messages.success(request, _('You have set your candidature successfully.') )
except NameError, e:
messages.error(request, e)
@@ -185,7 +184,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(request.user.openslidesuser)
+ assignment.delrun(request.user)
else:
messages.error(request, _('The candidate list is already closed.'))
except Exception, e:
diff --git a/openslides/openslides_settings.py b/openslides/openslides_settings.py
index b3f14315f..b14ff673e 100755
--- a/openslides/openslides_settings.py
+++ b/openslides/openslides_settings.py
@@ -101,7 +101,7 @@ MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'openslides.participant.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.locale.LocaleMiddleware',
)
diff --git a/openslides/participant/api.py b/openslides/participant/api.py
index d2919821b..6728016cd 100644
--- a/openslides/participant/api.py
+++ b/openslides/participant/api.py
@@ -10,13 +10,19 @@
:license: GNU GPL, see LICENSE for more details.
"""
+# for python 2.5 support
+from __future__ import with_statement
+
from random import choice
import string
+import csv
from django.contrib.auth.models import User
+from django.db import transaction
-from openslides.utils.person import get_person
-from openslides.participant.models import OpenSlidesUser
+from openslides.utils import csv_ext
+
+from openslides.participant.models import User
def gen_password():
@@ -47,3 +53,44 @@ def gen_username(first_name, last_name):
User.objects.get(username=testname)
except User.DoesNotExist:
return testname
+
+
+def import_users(csv_file):
+ error_messages = []
+ count_success = 0
+ try:
+ # check for valid encoding (will raise UnicodeDecodeError if not)
+ csv_file.read().decode('utf-8')
+ csv_file.seek(0)
+
+ with transaction.commit_on_success():
+ dialect = csv.Sniffer().sniff(csv_file.readline())
+ dialect = csv_ext.patchup(dialect)
+ csv_file.seek(0)
+
+ for (line_no, line) in enumerate(csv.reader(csv_file,
+ dialect=dialect)):
+ if line_no:
+ try:
+ (first_name, last_name, gender, category, type, committee, comment) = line[:7]
+ except ValueError:
+ error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
+ continue
+ user = User()
+ user.last_name = last_name
+ user.first_name = first_name
+ user.username = gen_username(first_name, last_name)
+ user.gender = gender
+ user.category = category
+ user.type = type
+ user.committee = committee
+ user.comment = comment
+ user.firstpassword = gen_password()
+ user.save()
+ user.reset_password()
+ count_success += 1
+ except csv.Error:
+ error_messages.appen(_('Import aborted because of severe errors in the input file.'))
+ except UnicodeDecodeError:
+ error_messages.appen(_('Import file has wrong character encoding, only UTF-8 is supported!'))
+ return (count_success, error_messages)
diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py
index f39db40fb..4fb13a570 100644
--- a/openslides/participant/forms.py
+++ b/openslides/participant/forms.py
@@ -11,79 +11,84 @@
"""
from django import forms
-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 django.contrib.auth.models import Permission
+from django.utils.translation import ugettext_lazy as _
from openslides.utils.forms import (
CssClassMixin, LocalizedModelMultipleChoiceField)
-from openslides.participant.models import OpenSlidesUser
+from openslides.participant.models import User, Group
-USER_APPLICATION_IMPORT_OPTIONS = [
- ('REASSIGN', _('Keep applications, try to reassign submitter')),
- ('INREVIEW', _('Keep applications, set status to "needs review"')),
- ('DISCARD', _('Discard applications'))
-]
-
-
-class UserNewForm(forms.ModelForm, CssClassMixin):
- first_name = forms.CharField(label=_("First name"))
- last_name = forms.CharField(label=_("Last name"))
+class UserCreateForm(forms.ModelForm, CssClassMixin):
groups = forms.ModelMultipleChoiceField(
- queryset=Group.objects.all(), label=_("User groups"), required=False)
- is_active = forms.BooleanField(
- label=_("Active"), required=False, initial=True)
+ queryset=Group.objects.exclude(name__iexact='anonymous'),
+ label=_("User groups"), required=False)
class Meta:
model = User
- exclude = ('username', 'password', 'is_staff', 'is_superuser',
- 'last_login', 'date_joined', 'user_permissions')
+ fields = ('first_name', 'last_name', 'is_active', 'groups', 'category',
+ 'gender', 'type', 'committee', 'comment', 'default_password')
-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)
- is_active = forms.BooleanField(label=_("Active"), required=False)
-
+class UserUpdateForm(UserCreateForm):
class Meta:
model = User
- exclude = ('password', 'is_staff', 'is_superuser', 'last_login',
- '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')
-
-
-class OpenSlidesUserForm(forms.ModelForm, CssClassMixin):
- class Meta:
- model = OpenSlidesUser
+ fields = ('username', 'first_name', 'last_name', 'is_active', 'groups',
+ 'category', 'gender', 'type', 'committee', 'comment',
+ 'default_password')
class GroupForm(forms.ModelForm, CssClassMixin):
- 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"))
+ queryset=Permission.objects.all(), label=_("Persmissions"),
+ required=False)
+ users = forms.ModelMultipleChoiceField(
+ queryset=User.objects.all(), label=_("Users"), required=False)
def __init__(self, *args, **kwargs):
- super(GroupForm, self).__init__(*args, **kwargs)
+ # Initial users
if kwargs.get('instance', None) is not None:
- self.fields['permissions'].initial = (
- [p.pk for p in kwargs['instance'].permissions.all()])
+ initial = kwargs.setdefault('initial', {})
+ initial['users'] = [django_user.user.pk for django_user in kwargs['instance'].user_set.all()]
+
+ super(GroupForm, self).__init__(*args, **kwargs)
+
+ def save(self, commit=True):
+ instance = forms.ModelForm.save(self, False)
+
+ old_save_m2m = self.save_m2m
+ def save_m2m():
+ old_save_m2m()
+
+ instance.user_set.clear()
+ for user in self.cleaned_data['users']:
+ instance.user_set.add(user)
+ self.save_m2m = save_m2m
+
+ if commit:
+ instance.save()
+ self.save_m2m()
+
+ return instance
+
+ def clean_name(self):
+ # Do not allow to change the name "anonymous" or give another group
+ # this name
+ data = self.cleaned_data['name']
+ if self.instance.name.lower() == 'anonymous':
+ # Editing the anonymous-user
+ if self.instance.name.lower() != data.lower():
+ raise forms.ValidationError(
+ _('You can not edit the name for the anonymous user'))
+ else:
+ if data.lower() == 'anonymous':
+ raise forms.ValidationError(
+ _('Group name "%s" is reserved for internal use.') % data)
+ return data
class Meta:
model = Group
- exclude = ('permissions',)
class UsersettingsForm(forms.ModelForm, CssClassMixin):
@@ -95,9 +100,6 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin):
class UserImportForm(forms.Form, CssClassMixin):
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"))
class ConfigForm(forms.Form, CssClassMixin):
diff --git a/openslides/participant/middleware.py b/openslides/participant/middleware.py
new file mode 100644
index 000000000..b2341f00f
--- /dev/null
+++ b/openslides/participant/middleware.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ openslides.utils.middleware
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Additional definitions for OpenSlides forms.
+
+ :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
+ :license: GNU GPL, see LICENSE for more details.
+"""
+
+from django.contrib.auth.middleware import AuthenticationMiddleware as _AuthenticationMiddleware
+from django.contrib.auth.models import AnonymousUser
+
+
+class AuthenticationMiddleware(_AuthenticationMiddleware):
+ def process_request(self, request):
+ super(AuthenticationMiddleware, self).process_request(request)
+
+ if not isinstance(request.user, AnonymousUser):
+ request.user = request.user.user
diff --git a/openslides/participant/models.py b/openslides/participant/models.py
index f7685994e..8daf6fcdc 100644
--- a/openslides/participant/models.py
+++ b/openslides/participant/models.py
@@ -10,20 +10,20 @@
:license: GNU GPL, see LICENSE for more details.
"""
-from django.contrib.auth.models import User, Group
+from django.contrib.auth.models import User as DjangoUser, Group as DjangoGroup
from django.db import models
-from django.db.models import Q, signals
+from django.db.models import signals
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _, ugettext_noop
from openslides.utils.person import PersonMixin
-from openslides.utils.person.signals import receiv_persons
+from openslides.utils.person.signals import receive_persons
from openslides.config.signals import default_config_value
-class OpenSlidesUser(models.Model, PersonMixin):
- person_prefix = 'openslides_user'
+class User(DjangoUser, PersonMixin):
+ person_prefix = 'user'
GENDER_CHOICES = (
('male', _('Male')),
('female', _('Female')),
@@ -35,10 +35,10 @@ class OpenSlidesUser(models.Model, PersonMixin):
('guest', _('Guest')),
)
- 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.'))
+ django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
+ category = models.CharField(
+ max_length=100, null=True, blank=True, verbose_name=_("Category"),
+ help_text=_('Will be 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.'))
@@ -51,21 +51,26 @@ class OpenSlidesUser(models.Model, PersonMixin):
comment = models.TextField(
null=True, blank=True, verbose_name=_('Comment'),
help_text=_('Only for notes.'))
- firstpassword = models.CharField(
+ default_password = models.CharField(
max_length=100, null=True, blank=True,
- verbose_name=_("First Password"))
+ verbose_name=_("Default password"))
+
+ def get_name_suffix(self):
+ return self.category
+
+ def set_name_suffix(self, value):
+ self.category = value
+
+ name_suffix = property(get_name_suffix, set_name_suffix)
def reset_password(self, password=None):
"""
Reset the password for the user to his default-password.
"""
if password is None:
- password = self.firstpassword
- self.user.set_password(password)
- self.user.save()
-
- def has_perm(self, perm):
- return self.user.has_perm(perm)
+ password = self.default_password
+ self.set_password(password)
+ self.save()
@models.permalink
def get_absolute_url(self, link='edit'):
@@ -77,14 +82,15 @@ class OpenSlidesUser(models.Model, PersonMixin):
* delete
"""
if link == 'edit':
- return ('user_edit', [str(self.user.id)])
+ return ('user_edit', [str(self.id)])
if link == 'delete':
- return ('user_delete', [str(self.user.id)])
+ return ('user_delete', [str(self.id)])
def __unicode__(self):
- if self.name_surfix:
- return "%s (%s)" % (self.user.get_full_name(), self.name_surfix)
- return "%s" % self.user.get_full_name()
+ name = self.get_full_name() or self.username
+ if self.name_suffix:
+ return u"%s (%s)" % (name, self.name_suffix)
+ return u"%s" % name
class Meta:
# Rename permissions
@@ -95,46 +101,63 @@ class OpenSlidesUser(models.Model, PersonMixin):
)
-class OpenSlidesGroup(models.Model, PersonMixin):
- person_prefix = 'openslides_group'
+class Group(DjangoGroup, PersonMixin):
+ person_prefix = 'group'
- group = models.OneToOneField(Group)
+ django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)
group_as_person = models.BooleanField(default=False)
+ description = models.TextField(blank=True)
+
+ @models.permalink
+ def get_absolute_url(self, link='edit'):
+ """
+ Return the URL to this user.
+
+ link can be:
+ * edit
+ * delete
+ """
+ if link == 'edit':
+ return ('user_group_edit', [str(self.id)])
+ if link == 'delete':
+ return ('user_group_delete', [str(self.id)])
def __unicode__(self):
- return unicode(self.group)
+ return unicode(self.name)
-class OpenSlidesUsersConnecter(object):
- def __init__(self, person_prefix=None, id=None):
- self.person_prefix = person_prefix
- self.id = id
+class UsersConnector(object):
+ def __init__(self, person_prefix_filter=None, id_filter=None):
+ self.person_prefix_filter = person_prefix_filter
+ self.id_filter = id_filter
+ self.users = User.objects.all()
+ self.groups = Group.objects.filter(group_as_person=True)
def __iter__(self):
- if (not self.person_prefix or
- self.person_prefix == OpenSlidesUser.person_prefix):
- if self.id:
- yield OpenSlidesUser.objects.get(pk=self.id)
+ if (not self.person_prefix_filter or
+ self.person_prefix_filter == User.person_prefix):
+ if self.id_filter:
+ yield users.get(pk=self.id_filter)
else:
- for user in OpenSlidesUser.objects.all():
+ for user in self.users:
yield user
- if (not self.person_prefix or
- self.person_prefix == OpenSlidesGroup.person_prefix):
- if self.id:
- yield OpenSlidesGroup.objects.get(pk=self.id)
+ if (not self.person_prefix_filter or
+ self.person_prefix_filter == Group.person_prefix):
+ if self.id_filter:
+ yield groups.get(pk=self.id_filter)
else:
- for group in OpenSlidesGroup.objects.all():
+ for group in self.groups:
yield group
def __getitem__(self, key):
- return OpenSlidesUser.objects.get(pk=key)
+ return User.objects.get(pk=key)
-@receiver(receiv_persons, dispatch_uid="participant")
-def receiv_persons(sender, **kwargs):
- return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'],
- id=kwargs['id'])
+@receiver(receive_persons, dispatch_uid="participant")
+def receive_persons(sender, **kwargs):
+ return UsersConnecter(person_prefix_filter=kwargs['person_prefix_filter'],
+ id=kwargs['id_filter'])
@receiver(default_config_value, dispatch_uid="participant_default_config")
@@ -150,7 +173,17 @@ def default_config(sender, key, **kwargs):
}.get(key)
-@receiver(signals.post_save, sender=User)
+@receiver(signals.post_save, sender=DjangoUser)
def user_post_save(sender, instance, signal, *args, **kwargs):
- # Creates OpenSlidesUser
- profile, new = OpenSlidesUser.objects.get_or_create(user=instance)
+ try:
+ instance.user
+ except User.DoesNotExist:
+ User(django_user=instance).save_base(raw=True)
+
+
+@receiver(signals.post_save, sender=DjangoGroup)
+def group_post_save(sender, instance, signal, *args, **kwargs):
+ try:
+ instance.group
+ except Group.DoesNotExist:
+ Group(django_group=instance).save_base(raw=True)
diff --git a/openslides/participant/static/javascript/participant.js b/openslides/participant/static/javascript/participant.js
index f02e6c3f6..bf17d5202 100644
--- a/openslides/participant/static/javascript/participant.js
+++ b/openslides/participant/static/javascript/participant.js
@@ -9,17 +9,20 @@ $(function() {
$('.status_link').click(function(event) {
event.preventDefault();
link = $(this);
+ group = $(this).parent();
$.ajax({
type: 'GET',
url: link.attr('href'),
dataType: 'json',
success: function(data) {
if (data.active) {
- link.addClass('active');
+ group.children('.status_link.deactivate').show();
+ group.children('.status_link.activate').hide();
} else {
- link.removeClass('active');
+ group.children('.status_link.deactivate').hide();
+ group.children('.status_link.activate').show();
}
}
});
});
-});
\ No newline at end of file
+});
diff --git a/openslides/participant/static/styles/participant.css b/openslides/participant/static/styles/participant.css
index 3d2820f49..0d656c9c8 100644
--- a/openslides/participant/static/styles/participant.css
+++ b/openslides/participant/static/styles/participant.css
@@ -4,14 +4,19 @@
* :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
* :license: GNU GPL, see LICENSE for more details.
*/
+
a.status_link span {
- background-image: url(../images/icons/off.png);
background-repeat: no-repeat;
background-position: center;
width: 16px;
height: 16px;
display: inline-block;
}
-a.status_link.active span {
+
+a.status_link.deactivate span {
background-image: url(../images/icons/on.png);
}
+
+a.status_link.activate span {
+ background-image: url(../images/icons/off.png);
+}
diff --git a/openslides/participant/templates/participant/edit.html b/openslides/participant/templates/participant/edit.html
index ca7c2b649..da910b19e 100644
--- a/openslides/participant/templates/participant/edit.html
+++ b/openslides/participant/templates/participant/edit.html
@@ -4,7 +4,7 @@
{% block title %}
{{ block.super }} –
- {% if edituser %}
+ {% if edit_user %}
{% trans "Edit participant" %}
{% else %}
{% trans "New participant" %}
@@ -13,30 +13,31 @@
{% block content %}
- {% if edituser %}
+ {% if edit_user %}
{% trans "Edit participant" %}
{% else %}
{% trans "New participant" %}
{% endif %}
diff --git a/openslides/participant/templates/participant/overview.html b/openslides/participant/templates/participant/overview.html
index f068dd69c..3e2762a37 100644
--- a/openslides/participant/templates/participant/overview.html
+++ b/openslides/participant/templates/participant/overview.html
@@ -8,99 +8,108 @@
{% block header %}
{% if perms.agenda.can_manage_agenda %}
-
-
+
+
{% endif %}
{% endblock %}
+
{% block content %}
{% trans "Participants" %}
-
- {% if users|length == allusers|length %}
- {{ users|length }}
- {% blocktrans count counter=users|length %}participant{% plural %}participants{% endblocktrans %}
+ {% if users.count == allusers %}
+ {{ users.count }}
+ {% blocktrans count counter=users.count %}participant{% plural %}participants{% endblocktrans %}
{% else %}
- {{ users|length }} {% trans "of" %} {{ allusers|length }} {% trans "Participants" %} (= {{ percent }} %)
+ {{ users.count }} {% trans "of" %} {{ allusers }} {% trans "Participants" %} (= {{ percent }} %)
{% endif %}
{% trans "First Name" %} |
{% trans "Last Name" %} |
- {% trans "Group" %} |
+ {% trans "Category" %} |
{% trans "Type" %} |
{% trans "Committee" %} |
{% if perms.participant.can_manage_participant %}
- {% trans "Comment" %} |
- {% trans "Last Login" %} |
- {% trans "Actions" %} |
+ {% trans "Comment" %} |
+ {% trans "Last Login" %} |
+ {% trans "Actions" %} |
{% endif %}
- {% for user in users %}
-
- {{ user.first_name }} |
- {{ user.last_name }} |
- {{ user.openslidesuser.name_surfix }} |
- {{ user.openslidesuser.get_type_display }} |
- {{ user.openslidesuser.committee }} |
- {% if perms.participant.can_manage_participant %}
- {{ user.openslidesuser.comment|first_line }} |
- {% if user.last_login > user.date_joined %}
- {{ user.last_login }}
- {% endif %} |
-
-
-
-
-
-
-
- |
- {% endif %}
-
- {% empty %}
-
- {% trans "No participants available." %} |
-
- {% endfor %}
+ {% for user in users %}
+
+ {{ user.first_name }} |
+ {{ user.last_name }} |
+ {{ user.category }} |
+ {{ user.get_type_display }} |
+ {{ user.committee }} |
+ {% if perms.participant.can_manage_participant %}
+ {{ user.comment|first_line }} |
+
+ {% if user.last_login > user.date_joined %}
+ {{ user.last_login }}
+ {% endif %}
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ {% endif %}
+
+ {% empty %}
+
+ {% trans "No participants available." %} |
+
+ {% endfor %}
{% endblock %}
diff --git a/openslides/participant/tests.py b/openslides/participant/tests.py
index c7dbadf46..4bba1168d 100644
--- a/openslides/participant/tests.py
+++ b/openslides/participant/tests.py
@@ -12,61 +12,65 @@
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.person import get_person, Persons
from openslides.participant.api import gen_username, gen_password
-from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup
+from openslides.participant.models import User, Group
-class OpenSlidesUserTest(TestCase):
+class UserTest(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 = User()
+ self.user1.first_name = u'Max'
+ self.user1.last_name = u'Mustermann'
+ self.user1.username = gen_username(
+ self.user1.first_name, self.user1.last_name)
+ self.user1.firstpassword = gen_password()
self.user1.save()
- self.openslidesuser1 = self.user1.openslidesuser
- self.openslidesuser1.firstpassword = gen_password()
- self.openslidesuser1.save()
- self.user1 = self.openslidesuser1.user
+ self.django_user1 = self.user1.django_user
def test_participant_user(self):
- self.assertEqual(self.user1.openslidesuser, self.openslidesuser1)
- self.assertEqual(self.user1, self.openslidesuser1.user)
+ self.assertEqual(self.django_user1.user, self.user1)
+ self.assertEqual(self.django_user1, self.user1.django_user)
def test_repr(self):
- self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann')
+ self.assertEqual(unicode(self.user1), u'Max Mustermann')
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)')
+ self.user1.category = u'München'
+ self.user1.save()
+ self.assertEqual(unicode(self.user1), u'Max Mustermann (München)')
def test_reset_password(self):
- self.assertIsInstance(self.openslidesuser1.firstpassword, basestring)
- self.assertEqual(len(self.openslidesuser1.firstpassword), 8)
+ self.assertIsInstance(self.user1.firstpassword, basestring)
+ self.assertEqual(len(self.user1.firstpassword), 8)
self.user1.set_unusable_password()
- self.assertFalse(self.user1.check_password(self.openslidesuser1.firstpassword))
- self.openslidesuser1.reset_password()
- self.assertTrue(self.user1.check_password(self.openslidesuser1.firstpassword))
+ self.assertFalse(self.user1.check_password(self.user1.firstpassword))
+ self.user1.reset_password()
+ self.assertTrue(self.user1.check_password(self.user1.firstpassword))
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)
+ self.assertTrue(hasattr(self.user1, 'person_id'))
+ self.assertEqual(self.user1.person_id, 'user:1')
+ self.assertEqual(get_person('user:1'), self.user1)
+ self.assertEqual(len(Persons(person_prefix='user')), 1)
-class OpenSlidesGroupTest(TestCase):
+class GroupTest(TestCase):
def setUp(self):
self.group1 = Group.objects.create(name='Test Group')
- self.openslidesgroup1 = OpenSlidesGroup.objects.create(group=self.group1)
+ self.django_group1 = self.group1.django_group
- def test_group_openslidesgroup(self):
- self.assertEqual(self.openslidesgroup1.group, self.group1)
+ def test_group_group(self):
+ self.assertEqual(self.group1.django_group, self.django_group1)
+ self.assertEqual(self.group1, self.django_group1.group)
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)
+ self.assertTrue(hasattr(self.group1, 'person_id'))
+ person_id = "group:%d" % self.group1.id
+ self.assertEqual(self.group1.person_id, person_id)
+ self.assertRaises(Group.DoesNotExist)
+ self.group1.group_as_person = True
+ self.group1.save()
+ self.assertEqual(get_person(person_id), self.group1)
diff --git a/openslides/participant/urls.py b/openslides/participant/urls.py
index e0245d575..f55c30756 100644
--- a/openslides/participant/urls.py
+++ b/openslides/participant/urls.py
@@ -13,70 +13,86 @@
from django.conf.urls.defaults import url, patterns
from django.core.urlresolvers import reverse
-from openslides.participant.views import (ParticipantsListPDF,
- ParticipantsPasswordsPDF)
+from openslides.participant.views import (
+ ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView,
+ UserUpdateView, UserDeleteView, SetUserStatusView, UserImportView,
+ ResetPasswordView, GroupOverviewView, GroupCreateView, GroupUpdateView,
+ GroupDeleteView)
urlpatterns = patterns('openslides.participant.views',
url(r'^$',
- 'get_overview',
+ Overview.as_view(),
name='user_overview',
),
url(r'^new/$',
- 'edit',
+ UserCreateView.as_view(),
name='user_new',
),
- url(r'^(?P\d+)/edit/$',
- 'edit',
+ url(r'^(?P\d+)/edit/$',
+ UserUpdateView.as_view(),
name='user_edit',
),
+ url(r'^(?P\d+)/del/$',
+ UserDeleteView.as_view(),
+ name='user_delete',
+ ),
+
+ url(r'^(?P\d+)/reset_password/$',
+ ResetPasswordView.as_view(),
+ name='user_reset_password',
+ ),
+
+ url(r'^(?P\d+)/status/toggle/$',
+ SetUserStatusView.as_view(),
+ {'action': 'toggle'},
+ name='user_status_toggle',
+ ),
+
+ url(r'^(?P\d+)/status/activate/$',
+ SetUserStatusView.as_view(),
+ {'action': 'activate'},
+ name='user_status_activate',
+ ),
+
+ url(r'^(?P\d+)/status/deactivate/$',
+ SetUserStatusView.as_view(),
+ {'action': 'deactivate'},
+ name='user_status_deactivate',
+ ),
+
+ url(r'^import/$',
+ UserImportView.as_view(),
+ name='user_import',
+ ),
+
+ url(r'^group/$',
+ GroupOverviewView.as_view(),
+ name='user_group_overview',
+ ),
+
+ url(r'^group/new/$',
+ GroupCreateView.as_view(),
+ name='user_group_new',
+ ),
+
+ url(r'^group/(?P\d+)/edit/$',
+ GroupUpdateView.as_view(),
+ name='user_group_edit',
+ ),
+
+ url(r'^group/(?P\d+)/del/$',
+ GroupDeleteView.as_view(),
+ name='user_group_delete',
+ ),
+
url(r'^print/$',
ParticipantsListPDF.as_view(),
name='user_print',
),
- url(r'^(?P\d+)/del/$',
- 'user_delete',
- name='user_delete',
- ),
-
- url(r'^(?P\d+)/status/$',
- 'user_set_status',
- name='user_status',
- ),
-
- url(r'^import/$',
- 'user_import',
- name='user_import',
- ),
-
- url(r'^group/$',
- 'get_group_overview',
- name='user_group_overview',
- ),
-
- url(r'^group/new/$',
- 'group_edit',
- name='user_group_new',
- ),
-
- url(r'^group/(?P\d+)/edit/$',
- 'group_edit',
- name='user_group_edit',
- ),
-
- url(r'^group/(?P\d+)/del/$',
- 'group_delete',
- name='user_group_delete',
- ),
-
- url(r'^resetpassword/(?P\d+)/$',
- 'reset_password',
- name='user_reset_password',
- ),
-
url(r'^passwords/print/$',
ParticipantsPasswordsPDF.as_view(),
name='print_passwords',
diff --git a/openslides/participant/views.py b/openslides/participant/views.py
index 3fd5f6a55..64538db49 100644
--- a/openslides/participant/views.py
+++ b/openslides/participant/views.py
@@ -13,7 +13,6 @@
# for python 2.5 support
from __future__ import with_statement
-import csv
from urllib import urlencode
try:
@@ -24,351 +23,405 @@ except ImportError: # python <= 2.5 grab it from cgi
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.platypus import (
- SimpleDocTemplate, PageBreak, Paragraph, LongTable, Spacer, Table,
- TableStyle)
+ SimpleDocTemplate, Paragraph, LongTable, Spacer, Table, TableStyle)
-from django.db import transaction
from django.contrib import messages
from django.contrib.auth.decorators import login_required
-from django.contrib.auth.models import User, Group
from django.contrib.auth.forms import PasswordChangeForm
+from django.contrib.auth.models import User
from django.contrib.auth.views import login as django_login
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
-from django.utils.translation import ugettext as _, ungettext, ugettext_lazy
+from django.utils.translation import ugettext as _, 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.views import FormView, PDFView
+ template, decodedict, encodedict, delete_default_permissions, html_strong)
+from openslides.utils.views import (
+ FormView, PDFView, CreateView, UpdateView, DeleteView,
+ RedirectView, SingleObjectMixin, ListView, QuestionMixin)
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.api import gen_username, gen_password, import_users
from openslides.participant.forms import (
- UserNewForm, UserEditForm, OpenSlidesUserForm, UsersettingsForm,
- UserImportForm, GroupForm, AdminPasswordChangeForm, ConfigForm)
+ UserCreateForm, UserUpdateForm, UsersettingsForm,
+ UserImportForm, GroupForm, ConfigForm)
+from openslides.participant.models import User, Group
-@permission_required('participant.can_see_participant')
-@template('participant/overview.html')
-def get_overview(request):
+class Overview(ListView):
"""
- Show all users.
+ Show all participants.
"""
- try:
- sortfilter = encodedict(parse_qs(
- request.COOKIES['participant_sortfilter']))
- except KeyError:
- sortfilter = {}
+ permission_required = 'participant.can_see_participant'
+ template_name = 'participant/overview.html'
+ context_object_name = 'users'
- for value in [u'gender', u'group', u'type', u'committee', u'status',
- u'sort', u'reverse']:
- if value in request.REQUEST:
- if request.REQUEST[value] == '---':
- try:
- del sortfilter[value]
- except KeyError:
- pass
- else:
- sortfilter[value] = [request.REQUEST[value]]
-
- query = User.objects
- if 'gender' in sortfilter:
- query = query.filter(
- openslidesuser__gender__iexact=sortfilter['gender'][0])
- if 'group' in sortfilter:
- query = query.filter(
- openslidesuser__name_surfix__iexact=sortfilter['group'][0])
- if 'type' in sortfilter:
- query = query.filter(
- openslidesuser__type__iexact=sortfilter['type'][0])
- if 'committee' in sortfilter:
- 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])
- else:
- query = query.order_by('last_name')
- if 'reverse' in sortfilter:
- query = query.reverse()
-
- # list of filtered users
- userlist = query.all()
- users = []
- for user in userlist:
+ def get_queryset(self):
try:
- user.openslidesuser
- except OpenSlidesUser.DoesNotExist:
- pass
+ sortfilter = encodedict(parse_qs(
+ self.request.COOKIES['participant_sortfilter']))
+ except KeyError:
+ sortfilter = {}
+
+ for value in [u'gender', u'category', u'type', u'committee', u'status',
+ u'sort', u'reverse']:
+ if value in self.request.REQUEST:
+ if self.request.REQUEST[value] == '---':
+ try:
+ del sortfilter[value]
+ except KeyError:
+ pass
+ else:
+ sortfilter[value] = [self.request.REQUEST[value]]
+
+ query = User.objects
+ if 'gender' in sortfilter:
+ query = query.filter(gender__iexact=sortfilter['gender'][0])
+ if 'category' in sortfilter:
+ query = query.filter(category__iexact=sortfilter['category'][0])
+ if 'type' in sortfilter:
+ query = query.filter(type__iexact=sortfilter['type'][0])
+ if 'committee' in sortfilter:
+ query = query.filter(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
+ ['category', 'type', 'committee', 'comment']):
+ query = query.order_by(
+ '%s' % sortfilter['sort'][0])
else:
- users.append(user)
- # list of all existing users
- allusers = []
- for user in User.objects.all():
- try:
- user.openslidesuser
- except OpenSlidesUser.DoesNotExist:
- pass
+ query = query.order_by('last_name')
+
+ if 'reverse' in sortfilter:
+ query = query.reverse()
+
+ self.sortfilter = sortfilter
+
+ return query.all()
+
+ def get_context_data(self, **kwargs):
+ context = super(Overview, self).get_context_data(**kwargs)
+
+ all_users = User.objects.count()
+
+ # quotient of selected users and all users
+ if all_users > 0:
+ percent = self.object_list.count() * 100 / float(all_users)
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['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')
- .exclude(committee='').distinct()]
- return {
- 'users': users,
- 'allusers': allusers,
- 'percent': round(percent, 1),
- 'groups': groups,
- 'committees': committees,
- 'cookie': ['participant_sortfilter', urlencode(decodedict(sortfilter),
- doseq=True)],
- 'sortfilter': sortfilter,
- }
+ percent = 0
+
+ # list of all existing categories
+ categories = [p['category'] for p in User.objects.values('category')
+ .exclude(category='').distinct()]
+
+ # list of all existing committees
+ committees = [p['committee'] for p in User.objects.values('committee')
+ .exclude(committee='').distinct()]
+ context.update({
+ 'allusers': all_users,
+ 'percent': round(percent, 1),
+ 'categories': categories,
+ 'committees': committees,
+ 'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
+ doseq=True)],
+ 'sortfilter': self.sortfilter})
+ return context
-@permission_required('participant.can_manage_participant')
-@template('participant/edit.html')
-def edit(request, user_id=None):
+class UserCreateView(CreateView):
"""
- View to create and edit users.
+ Create a new participant.
"""
- if user_id is not None:
- user = User.objects.get(id=user_id)
- else:
- user = None
+ permission_required = 'participant.can_manage_participant'
+ template_name = 'participant/edit.html'
+ model = User
+ context_object_name = 'edit_user'
+ form_class = UserCreateForm
+ success_url = 'user_overview'
+ apply_url = 'user_edit'
- if request.method == 'POST':
- if user_id is None:
- user_form = UserNewForm(request.POST, prefix="user")
- openslides_user_form = OpenSlidesUserForm(request.POST, prefix="openslidesuser")
- else:
- user_form = UserEditForm(request.POST, instance=user, prefix="user")
- openslides_user_form = OpenSlidesUserForm(request.POST, instance=user.openslidesuser,
- prefix="openslidesuser")
-
- 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()
- 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 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.'))
- else:
- messages.success(request,
- _('Participant was successfully modified.'))
- if not 'apply' in request.POST:
- return redirect(reverse('user_overview'))
- if user_id is None:
- return redirect(reverse('user_edit', args=[user.id]))
- else:
- messages.error(request, _('Please check the form for errors.'))
- else:
- if user_id is None:
- user_form = UserNewForm(prefix="user")
- openslides_user_form = OpenSlidesUserForm(prefix="openslidesuser")
- else:
- user_form = UserEditForm(instance=user, prefix="user")
- openslides_user_form = OpenSlidesUserForm(instance=user.openslidesuser, prefix="openslidesuser")
- # TODO: rename template vars
- return {
- 'userform': user_form,
- 'profileform': openslides_user_form,
- 'edituser': user,
- }
+ def manipulate_object(self, form):
+ self.object.username = gen_username(form.cleaned_data['first_name'],
+ form.cleaned_data['last_name'])
+ if not self.object.default_password:
+ self.object.default_password = gen_password()
-@permission_required('participant.can_manage_participant')
-@template('confirm.html')
-def user_delete(request, user_id):
+class UserUpdateView(UpdateView):
"""
- Delete an user.
+ Update an existing participant.
"""
- user = User.objects.get(pk=user_id)
- if request.method == 'POST':
- user.delete()
- messages.success(request,
- _('Participant %s was successfully deleted.') % user)
- else:
- gen_confirm_form(request,
- _('Do you really want to delete %s?') % user,
- reverse('user_delete', args=[user_id]))
- return redirect(reverse('user_overview'))
+ permission_required = 'participant.can_manage_participant'
+ template_name = 'participant/edit.html'
+ model = User
+ context_object_name = 'edit_user'
+ form_class = UserUpdateForm
+ success_url = 'user_overview'
+ apply_url = 'participant_edit'
-@permission_required('participant.can_manage_participant')
-@template('confirm.html')
-def user_set_status(request, user_id):
+class UserDeleteView(DeleteView):
"""
- Set the status of an user.
+ Delete an participant.
"""
- try:
- user = User.objects.get(pk=user_id)
- if user.is_active:
- user.is_active = False
- else:
- user.is_active = True
- user.save()
- except User.DoesNotExist:
- messages.error(request,
- _('Participant ID %d does not exist.') % int(user_id))
- return redirect(reverse('user_overview'))
-
- if request.is_ajax():
- return ajax_request({'active': user.is_active})
- # set success messages for page reload only (= not ajax request)
- if user.is_active:
- messages.success(request, _('%s is now present.') % user)
- else:
- messages.success(request, _('%s is now absent.') % user)
- return redirect(reverse('user_overview'))
+ permission_required = 'participant.can_manage_participant'
+ model = User
+ url = 'user_overview'
-@permission_required('participant.can_manage_participant')
-@template('participant/group_overview.html')
-def get_group_overview(request):
+class SetUserStatusView(RedirectView, SingleObjectMixin):
"""
- Show all groups.
+ Activate or deactivate an user.
"""
- if config['system_enable_anonymous']:
- groups = Group.objects.all()
- else:
- groups = Group.objects.exclude(name='Anonymous')
- return {
- 'groups': groups,
- }
+ permission_required = 'participant.can_manage_participant'
+ allow_ajax = True
+ url = 'user_overview'
+ model = User
+
+ def pre_redirect(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ action = kwargs['action']
+ if action == 'activate':
+ self.object.is_active = True
+ elif action == 'deactivate':
+ self.object.is_active = False
+ elif action == 'toggle':
+ self.object.is_active = not self.object.is_active
+ self.object.save()
+ return super(SetUserStatusView, self).pre_redirect(request, *args, **kwargs)
+
+ def get_ajax_context(self, **kwargs):
+ context = super(SetUserStatusView, self).get_ajax_context(**kwargs)
+ context['active'] = self.object.is_active
+ return context
-@permission_required('participant.can_manage_participant')
-@template('participant/group_edit.html')
-def group_edit(request, group_id=None):
+class ParticipantsListPDF(PDFView):
"""
- Edit a group.
+ Generate the userliste as PDF.
"""
- if group_id is not None:
- try:
- group = Group.objects.get(id=group_id)
- except Group.DoesNotExist:
- # TODO: return a 404 Object
- raise NameError("There is no group %d" % group_id)
- else:
- group = None
- delete_default_permissions()
+ permission_required = 'participant.can_see_participant'
+ filename = ugettext_lazy("Participant-list")
+ document_title = ugettext_lazy('List of Participants')
- if request.method == 'POST':
- form = GroupForm(request.POST, instance=group)
- if form.is_valid():
- # TODO: This can be done inside the form
- group_name = form.cleaned_data['name'].lower()
-
- # TODO: Why is this code called on any request and not only, if the
- # anonymous_group is edited?
- try:
- anonymous_group = Group.objects.get(name='Anonymous')
- except Group.DoesNotExist:
- anonymous_group = None
-
- # special handling for anonymous auth
- # TODO: This code should be a form validator.
- if group is None and group_name.strip().lower() == 'anonymous':
- # don't allow to create this group
- messages.error(request,
- _('Group name "%s" is reserved for internal use.')
- % group_name)
- return {
- 'form': form,
- 'group': group
- }
-
- group = form.save()
- try:
- openslides_group = OpenSlidesGroup.objects.get(group=group)
- except OpenSlidesGroup.DoesNotExist:
- django_group = None
- if form.cleaned_data['as_user'] and django_group is None:
- OpenSlidesGroup(group=group).save()
- 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 -
- # XXX: I'm sure this could be done as *one* group.save()
- group.name = 'Anonymous'
- group.save()
-
- if group_id is None:
- messages.success(request,
- _('New group was successfully created.'))
- else:
- messages.success(request, _('Group was successfully modified.'))
- if not 'apply' in request.POST:
- return redirect(reverse('user_group_overview'))
- if group_id is None:
- return redirect(reverse('user_group_edit', args=[group.id]))
- else:
- messages.error(request, _('Please check the form for errors.'))
- else:
- if group and OpenSlidesGroup.objects.filter(group=group).exists():
- initial = {'as_user': True}
- else:
- initial = {'as_user': False}
-
- form = GroupForm(instance=group, initial=initial)
- return {
- 'form': form,
- 'group': group,
- }
+ def append_to_pdf(self, story):
+ data = [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'),
+ _('Committee')]]
+ sort = 'last_name'
+ counter = 0
+ for user in User.objects.all().order_by(sort):
+ counter += 1
+ data.append([
+ counter,
+ Paragraph(user.last_name, stylesheet['Tablecell']),
+ Paragraph(user.first_name, stylesheet['Tablecell']),
+ Paragraph(user.category, stylesheet['Tablecell']),
+ Paragraph(user.type, stylesheet['Tablecell']),
+ Paragraph(user.committee, stylesheet['Tablecell'])])
+ 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),
+ ('ROWBACKGROUNDS', (0, 1), (-1, -1),
+ (colors.white, (.9, .9, .9)))])
+ t._argW[0] = 0.75 * cm
+ story.append(t)
-@permission_required('participant.can_manage_participant')
-def group_delete(request, group_id):
+class ParticipantsPasswordsPDF(PDFView):
"""
- Delete a group.
+ Generate the Welcomepaper for the users.
"""
- group = Group.objects.get(pk=group_id)
- if request.method == 'POST':
- group.delete()
- messages.success(request,
- _('Group %s was successfully deleted.') % group)
- else:
- gen_confirm_form(request,
- _('Do you really want to delete %s?') % group,
- reverse('user_group_delete', args=[group_id]))
- return redirect(reverse('user_group_overview'))
+ permission_required = 'participant.can_manage_participant'
+ filename = ugettext_lazy("Participant-passwords")
+ top_space = 0
+
+ def get_template(self, buffer):
+ return SimpleDocTemplate(
+ buffer, topMargin=-6, bottomMargin=-6,
+ leftMargin=0, rightMargin=0, showBoundary=False)
+
+ def build_document(self, pdf_document, story):
+ pdf_document.build(story)
+
+ def append_to_pdf(self, story):
+ 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'):
+ cell = []
+ cell.append(Spacer(0, 0.8 * cm))
+ cell.append(Paragraph(_("Account for OpenSlides"),
+ stylesheet['Ballot_title']))
+ cell.append(Paragraph(_("for %s") % (user),
+ stylesheet['Ballot_subtitle']))
+ cell.append(Spacer(0, 0.5 * cm))
+ cell.append(Paragraph(_("User: %s") % (user.username),
+ stylesheet['Monotype']))
+ cell.append(
+ Paragraph(
+ _("Password: %s")
+ % (user.firstpassword), stylesheet['Monotype']))
+ 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))
+ cell2 = []
+ cell2.append(Spacer(0, 0.8 * cm))
+ if participant_pdf_welcometext is not None:
+ cell2.append(Paragraph(
+ participant_pdf_welcometext.replace('\r\n', '
'),
+ stylesheet['Ballot_subtitle']))
+
+ data.append([cell, cell2])
+
+ # add empty table line if no participants available
+ if not data:
+ data.append(['', ''])
+ # build table
+ 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'),
+ ]))
+ story.append(t)
+
+
+class UserImportView(FormView):
+ """
+ Import Users via csv.
+ """
+ permission_required = 'participant.can_manage_participant'
+ template_name = 'participant/import.html'
+ form_class = UserImportForm
+
+ def form_valid(self, form):
+ # check for valid encoding (will raise UnicodeDecodeError if not)
+ success, error_messages = import_users(self.request.FILES['csvfile'])
+ for message in error_messages:
+ messages.error(self.request, message)
+ if success:
+ messages.success(
+ self.request,
+ _('%d new participants were successfully imported.') % success)
+ return super(UserImportView, self).form_valid(form)
+
+
+class ResetPasswordView(RedirectView, SingleObjectMixin, QuestionMixin):
+ """
+ Set the Passwort for a user to his firstpassword.
+ """
+ permission_required = 'participant.can_manage_participant'
+ model = User
+ allow_ajax = True
+ question = ugettext_lazy('Do you really want to reset the password?')
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ return super(ResetPasswordView, self).get(request, *args, **kwargs)
+
+ def get_redirect_url(self, **kwargs):
+ return reverse('user_edit', args=[self.object.id])
+
+ def pre_redirect(self, request, *args, **kwargs):
+ self.confirm_form()
+
+ def pre_post_redirect(self, request, *args, **kwargs):
+ if self.get_answer().lower() == 'yes':
+ self.object.reset_password()
+ messages.success(request,
+ _('The Password for %s was successfully reset.') % html_strong(self.object))
+
+ def get_answer_url(self):
+ return reverse('user_reset_password', args=[self.object.id])
+
+
+class GroupOverviewView(ListView):
+ """
+ Overview over all groups.
+ """
+ permission_required = 'participant.can_manage_participant'
+ template_name = 'participant/group_overview.html'
+ context_object_name = 'groups'
+ model = Group
+
+
+class GroupCreateView(CreateView):
+ """
+ Create a new group.
+ """
+ permission_required = 'participant.can_manage_participant'
+ template_name = 'participant/group_edit.html'
+ context_object_name = 'group'
+ model = Group
+ form_class = GroupForm
+ success_url = 'user_group_overview'
+ apply_url = 'user_group_edit'
+
+ def get(self, request, *args, **kwargs):
+ delete_default_permissions()
+ return super(GroupCreateView, self).get(request, *args, **kwargs)
+
+
+class GroupUpdateView(UpdateView):
+ """
+ Update an existing group.
+ """
+ permission_required = 'participant.can_manage_participant'
+ template_name = 'participant/group_edit.html'
+ model = Group
+ context_object_name = 'group'
+ form_class = GroupForm
+ success_url = 'user_group_overview'
+ apply_url = 'user_group_edit'
+
+ def get(self, request, *args, **kwargs):
+ delete_default_permissions()
+ return super(GroupUpdateView, self).get(request, *args, **kwargs)
+
+
+class GroupDeleteView(DeleteView):
+ """
+ Delete a Group.
+ """
+ permission_required = 'participant.can_manage_participant'
+ model = Group
+ url = 'user_group_overview'
+
+
+class Config(FormView):
+ """
+ Config page for the participant app.
+ """
+ permission_required = 'config.can_manage_config'
+ form_class = ConfigForm
+ template_name = 'participant/config.html'
+
+ def get_initial(self):
+ return {
+ 'participant_pdf_system_url': config['participant_pdf_system_url'],
+ 'participant_pdf_welcometext': config['participant_pdf_welcometext']}
+
+ def form_valid(self, form):
+ config['participant_pdf_system_url'] = (
+ form.cleaned_data['participant_pdf_system_url'])
+ config['participant_pdf_welcometext'] = (
+ form.cleaned_data['participant_pdf_welcometext'])
+ messages.success(
+ self.request,
+ _('Participants settings successfully saved.'))
+ return super(Config, self).form_valid(form)
@login_required
@@ -415,187 +468,6 @@ def user_settings_password(request):
}
-@permission_required('participant.can_manage_participant')
-@template('participant/import.html')
-def user_import(request):
- """
- Import Users via csv.
- """
- from openslides.application.models import Application
- try:
- request.user.profile
- messages.error(request, _('The import function is available for the admin (without user profile) only.'))
- return redirect(reverse('user_overview'))
- except Profile.DoesNotExist:
- pass
- except AttributeError:
- # AnonymousUser
- pass
-
- if request.method == 'POST':
- form = UserImportForm(request.POST, request.FILES)
- if form.is_valid():
- try:
- # check for valid encoding (will raise UnicodeDecodeError if not)
- request.FILES['csvfile'].read().decode('utf-8')
- request.FILES['csvfile'].seek(0)
-
- with transaction.commit_on_success():
-
- old_users = {}
- applications_mapped = 0
- applications_review = 0
- applications_removed = 0
-
- try:
- janitor = User.objects.get(username='__system__.janitor')
- except User.DoesNotExist:
- janitor = User()
- janitor.first_name = ''
- janitor.last_name = ''
- janitor.username = '__system__.janitor'
- janitor.save()
-
- applications = Application.objects.all()
- for application in applications:
- if form.cleaned_data['application_handling'] == 'DISCARD':
- # need to do this explicit since some applications may belong
- # to __system__.janitor which is a permanent user
- application.delete(force=True)
- applications_removed += 1
- else:
- # collect all applications and map them to their submitters
- submitter = application.submitter
- skey = '%s_%s' % (submitter.first_name, submitter.last_name)
-
- if not skey in old_users:
- old_users[skey] = []
- old_users[skey].append(application.id)
-
- application.submitter = janitor
- application.save()
-
- if application.supporter.all():
- application.writelog(_('Supporters removed after user import.'), user=request.user)
-
- profiles = Profile.objects.all()
- for profile in profiles:
- profile.user.delete()
- profile.delete()
- i = -1
- dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
- dialect = csv_ext.patchup(dialect)
- request.FILES['csvfile'].seek(0)
-
- for (lno, line) in enumerate(csv.reader(request.FILES['csvfile'], dialect=dialect)):
- i += 1
- if i > 0:
- try:
- (first_name, last_name, gender, group, type, committee, comment) = line[:7]
- except ValueError:
- messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
- i -= 1
- continue
- user = User()
- user.last_name = last_name
- user.first_name = first_name
- user.username = gen_username(first_name, last_name)
- #user.email = email
- user.save()
- profile = Profile()
- profile.user = user
- profile.gender = gender
- profile.group = group
- profile.type = type
- profile.committee = committee
- profile.comment = comment
- profile.firstpassword = gen_password()
- profile.user.set_password(profile.firstpassword)
- profile.user.save()
- profile.save()
-
- if type == 'delegate':
- delegate = Group.objects.get(name='Delegierter')
- user.groups.add(delegate)
- else:
- observer = Group.objects.get(name='Beobachter')
- user.groups.add(observer)
-
- if form.cleaned_data['application_handling'] == 'REASSIGN':
- # live remap
- skey = '%s_%s' % (user.first_name, user.last_name)
- if skey in old_users:
- for appid in old_users[skey]:
- try:
- application = Application.objects.get(id=appid)
- application.submitter = user
- application.save()
- application.writelog(_('Reassigned to "%s" after (re)importing users.') % ("%s %s" % (user.first_name, user.last_name)), user=request.user)
- applications_mapped += 1
- except Application.DoesNotExist:
- messages.error(request, _('Could not reassing application %d - object not found!') % appid)
- del old_users[skey]
-
- if old_users:
- # mark all applications without a valid user as 'needs review'
- # this will account for *all* applications if application_mode == 'INREVIEW'
- for skey in old_users:
- for appid in old_users[skey]:
- try:
- application = Application.objects.get(id=appid)
- if application.status != 'rev':
- application.set_status(user=request.user, status='rev', force=True)
- applications_review += 1
- except Application.DoesNotExist:
- messages.error(request, _('Could not reassing application %d - object not found!') % appid)
-
- if applications_review:
- messages.warning(request, ungettext('%d application could not be reassigned and needs a review!',
- '%d applications could not be reassigned and need a review!', applications_review) % applications_review)
- if applications_mapped:
- messages.success(request, ungettext('%d application was successfully reassigned.',
- '%d applications were successfully reassigned.', applications_mapped) % applications_mapped)
- if applications_removed:
- messages.warning(request, ungettext('%d application was discarded.',
- '%d applications were discarded.', applications_removed) % applications_removed)
-
- if i > 0:
- messages.success(request, _('%d new participants were successfully imported.') % i)
- return redirect(reverse('user_overview'))
- except csv.Error:
- message.error(request, _('Import aborted because of severe errors in the input file.'))
- except UnicodeDecodeError:
- messages.error(request, _('Import file has wrong character encoding, only UTF-8 is supported!'))
- else:
- messages.error(request, _('Please check the form for errors.'))
- else:
- messages.warning(request, _("Attention: All existing participants will be removed if you import new participants."))
- if Application.objects.all():
- messages.warning(request, _("Attention: Supporters from all existing applications will be removed."))
- messages.warning(request, _("Attention: Applications which can't be mapped to new users will be set to 'Needs Review'."))
- form = UserImportForm()
- return {
- 'form': form,
- }
-
-
-@permission_required('participant.can_manage_participant')
-def reset_password(request, user_id):
- """
- Reset the Password.
- """
- user = User.objects.get(pk=user_id)
- if request.method == 'POST':
- user.profile.reset_password()
- messages.success(request,
- _('The Password for %s was successfully reset.') % user)
- else:
- gen_confirm_form(request,
- _('Do you really want to reset the password for %s?') % user,
- reverse('user_reset_password', args=[user_id]))
- return redirect(reverse('user_edit', args=[user_id]))
-
-
def login(request):
extra_content = {}
try:
@@ -605,10 +477,10 @@ def login(request):
"Installation was successfully! Use %(user)s "
"(password: %(password)s) for first login.
"
"Important: Please change the password after "
- "first login! Otherwise this message still appears for everyone "
- "and could be a security risk.") % {
- 'user': html_strong(admin.username),
- 'password': html_strong(config['admin_password'])}
+ "first login! Otherwise this message still appears for "
+ "everyone and could be a security risk.") % {
+ 'user': html_strong(admin.username),
+ 'password': html_strong(config['admin_password'])}
extra_content['next'] = reverse('password_change')
except User.DoesNotExist:
pass
@@ -623,134 +495,6 @@ def register_tab(request):
return Tab(
title=_('Participants'),
url=reverse('user_overview'),
- permission=request.user.has_perm('participant.can_see_participant')
- or request.user.has_perm('participant.can_manage_participant'),
- selected=selected,
- )
-
-
-class ParticipantsListPDF(PDFView):
- """
- Generate the userliste as PDF.
- """
- permission_required = 'participant.can_see_participant'
- filename = ugettext_lazy("Participant-list")
- document_title = ugettext_lazy('List of Participants')
-
- def append_to_pdf(self, story):
- data = [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'),
- _('Committee')]]
- sort = 'last_name'
- counter = 0
- for user in User.objects.all().order_by(sort):
- try:
- counter += 1
- user.get_profile()
- 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'])
- ])
- 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),
- ('ROWBACKGROUNDS', (0, 1), (-1, -1),
- (colors.white, (.9, .9, .9)))])
- t._argW[0] = 0.75 * cm
- story.append(t)
-
-
-class ParticipantsPasswordsPDF(PDFView):
- """
- Generate the Welcomepaper for the users.
- """
- permission_required = 'participant.can_manage_participant'
- filename = ugettext_lazy("Participant-passwords")
- top_space = 0
-
- def get_template(self, buffer):
- return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6,
- leftMargin=0, rightMargin=0, showBoundary=False)
-
- def build_document(self, pdf_document, story):
- pdf_document.build(story)
-
- def append_to_pdf(self, story):
- 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(Paragraph(_("Account for OpenSlides"),
- stylesheet['Ballot_title']))
- cell.append(Paragraph(_("for %s") % (user.profile),
- stylesheet['Ballot_subtitle']))
- cell.append(Spacer(0, 0.5 * cm))
- cell.append(Paragraph(_("User: %s") % (user.username),
- stylesheet['Monotype']))
- cell.append(Paragraph(_("Password: %s")
- % (user.profile.firstpassword), stylesheet['Monotype']))
- 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))
- cell2 = []
- cell2.append(Spacer(0, 0.8 * cm))
- if participant_pdf_welcometext is not None:
- cell2.append(Paragraph(
- participant_pdf_welcometext.replace('\r\n', '
'),
- stylesheet['Ballot_subtitle']))
-
- data.append([cell, cell2])
- except OpenSlidesUser.DoesNotExist:
- pass
- # add empty table line if no participants available
- if data == []:
- data.append(['', ''])
- # build table
- 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'),
- ]))
- story.append(t)
-
-
-class Config(FormView):
- """
- Config page for the participant app.
- """
- permission_required = 'config.can_manage_config'
- form_class = ConfigForm
- template_name = 'participant/config.html'
-
- def get_initial(self):
- return {
- 'participant_pdf_system_url': config['participant_pdf_system_url'],
- 'participant_pdf_welcometext': config['participant_pdf_welcometext']
- }
-
- def form_valid(self, form):
- config['participant_pdf_system_url'] = \
- form.cleaned_data['participant_pdf_system_url']
- config['participant_pdf_welcometext'] = \
- form.cleaned_data['participant_pdf_welcometext']
- messages.success(self.request,
- _('Participants settings successfully saved.'))
- return super(Config, self).form_valid(form)
+ permission=request.user.has_perm('participant.can_see_participant') or
+ request.user.has_perm('participant.can_manage_participant'),
+ selected=selected)
diff --git a/openslides/urls.py b/openslides/urls.py
index d3f0e9d91..0a21c503e 100644
--- a/openslides/urls.py
+++ b/openslides/urls.py
@@ -55,7 +55,6 @@ for plugin in settings.INSTALLED_PLUGINS:
urlpatterns += patterns('',
- (r'^500/$', 'openslides.utils.views.server_error'),
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
url(r'^login/$',
diff --git a/openslides/utils/person/__init__.py b/openslides/utils/person/__init__.py
index e54e6258a..da896616f 100644
--- a/openslides/utils/person/__init__.py
+++ b/openslides/utils/person/__init__.py
@@ -10,7 +10,7 @@
:license: GNU GPL, see LICENSE for more details.
"""
-from openslides.utils.person.signals import receiv_persons
+from openslides.utils.person.signals import receive_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
diff --git a/openslides/utils/person/api.py b/openslides/utils/person/api.py
index 59e7d7a1a..55b4691a8 100644
--- a/openslides/utils/person/api.py
+++ b/openslides/utils/person/api.py
@@ -10,16 +10,16 @@
:license: GNU GPL, see LICENSE for more details.
"""
-from openslides.utils.person.signals import receiv_persons
+from openslides.utils.person.signals import receive_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 __init__(self, person_prefix_filter=None, id_filter=None):
+ self.person_prefix_filter = person_prefix_filter
+ self.id_filter = id_filter
def __iter__(self):
try:
@@ -35,14 +35,16 @@ class Persons(object):
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 receiver, persons in receive_persons.send(
+ sender='persons', person_prefix_filter=self.person_prefix_filter, id_filter=self.id_filter):
for person in persons:
self._cache.append(person)
yield person
def generate_person_id(prefix, id):
+ assert prefix is not None
+ assert id is not None
if ':' in prefix:
raise ValueError("':' is not allowed in a the 'person_prefix'")
return "%s:%d" % (prefix, id)
@@ -61,4 +63,4 @@ def get_person(person_id):
except TypeError:
from openslides.utils.person import EmtyPerson
return EmtyPerson()
- return Persons(person_prefix=person_prefix, id=id)[0]
+ return Persons(person_prefix_filter=person_prefix, id_filter=id)[0]
diff --git a/openslides/utils/person/models.py b/openslides/utils/person/models.py
index 3df620dfd..cf16f7286 100644
--- a/openslides/utils/person/models.py
+++ b/openslides/utils/person/models.py
@@ -57,7 +57,7 @@ class PersonMixin(object):
try:
return generate_person_id(self.person_prefix, self.pk)
except AttributeError:
- raise AttributeError("%s has to have a attribute 'user_prefix'"
+ raise AttributeError("%s has to have a attribute 'person_prefix'"
% self)
def __repr__(self):
diff --git a/openslides/utils/person/signals.py b/openslides/utils/person/signals.py
index 5d8dba88b..32d5879b4 100644
--- a/openslides/utils/person/signals.py
+++ b/openslides/utils/person/signals.py
@@ -12,4 +12,4 @@
from django.dispatch import Signal
-receiv_persons = Signal(providing_args=['person_prefix', 'id'])
+receive_persons = Signal(providing_args=['person_prefix_filter', 'id_filter'])
diff --git a/openslides/utils/views.py b/openslides/utils/views.py
index 0c3667025..becdbfc8b 100644
--- a/openslides/utils/views.py
+++ b/openslides/utils/views.py
@@ -34,7 +34,7 @@ from django.conf import settings
from django.dispatch import receiver
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
from django.utils.decorators import method_decorator
-from django.utils.translation import ugettext as _
+from django.utils.translation import ugettext as _, ugettext_noop, ugettext_lazy
from django.utils.importlib import import_module
from django.template import loader, RequestContext
from django.template.loader import render_to_string
@@ -105,6 +105,50 @@ class AjaxMixin(object):
return HttpResponse(json.dumps(self.get_ajax_context(**kwargs)))
+class QuestionMixin(object):
+ question = ugettext_lazy('Are you sure?')
+ success_message = ugettext_lazy('Thank you for your answer')
+ answer_options = [('yes', ugettext_lazy("Yes")), ('no', ugettext_lazy("No"))]
+
+ def get_answer_options(self):
+ return self.answer_options
+
+ def get_question(self):
+ return unicode(self.question)
+
+ def get_answer(self):
+ for option in self.get_answer_options():
+ if option[0] in self.request.POST:
+ return option[0]
+ return None
+
+ def get_answer_url(self):
+ return self.answer_url
+
+ def confirm_form(self):
+ option_fields = "\n".join([
+ '' % (option[0], unicode(option[1]))
+ for option in self.get_answer_options()])
+ messages.warning(self.request,
+ """
+ %(message)s
+
+ """ % {
+ 'message': self.get_question(),
+ 'url': self.get_answer_url(),
+ 'csrf': csrf(self.request)['csrf_token'],
+ 'option_fields': option_fields})
+
+ def pre_redirect(self, request, *args, **kwargs):
+ self.confirm_form(request, self.object)
+
+ def pre_post_redirect(self, request, *args, **kwargs):
+ messages.success(request)
+
+
class TemplateView(PermissionMixin, _TemplateView):
def get_context_data(self, **kwargs):
context = super(TemplateView, self).get_context_data(**kwargs)
@@ -208,42 +252,41 @@ class CreateView(PermissionMixin, _CreateView):
messages.error(self.request, _('Please check the form for errors.'))
return super(CreateView, self).form_invalid(form)
+ def form_valid(self, form):
+ self.object = form.save(commit=False)
+ self.manipulate_object(form)
+ self.object.save()
+ form.save_m2m()
+ return HttpResponseRedirect(self.get_success_url())
+
def get_success_message(self):
return _('%s was successfully created.') % html_strong(self.object)
+ def manipulate_object(self, form):
+ pass
-class DeleteView(RedirectView, SingleObjectMixin):
- def get_confirm_question(self):
+
+class DeleteView(RedirectView, SingleObjectMixin, QuestionMixin):
+ def get_question(self):
return _('Do you really want to delete %s?') % html_strong(self.object)
def get_success_message(self):
return _('%s was successfully deleted.') % html_strong(self.object)
def pre_redirect(self, request, *args, **kwargs):
- self.confirm_form(request, self.object)
+ self.confirm_form()
def pre_post_redirect(self, request, *args, **kwargs):
- self.object.delete()
- messages.success(request, self.get_success_message())
+ if self.get_answer().lower() == 'yes':
+ self.object.delete()
+ messages.success(request, self.get_success_message())
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(DeleteView, self).get(request, *args, **kwargs)
- def confirm_form(self, request, object):
- self.gen_confirm_form(request, self.get_confirm_question(),
- object.get_absolute_url('delete'))
-
- def gen_confirm_form(self, request, message, url):
- messages.warning(request,
- """
- %s
-
- """ % (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
+ def get_answer_url(self):
+ return self.object.get_absolute_url('delete')
class DetailView(TemplateView, SingleObjectMixin):