Merge pull request #5 from ostcar/participant

Participant
This commit is contained in:
Oskar Hahn 2012-08-13 09:23:55 -07:00
commit 3995765dc5
24 changed files with 906 additions and 1044 deletions

View File

@ -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",

View File

@ -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
<form action="%s" method="post">
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
<input type="submit" value="%s">
<input type="button" value="%s">
</form>
"""
% (message, url, csrf(request)['csrf_token'], _("Yes"),
_("No"))
)
else:
messages.warning(
request,
"""
%s
<form action="%s" method="post">
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
<input type="submit" value="%s">
<input type="submit" name="all" value="%s">
<input type="button" value="%s">
</form>
"""
% (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):
"""

View File

@ -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")),
)

View File

@ -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):

View File

@ -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: <b>%s</b>.") % 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 <b>%s</b>.") % application)
continue
@ -467,7 +466,7 @@ class ApplicationDelete(DeleteView):
messages.success(request, _("Application <b>%s</b> 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 <b>%s</b>.") % 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 <b>%s</b> accepted.") % (aversion.aid))
else:
gen_confirm_form(request, _('Do you really want to permit version <b>%s</b>?') % 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 <b>%s</b> 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():

View File

@ -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:

View File

@ -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',
)

View File

@ -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)

View File

@ -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):

View File

@ -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

View File

@ -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)

View File

@ -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();
}
}
});
});
});
});

View File

@ -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);
}

View File

@ -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 %}
<h1>{% trans "Edit participant" %}</h1>
{% else %}
<h1>{% trans "New participant" %}</h1>
{% endif %}
<form action="" method="post">{% csrf_token %}
{{ userform.as_p }}
{{ profileform.as_p }}
{% if edituser %}
<p><a href="{% url user_reset_password edituser.id %}">{% trans 'Reset to First Password' %}</a></p>
{{ form.as_p }}
{% if edit_user %}
<p>
<a href="{% url user_reset_password edit_user.id %}">{% trans 'Reset to First Password' %}</a>
</p>
{% endif %}
<p>
<button class="button" type="submit">
<span class="icon ok">{% trans 'Save' %}</span>
</button>
<button class="button" type="submit" name="apply">
<span class="icon apply">{% trans 'Apply' %}</span>
</button>
<a href='{% url user_overview %}'>
<button class="button" type="button" onclick="window.location='{% url user_overview %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span>
</button>
</a>
<button class="button" type="submit">
<span class="icon ok">{% trans 'Save' %}</span>
</button>
<button class="button" type="submit" name="apply">
<span class="icon apply">{% trans 'Apply' %}</span>
</button>
<a href='{% url user_overview %}'>
<button class="button" type="button" onclick="window.location='{% url user_overview %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span>
</button>
</a>
</p>
<small>* {% trans "required" %}</small>
</form>

View File

