cleaned up the participant app. Sort of...

This commit is contained in:
Oskar Hahn 2012-07-07 15:26:00 +02:00
parent e01d456e7b
commit dc9dabff6d
6 changed files with 251 additions and 167 deletions

View File

@ -17,6 +17,9 @@ from django.contrib.auth.models import User
def gen_password(): def gen_password():
"""
generates a random passwort.
"""
chars = string.letters + string.digits chars = string.letters + string.digits
newpassword = '' newpassword = ''
for i in range(8): for i in range(8):
@ -25,6 +28,9 @@ def gen_password():
def gen_username(first_name, last_name): def gen_username(first_name, last_name):
"""
generates the username for new users.
"""
testname = "%s%s" % (first_name, last_name) testname = "%s%s" % (first_name, last_name)
try: try:
User.objects.get(username=testname) User.objects.get(username=testname)

View File

@ -10,16 +10,15 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.forms import Form, ModelForm, CharField, EmailField, FileField, FileInput, TextInput, Textarea, MultipleChoiceField, ModelMultipleChoiceField, ChoiceField, BooleanField from django import forms
from django.contrib.auth.models import User, Group, Permission
from django.contrib.auth.forms import AdminPasswordChangeForm from django.contrib.auth.forms import AdminPasswordChangeForm
from django.contrib.auth.models import User, Group, Permission
from django.utils.translation import ugettext as _, ugettext_noop
from utils.forms import CssClassMixin from openslides.utils.forms import CssClassMixin
from utils.translation_ext import LocalizedModelMultipleChoiceField, ugettext as _ from openslides.utils.translation_ext import LocalizedModelMultipleChoiceField
# required for USER_VISIBLE_PERMISSIONS
from participant.models import Profile
from openslides.participant.models import Profile
USER_APPLICATION_IMPORT_OPTIONS = [ USER_APPLICATION_IMPORT_OPTIONS = [
@ -28,71 +27,85 @@ USER_APPLICATION_IMPORT_OPTIONS = [
('DISCARD' , _('Discard applications')) ('DISCARD' , _('Discard applications'))
] ]
class UserNewForm(ModelForm, CssClassMixin): class UserNewForm(forms.ModelForm, CssClassMixin):
first_name = CharField(label=_("First name")) first_name = forms.CharField(label=_("First name"))
last_name = CharField(label=_("Last name")) last_name = forms.CharField(label=_("Last name"))
groups = ModelMultipleChoiceField(queryset=Group.objects.all(), label=_("User groups"), required=False) groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),
is_active = BooleanField(label=_("Active"), required=False, initial=True) label=_("User groups"), required=False)
is_active = forms.BooleanField(label=_("Active"), required=False,
initial=True)
class Meta: class Meta:
model = User model = User
exclude = ('username', 'password', 'is_staff', 'is_superuser', 'last_login', 'date_joined', 'user_permissions') exclude = ('username', 'password', 'is_staff', 'is_superuser',
'last_login', 'date_joined', 'user_permissions')
class UserEditForm(ModelForm, CssClassMixin): class UserEditForm(forms.ModelForm, CssClassMixin):
first_name = CharField(label=_("First name")) first_name = forms.CharField(label=_("First name"))
last_name = CharField(label=_("Last name")) last_name = forms.CharField(label=_("Last name"))
groups = ModelMultipleChoiceField(queryset=Group.objects.all(), label=_("User groups"), required=False) groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),
is_active = BooleanField(label=_("Active"), required=False) label=_("User groups"), required=False)
is_active = forms.BooleanField(label=_("Active"), required=False)
class Meta: class Meta:
model = User model = User
exclude = ('password', 'is_staff', 'is_superuser', 'last_login', 'date_joined', 'user_permissions') exclude = ('password', 'is_staff', 'is_superuser', 'last_login',
'date_joined', 'user_permissions')
class UsernameForm(ModelForm, CssClassMixin): class UsernameForm(forms.ModelForm, CssClassMixin):
class Meta: class Meta:
model = User model = User
exclude = ('first_name', 'last_name', 'email', 'is_active', 'is_superuser', 'groups', 'password', 'is_staff', 'last_login', 'date_joined', 'user_permissions') exclude = ('first_name', 'last_name', 'email', 'is_active',
'is_superuser', 'groups', 'password', 'is_staff', 'last_login',
'date_joined', 'user_permissions')
class ProfileForm(ModelForm, CssClassMixin): class ProfileForm(forms.ModelForm, CssClassMixin):
class Meta: class Meta:
model = Profile model = Profile
class GroupForm(ModelForm, CssClassMixin): class GroupForm(forms.ModelForm, CssClassMixin):
permissions = LocalizedModelMultipleChoiceField(queryset=Permission.objects.all(), label=_("Persmissions")) permissions = LocalizedModelMultipleChoiceField(
queryset=Permission.objects.all(), label=_("Persmissions"))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(GroupForm, self).__init__(*args, **kwargs) super(GroupForm, self).__init__(*args, **kwargs)
if kwargs.get('instance', None) is not None: 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: class Meta:
model = Group model = Group
exclude = ('permissions',) exclude = ('permissions',)
class UsersettingsForm(ModelForm, CssClassMixin): class UsersettingsForm(forms.ModelForm, CssClassMixin):
class Meta: class Meta:
model = User model = User
fields = ('username', 'first_name', 'last_name', 'email') fields = ('username', 'first_name', 'last_name', 'email')
class UserImportForm(Form, CssClassMixin): class UserImportForm(forms.Form, CssClassMixin):
csvfile = FileField(widget=FileInput(attrs={'size':'50'}), label=_("CSV File")) csvfile = forms.FileField(widget=forms.FileInput(attrs={'size':'50'}),
application_handling = ChoiceField(required=True, choices=USER_APPLICATION_IMPORT_OPTIONS, label=_("For existing applications")) label=_("CSV File"))
application_handling = forms.ChoiceField(
required=True,
choices=USER_APPLICATION_IMPORT_OPTIONS,
label=_("For existing applications"),
)
class ConfigForm(Form, CssClassMixin): class ConfigForm(forms.Form, CssClassMixin):
participant_pdf_system_url = CharField( participant_pdf_system_url = forms.CharField(
widget=TextInput(), widget=forms.TextInput(),
required=False, required=False,
label=_("System URL"), 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 = CharField( participant_pdf_welcometext = forms.CharField(
widget=Textarea(), widget=forms.Textarea(),
required=False, required=False,
label=_("Welcome text"), label=_("Welcome text"),
help_text=_("Printed in PDF of first time passwords only."), help_text=_("Printed in PDF of first time passwords only."),

View File

@ -10,12 +10,17 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from django.contrib.auth.models import User from django.dispatch import receiver
from django.utils.translation import ugettext as _, ugettext_noop
from openslides.config.signals import default_config_value
from openslides.participant.api import gen_password
from utils.translation_ext import ugettext as _
from participant.api import gen_password
class Profile(models.Model): class Profile(models.Model):
GENDER_CHOICES = ( GENDER_CHOICES = (
@ -33,18 +38,23 @@ class Profile(models.Model):
group = models.CharField(max_length=100, null=True, blank=True, group = models.CharField(max_length=100, null=True, blank=True,
verbose_name = _("Group"), help_text=_('Shown behind the name.')) verbose_name = _("Group"), help_text=_('Shown behind the name.'))
gender = models.CharField(max_length=50, choices=GENDER_CHOICES, blank=True, gender = models.CharField(max_length=50, choices=GENDER_CHOICES, blank=True,
verbose_name = _("Gender"), help_text=_('Only for filter the userlist.')) verbose_name = _("Gender"),
help_text=_('Only for filter the userlist.'))
type = models.CharField(max_length=100, choices=TYPE_CHOICE, blank=True, type = models.CharField(max_length=100, choices=TYPE_CHOICE, blank=True,
verbose_name = _("Typ"), help_text=_('Only for filter the userlist.')) verbose_name = _("Typ"), help_text=_('Only for filter the userlist.'))
committee = models.CharField(max_length=100, null=True, blank=True, committee = models.CharField(max_length=100, null=True, blank=True,
verbose_name = _("Committee"), help_text=_('Only for filter the userlist.')) verbose_name = _("Committee"),
comment = models.TextField(null=True, blank=True, verbose_name = _('Comment'), help_text=_('Only for filter the userlist.'))
help_text=_('Only for notes.')) 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, firstpassword = models.CharField(max_length=100, null=True, blank=True,
verbose_name = _("First Password")) verbose_name = _("First Password"))
def reset_password(self): def reset_password(self):
"""
Reset the password for the user to his default-password.
"""
self.user.set_password(self.firstpassword) self.user.set_password(self.firstpassword)
self.user.save() self.user.save()
@ -71,17 +81,16 @@ class Profile(models.Model):
class Meta: class Meta:
permissions = ( permissions = (
('can_see_participant', _("Can see participant", fixstr=True)), ('can_see_participant', ugettext_noop("Can see participant")),
('can_manage_participant', _("Can manage participant", fixstr=True)), ('can_manage_participant', ugettext_noop("Can manage participant")),
) )
from django.dispatch import receiver
from openslides.config.signals import default_config_value
@receiver(default_config_value, dispatch_uid="participant_default_config") @receiver(default_config_value, dispatch_uid="participant_default_config")
def default_config(sender, key, **kwargs): def default_config(sender, key, **kwargs):
"""
Default values for the participant app.
"""
return { return {
'participant_pdf_system_url': 'http://example.com:8000', 'participant_pdf_system_url': 'http://example.com:8000',
'participant_pdf_welcometext': _('Welcome to OpenSlides!'), 'participant_pdf_welcometext': _('Welcome to OpenSlides!'),

View File

@ -1,28 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
openslides.participant.tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests 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
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

View File

@ -10,7 +10,7 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.conf.urls.defaults import * from django.conf.urls.defaults import url, patterns
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from participant.views import ParticipantsListPDF, ParticipantsPasswordsPDF from participant.views import ParticipantsListPDF, ParticipantsPasswordsPDF
@ -21,22 +21,22 @@ urlpatterns = patterns('participant.views',
name='user_overview', name='user_overview',
), ),
url(r'^new$', url(r'^new/$',
'edit', 'edit',
name='user_new', name='user_new',
), ),
url(r'^(?P<user_id>\d+)/edit$', url(r'^(?P<user_id>\d+)/edit/$',
'edit', 'edit',
name='user_edit', name='user_edit',
), ),
url(r'^print$', url(r'^print/$',
ParticipantsListPDF.as_view(), ParticipantsListPDF.as_view(),
name='user_print', name='user_print',
), ),
url(r'^(?P<user_id>\d+)/del$', url(r'^(?P<user_id>\d+)/del/$',
'user_delete', 'user_delete',
name='user_delete', name='user_delete',
), ),
@ -46,7 +46,7 @@ urlpatterns = patterns('participant.views',
name='user_status', name='user_status',
), ),
url(r'^import$', url(r'^import/$',
'user_import', 'user_import',
name='user_import', name='user_import',
), ),
@ -56,27 +56,27 @@ urlpatterns = patterns('participant.views',
name='user_group_overview', name='user_group_overview',
), ),
url(r'^group/new$', url(r'^group/new/$',
'group_edit', 'group_edit',
name='user_group_new', name='user_group_new',
), ),
url(r'^group/(?P<group_id>\d+)/edit$', url(r'^group/(?P<group_id>\d+)/edit/$',
'group_edit', 'group_edit',
name='user_group_edit', name='user_group_edit',
), ),
url(r'^group/(?P<group_id>\d+)/del$', url(r'^group/(?P<group_id>\d+)/del/$',
'group_delete', 'group_delete',
name='user_group_delete', name='user_group_delete',
), ),
url(r'^resetpassword/(?P<user_id>\d+)$', url(r'^resetpassword/(?P<user_id>\d+)/$',
'reset_password', 'reset_password',
name='user_reset_password', name='user_reset_password',
), ),
url(r'^passwords/print$', url(r'^passwords/print/$',
ParticipantsPasswordsPDF.as_view(), ParticipantsPasswordsPDF.as_view(),
name='print_passwords', name='print_passwords',
), ),

View File

@ -10,10 +10,10 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
# for python 2.5 support
from __future__ import with_statement from __future__ import with_statement
import csv import csv
import utils.csv_ext
from urllib import urlencode from urllib import urlencode
try: try:
@ -21,47 +21,50 @@ try:
except ImportError: # python <= 2.5 grab it from cgi except ImportError: # python <= 2.5 grab it from cgi
from cgi import parse_qs from cgi import parse_qs
from django.http import HttpResponse
from django.shortcuts import redirect
from django.template import RequestContext
from django.contrib.auth.models import User, Group
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _, ungettext
from django.db import transaction
from django.db.models import Avg, Max, Min, Count
from reportlab.lib import colors from reportlab.lib import colors
from reportlab.lib.units import cm 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 participant.models import Profile from django.db import transaction
from participant.api import gen_username, gen_password from django.contrib import messages
from participant.forms import (UserNewForm, UserEditForm, ProfileForm, from django.contrib.auth.decorators import login_required
UsersettingsForm, UserImportForm, GroupForm, from django.contrib.auth.models import User, Group
AdminPasswordChangeForm, ConfigForm) from django.core.urlresolvers import reverse
from application.models import Application from django.shortcuts import redirect
from django.utils.translation import ugettext as _, ungettext
from config.models import config 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)
from openslides.utils.views import FormView, PDFView
from utils.utils import (template, permission_required, gen_confirm_form, from openslides.config.models import config
ajax_request, decodedict, encodedict)
from utils.pdf import stylesheet from openslides.participant.models import Profile
from utils.template import Tab from openslides.participant.api import gen_username, gen_password
from utils.views import (FormView, PDFView) from openslides.participant.forms import (UserNewForm, UserEditForm,
from utils.utils import delete_default_permissions ProfileForm, sersettingsForm, UserImportForm, GroupForm,
AdminPasswordChangeForm, ConfigForm)
@permission_required('participant.can_see_participant') @permission_required('participant.can_see_participant')
@template('participant/overview.html') @template('participant/overview.html')
def get_overview(request): def get_overview(request):
"""
Show all users.
"""
try: try:
sortfilter = encodedict(parse_qs(request.COOKIES['participant_sortfilter'])) sortfilter = encodedict(parse_qs(
request.COOKIES['participant_sortfilter']))
except KeyError: except KeyError:
sortfilter = {} sortfilter = {}
for value in [u'gender', u'group', u'type', u'committee', u'status', u'sort', u'reverse']: for value in [u'gender', u'group', u'type', u'committee', u'status',
u'sort', u'reverse']:
if value in request.REQUEST: if value in request.REQUEST:
if request.REQUEST[value] == '---': if request.REQUEST[value] == '---':
try: try:
@ -79,7 +82,8 @@ def get_overview(request):
if 'type' in sortfilter: if 'type' in sortfilter:
query = query.filter(profile__type__iexact=sortfilter['type'][0]) query = query.filter(profile__type__iexact=sortfilter['type'][0])
if 'committee' in sortfilter: if 'committee' in sortfilter:
query = query.filter(profile__committee__iexact=sortfilter['committee'][0]) query = query. \
filter(profile__committee__iexact=sortfilter['committee'][0])
if 'status' in sortfilter: if 'status' in sortfilter:
query = query.filter(is_active=sortfilter['status'][0]) query = query.filter(is_active=sortfilter['status'][0])
if 'sort' in sortfilter: if 'sort' in sortfilter:
@ -115,19 +119,23 @@ def get_overview(request):
else: else:
percent = 0 percent = 0
# list of all existing groups # list of all existing groups
groups = [p['group'] for p in Profile.objects.values('group').exclude(group='').distinct()] groups = [p['group'] for p in Profile.objects.values('group') \
.exclude(group='').distinct()]
# list of all existing committees # list of all existing committees
committees = [p['committee'] for p in Profile.objects.values('committee').exclude(committee='').distinct()] committees = [p['committee'] for p in Profile.objects.values('committee') \
.exclude(committee='').distinct()]
return { return {
'users': users, 'users': users,
'allusers': allusers, 'allusers': allusers,
'percent': round(percent, 1), 'percent': round(percent, 1),
'groups': groups, 'groups': groups,
'committees': committees, 'committees': committees,
'cookie': ['participant_sortfilter', urlencode(decodedict(sortfilter), doseq=True)], 'cookie': ['participant_sortfilter', urlencode(decodedict(sortfilter),
doseq=True)],
'sortfilter': sortfilter, 'sortfilter': sortfilter,
} }
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
@template('participant/edit.html') @template('participant/edit.html')
def edit(request, user_id=None): def edit(request, user_id=None):
@ -145,7 +153,8 @@ def edit(request, user_id=None):
profileform = ProfileForm(request.POST, prefix="profile") profileform = ProfileForm(request.POST, prefix="profile")
else: else:
userform = UserEditForm(request.POST, instance=user, prefix="user") userform = UserEditForm(request.POST, instance=user, prefix="user")
profileform = ProfileForm(request.POST, instance=user.profile, prefix="profile") profileform = ProfileForm(request.POST, instance=user.profile,
prefix="profile")
if userform.is_valid() and profileform.is_valid(): if userform.is_valid() and profileform.is_valid():
user = userform.save() user = userform.save()
@ -161,9 +170,11 @@ def edit(request, user_id=None):
profile.user.save() profile.user.save()
profile.save() profile.save()
if user_id is None: if user_id is None:
messages.success(request, _('New participant was successfully created.')) messages.success(request,
_('New participant was successfully created.'))
else: else:
messages.success(request, _('Participant was successfully modified.')) messages.success(request,
_('Participant was successfully modified.'))
if not 'apply' in request.POST: if not 'apply' in request.POST:
return redirect(reverse('user_overview')) return redirect(reverse('user_overview'))
if user_id is None: if user_id is None:
@ -184,20 +195,31 @@ def edit(request, user_id=None):
'edituser': user, 'edituser': user,
} }
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
@template('confirm.html') @template('confirm.html')
def user_delete(request, user_id): def user_delete(request, user_id):
"""
Delete an user.
"""
user = User.objects.get(pk=user_id) user = User.objects.get(pk=user_id)
if request.method == 'POST': if request.method == 'POST':
user.delete() user.delete()
messages.success(request, _('Participant <b>%s</b> was successfully deleted.') % user) messages.success(request,
_('Participant <b>%s</b> was successfully deleted.') % user)
else: else:
gen_confirm_form(request, _('Do you really want to delete <b>%s</b>?') % user, reverse('user_delete', args=[user_id])) gen_confirm_form(request,
_('Do you really want to delete <b>%s</b>?') % user,
reverse('user_delete', args=[user_id]))
return redirect(reverse('user_overview')) return redirect(reverse('user_overview'))
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
@template('confirm.html') @template('confirm.html')
def user_set_status(request, user_id): def user_set_status(request, user_id):
"""
Set the status of an user.
"""
try: try:
user = User.objects.get(pk=user_id) user = User.objects.get(pk=user_id)
if user.is_active: if user.is_active:
@ -206,7 +228,8 @@ def user_set_status(request, user_id):
user.is_active = True user.is_active = True
user.save() user.save()
except User.DoesNotExist: except User.DoesNotExist:
messages.error(request, _('Participant ID %d does not exist.') % int(user_id)) messages.error(request,
_('Participant ID %d does not exist.') % int(user_id))
return redirect(reverse('user_overview')) return redirect(reverse('user_overview'))
if request.is_ajax(): if request.is_ajax():
@ -218,9 +241,13 @@ def user_set_status(request, user_id):
messages.success(request, _('<b>%s</b> is now <b>absent</b>.') % user) messages.success(request, _('<b>%s</b> is now <b>absent</b>.') % user)
return redirect(reverse('user_overview')) return redirect(reverse('user_overview'))
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
@template('participant/group_overview.html') @template('participant/group_overview.html')
def get_group_overview(request): def get_group_overview(request):
"""
Show all groups.
"""
if config['system_enable_anonymous']: if config['system_enable_anonymous']:
groups = Group.objects.all() groups = Group.objects.all()
else: else:
@ -229,9 +256,13 @@ def get_group_overview(request):
'groups': groups, 'groups': groups,
} }
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
@template('participant/group_edit.html') @template('participant/group_edit.html')
def group_edit(request, group_id=None): def group_edit(request, group_id=None):
"""
Edit a group.
"""
if group_id is not None: if group_id is not None:
try: try:
group = Group.objects.get(id=group_id) group = Group.objects.get(id=group_id)
@ -254,7 +285,9 @@ def group_edit(request, group_id=None):
# special handling for anonymous auth # special handling for anonymous auth
if group is None and group_name.strip().lower() == 'anonymous': if group is None and group_name.strip().lower() == 'anonymous':
# don't allow to create this group # don't allow to create this group
messages.error(request, _('Group name "%s" is reserved for internal use.') % group_name) messages.error(request,
_('Group name "%s" is reserved for internal use.')
% group_name)
return { return {
'form' : form, 'form' : form,
'group': group 'group': group
@ -263,12 +296,14 @@ def group_edit(request, group_id=None):
group = form.save() group = form.save()
if anonymous_group is not None and \ if anonymous_group is not None and \
anonymous_group.id == group.id: anonymous_group.id == group.id:
# prevent name changes - XXX: I'm sure this could be done as *one* group.save() # prevent name changes -
# XXX: I'm sure this could be done as *one* group.save()
group.name = 'Anonymous' group.name = 'Anonymous'
group.save() group.save()
if group_id is None: if group_id is None:
messages.success(request, _('New group was successfully created.')) messages.success(request,
_('New group was successfully created.'))
else: else:
messages.success(request, _('Group was successfully modified.')) messages.success(request, _('Group was successfully modified.'))
if not 'apply' in request.POST: if not 'apply' in request.POST:
@ -284,19 +319,30 @@ def group_edit(request, group_id=None):
'group': group, 'group': group,
} }
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
def group_delete(request, group_id): def group_delete(request, group_id):
"""
Delete a group.
"""
group = Group.objects.get(pk=group_id) group = Group.objects.get(pk=group_id)
if request.method == 'POST': if request.method == 'POST':
group.delete() group.delete()
messages.success(request, _('Group <b>%s</b> was successfully deleted.') % group) messages.success(request,
_('Group <b>%s</b> was successfully deleted.') % group)
else: else:
gen_confirm_form(request, _('Do you really want to delete <b>%s</b>?') % group, reverse('user_group_delete', args=[group_id])) gen_confirm_form(request,
_('Do you really want to delete <b>%s</b>?') % group,
reverse('user_group_delete', args=[group_id]))
return redirect(reverse('user_group_overview')) return redirect(reverse('user_group_overview'))
@login_required @login_required
@template('participant/settings.html') @template('participant/settings.html')
def user_settings(request): def user_settings(request):
"""
Edit own user account.
"""
if request.method == 'POST': 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(): if form_user.is_valid():
@ -312,9 +358,14 @@ def user_settings(request):
'edituser': request.user, 'edituser': request.user,
} }
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
@template('participant/import.html') @template('participant/import.html')
def user_import(request): def user_import(request):
"""
Import Users via csv.
"""
from openslides.application.models import Application
try: try:
request.user.profile request.user.profile
messages.error(request, _('The import function is available for the superuser (without user profile) only.')) messages.error(request, _('The import function is available for the superuser (without user profile) only.'))
@ -377,7 +428,7 @@ def user_import(request):
profile.delete() profile.delete()
i = -1 i = -1
dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline()) dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
dialect = utils.csv_ext.patchup(dialect) dialect = csv_ext.patchup(dialect)
request.FILES['csvfile'].seek(0) request.FILES['csvfile'].seek(0)
for (lno, line) in enumerate(csv.reader(request.FILES['csvfile'], dialect=dialect)): for (lno, line) in enumerate(csv.reader(request.FILES['csvfile'], dialect=dialect)):
@ -473,33 +524,46 @@ def user_import(request):
@permission_required('participant.can_manage_participant') @permission_required('participant.can_manage_participant')
def reset_password(request, user_id): def reset_password(request, user_id):
"""
Reset the Password.
"""
user = User.objects.get(pk=user_id) user = User.objects.get(pk=user_id)
if request.method == 'POST': if request.method == 'POST':
user.profile.reset_password() user.profile.reset_password()
messages.success(request, _('The Password for <b>%s</b> was successfully reset.') % user) messages.success(request,
_('The Password for <b>%s</b> was successfully reset.') % user)
else: else:
gen_confirm_form(request, _('Do you really want to reset the password for <b>%s</b>?') % user, gen_confirm_form(request,
reverse('user_reset_password', args=[user_id])) _('Do you really want to reset the password for <b>%s</b>?') % user,
reverse('user_reset_password', args=[user_id]))
return redirect(reverse('user_edit', args=[user_id])) return redirect(reverse('user_edit', args=[user_id]))
def register_tab(request): def register_tab(request):
selected = True if request.path.startswith('/participant/') else False """
Register the participant tab.
"""
selected = request.path.startswith('/participant/')
return Tab( return Tab(
title=_('Participants'), title=_('Participants'),
url=reverse('user_overview'), url=reverse('user_overview'),
permission=request.user.has_perm('participant.can_see_participant') or request.user.has_perm('participant.can_manage_participant'), permission=request.user.has_perm('participant.can_see_participant')
or request.user.has_perm('participant.can_manage_participant'),
selected=selected, selected=selected,
) )
class ParticipantsListPDF(PDFView): class ParticipantsListPDF(PDFView):
"""
Generate the userliste as PDF.
"""
permission_required = 'participant.can_see_participant' permission_required = 'participant.can_see_participant'
filename = _("Participant-list") filename = _("Participant-list")
document_title = _('List of Participants') document_title = _('List of Participants')
def append_to_pdf(self, story): def append_to_pdf(self, story):
data= [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'), _('Committee')]] data= [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'),
_('Committee')]]
sort = 'last_name' sort = 'last_name'
counter = 0 counter = 0
for user in User.objects.all().order_by(sort): for user in User.objects.all().order_by(sort):
@ -507,34 +571,40 @@ class ParticipantsListPDF(PDFView):
counter += 1 counter += 1
user.get_profile() user.get_profile()
data.append([counter, data.append([counter,
Paragraph(user.last_name, stylesheet['Tablecell']), Paragraph(user.last_name, stylesheet['Tablecell']),
Paragraph(user.first_name, stylesheet['Tablecell']), Paragraph(user.first_name, stylesheet['Tablecell']),
Paragraph(user.profile.group, stylesheet['Tablecell']), Paragraph(user.profile.group, stylesheet['Tablecell']),
Paragraph(user.profile.get_type_display(), stylesheet['Tablecell']), Paragraph(user.profile.get_type_display(),
Paragraph(user.profile.committee, stylesheet['Tablecell']), stylesheet['Tablecell']),
]) Paragraph(user.profile.committee, stylesheet['Tablecell']),
])
except Profile.DoesNotExist: except Profile.DoesNotExist:
counter -= 1 counter -= 1
pass pass
t=LongTable(data, t = LongTable(data,
style=[ style=[
('VALIGN',(0,0),(-1,-1), 'TOP'), ('VALIGN',(0,0),(-1,-1), 'TOP'),
('LINEABOVE',(0,0),(-1,0),2,colors.black), ('LINEABOVE',(0,0),(-1,0),2,colors.black),
('LINEABOVE',(0,1),(-1,1),1,colors.black), ('LINEABOVE',(0,1),(-1,1),1,colors.black),
('LINEBELOW',(0,-1),(-1,-1),2,colors.black), ('LINEBELOW',(0,-1),(-1,-1),2,colors.black),
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9))), ('ROWBACKGROUNDS', (0, 1), (-1, -1),
]) (colors.white, (.9, .9, .9))),
])
t._argW[0]=0.75*cm t._argW[0]=0.75*cm
story.append(t) story.append(t)
class ParticipantsPasswordsPDF(PDFView): class ParticipantsPasswordsPDF(PDFView):
"""
Generate the Welcomepaper for the users.
"""
permission_required = 'participant.can_manage_participant' permission_required = 'participant.can_manage_participant'
filename = _("Participant-passwords") filename = _("Participant-passwords")
top_space = 0 top_space = 0
def get_template(self, buffer): def get_template(self, buffer):
return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6, leftMargin=0, rightMargin=0, showBoundary=False) return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6,
leftMargin=0, rightMargin=0, showBoundary=False)
def build_document(self, pdf_document, story): def build_document(self, pdf_document, story):
pdf_document.build(story) pdf_document.build(story)
@ -548,34 +618,45 @@ class ParticipantsPasswordsPDF(PDFView):
user.get_profile() user.get_profile()
cell = [] cell = []
cell.append(Spacer(0,0.8*cm)) cell.append(Spacer(0,0.8*cm))
cell.append(Paragraph(_("Account for OpenSlides"), stylesheet['Ballot_title'])) cell.append(Paragraph(_("Account for OpenSlides"),
cell.append(Paragraph(_("for %s") % (user.profile), stylesheet['Ballot_subtitle'])) stylesheet['Ballot_title']))
cell.append(Paragraph(_("for %s") % (user.profile),
stylesheet['Ballot_subtitle']))
cell.append(Spacer(0,0.5*cm)) cell.append(Spacer(0,0.5*cm))
cell.append(Paragraph(_("User: %s") % (user.username), stylesheet['Monotype'])) cell.append(Paragraph(_("User: %s") % (user.username),
cell.append(Paragraph(_("Password: %s") % (user.profile.firstpassword), 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(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 = []
cell2.append(Spacer(0,0.8*cm)) cell2.append(Spacer(0,0.8*cm))
if participant_pdf_welcometext is not None: if participant_pdf_welcometext is not None:
cell2.append(Paragraph(participant_pdf_welcometext.replace('\r\n','<br/>'), stylesheet['Ballot_subtitle'])) cell2.append(Paragraph(
participant_pdf_welcometext.replace('\r\n','<br/>'),
stylesheet['Ballot_subtitle']))
data.append([cell,cell2]) data.append([cell,cell2])
except Profile.DoesNotExist: except Profile.DoesNotExist:
pass pass
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), t.setStyle(TableStyle([
('LINEBELOW', (0,1), (-1,1), 0.25, colors.grey), ('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,1), (-1,-1), 0.25, colors.grey),
])) ('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(t) story.append(t)
class Config(FormView): class Config(FormView):
"""
Config page for the participant app.
"""
permission_required = 'config.can_manage_config' permission_required = 'config.can_manage_config'
form_class = ConfigForm form_class = ConfigForm
template_name = 'participant/config.html' template_name = 'participant/config.html'
@ -583,11 +664,14 @@ class Config(FormView):
def get_initial(self): def get_initial(self):
return { return {
'participant_pdf_system_url': config['participant_pdf_system_url'], 'participant_pdf_system_url': config['participant_pdf_system_url'],
'participant_pdf_welcometext': config['participant_pdf_welcometext'], 'participant_pdf_welcometext': config['participant_pdf_welcometext']
} }
def form_valid(self, form): def form_valid(self, form):
config['participant_pdf_system_url'] = form.cleaned_data['participant_pdf_system_url'] config['participant_pdf_system_url'] = \
config['participant_pdf_welcometext'] = form.cleaned_data['participant_pdf_welcometext'] form.cleaned_data['participant_pdf_system_url']
messages.success(self.request, _('Participants settings successfully saved.')) 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) return super(Config, self).form_valid(form)