commit
3995765dc5
@ -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",
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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")),
|
||||
)
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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():
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
22
openslides/participant/middleware.py
Normal file
22
openslides/participant/middleware.py
Normal 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
|
@ -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)
|
||||
|
@ -9,15 +9,18 @@ $(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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
{% block title %}
|
||||
{{ block.super }} –
|
||||
{% if edituser %}
|
||||
{% if edit_user %}
|
||||
{% trans "Edit participant" %}
|
||||
{% else %}
|
||||
{% trans "New participant" %}
|
||||
@ -13,17 +13,18 @@
|
||||
|
||||
|
||||
{% 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">
|
||||
|
@ -13,58 +13,59 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans "Participants" %}</h1>
|
||||
|
||||
<p><form action="{{request.url}}" name="filter" method="post">
|
||||
{% csrf_token %}
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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 %}>
|
||||
<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>
|
||||
<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 %}
|
||||
@ -77,20 +78,28 @@
|
||||
<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>
|
||||
<td>{{ user.category }}</td>
|
||||
<td>{{ user.get_type_display }}</td>
|
||||
<td>{{ user.committee }}</td>
|
||||
{% if perms.participant.can_manage_participant %}
|
||||
<td>{{ user.openslidesuser.comment|first_line }}</td>
|
||||
<td>{% if user.last_login > user.date_joined %}
|
||||
<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 {% if user.is_active %}active{% endif %}"
|
||||
href="{% url user_status user.id %}"
|
||||
title="{% trans 'Change status (active/inactive)' %}">
|
||||
{% 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>
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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/$',
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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):
|
||||
|
@ -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'])
|
||||
|
@ -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,21 +252,32 @@ 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):
|
||||
if self.get_answer().lower() == 'yes':
|
||||
self.object.delete()
|
||||
messages.success(request, self.get_success_message())
|
||||
|
||||
@ -230,20 +285,8 @@ class DeleteView(RedirectView, SingleObjectMixin):
|
||||
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):
|
||||
|
Loading…
Reference in New Issue
Block a user