@ -8,99 +8,108 @@
{% block header %}
{% if perms.agenda.can_manage_agenda %}
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/participant.css' %}" />
<script type="text/javascript" src="{% static 'javascript/participant.js' %}"></script>
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/participant.css' %}" />
<script type="text/javascript" src="{% static 'javascript/participant.js' %}"></script>
{% endif %}
{% endblock %}
{% block content %}
<h1>{% trans "Participants" %}</h1>
<p><form action="{{request.url}}" name="filter" method="post">
{% csrf_token %}
{% trans "Filter" %}:
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Gender" %} --</option>
<option value="male" {% if 'male' in sortfilter.gender %}selected{% endif %}>{% trans "Male" %}</option>
<option value="female" {% if 'female' in sortfilter.gender %}selected{% endif %}>{% trans "Female" %}</option>
<option value="" {% if '' in sortfilter.gender %}selected{% endif %}>{% trans "Not specified" %}</option>
</select>
<select class="default-input" name="group" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Group" %} --</option>
{% for group in groups %}
<option value="{{ group }}" {% if group in sortfilter.group %}selected{% endif %}>
{{ group }}</option>
{% endfor %}
</select>
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Type" %} --</option>
<option value="delegate" {% if 'delegate' in sortfilter.type %}selected{% endif %}>{% trans "Delegate" %}</option>
<option value="observer" {% if 'observer' in sortfilter.type %}selected{% endif %}>{% trans "Observer" %}</option>
<option value="staff" {% if 'staff' in sortfilter.type %}selected{% endif %}>{% trans "Staff" %}</option>
<option value="guest" {% if 'guest' in sortfilter.type %}selected{% endif %}>{% trans "Guest" %}</option>
<option value="" {% if '' in sortfilter.type %}selected{% endif %}>{% trans "Not specified" %}</option>
</select>
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Committee" %} --</option>
{% for committee in committees %}
<option value="{{ committee }}" {% if committee in sortfilter.committee %}selected{% endif %}>
{{ committee }}</option>
{% endfor %}
</select>
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Status" %} --</option>
<option value="1" {% if '1' in sortfilter.status %}selected{% endif %}>{% trans "Active" %}</option>
<option value="0" {% if '0' in sortfilter.status %}selected{% endif %}>{% trans "Inactive" %}</option>
</select>
<p>
<form action="" name="filter" method="get">
{% trans "Filter" %}:
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Gender" %} --</option>
<option value="male"{% if 'male' in sortfilter.gender %} selected{% endif %}>{% trans "Male" %}</option>
<option value="female"{% if 'female' in sortfilter.gender %} selected{% endif %}>{% trans "Female" %}</option>
<option value=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option>
</select>
<select class="default-input" name="category" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Category" %} --</option>
{% for category in categories %}
<option value="{{ category }}"{% if category in sortfilter.category %} selected{% endif %}>
{{ category }}</option>
{% endfor %}
</select>
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Type" %} --</option>
<option value="delegate"{% if 'delegate' in sortfilter.type %} selected{% endif %}>{% trans "Delegate" %}</option>
<option value="observer"{% if 'observer' in sortfilter.type %} selected{% endif %}>{% trans "Observer" %}</option>
<option value="staff"{% if 'staff' in sortfilter.type %} selected{% endif %}>{% trans "Staff" %}</option>
<option value="guest"{% if 'guest' in sortfilter.type %} selected{% endif %}>{% trans "Guest" %}</option>
<option value=""{% if '' in sortfilter.type %} selected{% endif %}>{% trans "Not specified" %}</option>
</select>
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Committee" %} --</option>
{% for committee in committees %}
<option value="{{ committee }}"{% if committee in sortfilter.committee %} selected{% endif %}>
{{ committee }}</option>
{% endfor %}
</select>
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Status" %} --</option>
<option value="1"{% if '1' in sortfilter.status %} selected{% endif %}>{% trans "Active" %}</option>
<option value="0"{% if '0' in sortfilter.status %} selected{% endif %}>{% trans "Inactive" %}</option>
</select>
</form>
</p>
{% 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 %}
<table>
<tr>
<th><a href="?sort=first_name&reverse={% if 'first_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "First Name" %}</a></th>
<th><a href="?sort=last_name&reverse={% if 'last_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Name" %}</a></th>
<th><a href="?sort=group&reverse={% if 'group' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Group" %}</a></th>
<th><a href="?sort=group&reverse={% if 'category' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Category" %}</a></th>
<th><a href="?sort=type&reverse={% if 'type' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Type" %}</a></th>
<th><a href="?sort=committee&reverse={% if 'committee' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Committee" %}</a></th>
{% if perms.participant.can_manage_participant %}
<th><a href="?sort=comment&reverse={% if 'comment' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Comment" %}</a></th>
<th><a href="?sort=last_login&reverse={% if 'last_login' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Login" %}</a></th>
<th>{% trans "Actions" %}</th>
<th><a href="?sort=comment&reverse={% if 'comment' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Comment" %}</a></th>
<th><a href="?sort=last_login&reverse={% if 'last_login' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Login" %}</a></th>
<th>{% trans "Actions" %}</th>
{% endif %}
</tr>
{% for user in users %}
<tr class="{% cycle '' 'odd' %}">
<td>{{ user.first_name }}</td>
<td>{{ user.last_name }}</td>
<td>{{ user.openslidesuser.name_surfix }}</td>
<td>{{ user.openslidesuser.get_type_display }}</td>
<td>{{ user.openslidesuser.committee }}</td>
{% if perms.participant.can_manage_participant %}
<td>{{ user.openslidesuser.comment|first_line }}</td>
<td>{% if user.last_login > user.date_joined %}
{{ user.last_login }}
{% endif %}</td>
<td><span style="width: 1px; white-space: nowrap;">
<a href="{% url user_edit user.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}"></a>
<a href="{% url user_delete user.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}"></a>
<a class="status_link {% if user.is_active %}active{% endif %}"
href="{% url user_status user.id %}"
title="{% trans 'Change status (active/inactive)' %}">
<span></span>
</a>
</span>
</td>
{% endif %}
</tr>
{% empty %}
<tr>
<td colspan="9"><i>{% trans "No participants available." %}</i></td>
</tr>
{% endfor %}
{% for user in users %}
<tr class="{% cycle '' 'odd' %}">
<td>{{ user.first_name }}</td>
<td>{{ user.last_name }}</td>
<td>{{ user.category }}</td>
<td>{{ user.get_type_display }}</td>
<td>{{ user.committee }}</td>
{% if perms.participant.can_manage_participant %}
<td>{{ user.comment|first_line }}</td>
<td>
{% if user.last_login > user.date_joined %}
{{ user.last_login }}
{% endif %}
</td>
<td>
<span style="width: 1px; white-space: nowrap;">
<a href="{% url user_edit user.id %}">
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
</a>
<a href="{% url user_delete user.id %}">
<img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}">
</a>
<a class="status_link deactivate" href="{% url user_status_deactivate user.id %}" title="{% trans 'Change status to inactive' %}"{% if not user.is_active %} style="display:none"{% endif %}>
<span></span>
</a>
<a class="status_link activate" href="{% url user_status_activate user.id %}" title="{% trans 'Change status to active' %}"{% if user.is_active %} style="display:none"{% endif %}>
<span></span>
</a>
</span>
</td>
{% endif %}
</tr>
{% empty %}
<tr>
<td colspan="9"><i>{% trans "No participants available." %}</i></td>
</tr>
{% endfor %}
</table>
{% endblock %}

