commit
3995765dc5
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"pk": 2,
|
"pk": 1,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Beobachter",
|
"name": "Beobachter",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_projector",
|
"can_see_projector",
|
||||||
@ -49,7 +49,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 3,
|
"pk": 2,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Delegierter",
|
"name": "Delegierter",
|
||||||
@ -92,7 +92,7 @@
|
|||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_projector",
|
"can_see_projector",
|
||||||
@ -103,7 +103,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 4,
|
"pk": 3,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Versammlungsleitung",
|
"name": "Versammlungsleitung",
|
||||||
@ -161,12 +161,12 @@
|
|||||||
[
|
[
|
||||||
"can_manage_participant",
|
"can_manage_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_manage_projector",
|
"can_manage_projector",
|
||||||
@ -182,7 +182,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 5,
|
"pk": 4,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Teilnehmerverwaltung",
|
"name": "Teilnehmerverwaltung",
|
||||||
@ -195,12 +195,12 @@
|
|||||||
[
|
[
|
||||||
"can_manage_participant",
|
"can_manage_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_projector",
|
"can_see_projector",
|
||||||
|
@ -167,69 +167,24 @@ class ItemDelete(DeleteView):
|
|||||||
model = Item
|
model = Item
|
||||||
url = 'item_overview'
|
url = 'item_overview'
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def get_answer_options(self):
|
||||||
self.object = self.get_object()
|
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)
|
self.object.delete(with_children=True)
|
||||||
messages.success(request,
|
messages.success(request,
|
||||||
_("Item %s and his children were successfully deleted.") \
|
_("Item %s and his children were successfully deleted.") \
|
||||||
% html_strong(self.object))
|
% html_strong(self.object))
|
||||||
else:
|
elif self.get_answer() == 'yes':
|
||||||
self.object.delete(with_children=False)
|
self.object.delete(with_children=False)
|
||||||
messages.success(request,
|
messages.success(request,
|
||||||
_("Item %s was successfully deleted.") \
|
_("Item %s was successfully deleted.") \
|
||||||
% html_strong(self.object))
|
% 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):
|
class AgendaPDF(PDFView):
|
||||||
"""
|
"""
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Max
|
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.models import config
|
||||||
from openslides.config.signals import default_config_value
|
from openslides.config.signals import default_config_value
|
||||||
|
|
||||||
from openslides.participant.models import OpenSlidesUser
|
|
||||||
|
|
||||||
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
||||||
CountInvalid, BaseVote)
|
CountInvalid, BaseVote)
|
||||||
|
|
||||||
@ -360,15 +357,6 @@ class Application(models.Model, SlideMixin):
|
|||||||
Return a list of all the allowed status.
|
Return a list of all the allowed status.
|
||||||
"""
|
"""
|
||||||
actions = []
|
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
|
# check if user allowed to withdraw an application
|
||||||
if ((self.status == "pub"
|
if ((self.status == "pub"
|
||||||
@ -405,11 +393,10 @@ class Application(models.Model, SlideMixin):
|
|||||||
|
|
||||||
# Check if the user can delete the application (admin, manager, owner)
|
# Check if the user can delete the application (admin, manager, owner)
|
||||||
# reworked as requiered in #100
|
# reworked as requiered in #100
|
||||||
if is_admin \
|
if (user.has_perm("applicatoin.can_delete_all_applications") or
|
||||||
or (user.has_perm("application.can_manage_application") \
|
(user.has_perm("application.can_manage_application") and
|
||||||
and (self.status == "pub" or self.number is None)) \
|
self.number is None) or
|
||||||
or (self.submitter == user \
|
(self.submitter == user and self.number is None)):
|
||||||
and (self.status == "pub" or self.number is None)):
|
|
||||||
actions.append("delete")
|
actions.append("delete")
|
||||||
|
|
||||||
#For the rest, all actions need the manage permission
|
#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_create_application', ugettext_noop("Can create application")),
|
||||||
('can_support_application', ugettext_noop("Can support application")),
|
('can_support_application', ugettext_noop("Can support application")),
|
||||||
('can_manage_application', ugettext_noop("Can manage 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 import TestCase
|
||||||
from django.test.client import Client
|
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
|
from openslides.application.models import Application, AVersion
|
||||||
|
|
||||||
class ApplicationTest(TestCase):
|
class ApplicationTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.admin = User.objects.create_user('testadmin', '', 'default')
|
self.admin = User(username='testadmin')
|
||||||
self.anonym = User.objects.create_user('testanoym', '', 'default')
|
self.admin.save()
|
||||||
self.app1 = Application(submitter=self.admin.openslidesuser)
|
self.anonym = User(username='testanoym')
|
||||||
|
self.anonym.save()
|
||||||
|
self.app1 = Application(submitter=self.admin)
|
||||||
self.app1.save()
|
self.app1.save()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
|
@ -51,7 +51,7 @@ from openslides.projector.projector import Widget
|
|||||||
from openslides.poll.views import PollFormView
|
from openslides.poll.views import PollFormView
|
||||||
|
|
||||||
from openslides.participant.api import gen_username, gen_password
|
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
|
from openslides.agenda.models import Item
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ def overview(request):
|
|||||||
for (i, application) in enumerate(applications):
|
for (i, application) in enumerate(applications):
|
||||||
try:
|
try:
|
||||||
applications[i] = {
|
applications[i] = {
|
||||||
'actions' : application.get_allowed_actions(request.user.openslidesuser),
|
'actions' : application.get_allowed_actions(request.user),
|
||||||
'application' : application
|
'application' : application
|
||||||
}
|
}
|
||||||
except:
|
except:
|
||||||
@ -152,8 +152,7 @@ def view(request, application_id, newest=False):
|
|||||||
else:
|
else:
|
||||||
version = application.public_version
|
version = application.public_version
|
||||||
revisions = application.versions
|
revisions = application.versions
|
||||||
user = request.user.openslidesuser
|
actions = application.get_allowed_actions(user=request.user)
|
||||||
actions = application.get_allowed_actions(user=user)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'application': application,
|
'application': application,
|
||||||
@ -183,11 +182,11 @@ def edit(request, application_id=None):
|
|||||||
if application_id is not None:
|
if application_id is not None:
|
||||||
application = Application.objects.get(id=application_id)
|
application = Application.objects.get(id=application_id)
|
||||||
if (not hasattr(application.submitter, 'user') or
|
if (not hasattr(application.submitter, 'user') or
|
||||||
not request.user.openslidesuser == application.submitter.user) \
|
not request.user == application.submitter.user) \
|
||||||
and not is_manager:
|
and not is_manager:
|
||||||
messages.error(request, _("You can not edit this application. You are not the submitter."))
|
messages.error(request, _("You can not edit this application. You are not the submitter."))
|
||||||
return redirect(reverse('application_view', args=[application.id]))
|
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:
|
else:
|
||||||
application = None
|
application = None
|
||||||
actions = None
|
actions = None
|
||||||
@ -221,7 +220,7 @@ def edit(request, application_id=None):
|
|||||||
original_supporters = []
|
original_supporters = []
|
||||||
application = managerform.save(commit=False)
|
application = managerform.save(commit=False)
|
||||||
elif application_id is None:
|
elif application_id is None:
|
||||||
application = Application(submitter=request.user.openslidesuser)
|
application = Application(submitter=request.user)
|
||||||
application.title = dataform.cleaned_data['title']
|
application.title = dataform.cleaned_data['title']
|
||||||
application.text = dataform.cleaned_data['text']
|
application.text = dataform.cleaned_data['text']
|
||||||
application.reason = dataform.cleaned_data['reason']
|
application.reason = dataform.cleaned_data['reason']
|
||||||
@ -231,7 +230,7 @@ def edit(request, application_id=None):
|
|||||||
and dataform.cleaned_data['trivial_change']
|
and dataform.cleaned_data['trivial_change']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
trivial_change = False
|
trivial_change = False
|
||||||
application.save(request.user.openslidesuser, trivial_change=trivial_change)
|
application.save(request.user, trivial_change=trivial_change)
|
||||||
if is_manager:
|
if is_manager:
|
||||||
try:
|
try:
|
||||||
new_supporters = set(managerform.cleaned_data['supporter'])
|
new_supporters = set(managerform.cleaned_data['supporter'])
|
||||||
@ -273,7 +272,7 @@ def edit(request, application_id=None):
|
|||||||
dataform = formclass(initial=initial, prefix="data")
|
dataform = formclass(initial=initial, prefix="data")
|
||||||
if is_manager:
|
if is_manager:
|
||||||
if application_id is None:
|
if application_id is None:
|
||||||
initial = {'submitter': request.user.openslidesuser.person_id}
|
initial = {'submitter': request.user.person_id}
|
||||||
else:
|
else:
|
||||||
initial = {'submitter': application.submitter.person_id,
|
initial = {'submitter': application.submitter.person_id,
|
||||||
'supporter': [supporter.person_id for supporter in application.supporters]}
|
'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.
|
set a number for an application.
|
||||||
"""
|
"""
|
||||||
try:
|
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."))
|
messages.success(request, _("Application number was successfully set."))
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
@ -312,7 +311,7 @@ def permit(request, application_id):
|
|||||||
permit an application.
|
permit an application.
|
||||||
"""
|
"""
|
||||||
try:
|
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."))
|
messages.success(request, _("Application was successfully permitted."))
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
@ -327,7 +326,7 @@ def notpermit(request, application_id):
|
|||||||
reject (not permit) an application.
|
reject (not permit) an application.
|
||||||
"""
|
"""
|
||||||
try:
|
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."))
|
messages.success(request, _("Application was successfully rejected."))
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
@ -343,7 +342,7 @@ def set_status(request, application_id=None, status=None):
|
|||||||
try:
|
try:
|
||||||
if status is not None:
|
if status is not None:
|
||||||
application = Application.objects.get(pk=application_id)
|
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())
|
messages.success(request, _("Application status was set to: <b>%s</b>.") % application.get_status_display())
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
@ -387,7 +386,7 @@ def unsupport(request, application_id):
|
|||||||
unsupport an application.
|
unsupport an application.
|
||||||
"""
|
"""
|
||||||
try:
|
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.") )
|
messages.success(request, _("You have unsupport the application successfully.") )
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
@ -401,7 +400,7 @@ def gen_poll(request, application_id):
|
|||||||
gen a poll for this application.
|
gen a poll for this application.
|
||||||
"""
|
"""
|
||||||
try:
|
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.") )
|
messages.success(request, _("New vote was successfully created.") )
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass # TODO: do not call poll after this excaption
|
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()
|
count = application.polls.filter(id__lte=poll_id).count()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
poll.delete()
|
poll.delete()
|
||||||
application.writelog(_("Poll deleted"), request.user.openslidesuser)
|
application.writelog(_("Poll deleted"), request.user)
|
||||||
messages.success(request, _('Poll was successfully deleted.'))
|
messages.success(request, _('Poll was successfully deleted.'))
|
||||||
else:
|
else:
|
||||||
del_confirm_form(request, poll, name=_("the %s. poll") % count, delete_link=reverse('application_poll_delete', args=[poll_id]))
|
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):
|
if len(self.applications):
|
||||||
for application in 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)
|
messages.error(request, _("You can not delete application <b>%s</b>.") % application)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -467,7 +466,7 @@ class ApplicationDelete(DeleteView):
|
|||||||
messages.success(request, _("Application <b>%s</b> was successfully deleted.") % title)
|
messages.success(request, _("Application <b>%s</b> was successfully deleted.") % title)
|
||||||
|
|
||||||
elif self.object:
|
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)
|
messages.error(request, _("You can not delete application <b>%s</b>.") % self.object)
|
||||||
else:
|
else:
|
||||||
title = self.object.title
|
title = self.object.title
|
||||||
@ -508,12 +507,12 @@ class ViewPoll(PollFormView):
|
|||||||
self.application = self.poll.get_application()
|
self.application = self.poll.get_application()
|
||||||
context['application'] = self.application
|
context['application'] = self.application
|
||||||
context['ballot'] = self.poll.get_ballot()
|
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
|
return context
|
||||||
|
|
||||||
def get_modelform_class(self):
|
def get_modelform_class(self):
|
||||||
cls = super(ViewPoll, self).get_modelform_class()
|
cls = super(ViewPoll, self).get_modelform_class()
|
||||||
user = self.request.user.openslidesuser
|
user = self.request.user
|
||||||
|
|
||||||
class ViewPollFormClass(cls):
|
class ViewPollFormClass(cls):
|
||||||
def save(self, commit = True):
|
def save(self, commit = True):
|
||||||
@ -535,7 +534,7 @@ def permit_version(request, aversion_id):
|
|||||||
aversion = AVersion.objects.get(pk=aversion_id)
|
aversion = AVersion.objects.get(pk=aversion_id)
|
||||||
application = aversion.application
|
application = aversion.application
|
||||||
if request.method == 'POST':
|
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))
|
messages.success(request, _("Version <b>%s</b> accepted.") % (aversion.aid))
|
||||||
else:
|
else:
|
||||||
gen_confirm_form(request, _('Do you really want to permit version <b>%s</b>?') % aversion.aid, reverse('application_version_permit', args=[aversion.id]))
|
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)
|
aversion = AVersion.objects.get(pk=aversion_id)
|
||||||
application = aversion.application
|
application = aversion.application
|
||||||
if request.method == 'POST':
|
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))
|
messages.success(request, _("Version <b>%s</b> rejected.") % (aversion.aid))
|
||||||
else:
|
else:
|
||||||
messages.error(request, _("ERROR by rejecting the version.") )
|
messages.error(request, _("ERROR by rejecting the version.") )
|
||||||
@ -559,17 +558,6 @@ def reject_version(request, aversion_id):
|
|||||||
@permission_required('application.can_manage_application')
|
@permission_required('application.can_manage_application')
|
||||||
@template('application/import.html')
|
@template('application/import.html')
|
||||||
def application_import(request):
|
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':
|
if request.method == 'POST':
|
||||||
form = ApplicationImportForm(request.POST, request.FILES)
|
form = ApplicationImportForm(request.POST, request.FILES)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
@ -34,7 +34,7 @@ from openslides.utils.person import get_person
|
|||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
|
||||||
from openslides.participant.models import OpenSlidesUser
|
from openslides.participant.models import User
|
||||||
|
|
||||||
from openslides.projector.projector import Widget
|
from openslides.projector.projector import Widget
|
||||||
|
|
||||||
@ -97,13 +97,12 @@ def view(request, assignment_id=None):
|
|||||||
polls = assignment.poll_set.all()
|
polls = assignment.poll_set.all()
|
||||||
vote_results = assignment.vote_results(only_published=False)
|
vote_results = assignment.vote_results(only_published=False)
|
||||||
|
|
||||||
user = request.user.openslidesuser
|
|
||||||
return {
|
return {
|
||||||
'assignment': assignment,
|
'assignment': assignment,
|
||||||
'form': form,
|
'form': form,
|
||||||
'vote_results': vote_results,
|
'vote_results': vote_results,
|
||||||
'polls': polls,
|
'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):
|
def run(request, assignment_id):
|
||||||
assignment = Assignment.objects.get(pk=assignment_id)
|
assignment = Assignment.objects.get(pk=assignment_id)
|
||||||
try:
|
try:
|
||||||
assignment.run(request.user.openslidesuser, request.user)
|
assignment.run(request.user, request.user)
|
||||||
messages.success(request, _('You have set your candidature successfully.') )
|
messages.success(request, _('You have set your candidature successfully.') )
|
||||||
except NameError, e:
|
except NameError, e:
|
||||||
messages.error(request, e)
|
messages.error(request, e)
|
||||||
@ -185,7 +184,7 @@ def delrun(request, assignment_id):
|
|||||||
assignment = Assignment.objects.get(pk=assignment_id)
|
assignment = Assignment.objects.get(pk=assignment_id)
|
||||||
try:
|
try:
|
||||||
if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"):
|
if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"):
|
||||||
assignment.delrun(request.user.openslidesuser)
|
assignment.delrun(request.user)
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('The candidate list is already closed.'))
|
messages.error(request, _('The candidate list is already closed.'))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
@ -101,7 +101,7 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'openslides.participant.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
)
|
)
|
||||||
|
@ -10,13 +10,19 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# for python 2.5 support
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
from random import choice
|
from random import choice
|
||||||
import string
|
import string
|
||||||
|
import csv
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from openslides.utils.person import get_person
|
from openslides.utils import csv_ext
|
||||||
from openslides.participant.models import OpenSlidesUser
|
|
||||||
|
from openslides.participant.models import User
|
||||||
|
|
||||||
|
|
||||||
def gen_password():
|
def gen_password():
|
||||||
@ -47,3 +53,44 @@ def gen_username(first_name, last_name):
|
|||||||
User.objects.get(username=testname)
|
User.objects.get(username=testname)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return testname
|
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 import forms
|
||||||
from django.contrib.auth.forms import AdminPasswordChangeForm
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
|
||||||
|
|
||||||
from openslides.utils.forms import (
|
from openslides.utils.forms import (
|
||||||
CssClassMixin, LocalizedModelMultipleChoiceField)
|
CssClassMixin, LocalizedModelMultipleChoiceField)
|
||||||
|
|
||||||
from openslides.participant.models import OpenSlidesUser
|
from openslides.participant.models import User, Group
|
||||||
|
|
||||||
|
|
||||||
USER_APPLICATION_IMPORT_OPTIONS = [
|
class UserCreateForm(forms.ModelForm, CssClassMixin):
|
||||||
('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"))
|
|
||||||
groups = forms.ModelMultipleChoiceField(
|
groups = forms.ModelMultipleChoiceField(
|
||||||
queryset=Group.objects.all(), label=_("User groups"), required=False)
|
queryset=Group.objects.exclude(name__iexact='anonymous'),
|
||||||
is_active = forms.BooleanField(
|
label=_("User groups"), required=False)
|
||||||
label=_("Active"), required=False, initial=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
exclude = ('username', 'password', 'is_staff', 'is_superuser',
|
fields = ('first_name', 'last_name', 'is_active', 'groups', 'category',
|
||||||
'last_login', 'date_joined', 'user_permissions')
|
'gender', 'type', 'committee', 'comment', 'default_password')
|
||||||
|
|
||||||
|
|
||||||
class UserEditForm(forms.ModelForm, CssClassMixin):
|
class UserUpdateForm(UserCreateForm):
|
||||||
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 Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
exclude = ('password', 'is_staff', 'is_superuser', 'last_login',
|
fields = ('username', 'first_name', 'last_name', 'is_active', 'groups',
|
||||||
'date_joined', 'user_permissions')
|
'category', 'gender', 'type', 'committee', 'comment',
|
||||||
|
'default_password')
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class GroupForm(forms.ModelForm, CssClassMixin):
|
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(
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(GroupForm, self).__init__(*args, **kwargs)
|
# Initial users
|
||||||
if kwargs.get('instance', None) is not None:
|
if kwargs.get('instance', None) is not None:
|
||||||
self.fields['permissions'].initial = (
|
initial = kwargs.setdefault('initial', {})
|
||||||
[p.pk for p in kwargs['instance'].permissions.all()])
|
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:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
exclude = ('permissions',)
|
|
||||||
|
|
||||||
|
|
||||||
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
||||||
@ -95,9 +100,6 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
|||||||
class UserImportForm(forms.Form, CssClassMixin):
|
class UserImportForm(forms.Form, CssClassMixin):
|
||||||
csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}),
|
csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}),
|
||||||
label=_("CSV File"))
|
label=_("CSV File"))
|
||||||
application_handling = forms.ChoiceField(
|
|
||||||
required=True, choices=USER_APPLICATION_IMPORT_OPTIONS,
|
|
||||||
label=_("For existing applications"))
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigForm(forms.Form, CssClassMixin):
|
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.
|
: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 import models
|
||||||
from django.db.models import Q, signals
|
from django.db.models import signals
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
||||||
|
|
||||||
from openslides.utils.person import PersonMixin
|
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
|
from openslides.config.signals import default_config_value
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesUser(models.Model, PersonMixin):
|
class User(DjangoUser, PersonMixin):
|
||||||
person_prefix = 'openslides_user'
|
person_prefix = 'user'
|
||||||
GENDER_CHOICES = (
|
GENDER_CHOICES = (
|
||||||
('male', _('Male')),
|
('male', _('Male')),
|
||||||
('female', _('Female')),
|
('female', _('Female')),
|
||||||
@ -35,10 +35,10 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
('guest', _('Guest')),
|
('guest', _('Guest')),
|
||||||
)
|
)
|
||||||
|
|
||||||
user = models.OneToOneField(User, unique=True, editable=False)
|
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
|
||||||
name_surfix = models.CharField(
|
category = models.CharField(
|
||||||
max_length=100, null=True, blank=True, verbose_name=_("Name Surfix"),
|
max_length=100, null=True, blank=True, verbose_name=_("Category"),
|
||||||
help_text=_('Shown behind the name.'))
|
help_text=_('Will be shown behind the name.'))
|
||||||
gender = models.CharField(
|
gender = models.CharField(
|
||||||
max_length=50, choices=GENDER_CHOICES, blank=True,
|
max_length=50, choices=GENDER_CHOICES, blank=True,
|
||||||
verbose_name=_("Gender"), help_text=_('Only for filter the userlist.'))
|
verbose_name=_("Gender"), help_text=_('Only for filter the userlist.'))
|
||||||
@ -51,21 +51,26 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
comment = models.TextField(
|
comment = models.TextField(
|
||||||
null=True, blank=True, verbose_name=_('Comment'),
|
null=True, blank=True, verbose_name=_('Comment'),
|
||||||
help_text=_('Only for notes.'))
|
help_text=_('Only for notes.'))
|
||||||
firstpassword = models.CharField(
|
default_password = models.CharField(
|
||||||
max_length=100, null=True, blank=True,
|
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):
|
def reset_password(self, password=None):
|
||||||
"""
|
"""
|
||||||
Reset the password for the user to his default-password.
|
Reset the password for the user to his default-password.
|
||||||
"""
|
"""
|
||||||
if password is None:
|
if password is None:
|
||||||
password = self.firstpassword
|
password = self.default_password
|
||||||
self.user.set_password(password)
|
self.set_password(password)
|
||||||
self.user.save()
|
self.save()
|
||||||
|
|
||||||
def has_perm(self, perm):
|
|
||||||
return self.user.has_perm(perm)
|
|
||||||
|
|
||||||
@models.permalink
|
@models.permalink
|
||||||
def get_absolute_url(self, link='edit'):
|
def get_absolute_url(self, link='edit'):
|
||||||
@ -77,14 +82,15 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
* delete
|
* delete
|
||||||
"""
|
"""
|
||||||
if link == 'edit':
|
if link == 'edit':
|
||||||
return ('user_edit', [str(self.user.id)])
|
return ('user_edit', [str(self.id)])
|
||||||
if link == 'delete':
|
if link == 'delete':
|
||||||
return ('user_delete', [str(self.user.id)])
|
return ('user_delete', [str(self.id)])
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if self.name_surfix:
|
name = self.get_full_name() or self.username
|
||||||
return "%s (%s)" % (self.user.get_full_name(), self.name_surfix)
|
if self.name_suffix:
|
||||||
return "%s" % self.user.get_full_name()
|
return u"%s (%s)" % (name, self.name_suffix)
|
||||||
|
return u"%s" % name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
# Rename permissions
|
# Rename permissions
|
||||||
@ -95,46 +101,63 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesGroup(models.Model, PersonMixin):
|
class Group(DjangoGroup, PersonMixin):
|
||||||
person_prefix = 'openslides_group'
|
person_prefix = 'group'
|
||||||
|
|
||||||
group = models.OneToOneField(Group)
|
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)
|
||||||
group_as_person = models.BooleanField(default=False)
|
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):
|
def __unicode__(self):
|
||||||
return unicode(self.group)
|
return unicode(self.name)
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesUsersConnecter(object):
|
class UsersConnector(object):
|
||||||
def __init__(self, person_prefix=None, id=None):
|
def __init__(self, person_prefix_filter=None, id_filter=None):
|
||||||
self.person_prefix = person_prefix
|
self.person_prefix_filter = person_prefix_filter
|
||||||
self.id = id
|
self.id_filter = id_filter
|
||||||
|
self.users = User.objects.all()
|
||||||
|
self.groups = Group.objects.filter(group_as_person=True)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
if (not self.person_prefix or
|
if (not self.person_prefix_filter or
|
||||||
self.person_prefix == OpenSlidesUser.person_prefix):
|
self.person_prefix_filter == User.person_prefix):
|
||||||
if self.id:
|
if self.id_filter:
|
||||||
yield OpenSlidesUser.objects.get(pk=self.id)
|
yield users.get(pk=self.id_filter)
|
||||||
else:
|
else:
|
||||||
for user in OpenSlidesUser.objects.all():
|
for user in self.users:
|
||||||
yield user
|
yield user
|
||||||
|
|
||||||
if (not self.person_prefix or
|
if (not self.person_prefix_filter or
|
||||||
self.person_prefix == OpenSlidesGroup.person_prefix):
|
self.person_prefix_filter == Group.person_prefix):
|
||||||
if self.id:
|
if self.id_filter:
|
||||||
yield OpenSlidesGroup.objects.get(pk=self.id)
|
yield groups.get(pk=self.id_filter)
|
||||||
else:
|
else:
|
||||||
for group in OpenSlidesGroup.objects.all():
|
for group in self.groups:
|
||||||
yield group
|
yield group
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return OpenSlidesUser.objects.get(pk=key)
|
return User.objects.get(pk=key)
|
||||||
|
|
||||||
|
|
||||||
@receiver(receiv_persons, dispatch_uid="participant")
|
@receiver(receive_persons, dispatch_uid="participant")
|
||||||
def receiv_persons(sender, **kwargs):
|
def receive_persons(sender, **kwargs):
|
||||||
return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'],
|
return UsersConnecter(person_prefix_filter=kwargs['person_prefix_filter'],
|
||||||
id=kwargs['id'])
|
id=kwargs['id_filter'])
|
||||||
|
|
||||||
|
|
||||||
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
||||||
@ -150,7 +173,17 @@ def default_config(sender, key, **kwargs):
|
|||||||
}.get(key)
|
}.get(key)
|
||||||
|
|
||||||
|
|
||||||
@receiver(signals.post_save, sender=User)
|
@receiver(signals.post_save, sender=DjangoUser)
|
||||||
def user_post_save(sender, instance, signal, *args, **kwargs):
|
def user_post_save(sender, instance, signal, *args, **kwargs):
|
||||||
# Creates OpenSlidesUser
|
try:
|
||||||
profile, new = OpenSlidesUser.objects.get_or_create(user=instance)
|
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) {
|
$('.status_link').click(function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
link = $(this);
|
link = $(this);
|
||||||
|
group = $(this).parent();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: link.attr('href'),
|
url: link.attr('href'),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
if (data.active) {
|
if (data.active) {
|
||||||
link.addClass('active');
|
group.children('.status_link.deactivate').show();
|
||||||
|
group.children('.status_link.activate').hide();
|
||||||
} else {
|
} 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.
|
* :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
||||||
* :license: GNU GPL, see LICENSE for more details.
|
* :license: GNU GPL, see LICENSE for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
a.status_link span {
|
a.status_link span {
|
||||||
background-image: url(../images/icons/off.png);
|
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
a.status_link.active span {
|
|
||||||
|
a.status_link.deactivate span {
|
||||||
background-image: url(../images/icons/on.png);
|
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 title %}
|
||||||
{{ block.super }} –
|
{{ block.super }} –
|
||||||
{% if edituser %}
|
{% if edit_user %}
|
||||||
{% trans "Edit participant" %}
|
{% trans "Edit participant" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% trans "New participant" %}
|
{% trans "New participant" %}
|
||||||
@ -13,30 +13,31 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if edituser %}
|
{% if edit_user %}
|
||||||
<h1>{% trans "Edit participant" %}</h1>
|
<h1>{% trans "Edit participant" %}</h1>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h1>{% trans "New participant" %}</h1>
|
<h1>{% trans "New participant" %}</h1>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form action="" method="post">{% csrf_token %}
|
<form action="" method="post">{% csrf_token %}
|
||||||
{{ userform.as_p }}
|
{{ form.as_p }}
|
||||||
{{ profileform.as_p }}
|
{% if edit_user %}
|
||||||
{% if edituser %}
|
<p>
|
||||||
<p><a href="{% url user_reset_password edituser.id %}">{% trans 'Reset to First Password' %}</a></p>
|
<a href="{% url user_reset_password edit_user.id %}">{% trans 'Reset to First Password' %}</a>
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<button class="button" type="submit">
|
<button class="button" type="submit">
|
||||||
<span class="icon ok">{% trans 'Save' %}</span>
|
<span class="icon ok">{% trans 'Save' %}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="button" type="submit" name="apply">
|
<button class="button" type="submit" name="apply">
|
||||||
<span class="icon apply">{% trans 'Apply' %}</span>
|
<span class="icon apply">{% trans 'Apply' %}</span>
|
||||||
</button>
|
</button>
|
||||||
<a href='{% url user_overview %}'>
|
<a href='{% url user_overview %}'>
|
||||||
<button class="button" type="button" onclick="window.location='{% url user_overview %}'">
|
<button class="button" type="button" onclick="window.location='{% url user_overview %}'">
|
||||||
<span class="icon cancel">{% trans 'Cancel' %}</span>
|
<span class="icon cancel">{% trans 'Cancel' %}</span>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<small>* {% trans "required" %}</small>
|
<small>* {% trans "required" %}</small>
|
||||||
</form>
|
</form>
|
||||||
|
@ -8,99 +8,108 @@
|
|||||||
|
|
||||||
{% block header %}
|
{% block header %}
|
||||||
{% if perms.agenda.can_manage_agenda %}
|
{% if perms.agenda.can_manage_agenda %}
|
||||||
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/participant.css' %}" />
|
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/participant.css' %}" />
|
||||||
<script type="text/javascript" src="{% static 'javascript/participant.js' %}"></script>
|
<script type="text/javascript" src="{% static 'javascript/participant.js' %}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Participants" %}</h1>
|
<h1>{% trans "Participants" %}</h1>
|
||||||
|
|
||||||
<p><form action="{{request.url}}" name="filter" method="post">
|
<p>
|
||||||
{% csrf_token %}
|
<form action="" name="filter" method="get">
|
||||||
{% trans "Filter" %}:
|
{% trans "Filter" %}:
|
||||||
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Gender" %} --</option>
|
<option value="---">-- {% trans "Gender" %} --</option>
|
||||||
<option value="male" {% if 'male' in sortfilter.gender %}selected{% endif %}>{% trans "Male" %}</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="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=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option>
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="group" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="category" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Group" %} --</option>
|
<option value="---">-- {% trans "Category" %} --</option>
|
||||||
{% for group in groups %}
|
{% for category in categories %}
|
||||||
<option value="{{ group }}" {% if group in sortfilter.group %}selected{% endif %}>
|
<option value="{{ category }}"{% if category in sortfilter.category %} selected{% endif %}>
|
||||||
{{ group }}</option>
|
{{ category }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Type" %} --</option>
|
<option value="---">-- {% trans "Type" %} --</option>
|
||||||
<option value="delegate" {% if 'delegate' in sortfilter.type %}selected{% endif %}>{% trans "Delegate" %}</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="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="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="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=""{% if '' in sortfilter.type %} selected{% endif %}>{% trans "Not specified" %}</option>
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Committee" %} --</option>
|
<option value="---">-- {% trans "Committee" %} --</option>
|
||||||
{% for committee in committees %}
|
{% 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>
|
{{ committee }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Status" %} --</option>
|
<option value="---">-- {% trans "Status" %} --</option>
|
||||||
<option value="1" {% if '1' in sortfilter.status %}selected{% endif %}>{% trans "Active" %}</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="0"{% if '0' in sortfilter.status %} selected{% endif %}>{% trans "Inactive" %}</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
{% if users|length == allusers|length %}
|
{% if users.count == allusers %}
|
||||||
{{ users|length }}
|
{{ users.count }}
|
||||||
{% blocktrans count counter=users|length %}participant{% plural %}participants{% endblocktrans %}
|
{% blocktrans count counter=users.count %}participant{% plural %}participants{% endblocktrans %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ users|length }} {% trans "of" %} {{ allusers|length }} {% trans "Participants" %} (= {{ percent }} %)
|
{{ users.count }} {% trans "of" %} {{ allusers }} {% trans "Participants" %} (= {{ percent }} %)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<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=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=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=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>
|
<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 %}
|
{% 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=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><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>{% trans "Actions" %}</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
<tr class="{% cycle '' 'odd' %}">
|
<tr class="{% cycle '' 'odd' %}">
|
||||||
<td>{{ user.first_name }}</td>
|
<td>{{ user.first_name }}</td>
|
||||||
<td>{{ user.last_name }}</td>
|
<td>{{ user.last_name }}</td>
|
||||||
<td>{{ user.openslidesuser.name_surfix }}</td>
|
<td>{{ user.category }}</td>
|
||||||
<td>{{ user.openslidesuser.get_type_display }}</td>
|
<td>{{ user.get_type_display }}</td>
|
||||||
<td>{{ user.openslidesuser.committee }}</td>
|
<td>{{ user.committee }}</td>
|
||||||
{% if perms.participant.can_manage_participant %}
|
{% if perms.participant.can_manage_participant %}
|
||||||
<td>{{ user.openslidesuser.comment|first_line }}</td>
|
<td>{{ user.comment|first_line }}</td>
|
||||||
<td>{% if user.last_login > user.date_joined %}
|
<td>
|
||||||
{{ user.last_login }}
|
{% if user.last_login > user.date_joined %}
|
||||||
{% endif %}</td>
|
{{ user.last_login }}
|
||||||
<td><span style="width: 1px; white-space: nowrap;">
|
{% endif %}
|
||||||
<a href="{% url user_edit user.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}"></a>
|
</td>
|
||||||
<a href="{% url user_delete user.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}"></a>
|
<td>
|
||||||
<a class="status_link {% if user.is_active %}active{% endif %}"
|
<span style="width: 1px; white-space: nowrap;">
|
||||||
href="{% url user_status user.id %}"
|
<a href="{% url user_edit user.id %}">
|
||||||
title="{% trans 'Change status (active/inactive)' %}">
|
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
|
||||||
<span></span>
|
</a>
|
||||||
</a>
|
<a href="{% url user_delete user.id %}">
|
||||||
</span>
|
<img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}">
|
||||||
</td>
|
</a>
|
||||||
{% endif %}
|
<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 %}>
|
||||||
</tr>
|
<span></span>
|
||||||
{% empty %}
|
</a>
|
||||||
<tr>
|
<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 %}>
|
||||||
<td colspan="9"><i>{% trans "No participants available." %}</i></td>
|
<span></span>
|
||||||
</tr>
|
</a>
|
||||||
{% endfor %}
|
</span>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="9"><i>{% trans "No participants available." %}</i></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,61 +12,65 @@
|
|||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
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 django.contrib.auth.hashers import check_password
|
||||||
|
|
||||||
from openslides.utils.person import get_person, Persons
|
from openslides.utils.person import get_person, Persons
|
||||||
from openslides.participant.api import gen_username, gen_password
|
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):
|
def setUp(self):
|
||||||
self.user1 = User(first_name=u'Max', last_name=u'Mustermann')
|
self.user1 = User()
|
||||||
self.user1.username = gen_username(self.user1.first_name, self.user1.last_name)
|
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.user1.save()
|
||||||
self.openslidesuser1 = self.user1.openslidesuser
|
self.django_user1 = self.user1.django_user
|
||||||
self.openslidesuser1.firstpassword = gen_password()
|
|
||||||
self.openslidesuser1.save()
|
|
||||||
self.user1 = self.openslidesuser1.user
|
|
||||||
|
|
||||||
def test_participant_user(self):
|
def test_participant_user(self):
|
||||||
self.assertEqual(self.user1.openslidesuser, self.openslidesuser1)
|
self.assertEqual(self.django_user1.user, self.user1)
|
||||||
self.assertEqual(self.user1, self.openslidesuser1.user)
|
self.assertEqual(self.django_user1, self.user1.django_user)
|
||||||
|
|
||||||
def test_repr(self):
|
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):
|
def test_name_surfix(self):
|
||||||
self.openslidesuser1.name_surfix = u'München'
|
self.user1.category = u'München'
|
||||||
self.openslidesuser1.save()
|
self.user1.save()
|
||||||
self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann (München)')
|
self.assertEqual(unicode(self.user1), u'Max Mustermann (München)')
|
||||||
|
|
||||||
def test_reset_password(self):
|
def test_reset_password(self):
|
||||||
self.assertIsInstance(self.openslidesuser1.firstpassword, basestring)
|
self.assertIsInstance(self.user1.firstpassword, basestring)
|
||||||
self.assertEqual(len(self.openslidesuser1.firstpassword), 8)
|
self.assertEqual(len(self.user1.firstpassword), 8)
|
||||||
self.user1.set_unusable_password()
|
self.user1.set_unusable_password()
|
||||||
self.assertFalse(self.user1.check_password(self.openslidesuser1.firstpassword))
|
self.assertFalse(self.user1.check_password(self.user1.firstpassword))
|
||||||
self.openslidesuser1.reset_password()
|
self.user1.reset_password()
|
||||||
self.assertTrue(self.user1.check_password(self.openslidesuser1.firstpassword))
|
self.assertTrue(self.user1.check_password(self.user1.firstpassword))
|
||||||
|
|
||||||
def test_person_api(self):
|
def test_person_api(self):
|
||||||
self.assertTrue(hasattr(self.openslidesuser1, 'person_id'))
|
self.assertTrue(hasattr(self.user1, 'person_id'))
|
||||||
self.assertEqual(self.openslidesuser1.person_id, 'openslides_user:1')
|
self.assertEqual(self.user1.person_id, 'user:1')
|
||||||
self.assertEqual(get_person('openslides_user:1'), self.openslidesuser1)
|
self.assertEqual(get_person('user:1'), self.user1)
|
||||||
self.assertEqual(len(Persons()), 1)
|
self.assertEqual(len(Persons(person_prefix='user')), 1)
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesGroupTest(TestCase):
|
class GroupTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.group1 = Group.objects.create(name='Test Group')
|
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):
|
def test_group_group(self):
|
||||||
self.assertEqual(self.openslidesgroup1.group, self.group1)
|
self.assertEqual(self.group1.django_group, self.django_group1)
|
||||||
|
self.assertEqual(self.group1, self.django_group1.group)
|
||||||
|
|
||||||
def test_person_api(self):
|
def test_person_api(self):
|
||||||
self.assertTrue(hasattr(self.openslidesgroup1, 'person_id'))
|
self.assertTrue(hasattr(self.group1, 'person_id'))
|
||||||
self.assertEqual(self.openslidesgroup1.person_id, 'openslides_group:1')
|
person_id = "group:%d" % self.group1.id
|
||||||
self.assertEqual(get_person('openslides_group:1'), self.openslidesgroup1)
|
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.conf.urls.defaults import url, patterns
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
from openslides.participant.views import (ParticipantsListPDF,
|
from openslides.participant.views import (
|
||||||
ParticipantsPasswordsPDF)
|
ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView,
|
||||||
|
UserUpdateView, UserDeleteView, SetUserStatusView, UserImportView,
|
||||||
|
ResetPasswordView, GroupOverviewView, GroupCreateView, GroupUpdateView,
|
||||||
|
GroupDeleteView)
|
||||||
|
|
||||||
urlpatterns = patterns('openslides.participant.views',
|
urlpatterns = patterns('openslides.participant.views',
|
||||||
url(r'^$',
|
url(r'^$',
|
||||||
'get_overview',
|
Overview.as_view(),
|
||||||
name='user_overview',
|
name='user_overview',
|
||||||
),
|
),
|
||||||
|
|
||||||
url(r'^new/$',
|
url(r'^new/$',
|
||||||
'edit',
|
UserCreateView.as_view(),
|
||||||
name='user_new',
|
name='user_new',
|
||||||
),
|
),
|
||||||
|
|
||||||
url(r'^(?P<user_id>\d+)/edit/$',
|
url(r'^(?P<pk>\d+)/edit/$',
|
||||||
'edit',
|
UserUpdateView.as_view(),
|
||||||
name='user_edit',
|
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/$',
|
url(r'^print/$',
|
||||||
ParticipantsListPDF.as_view(),
|
ParticipantsListPDF.as_view(),
|
||||||
name='user_print',
|
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/$',
|
url(r'^passwords/print/$',
|
||||||
ParticipantsPasswordsPDF.as_view(),
|
ParticipantsPasswordsPDF.as_view(),
|
||||||
name='print_passwords',
|
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('',
|
urlpatterns += patterns('',
|
||||||
(r'^500/$', 'openslides.utils.views.server_error'),
|
|
||||||
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
||||||
|
|
||||||
url(r'^login/$',
|
url(r'^login/$',
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
: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.api import generate_person_id, get_person, Persons
|
||||||
from openslides.utils.person.forms import PersonFormField, MultiplePersonFormField
|
from openslides.utils.person.forms import PersonFormField, MultiplePersonFormField
|
||||||
from openslides.utils.person.models import PersonField, PersonMixin
|
from openslides.utils.person.models import PersonField, PersonMixin
|
||||||
|
@ -10,16 +10,16 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
: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):
|
class Persons(object):
|
||||||
"""
|
"""
|
||||||
A Storage for a multiplicity of different Person-Objects.
|
A Storage for a multiplicity of different Person-Objects.
|
||||||
"""
|
"""
|
||||||
def __init__(self, person_prefix=None, id=None):
|
def __init__(self, person_prefix_filter=None, id_filter=None):
|
||||||
self.person_prefix = person_prefix
|
self.person_prefix_filter = person_prefix_filter
|
||||||
self.id = id
|
self.id_filter = id_filter
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
try:
|
try:
|
||||||
@ -35,14 +35,16 @@ class Persons(object):
|
|||||||
|
|
||||||
def iter_persons(self):
|
def iter_persons(self):
|
||||||
self._cache = list()
|
self._cache = list()
|
||||||
for receiver, persons in receiv_persons.send(
|
for receiver, persons in receive_persons.send(
|
||||||
sender='persons', person_prefix=self.person_prefix, id=self.id):
|
sender='persons', person_prefix_filter=self.person_prefix_filter, id_filter=self.id_filter):
|
||||||
for person in persons:
|
for person in persons:
|
||||||
self._cache.append(person)
|
self._cache.append(person)
|
||||||
yield person
|
yield person
|
||||||
|
|
||||||
|
|
||||||
def generate_person_id(prefix, id):
|
def generate_person_id(prefix, id):
|
||||||
|
assert prefix is not None
|
||||||
|
assert id is not None
|
||||||
if ':' in prefix:
|
if ':' in prefix:
|
||||||
raise ValueError("':' is not allowed in a the 'person_prefix'")
|
raise ValueError("':' is not allowed in a the 'person_prefix'")
|
||||||
return "%s:%d" % (prefix, id)
|
return "%s:%d" % (prefix, id)
|
||||||
@ -61,4 +63,4 @@ def get_person(person_id):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
from openslides.utils.person import EmtyPerson
|
from openslides.utils.person import EmtyPerson
|
||||||
return 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:
|
try:
|
||||||
return generate_person_id(self.person_prefix, self.pk)
|
return generate_person_id(self.person_prefix, self.pk)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise AttributeError("%s has to have a attribute 'user_prefix'"
|
raise AttributeError("%s has to have a attribute 'person_prefix'"
|
||||||
% self)
|
% self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
from django.dispatch import Signal
|
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.dispatch import receiver
|
||||||
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
|
||||||
from django.utils.decorators import method_decorator
|
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.utils.importlib import import_module
|
||||||
from django.template import loader, RequestContext
|
from django.template import loader, RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
@ -105,6 +105,50 @@ class AjaxMixin(object):
|
|||||||
return HttpResponse(json.dumps(self.get_ajax_context(**kwargs)))
|
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):
|
class TemplateView(PermissionMixin, _TemplateView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(TemplateView, self).get_context_data(**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.'))
|
messages.error(self.request, _('Please check the form for errors.'))
|
||||||
return super(CreateView, self).form_invalid(form)
|
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):
|
def get_success_message(self):
|
||||||
return _('%s was successfully created.') % html_strong(self.object)
|
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)
|
return _('Do you really want to delete %s?') % html_strong(self.object)
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_success_message(self):
|
||||||
return _('%s was successfully deleted.') % html_strong(self.object)
|
return _('%s was successfully deleted.') % html_strong(self.object)
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
self.confirm_form(request, self.object)
|
self.confirm_form()
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def pre_post_redirect(self, request, *args, **kwargs):
|
||||||
self.object.delete()
|
if self.get_answer().lower() == 'yes':
|
||||||
messages.success(request, self.get_success_message())
|
self.object.delete()
|
||||||
|
messages.success(request, self.get_success_message())
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
return super(DeleteView, self).get(request, *args, **kwargs)
|
return super(DeleteView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def confirm_form(self, request, object):
|
def get_answer_url(self):
|
||||||
self.gen_confirm_form(request, self.get_confirm_question(),
|
return self.object.get_absolute_url('delete')
|
||||||
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")))
|
|
||||||
|
|
||||||
|
|
||||||
class DetailView(TemplateView, SingleObjectMixin):
|
class DetailView(TemplateView, SingleObjectMixin):
|
||||||
|
Loading…
Reference in New Issue
Block a user