View File

@ -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)

View File

@ -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<user_id>\d+)/edit/$',
'edit',
url(r'^(?P<pk>\d+)/edit/$',
UserUpdateView.as_view(),
name='user_edit',
),
url(r'^(?P<pk>\d+)/del/$',
UserDeleteView.as_view(),
name='user_delete',
),
url(r'^(?P<pk>\d+)/reset_password/$',
ResetPasswordView.as_view(),
name='user_reset_password',
),
url(r'^(?P<pk>\d+)/status/toggle/$',
SetUserStatusView.as_view(),
{'action': 'toggle'},
name='user_status_toggle',
),
url(r'^(?P<pk>\d+)/status/activate/$',
SetUserStatusView.as_view(),
{'action': 'activate'},
name='user_status_activate',
),
url(r'^(?P<pk>\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<pk>\d+)/edit/$',
GroupUpdateView.as_view(),
name='user_group_edit',
),
url(r'^group/(?P<pk>\d+)/del/$',
GroupDeleteView.as_view(),
name='user_group_delete',
),
url(r'^print/$',
ParticipantsListPDF.as_view(),
name='user_print',
),
url(r'^(?P<user_id>\d+)/del/$',
'user_delete',
name='user_delete',
),
url(r'^(?P<user_id>\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<group_id>\d+)/edit/$',
'group_edit',
name='user_group_edit',
),
url(r'^group/(?P<group_id>\d+)/del/$',
'group_delete',
name='user_group_delete',
),
url(r'^resetpassword/(?P<user_id>\d+)/$',
'reset_password',
name='user_reset_password',
),
url(r'^passwords/print/$',
ParticipantsPasswordsPDF.as_view(),
name='print_passwords',

File diff suppressed because it is too large Load Diff

View File

@ -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/$',

View File

@ -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

View File

@ -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]

View File

@ -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):

View File

@ -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'])

View File

@ -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([
'<input type="submit" name="%s" value="%s">' % (option[0], unicode(option[1]))
for option in self.get_answer_options()])
messages.warning(self.request,
"""
%(message)s
<form action="%(url)s" method="post">
<input type="hidden" value="%(csrf)s" name="csrfmiddlewaretoken">
%(option_fields)s
</form>
""" % {
'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
<form action="%s" method="post">
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
<input type="submit" value="%s">
<input type="button" value="%s">
</form>
""" % (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
def get_answer_url(self):
return self.object.get_absolute_url('delete')
class DetailView(TemplateView, SingleObjectMixin):