cleanup
Removed unused imports and fixed pep8 errors
This commit is contained in:
parent
4f82151004
commit
bd32994296
@ -24,8 +24,8 @@ class ItemForm(forms.ModelForm, CssClassMixin):
|
|||||||
"""
|
"""
|
||||||
Form to create of update an item.
|
Form to create of update an item.
|
||||||
"""
|
"""
|
||||||
parent = TreeNodeChoiceField(queryset=Item.objects.all(),
|
parent = TreeNodeChoiceField(
|
||||||
label=_("Parent item"), required=False)
|
queryset=Item.objects.all(), label=_("Parent item"), required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Item
|
model = Item
|
||||||
|
@ -10,12 +10,6 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
# for python 2.5 support
|
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext
|
from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext
|
||||||
@ -23,11 +17,9 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext
|
|||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from mptt.models import MPTTModel, TreeForeignKey
|
||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
|
||||||
from openslides.projector.projector import SlideMixin
|
from openslides.projector.projector import SlideMixin
|
||||||
from openslides.projector.api import (register_slidemodel, get_slide_from_sid,
|
from openslides.projector.api import (
|
||||||
register_slidefunc, split_sid)
|
register_slidemodel, get_slide_from_sid, register_slidefunc)
|
||||||
|
|
||||||
from openslides.agenda.slides import agenda_show
|
from openslides.agenda.slides import agenda_show
|
||||||
|
|
||||||
|
|
||||||
@ -45,7 +37,7 @@ class Item(MPTTModel, SlideMixin):
|
|||||||
closed = models.BooleanField(default=False, verbose_name=_("Closed"))
|
closed = models.BooleanField(default=False, verbose_name=_("Closed"))
|
||||||
weight = models.IntegerField(default=0, verbose_name=_("Weight"))
|
weight = models.IntegerField(default=0, verbose_name=_("Weight"))
|
||||||
parent = TreeForeignKey('self', null=True, blank=True,
|
parent = TreeForeignKey('self', null=True, blank=True,
|
||||||
related_name='children')
|
related_name='children')
|
||||||
related_sid = models.CharField(null=True, blank=True, max_length=63)
|
related_sid = models.CharField(null=True, blank=True, max_length=63)
|
||||||
|
|
||||||
def get_related_slide(self):
|
def get_related_slide(self):
|
||||||
@ -84,7 +76,6 @@ class Item(MPTTModel, SlideMixin):
|
|||||||
return self.title
|
return self.title
|
||||||
return self.get_related_slide().get_agenda_title()
|
return self.get_related_slide().get_agenda_title()
|
||||||
|
|
||||||
|
|
||||||
def get_title_supplement(self):
|
def get_title_supplement(self):
|
||||||
"""
|
"""
|
||||||
return a supplement for the title.
|
return a supplement for the title.
|
||||||
|
@ -12,12 +12,12 @@
|
|||||||
|
|
||||||
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 django.db.models.query import EmptyQuerySet
|
from django.db.models.query import EmptyQuerySet
|
||||||
|
|
||||||
from openslides.projector.api import get_active_slide
|
from openslides.projector.api import get_active_slide
|
||||||
|
from openslides.participant.models import User
|
||||||
|
from .models import Item
|
||||||
|
|
||||||
from openslides.agenda.models import Item
|
|
||||||
|
|
||||||
class ItemTest(TestCase):
|
class ItemTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -47,8 +47,9 @@ class ItemTest(TestCase):
|
|||||||
self.assertFalse(self.item4 in self.item1.get_children())
|
self.assertFalse(self.item4 in self.item1.get_children())
|
||||||
|
|
||||||
l = Item.objects.all()
|
l = Item.objects.all()
|
||||||
self.assertEqual(str(l),
|
self.assertEqual(
|
||||||
"[<Item: item1>, <Item: item1A>, <Item: item1Aa>, <Item: item2>]")
|
str(l),
|
||||||
|
"[<Item: item1>, <Item: item1A>, <Item: item1Aa>, <Item: item2>]")
|
||||||
|
|
||||||
def testForms(self):
|
def testForms(self):
|
||||||
for item in Item.objects.all():
|
for item in Item.objects.all():
|
||||||
@ -71,8 +72,10 @@ class ViewTest(TestCase):
|
|||||||
self.item2 = Item.objects.create(title='item2')
|
self.item2 = Item.objects.create(title='item2')
|
||||||
self.refreshItems()
|
self.refreshItems()
|
||||||
|
|
||||||
self.admin = User.objects.create_user('testadmin', '', 'default')
|
self.admin, created = User.objects.get_or_create(username='testadmin')
|
||||||
self.anonym = User.objects.create_user('testanoym', '', 'default')
|
self.anonym, created = User.objects.get_or_create(username='testanonym')
|
||||||
|
self.admin.reset_password('default')
|
||||||
|
self.anonym.reset_password('default')
|
||||||
|
|
||||||
self.admin.is_superuser = True
|
self.admin.is_superuser = True
|
||||||
self.admin.save()
|
self.admin.save()
|
||||||
@ -131,7 +134,7 @@ class ViewTest(TestCase):
|
|||||||
response = c.get('/agenda/%d/edit/' % 1000)
|
response = c.get('/agenda/%d/edit/' % 1000)
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
data = {'title': 'newitem1', 'text': 'item1-text', 'weight':'0'}
|
data = {'title': 'newitem1', 'text': 'item1-text', 'weight': '0'}
|
||||||
response = c.post('/agenda/%d/edit/' % self.item1.id, data)
|
response = c.post('/agenda/%d/edit/' % self.item1.id, data)
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.refreshItems()
|
self.refreshItems()
|
||||||
@ -143,4 +146,3 @@ class ViewTest(TestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.refreshItems()
|
self.refreshItems()
|
||||||
self.assertEqual(self.item1.title, 'newitem1')
|
self.assertEqual(self.item1.title, 'newitem1')
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
"""
|
"""
|
||||||
from reportlab.platypus import Paragraph
|
from reportlab.platypus import Paragraph
|
||||||
|
|
||||||
from django.core.context_processors import csrf
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
@ -20,18 +19,15 @@ from django.utils.translation import ugettext as _, ugettext_lazy
|
|||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
|
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.views import (TemplateView, RedirectView, UpdateView,
|
from openslides.utils.views import (
|
||||||
CreateView, DeleteView, PDFView, DetailView)
|
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
|
||||||
|
DetailView)
|
||||||
from openslides.utils.template import Tab
|
from openslides.utils.template import Tab
|
||||||
from openslides.utils.utils import html_strong
|
from openslides.utils.utils import html_strong
|
||||||
|
|
||||||
from openslides.config.models import config
|
|
||||||
|
|
||||||
from openslides.projector.api import get_active_slide
|
from openslides.projector.api import get_active_slide
|
||||||
from openslides.projector.projector import Widget, SLIDE
|
from openslides.projector.projector import Widget, SLIDE
|
||||||
|
from .models import Item
|
||||||
from openslides.agenda.models import Item
|
from .agenda.forms import ItemOrderForm, ItemForm
|
||||||
from openslides.agenda.forms import ItemOrderForm, ItemForm
|
|
||||||
|
|
||||||
|
|
||||||
class Overview(TemplateView):
|
class Overview(TemplateView):
|
||||||
@ -53,7 +49,8 @@ class Overview(TemplateView):
|
|||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
context = self.get_context_data(**kwargs)
|
context = self.get_context_data(**kwargs)
|
||||||
if not request.user.has_perm('agenda.can_manage_agenda'):
|
if not request.user.has_perm('agenda.can_manage_agenda'):
|
||||||
messages.error(request,
|
messages.error(
|
||||||
|
request,
|
||||||
_('You are not authorized to manage the agenda.'))
|
_('You are not authorized to manage the agenda.'))
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
@ -69,8 +66,8 @@ class Overview(TemplateView):
|
|||||||
Model.save(item)
|
Model.save(item)
|
||||||
else:
|
else:
|
||||||
transaction.rollback()
|
transaction.rollback()
|
||||||
messages.error(request,
|
messages.error(
|
||||||
_('Errors when reordering of the agenda'))
|
request, _('Errors when reordering of the agenda'))
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
Item.objects.rebuild()
|
Item.objects.rebuild()
|
||||||
# TODO: assure, that it is a valid tree
|
# TODO: assure, that it is a valid tree
|
||||||
@ -130,8 +127,8 @@ class ItemUpdate(UpdateView):
|
|||||||
apply_url = 'item_edit'
|
apply_url = 'item_edit'
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
messages.success(self.request,
|
messages.success(
|
||||||
_("Item %s was successfully modified.") \
|
self.request, _("Item %s was successfully modified.")
|
||||||
% html_strong(self.request.POST['title']))
|
% html_strong(self.request.POST['title']))
|
||||||
if 'apply' in self.request.POST:
|
if 'apply' in self.request.POST:
|
||||||
return ''
|
return ''
|
||||||
@ -151,8 +148,8 @@ class ItemCreate(CreateView):
|
|||||||
apply_url = 'item_edit'
|
apply_url = 'item_edit'
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
messages.success(self.request,
|
messages.success(
|
||||||
_("Item %s was successfully created.") \
|
self.request, _("Item %s was successfully created.")
|
||||||
% html_strong(self.request.POST['title']))
|
% html_strong(self.request.POST['title']))
|
||||||
if 'apply' in self.request.POST:
|
if 'apply' in self.request.POST:
|
||||||
return reverse(self.get_apply_url(), args=[self.object.id])
|
return reverse(self.get_apply_url(), args=[self.object.id])
|
||||||
@ -176,13 +173,13 @@ class ItemDelete(DeleteView):
|
|||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def pre_post_redirect(self, request, *args, **kwargs):
|
||||||
if self.get_answer() == 'all':
|
if self.get_answer() == 'all':
|
||||||
self.object.delete(with_children=True)
|
self.object.delete(with_children=True)
|
||||||
messages.success(request,
|
messages.success(
|
||||||
_("Item %s and his children were successfully deleted.")
|
request, _("Item %s and his children were successfully deleted.")
|
||||||
% html_strong(self.object))
|
% html_strong(self.object))
|
||||||
elif self.get_answer() == 'yes':
|
elif self.get_answer() == 'yes':
|
||||||
self.object.delete(with_children=False)
|
self.object.delete(with_children=False)
|
||||||
messages.success(request,
|
messages.success(
|
||||||
_("Item %s was successfully deleted.")
|
request, _("Item %s was successfully deleted.")
|
||||||
% html_strong(self.object))
|
% html_strong(self.object))
|
||||||
|
|
||||||
|
|
||||||
@ -199,7 +196,8 @@ class AgendaPDF(PDFView):
|
|||||||
ancestors = item.get_ancestors()
|
ancestors = item.get_ancestors()
|
||||||
if ancestors:
|
if ancestors:
|
||||||
space = " " * 6 * ancestors.count()
|
space = " " * 6 * ancestors.count()
|
||||||
story.append(Paragraph("%s%s" % (space, item.get_title()),
|
story.append(Paragraph(
|
||||||
|
"%s%s" % (space, item.get_title()),
|
||||||
stylesheet['Subitem']))
|
stylesheet['Subitem']))
|
||||||
else:
|
else:
|
||||||
story.append(Paragraph(item.get_title(), stylesheet['Item']))
|
story.append(Paragraph(item.get_title(), stylesheet['Item']))
|
||||||
@ -213,10 +211,9 @@ def register_tab(request):
|
|||||||
return Tab(
|
return Tab(
|
||||||
title=_('Agenda'),
|
title=_('Agenda'),
|
||||||
url=reverse('item_overview'),
|
url=reverse('item_overview'),
|
||||||
permission=request.user.has_perm('agenda.can_see_agenda')
|
permission=(request.user.has_perm('agenda.can_see_agenda') or
|
||||||
or request.user.has_perm('agenda.can_manage_agenda'),
|
request.user.has_perm('agenda.can_manage_agenda')),
|
||||||
selected=selected,
|
selected=selected)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_widgets(request):
|
def get_widgets(request):
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openslides.utils.forms import CssClassMixin
|
from openslides.utils.forms import CssClassMixin
|
||||||
from openslides.utils.person import PersonFormField
|
from openslides.utils.person import PersonFormField
|
||||||
@ -20,8 +20,8 @@ from openslides.assignment.models import Assignment
|
|||||||
|
|
||||||
|
|
||||||
class AssignmentForm(forms.ModelForm, CssClassMixin):
|
class AssignmentForm(forms.ModelForm, CssClassMixin):
|
||||||
posts = forms.IntegerField(min_value=1, initial=1,
|
posts = forms.IntegerField(
|
||||||
label=_("Number of available posts"))
|
min_value=1, initial=1, label=_("Number of available posts"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Assignment
|
model = Assignment
|
||||||
@ -39,8 +39,7 @@ class ConfigForm(forms.Form, CssClassMixin):
|
|||||||
assignment_publish_winner_results_only = forms.BooleanField(
|
assignment_publish_winner_results_only = forms.BooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Only publish voting results for selected winners "
|
label=_("Only publish voting results for selected winners "
|
||||||
"(Projector view only)")
|
"(Projector view only)"))
|
||||||
)
|
|
||||||
assignment_pdf_ballot_papers_selection = forms.ChoiceField(
|
assignment_pdf_ballot_papers_selection = forms.ChoiceField(
|
||||||
widget=forms.Select(),
|
widget=forms.Select(),
|
||||||
required=False,
|
required=False,
|
||||||
@ -48,31 +47,25 @@ class ConfigForm(forms.Form, CssClassMixin):
|
|||||||
choices=(
|
choices=(
|
||||||
("NUMBER_OF_DELEGATES", _("Number of all delegates")),
|
("NUMBER_OF_DELEGATES", _("Number of all delegates")),
|
||||||
("NUMBER_OF_ALL_PARTICIPANTS", _("Number of all participants")),
|
("NUMBER_OF_ALL_PARTICIPANTS", _("Number of all participants")),
|
||||||
("CUSTOM_NUMBER", _("Use the following custom number"))
|
("CUSTOM_NUMBER", _("Use the following custom number"))))
|
||||||
)
|
|
||||||
)
|
|
||||||
assignment_pdf_ballot_papers_number = forms.IntegerField(
|
assignment_pdf_ballot_papers_number = forms.IntegerField(
|
||||||
widget=forms.TextInput(attrs={'class':'small-input'}),
|
widget=forms.TextInput(attrs={'class': 'small-input'}),
|
||||||
required=False,
|
required=False,
|
||||||
min_value=1,
|
min_value=1,
|
||||||
label=_("Custom number of ballot papers")
|
label=_("Custom number of ballot papers"))
|
||||||
)
|
|
||||||
assignment_pdf_title = forms.CharField(
|
assignment_pdf_title = forms.CharField(
|
||||||
widget=forms.TextInput(),
|
widget=forms.TextInput(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Title for PDF document (all elections)")
|
label=_("Title for PDF document (all elections)"))
|
||||||
)
|
|
||||||
assignment_pdf_preamble = forms.CharField(
|
assignment_pdf_preamble = forms.CharField(
|
||||||
widget=forms.Textarea(),
|
widget=forms.Textarea(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Preamble text for PDF document (all elections)")
|
label=_("Preamble text for PDF document (all elections)"))
|
||||||
)
|
assignment_poll_vote_values = forms.ChoiceField(
|
||||||
assignment_poll_vote_values = forms.ChoiceField(widget=forms.Select(),
|
widget=forms.Select(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Election method"),
|
label=_("Election method"),
|
||||||
choices=(
|
choices=(
|
||||||
("auto", _("Automatic assign of method.")),
|
("auto", _("Automatic assign of method.")),
|
||||||
("votes", _("Always one option per candidate.")),
|
("votes", _("Always one option per candidate.")),
|
||||||
("yesnoabstain", _("Always Yes-No-Abstain per candidate.")),
|
("yesnoabstain", _("Always Yes-No-Abstain per candidate."))))
|
||||||
)
|
|
||||||
)
|
|
||||||
|
@ -16,16 +16,12 @@ 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 PersonField
|
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.projector.api import register_slidemodel
|
from openslides.projector.api import register_slidemodel
|
||||||
from openslides.projector.projector import SlideMixin
|
from openslides.projector.projector import SlideMixin
|
||||||
|
from openslides.poll.models import (
|
||||||
from openslides.poll.models import (BasePoll, CountInvalid, CountVotesCast,
|
BasePoll, CountInvalid, CountVotesCast, BaseOption, PublishPollMixin, BaseVote)
|
||||||
BaseOption, PublishPollMixin, BaseVote)
|
|
||||||
|
|
||||||
from openslides.agenda.models import Item
|
from openslides.agenda.models import Item
|
||||||
|
|
||||||
|
|
||||||
@ -51,11 +47,10 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
name = models.CharField(max_length=100, verbose_name=_("Name"))
|
name = models.CharField(max_length=100, verbose_name=_("Name"))
|
||||||
description = models.TextField(null=True, blank=True,
|
description = models.TextField(null=True, blank=True, verbose_name=_("Description"))
|
||||||
verbose_name=_("Description"))
|
posts = models.PositiveSmallIntegerField(verbose_name=_("Number of available posts"))
|
||||||
posts = models.PositiveSmallIntegerField(
|
polldescription = models.CharField(
|
||||||
verbose_name=_("Number of available posts"))
|
max_length=100, null=True, blank=True,
|
||||||
polldescription = models.CharField(max_length=100, null=True, blank=True,
|
|
||||||
verbose_name=_("Comment on the ballot paper"))
|
verbose_name=_("Comment on the ballot paper"))
|
||||||
status = models.CharField(max_length=3, choices=STATUS, default='sea')
|
status = models.CharField(max_length=3, choices=STATUS, default='sea')
|
||||||
|
|
||||||
@ -68,8 +63,8 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
if error:
|
if error:
|
||||||
raise NameError(_('%s is not a valid status.') % status)
|
raise NameError(_('%s is not a valid status.') % status)
|
||||||
if self.status == status:
|
if self.status == status:
|
||||||
raise NameError(_('The assignment status is already %s.')
|
raise NameError(
|
||||||
% self.status)
|
_('The assignment status is already %s.') % self.status)
|
||||||
self.status = status
|
self.status = status
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@ -116,14 +111,12 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
else:
|
else:
|
||||||
candidation.delete()
|
candidation.delete()
|
||||||
|
|
||||||
|
|
||||||
def is_candidate(self, person):
|
def is_candidate(self, person):
|
||||||
"""
|
"""
|
||||||
return True, if person is a candidate.
|
return True, if person is a candidate.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self.assignment_candidates.filter(person=person) \
|
return self.assignment_candidates.filter(person=person).exclude(blocked=True).exists()
|
||||||
.exclude(blocked=True).exists()
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -131,8 +124,7 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
"""
|
"""
|
||||||
return True, if the person is blockt for candidation.
|
return True, if the person is blockt for candidation.
|
||||||
"""
|
"""
|
||||||
return self.assignment_candidates.filter(person=person) \
|
return self.assignment_candidates.filter(person=person).filter(blocked=True).exists()
|
||||||
.filter(blocked=True).exists()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def assignment_candidates(self):
|
def assignment_candidates(self):
|
||||||
@ -164,7 +156,6 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
return participants
|
return participants
|
||||||
#return candidates.values_list('person', flat=True)
|
#return candidates.values_list('person', flat=True)
|
||||||
|
|
||||||
|
|
||||||
def set_elected(self, person, value=True):
|
def set_elected(self, person, value=True):
|
||||||
candidate = self.assignment_candidates.get(person=person)
|
candidate = self.assignment_candidates.get(person=person)
|
||||||
candidate.elected = value
|
candidate.elected = value
|
||||||
@ -212,7 +203,6 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
vote_results_dict[candidate].append(votes)
|
vote_results_dict[candidate].append(votes)
|
||||||
return vote_results_dict
|
return vote_results_dict
|
||||||
|
|
||||||
|
|
||||||
def get_agenda_title(self):
|
def get_agenda_title(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@ -298,8 +288,7 @@ class AssignmentPoll(BasePoll, CountInvalid, CountVotesCast, PublishPollMixin):
|
|||||||
self.yesnoabstain = False
|
self.yesnoabstain = False
|
||||||
self.save()
|
self.save()
|
||||||
if self.yesnoabstain:
|
if self.yesnoabstain:
|
||||||
return [ugettext_noop('Yes'), ugettext_noop('No'),
|
return [ugettext_noop('Yes'), ugettext_noop('No'), ugettext_noop('Abstain')]
|
||||||
ugettext_noop('Abstain')]
|
|
||||||
else:
|
else:
|
||||||
return [ugettext_noop('Votes')]
|
return [ugettext_noop('Votes')]
|
||||||
|
|
||||||
|
@ -13,39 +13,31 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
from reportlab.platypus import (SimpleDocTemplate, PageBreak, Paragraph,
|
from reportlab.platypus import (
|
||||||
Spacer, Table, TableStyle)
|
SimpleDocTemplate, PageBreak, Paragraph, Spacer, Table, TableStyle)
|
||||||
from reportlab.lib.units import cm
|
from reportlab.lib.units import cm
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import ungettext, ugettext as _
|
from django.utils.translation import ungettext, ugettext as _
|
||||||
|
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.template import Tab
|
from openslides.utils.template import Tab
|
||||||
from openslides.utils.utils import (template, permission_required,
|
from openslides.utils.utils import (
|
||||||
gen_confirm_form, del_confirm_form, ajax_request)
|
template, permission_required, gen_confirm_form, del_confirm_form, ajax_request)
|
||||||
from openslides.utils.views import FormView, DeleteView, PDFView, RedirectView
|
from openslides.utils.views import FormView, DeleteView, PDFView, RedirectView
|
||||||
from openslides.utils.person import get_person
|
from openslides.utils.person import get_person
|
||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
|
||||||
from openslides.participant.models import User
|
from openslides.participant.models import User
|
||||||
|
|
||||||
from openslides.projector.projector import Widget
|
from openslides.projector.projector import Widget
|
||||||
|
|
||||||
from openslides.poll.views import PollFormView
|
from openslides.poll.views import PollFormView
|
||||||
|
|
||||||
from openslides.agenda.models import Item
|
from openslides.agenda.models import Item
|
||||||
|
from openslides.assignment.models import Assignment, AssignmentPoll
|
||||||
from openslides.assignment.models import (Assignment, AssignmentPoll,
|
from openslides.assignment.forms import (
|
||||||
AssignmentOption)
|
AssignmentForm, AssignmentRunForm, ConfigForm)
|
||||||
from openslides.assignment.forms import (AssignmentForm, AssignmentRunForm,
|
|
||||||
ConfigForm)
|
|
||||||
|
|
||||||
|
|
||||||
@permission_required('assignment.can_see_assignment')
|
@permission_required('assignment.can_see_assignment')
|
||||||
@ -56,7 +48,7 @@ def get_overview(request):
|
|||||||
query = query.filter(status__iexact=request.GET['status'])
|
query = query.filter(status__iexact=request.GET['status'])
|
||||||
try:
|
try:
|
||||||
sort = request.GET['sort']
|
sort = request.GET['sort']
|
||||||
if sort in ['name','status']:
|
if sort in ['name', 'status']:
|
||||||
query = query.order_by(sort)
|
query = query.order_by(sort)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@ -91,7 +83,6 @@ def view(request, assignment_id=None):
|
|||||||
if request.user.has_perm('assignment.can_nominate_other'):
|
if request.user.has_perm('assignment.can_nominate_other'):
|
||||||
form = AssignmentRunForm()
|
form = AssignmentRunForm()
|
||||||
|
|
||||||
|
|
||||||
polls = assignment.poll_set.all()
|
polls = assignment.poll_set.all()
|
||||||
if not request.user.has_perm('assignment.can_manage_assignment'):
|
if not request.user.has_perm('assignment.can_manage_assignment'):
|
||||||
polls = assignment.poll_set.filter(published=True)
|
polls = assignment.poll_set.filter(published=True)
|
||||||
@ -100,7 +91,8 @@ 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)
|
||||||
|
|
||||||
blocked_candidates = [candidate.person for candidate in \
|
blocked_candidates = [
|
||||||
|
candidate.person for candidate in
|
||||||
assignment.assignment_candidates.filter(blocked=True)]
|
assignment.assignment_candidates.filter(blocked=True)]
|
||||||
return {
|
return {
|
||||||
'assignment': assignment,
|
'assignment': assignment,
|
||||||
@ -180,7 +172,7 @@ 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, 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)
|
||||||
return redirect(reverse('assignment_view', args=[assignment_id]))
|
return redirect(reverse('assignment_view', args=[assignment_id]))
|
||||||
@ -195,7 +187,8 @@ def delrun(request, assignment_id):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
messages.error(request, e)
|
messages.error(request, e)
|
||||||
else:
|
else:
|
||||||
messages.success(request,
|
messages.success(
|
||||||
|
request,
|
||||||
_("You have withdrawn your candidature successfully. "
|
_("You have withdrawn your candidature successfully. "
|
||||||
"You can not be nominated by other participants anymore."))
|
"You can not be nominated by other participants anymore."))
|
||||||
else:
|
else:
|
||||||
@ -240,7 +233,7 @@ def set_active(request, assignment_id):
|
|||||||
@permission_required('assignment.can_manage_assignment')
|
@permission_required('assignment.can_manage_assignment')
|
||||||
def gen_poll(request, assignment_id):
|
def gen_poll(request, assignment_id):
|
||||||
poll = Assignment.objects.get(pk=assignment_id).gen_poll()
|
poll = Assignment.objects.get(pk=assignment_id).gen_poll()
|
||||||
messages.success(request, _("New ballot was successfully created.") )
|
messages.success(request, _("New ballot was successfully created."))
|
||||||
return redirect(reverse('assignment_poll_view', args=[poll.id]))
|
return redirect(reverse('assignment_poll_view', args=[poll.id]))
|
||||||
|
|
||||||
|
|
||||||
@ -279,9 +272,9 @@ def set_publish_status(request, poll_id):
|
|||||||
return ajax_request({'published': poll.published})
|
return ajax_request({'published': poll.published})
|
||||||
|
|
||||||
if poll.published:
|
if poll.published:
|
||||||
messages.success(request, _("Ballot successfully published.") )
|
messages.success(request, _("Ballot successfully published."))
|
||||||
else:
|
else:
|
||||||
messages.success(request, _("Ballot successfully unpublished.") )
|
messages.success(request, _("Ballot successfully unpublished."))
|
||||||
return redirect(reverse('assignment_view', args=[poll.assignment.id]))
|
return redirect(reverse('assignment_view', args=[poll.assignment.id]))
|
||||||
|
|
||||||
|
|
||||||
@ -336,8 +329,9 @@ class AssignmentPDF(PDFView):
|
|||||||
try:
|
try:
|
||||||
assignment_id = self.kwargs['assignment_id']
|
assignment_id = self.kwargs['assignment_id']
|
||||||
assignment = Assignment.objects.get(id=assignment_id)
|
assignment = Assignment.objects.get(id=assignment_id)
|
||||||
filename = u'%s-%s' % (_("Assignment"),
|
filename = u'%s-%s' % (
|
||||||
assignment.name.replace(' ','_'))
|
_("Assignment"),
|
||||||
|
assignment.name.replace(' ', '_'))
|
||||||
except:
|
except:
|
||||||
filename = _("Elections")
|
filename = _("Elections")
|
||||||
return filename
|
return filename
|
||||||
@ -347,23 +341,24 @@ class AssignmentPDF(PDFView):
|
|||||||
assignment_id = self.kwargs['assignment_id']
|
assignment_id = self.kwargs['assignment_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
assignment_id = None
|
assignment_id = None
|
||||||
if assignment_id is None: #print all assignments
|
if assignment_id is None: # print all assignments
|
||||||
title = config["assignment_pdf_title"]
|
title = config["assignment_pdf_title"]
|
||||||
story.append(Paragraph(title, stylesheet['Heading1']))
|
story.append(Paragraph(title, stylesheet['Heading1']))
|
||||||
preamble = config["assignment_pdf_preamble"]
|
preamble = config["assignment_pdf_preamble"]
|
||||||
if preamble:
|
if preamble:
|
||||||
story.append(Paragraph("%s" % preamble.replace('\r\n', '<br/>'),
|
story.append(Paragraph(
|
||||||
|
"%s" % preamble.replace('\r\n', '<br/>'),
|
||||||
stylesheet['Paragraph']))
|
stylesheet['Paragraph']))
|
||||||
story.append(Spacer(0, 0.75 * cm))
|
story.append(Spacer(0, 0.75 * cm))
|
||||||
assignments = Assignment.objects.all()
|
assignments = Assignment.objects.all()
|
||||||
if not assignments: # No assignments existing
|
if not assignments: # No assignments existing
|
||||||
story.append(Paragraph(_("No assignments available."),
|
story.append(Paragraph(
|
||||||
stylesheet['Heading3']))
|
_("No assignments available."), stylesheet['Heading3']))
|
||||||
else: # Print all assignments
|
else: # Print all assignments
|
||||||
# List of assignments
|
# List of assignments
|
||||||
for assignment in assignments:
|
for assignment in assignments:
|
||||||
story.append(Paragraph(assignment.name,
|
story.append(Paragraph(
|
||||||
stylesheet['Heading3']))
|
assignment.name, stylesheet['Heading3']))
|
||||||
# Assignment details (each assignment on single page)
|
# Assignment details (each assignment on single page)
|
||||||
for assignment in assignments:
|
for assignment in assignments:
|
||||||
story.append(PageBreak())
|
story.append(PageBreak())
|
||||||
@ -376,28 +371,33 @@ class AssignmentPDF(PDFView):
|
|||||||
|
|
||||||
def get_assignment(self, assignment, story):
|
def get_assignment(self, assignment, story):
|
||||||
# title
|
# title
|
||||||
story.append(Paragraph(_("Election: %s") % assignment.name,
|
story.append(Paragraph(
|
||||||
stylesheet['Heading1']))
|
_("Election: %s") % assignment.name, stylesheet['Heading1']))
|
||||||
story.append(Spacer(0, 0.5 * cm))
|
story.append(Spacer(0, 0.5 * cm))
|
||||||
# posts
|
# posts
|
||||||
cell1a = []
|
cell1a = []
|
||||||
cell1a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font>" %
|
cell1a.append(Paragraph(
|
||||||
|
"<font name='Ubuntu-Bold'>%s:</font>" %
|
||||||
_("Number of available posts"), stylesheet['Bold']))
|
_("Number of available posts"), stylesheet['Bold']))
|
||||||
cell1b = []
|
cell1b = []
|
||||||
cell1b.append(Paragraph(str(assignment.posts), stylesheet['Paragraph']))
|
cell1b.append(Paragraph(str(assignment.posts), stylesheet['Paragraph']))
|
||||||
# candidates
|
# candidates
|
||||||
cell2a = []
|
cell2a = []
|
||||||
cell2a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font><seqreset" \
|
cell2a.append(Paragraph(
|
||||||
|
"<font name='Ubuntu-Bold'>%s:</font><seqreset"
|
||||||
" id='counter'>" % _("Candidates"), stylesheet['Heading4']))
|
" id='counter'>" % _("Candidates"), stylesheet['Heading4']))
|
||||||
cell2b = []
|
cell2b = []
|
||||||
for candidate in assignment.candidates:
|
for candidate in assignment.candidates:
|
||||||
cell2b.append(Paragraph("<seq id='counter'/>. %s" % candidate,
|
cell2b.append(Paragraph(
|
||||||
|
"<seq id='counter'/>. %s" % candidate,
|
||||||
stylesheet['Signaturefield']))
|
stylesheet['Signaturefield']))
|
||||||
if assignment.status == "sea":
|
if assignment.status == "sea":
|
||||||
for x in range(0, 2 * assignment.posts):
|
for x in range(0, 2 * assignment.posts):
|
||||||
cell2b.append(Paragraph("<seq id='counter'/>. "
|
cell2b.append(
|
||||||
"__________________________________________",
|
Paragraph(
|
||||||
stylesheet['Signaturefield']))
|
"<seq id='counter'/>. "
|
||||||
|
"__________________________________________",
|
||||||
|
stylesheet['Signaturefield']))
|
||||||
cell2b.append(Spacer(0, 0.2 * cm))
|
cell2b.append(Spacer(0, 0.2 * cm))
|
||||||
|
|
||||||
# Vote results
|
# Vote results
|
||||||
@ -409,15 +409,15 @@ class AssignmentPDF(PDFView):
|
|||||||
|
|
||||||
# Left side
|
# Left side
|
||||||
cell3a = []
|
cell3a = []
|
||||||
cell3a.append(Paragraph("%s:" % (_("Vote results")),
|
cell3a.append(Paragraph(
|
||||||
stylesheet['Heading4']))
|
"%s:" % (_("Vote results")), stylesheet['Heading4']))
|
||||||
|
|
||||||
if polls.count() == 1:
|
if polls.count() == 1:
|
||||||
cell3a.append(Paragraph("%s %s" % (polls.count(), _("ballot")),
|
cell3a.append(Paragraph(
|
||||||
stylesheet['Normal']))
|
"%s %s" % (polls.count(), _("ballot")), stylesheet['Normal']))
|
||||||
elif polls.count() > 1:
|
elif polls.count() > 1:
|
||||||
cell3a.append(Paragraph("%s %s" % (polls.count(), _("ballots")),
|
cell3a.append(Paragraph(
|
||||||
stylesheet['Normal']))
|
"%s %s" % (polls.count(), _("ballots")), stylesheet['Normal']))
|
||||||
|
|
||||||
# Add table head row
|
# Add table head row
|
||||||
headrow = []
|
headrow = []
|
||||||
@ -426,7 +426,6 @@ class AssignmentPDF(PDFView):
|
|||||||
headrow.append("%s." % poll.get_ballot())
|
headrow.append("%s." % poll.get_ballot())
|
||||||
data_votes.append(headrow)
|
data_votes.append(headrow)
|
||||||
|
|
||||||
|
|
||||||
# Add result rows
|
# Add result rows
|
||||||
elected_candidates = list(assignment.elected)
|
elected_candidates = list(assignment.elected)
|
||||||
for candidate, poll_list in vote_results.iteritems():
|
for candidate, poll_list in vote_results.iteritems():
|
||||||
@ -439,12 +438,13 @@ class AssignmentPDF(PDFView):
|
|||||||
candidate_string += "\n(%s)" % candidate.name_suffix
|
candidate_string += "\n(%s)" % candidate.name_suffix
|
||||||
row.append(candidate_string)
|
row.append(candidate_string)
|
||||||
for vote in poll_list:
|
for vote in poll_list:
|
||||||
if vote == None:
|
if vote is None:
|
||||||
row.append('–')
|
row.append('–')
|
||||||
elif 'Yes' in vote and 'No' in vote and 'Abstain' in vote:
|
elif 'Yes' in vote and 'No' in vote and 'Abstain' in vote:
|
||||||
row.append(_("Y: %(YES)s\nN: %(NO)s\nA: %(ABSTAIN)s")
|
row.append(
|
||||||
% {'YES':vote['Yes'], 'NO': vote['No'],
|
_("Y: %(YES)s\nN: %(NO)s\nA: %(ABSTAIN)s")
|
||||||
'ABSTAIN': vote['Abstain']})
|
% {'YES': vote['Yes'], 'NO': vote['No'],
|
||||||
|
'ABSTAIN': vote['Abstain']})
|
||||||
elif 'Votes' in vote:
|
elif 'Votes' in vote:
|
||||||
row.append(vote['Votes'])
|
row.append(vote['Votes'])
|
||||||
else:
|
else:
|
||||||
@ -465,15 +465,14 @@ class AssignmentPDF(PDFView):
|
|||||||
footrow_two.append(poll.print_votescast())
|
footrow_two.append(poll.print_votescast())
|
||||||
data_votes.append(footrow_two)
|
data_votes.append(footrow_two)
|
||||||
|
|
||||||
table_votes=Table(data_votes)
|
table_votes = Table(data_votes)
|
||||||
table_votes.setStyle( TableStyle([
|
table_votes.setStyle(TableStyle([
|
||||||
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
|
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
|
||||||
('VALIGN',(0, 0),(-1, -1), 'TOP'),
|
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||||
('LINEABOVE',(0, 0),(-1, 0), 2, colors.black),
|
('LINEABOVE', (0, 0), (-1, 0), 2, colors.black),
|
||||||
('LINEABOVE',(0, 1),(-1, 1), 1, colors.black),
|
('LINEABOVE', (0, 1), (-1, 1), 1, colors.black),
|
||||||
('LINEBELOW',(0, -1),(-1, -1), 2, colors.black),
|
('LINEBELOW', (0, -1), (-1, -1), 2, colors.black),
|
||||||
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9))),
|
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9)))]))
|
||||||
]))
|
|
||||||
|
|
||||||
# table
|
# table
|
||||||
data = []
|
data = []
|
||||||
@ -484,17 +483,18 @@ class AssignmentPDF(PDFView):
|
|||||||
else:
|
else:
|
||||||
data.append([cell2a, cell2b])
|
data.append([cell2a, cell2b])
|
||||||
data.append([Spacer(0, 0.2 * cm), ''])
|
data.append([Spacer(0, 0.2 * cm), ''])
|
||||||
t=Table(data)
|
t = Table(data)
|
||||||
t._argW[0] = 4.5 * cm
|
t._argW[0] = 4.5 * cm
|
||||||
t._argW[1] = 11 * cm
|
t._argW[1] = 11 * cm
|
||||||
t.setStyle(TableStyle([ ('BOX', (0,0), (-1, -1), 1, colors.black),
|
t.setStyle(TableStyle([
|
||||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
('BOX', (0, 0), (-1, -1), 1, colors.black),
|
||||||
]))
|
('VALIGN', (0, 0), (-1, -1), 'TOP')]))
|
||||||
story.append(t)
|
story.append(t)
|
||||||
story.append(Spacer(0, 1 * cm))
|
story.append(Spacer(0, 1 * cm))
|
||||||
|
|
||||||
# text
|
# text
|
||||||
story.append(Paragraph("%s" % assignment.description.replace('\r\n',
|
story.append(Paragraph(
|
||||||
|
"%s" % assignment.description.replace('\r\n',
|
||||||
'<br/>'), stylesheet['Paragraph']))
|
'<br/>'), stylesheet['Paragraph']))
|
||||||
|
|
||||||
|
|
||||||
@ -519,13 +519,15 @@ class AssignmentPollPDF(PDFView):
|
|||||||
return super(AssignmentPollPDF, self).get(request, *args, **kwargs)
|
return super(AssignmentPollPDF, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_filename(self):
|
def get_filename(self):
|
||||||
filename = u'%s-%s_%s' % (_("Election"), self.poll.assignment.name.replace(' ', '_'),
|
filename = u'%s-%s_%s' % (
|
||||||
|
_("Election"), self.poll.assignment.name.replace(' ', '_'),
|
||||||
self.poll.get_ballot())
|
self.poll.get_ballot())
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def get_template(self, buffer):
|
def get_template(self, buffer):
|
||||||
return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6,
|
return SimpleDocTemplate(
|
||||||
leftMargin=0, rightMargin=0, showBoundary=False)
|
buffer, topMargin=-6, bottomMargin=-6, leftMargin=0, rightMargin=0,
|
||||||
|
showBoundary=False)
|
||||||
|
|
||||||
def build_document(self, pdf_document, story):
|
def build_document(self, pdf_document, story):
|
||||||
pdf_document.build(story)
|
pdf_document.build(story)
|
||||||
@ -534,23 +536,27 @@ class AssignmentPollPDF(PDFView):
|
|||||||
imgpath = os.path.join(settings.SITE_ROOT, 'static/images/circle.png')
|
imgpath = os.path.join(settings.SITE_ROOT, 'static/images/circle.png')
|
||||||
circle = "<img src='%s' width='15' height='15'/> " % imgpath
|
circle = "<img src='%s' width='15' height='15'/> " % imgpath
|
||||||
cell = []
|
cell = []
|
||||||
cell.append(Spacer(0,0.8*cm))
|
cell.append(Spacer(0, 0.8 * cm))
|
||||||
cell.append(Paragraph(_("Election") + ": " + self.poll.assignment.name,
|
cell.append(Paragraph(
|
||||||
|
_("Election") + ": " + self.poll.assignment.name,
|
||||||
stylesheet['Ballot_title']))
|
stylesheet['Ballot_title']))
|
||||||
cell.append(Paragraph(self.poll.assignment.polldescription,
|
cell.append(Paragraph(
|
||||||
|
self.poll.assignment.polldescription,
|
||||||
stylesheet['Ballot_subtitle']))
|
stylesheet['Ballot_subtitle']))
|
||||||
options = self.poll.get_options()
|
options = self.poll.get_options()
|
||||||
|
|
||||||
ballot_string = _("%d. ballot") % self.poll.get_ballot()
|
ballot_string = _("%d. ballot") % self.poll.get_ballot()
|
||||||
candidate_string = ungettext("%d candidate", "%d candidates",
|
candidate_string = ungettext(
|
||||||
len(options)) % len(options)
|
"%d candidate", "%d candidates", len(options)) % len(options)
|
||||||
available_posts_string = ungettext("%d available post", "%d available posts",
|
available_posts_string = ungettext(
|
||||||
|
"%d available post", "%d available posts",
|
||||||
self.poll.assignment.posts) % self.poll.assignment.posts
|
self.poll.assignment.posts) % self.poll.assignment.posts
|
||||||
cell.append(Paragraph("%s, %s, %s" % (ballot_string, candidate_string,
|
cell.append(Paragraph(
|
||||||
|
"%s, %s, %s" % (ballot_string, candidate_string,
|
||||||
available_posts_string), stylesheet['Ballot_description']))
|
available_posts_string), stylesheet['Ballot_description']))
|
||||||
cell.append(Spacer(0, 0.4 * cm))
|
cell.append(Spacer(0, 0.4 * cm))
|
||||||
|
|
||||||
data= []
|
data = []
|
||||||
# get ballot papers config values
|
# get ballot papers config values
|
||||||
ballot_papers_selection = config["assignment_pdf_ballot_papers_selection"]
|
ballot_papers_selection = config["assignment_pdf_ballot_papers_selection"]
|
||||||
ballot_papers_number = config["assignment_pdf_ballot_papers_number"]
|
ballot_papers_number = config["assignment_pdf_ballot_papers_number"]
|
||||||
@ -560,7 +566,7 @@ class AssignmentPollPDF(PDFView):
|
|||||||
number = User.objects.filter(type__iexact="delegate").count()
|
number = User.objects.filter(type__iexact="delegate").count()
|
||||||
elif ballot_papers_selection == "NUMBER_OF_ALL_PARTICIPANTS":
|
elif ballot_papers_selection == "NUMBER_OF_ALL_PARTICIPANTS":
|
||||||
number = int(User.objects.count())
|
number = int(User.objects.count())
|
||||||
else: # ballot_papers_selection == "CUSTOM_NUMBER"
|
else: # ballot_papers_selection == "CUSTOM_NUMBER"
|
||||||
number = int(ballot_papers_number)
|
number = int(ballot_papers_number)
|
||||||
number = max(1, number)
|
number = max(1, number)
|
||||||
|
|
||||||
@ -568,16 +574,18 @@ class AssignmentPollPDF(PDFView):
|
|||||||
if self.poll.yesnoabstain:
|
if self.poll.yesnoabstain:
|
||||||
for option in options:
|
for option in options:
|
||||||
candidate = option.candidate
|
candidate = option.candidate
|
||||||
cell.append(Paragraph(candidate.clean_name,
|
cell.append(Paragraph(
|
||||||
stylesheet['Ballot_option_name']))
|
candidate.clean_name, stylesheet['Ballot_option_name']))
|
||||||
if candidate.name_suffix:
|
if candidate.name_suffix:
|
||||||
cell.append(Paragraph("(%s)" % candidate.name_suffix,
|
cell.append(Paragraph(
|
||||||
|
"(%s)" % candidate.name_suffix,
|
||||||
stylesheet['Ballot_option_group']))
|
stylesheet['Ballot_option_group']))
|
||||||
else:
|
else:
|
||||||
cell.append(Paragraph(" ",
|
cell.append(Paragraph(
|
||||||
stylesheet['Ballot_option_group']))
|
" ", stylesheet['Ballot_option_group']))
|
||||||
cell.append(Paragraph(circle + _("Yes") + " " * 3 + circle
|
cell.append(Paragraph(
|
||||||
+ _("No") + " " * 3 + circle+ _("Abstention"),
|
circle + _("Yes") + " " * 3 + circle
|
||||||
|
+ _("No") + " " * 3 + circle + _("Abstention"),
|
||||||
stylesheet['Ballot_option_YNA']))
|
stylesheet['Ballot_option_YNA']))
|
||||||
# print ballot papers
|
# print ballot papers
|
||||||
for user in xrange(number / 2):
|
for user in xrange(number / 2):
|
||||||
@ -594,14 +602,16 @@ class AssignmentPollPDF(PDFView):
|
|||||||
else:
|
else:
|
||||||
for option in options:
|
for option in options:
|
||||||
candidate = option.candidate
|
candidate = option.candidate
|
||||||
cell.append(Paragraph(circle + candidate.clean_name,
|
cell.append(Paragraph(
|
||||||
|
circle + candidate.clean_name,
|
||||||
stylesheet['Ballot_option_name']))
|
stylesheet['Ballot_option_name']))
|
||||||
if candidate.name_suffix:
|
if candidate.name_suffix:
|
||||||
cell.append(Paragraph("(%s)" % candidate.name_suffix,
|
cell.append(Paragraph(
|
||||||
|
"(%s)" % candidate.name_suffix,
|
||||||
stylesheet['Ballot_option_group_right']))
|
stylesheet['Ballot_option_group_right']))
|
||||||
else:
|
else:
|
||||||
cell.append(Paragraph(" ",
|
cell.append(Paragraph(
|
||||||
stylesheet['Ballot_option_group_right']))
|
" ", stylesheet['Ballot_option_group_right']))
|
||||||
# print ballot papers
|
# print ballot papers
|
||||||
for user in xrange(number / 2):
|
for user in xrange(number / 2):
|
||||||
data.append([cell, cell])
|
data.append([cell, cell])
|
||||||
@ -615,9 +625,9 @@ class AssignmentPollPDF(PDFView):
|
|||||||
else:
|
else:
|
||||||
t = Table(data, 10.5 * cm, 29.7 * cm)
|
t = Table(data, 10.5 * cm, 29.7 * cm)
|
||||||
|
|
||||||
t.setStyle(TableStyle([('GRID', (0, 0), (-1, -1), 0.25, colors.grey),
|
t.setStyle(TableStyle([
|
||||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
('GRID', (0, 0), (-1, -1), 0.25, colors.grey),
|
||||||
]))
|
('VALIGN', (0, 0), (-1, -1), 'TOP')]))
|
||||||
story.append(t)
|
story.append(t)
|
||||||
|
|
||||||
|
|
||||||
@ -629,16 +639,15 @@ class Config(FormView):
|
|||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
return {
|
return {
|
||||||
'assignment_publish_winner_results_only':
|
'assignment_publish_winner_results_only':
|
||||||
config['assignment_publish_winner_results_only'],
|
config['assignment_publish_winner_results_only'],
|
||||||
'assignment_pdf_ballot_papers_selection':
|
'assignment_pdf_ballot_papers_selection':
|
||||||
config['assignment_pdf_ballot_papers_selection'],
|
config['assignment_pdf_ballot_papers_selection'],
|
||||||
'assignment_pdf_ballot_papers_number':
|
'assignment_pdf_ballot_papers_number':
|
||||||
config['assignment_pdf_ballot_papers_number'],
|
config['assignment_pdf_ballot_papers_number'],
|
||||||
'assignment_pdf_title': config['assignment_pdf_title'],
|
'assignment_pdf_title': config['assignment_pdf_title'],
|
||||||
'assignment_pdf_preamble': config['assignment_pdf_preamble'],
|
'assignment_pdf_preamble': config['assignment_pdf_preamble'],
|
||||||
'assignment_poll_vote_values':
|
'assignment_poll_vote_values':
|
||||||
config['assignment_poll_vote_values'],
|
config['assignment_poll_vote_values']}
|
||||||
}
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
if form.cleaned_data['assignment_publish_winner_results_only']:
|
if form.cleaned_data['assignment_publish_winner_results_only']:
|
||||||
@ -655,8 +664,8 @@ class Config(FormView):
|
|||||||
form.cleaned_data['assignment_pdf_preamble']
|
form.cleaned_data['assignment_pdf_preamble']
|
||||||
config['assignment_poll_vote_values'] = \
|
config['assignment_poll_vote_values'] = \
|
||||||
form.cleaned_data['assignment_poll_vote_values']
|
form.cleaned_data['assignment_poll_vote_values']
|
||||||
messages.success(self.request,
|
messages.success(
|
||||||
_('Election settings successfully saved.'))
|
self.request, _('Election settings successfully saved.'))
|
||||||
return super(Config, self).form_valid(form)
|
return super(Config, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
@ -665,10 +674,11 @@ def register_tab(request):
|
|||||||
return Tab(
|
return Tab(
|
||||||
title=_('Elections'),
|
title=_('Elections'),
|
||||||
url=reverse('assignment_overview'),
|
url=reverse('assignment_overview'),
|
||||||
permission=request.user.has_perm('assignment.can_see_assignment')
|
permission=(
|
||||||
or request.user.has_perm('assignment.can_nominate_other')
|
request.user.has_perm('assignment.can_see_assignment') or
|
||||||
or request.user.has_perm('assignment.can_nominate_self')
|
request.user.has_perm('assignment.can_nominate_other') or
|
||||||
or request.user.has_perm('assignment.can_manage_assignment'),
|
request.user.has_perm('assignment.can_nominate_self') or
|
||||||
|
request.user.has_perm('assignment.can_manage_assignment')),
|
||||||
selected=selected,
|
selected=selected,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
from openslides.utils.forms import CssClassMixin
|
from openslides.utils.forms import CssClassMixin
|
||||||
|
|
||||||
from openslides.config.models import config
|
|
||||||
|
|
||||||
|
|
||||||
class GeneralConfigForm(forms.Form, CssClassMixin):
|
class GeneralConfigForm(forms.Form, CssClassMixin):
|
||||||
event_name = forms.CharField(
|
event_name = forms.CharField(
|
||||||
|
@ -51,7 +51,7 @@ class Config(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
for receiver, value in default_config_value.send(sender='config',
|
for receiver, value in default_config_value.send(sender='config',
|
||||||
key=key):
|
key=key):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return value
|
return value
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
@ -69,7 +69,6 @@ class Config(object):
|
|||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
return ConfigStore.objects.filter(key=item).exists()
|
return ConfigStore.objects.filter(key=item).exists()
|
||||||
|
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
|
|
||||||
|
|
||||||
@ -81,7 +80,7 @@ def default_config(sender, key, **kwargs):
|
|||||||
return {
|
return {
|
||||||
'event_name': 'OpenSlides',
|
'event_name': 'OpenSlides',
|
||||||
'event_description':
|
'event_description':
|
||||||
_('Presentation and assembly system'),
|
_('Presentation and assembly system'),
|
||||||
'event_date': '',
|
'event_date': '',
|
||||||
'event_location': '',
|
'event_location': '',
|
||||||
'event_organizer': '',
|
'event_organizer': '',
|
||||||
@ -123,11 +122,9 @@ def set_submenu(sender, request, context, **kwargs):
|
|||||||
(reverse('config_%s' % appname), _(title), selected)
|
(reverse('config_%s' % appname), _(title), selected)
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_links.append (
|
menu_links.append((
|
||||||
(reverse('config_version'), _('Version'),
|
reverse('config_version'), _('Version'),
|
||||||
request.path == reverse('config_version'))
|
request.path == reverse('config_version')))
|
||||||
)
|
|
||||||
|
|
||||||
context.update({
|
context.update({
|
||||||
'menu_links': menu_links,
|
'menu_links': menu_links})
|
||||||
})
|
|
||||||
|
@ -17,12 +17,12 @@ from django.utils.importlib import import_module
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from openslides import get_version
|
from openslides import get_version
|
||||||
|
|
||||||
from openslides.utils.template import Tab
|
from openslides.utils.template import Tab
|
||||||
from openslides.utils.views import FormView, TemplateView
|
from openslides.utils.views import FormView, TemplateView
|
||||||
|
from .forms import GeneralConfigForm
|
||||||
|
from .models import config
|
||||||
|
|
||||||
from openslides.config.forms import GeneralConfigForm
|
# TODO: Do not import the participant module in config
|
||||||
from openslides.config.models import config
|
|
||||||
from openslides.participant.api import get_or_create_anonymous_group
|
from openslides.participant.api import get_or_create_anonymous_group
|
||||||
|
|
||||||
|
|
||||||
@ -61,12 +61,12 @@ class GeneralConfig(FormView):
|
|||||||
# system
|
# system
|
||||||
if form.cleaned_data['system_enable_anonymous']:
|
if form.cleaned_data['system_enable_anonymous']:
|
||||||
config['system_enable_anonymous'] = True
|
config['system_enable_anonymous'] = True
|
||||||
anonymous = get_or_create_anonymous_group()
|
get_or_create_anonymous_group()
|
||||||
else:
|
else:
|
||||||
config['system_enable_anonymous'] = False
|
config['system_enable_anonymous'] = False
|
||||||
|
|
||||||
messages.success(self.request,
|
messages.success(
|
||||||
_('General settings successfully saved.'))
|
self.request, _('General settings successfully saved.'))
|
||||||
return super(GeneralConfig, self).form_valid(form)
|
return super(GeneralConfig, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,15 +13,12 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
_fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
from openslides.main import fs2unicode
|
||||||
def _fs2unicode(s):
|
|
||||||
if isinstance(s, unicode):
|
|
||||||
return s
|
|
||||||
return s.decode(_fs_encoding)
|
|
||||||
|
|
||||||
SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
|
SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
'openslides.utils.auth.AnonymousAuth',)
|
'openslides.utils.auth.AnonymousAuth',)
|
||||||
|
|
||||||
LOGIN_URL = '/login/'
|
LOGIN_URL = '/login/'
|
||||||
@ -48,12 +45,12 @@ USE_I18N = True
|
|||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
|
|
||||||
LOCALE_PATHS = (
|
LOCALE_PATHS = (
|
||||||
_fs2unicode(os.path.join(SITE_ROOT, 'locale')),
|
fs2unicode(os.path.join(SITE_ROOT, 'locale')),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Absolute path to the directory that holds media.
|
# Absolute path to the directory that holds media.
|
||||||
# Example: "/home/media/media.lawrence.com/"
|
# Example: "/home/media/media.lawrence.com/"
|
||||||
MEDIA_ROOT = _fs2unicode(os.path.join(SITE_ROOT, './static/'))
|
MEDIA_ROOT = fs2unicode(os.path.join(SITE_ROOT, './static/'))
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||||
# trailing slash if there is a path component (optional in other cases).
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
@ -62,17 +59,17 @@ MEDIA_URL = ''
|
|||||||
|
|
||||||
# Absolute path to the directory that holds static media from ``collectstatic``
|
# Absolute path to the directory that holds static media from ``collectstatic``
|
||||||
# Example: "/home/media/static.lawrence.com/"
|
# Example: "/home/media/static.lawrence.com/"
|
||||||
STATIC_ROOT = _fs2unicode(os.path.join(SITE_ROOT, '../site-static'))
|
STATIC_ROOT = fs2unicode(os.path.join(SITE_ROOT, '../site-static'))
|
||||||
|
|
||||||
# URL that handles the media served from STATIC_ROOT. Make sure to use a
|
# URL that handles the media served from STATIC_ROOT. Make sure to use a
|
||||||
# trailing slash if there is a path component (optional in other cases).
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
# Examples: "http://static.lawrence.com", "http://example.com/static/"
|
# Examples: "http://static.lawrence.com", "http://example.com/static/"
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
# Additional directories containing static files (not application specific)
|
# Additional directories containing static files (not application specific)
|
||||||
# Examples: "/home/media/lawrence.com/extra-static/"
|
# Examples: "/home/media/lawrence.com/extra-static/"
|
||||||
STATICFILES_DIRS = (
|
STATICFILES_DIRS = (
|
||||||
_fs2unicode(os.path.join(SITE_ROOT, 'static')),
|
fs2unicode(os.path.join(SITE_ROOT, 'static')),
|
||||||
)
|
)
|
||||||
|
|
||||||
#XXX: Note this setting (as well as our workaround finder)
|
#XXX: Note this setting (as well as our workaround finder)
|
||||||
@ -106,7 +103,7 @@ TEMPLATE_DIRS = (
|
|||||||
# "C:/www/django/templates".
|
# "C:/www/django/templates".
|
||||||
# Always use forward slashes, even on Windows.
|
# Always use forward slashes, even on Windows.
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
# Don't forget to use absolute paths, not relative paths.
|
||||||
_fs2unicode(os.path.join(SITE_ROOT, 'templates')),
|
fs2unicode(os.path.join(SITE_ROOT, 'templates')),
|
||||||
)
|
)
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
|
@ -65,13 +65,6 @@ INSTALLED_APPS += INSTALLED_PLUGINS
|
|||||||
KEY_LENGTH = 30
|
KEY_LENGTH = 30
|
||||||
|
|
||||||
|
|
||||||
_fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
|
||||||
def _fs2unicode(s):
|
|
||||||
if isinstance(s, unicode):
|
|
||||||
return s
|
|
||||||
return s.decode(_fs_encoding)
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None, opt_defaults=None, database_path=None):
|
def main(argv=None, opt_defaults=None, database_path=None):
|
||||||
if argv is None:
|
if argv is None:
|
||||||
argv = sys.argv[1:]
|
argv = sys.argv[1:]
|
||||||
@ -102,7 +95,8 @@ def main(argv=None, opt_defaults=None, database_path=None):
|
|||||||
# Find the path to the settings
|
# Find the path to the settings
|
||||||
settings_path = opts.settings
|
settings_path = opts.settings
|
||||||
if settings_path is None:
|
if settings_path is None:
|
||||||
config_home = os.environ.get('XDG_CONFIG_HOME', \
|
config_home = os.environ.get(
|
||||||
|
'XDG_CONFIG_HOME',
|
||||||
os.path.join(os.path.expanduser('~'), '.config'))
|
os.path.join(os.path.expanduser('~'), '.config'))
|
||||||
settings_path = os.path.join(config_home, 'openslides', 'settings.py')
|
settings_path = os.path.join(config_home, 'openslides', 'settings.py')
|
||||||
|
|
||||||
@ -142,13 +136,14 @@ def create_settings(settings_path, database_path=None):
|
|||||||
settings_module = os.path.dirname(settings_path)
|
settings_module = os.path.dirname(settings_path)
|
||||||
|
|
||||||
if database_path is None:
|
if database_path is None:
|
||||||
data_home = os.environ.get('XDG_DATA_HOME', \
|
data_home = os.environ.get(
|
||||||
|
'XDG_DATA_HOME',
|
||||||
os.path.join(os.path.expanduser('~'), '.local', 'share'))
|
os.path.join(os.path.expanduser('~'), '.local', 'share'))
|
||||||
database_path = os.path.join(data_home, 'openslides', 'database.sqlite')
|
database_path = os.path.join(data_home, 'openslides', 'database.sqlite')
|
||||||
|
|
||||||
settings_content = CONFIG_TEMPLATE % dict(
|
settings_content = CONFIG_TEMPLATE % dict(
|
||||||
default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
|
default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
|
||||||
dbpath=_fs2unicode(database_path))
|
dbpath=fs2unicode(database_path))
|
||||||
|
|
||||||
if not os.path.exists(settings_module):
|
if not os.path.exists(settings_module):
|
||||||
os.makedirs(settings_module)
|
os.makedirs(settings_module)
|
||||||
@ -269,6 +264,14 @@ def start_browser(url):
|
|||||||
t = threading.Thread(target=f)
|
t = threading.Thread(target=f)
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
|
|
||||||
|
def fs2unicode(s):
|
||||||
|
if isinstance(s, unicode):
|
||||||
|
return s
|
||||||
|
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
||||||
|
return s.decode(fs_encoding)
|
||||||
|
|
||||||
|
|
||||||
def win32_portable_main(argv=None):
|
def win32_portable_main(argv=None):
|
||||||
"""special entry point for the win32 portable version"""
|
"""special entry point for the win32 portable version"""
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -287,17 +290,18 @@ def win32_portable_main(argv=None):
|
|||||||
os.unlink(test_file)
|
os.unlink(test_file)
|
||||||
|
|
||||||
if portable_dir_writeable:
|
if portable_dir_writeable:
|
||||||
default_settings = os.path.join(portable_dir, "openslides",
|
default_settings = os.path.join(
|
||||||
"openslides_personal_settings.py")
|
portable_dir, "openslides", "openslides_personal_settings.py")
|
||||||
database_path = os.path.join(portable_dir, "openslides",
|
database_path = os.path.join(
|
||||||
"database.sqlite")
|
portable_dir, "openslides", "database.sqlite")
|
||||||
else:
|
else:
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
shell32 = ctypes.WinDLL("shell32.dll")
|
shell32 = ctypes.WinDLL("shell32.dll")
|
||||||
SHGetFolderPath = shell32.SHGetFolderPathW
|
SHGetFolderPath = shell32.SHGetFolderPathW
|
||||||
SHGetFolderPath.argtypes = (ctypes.c_void_p, ctypes.c_int,
|
SHGetFolderPath.argtypes = (
|
||||||
ctypes.c_void_p, ctypes.c_uint32, ctypes.c_wchar_p)
|
ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_uint32,
|
||||||
|
ctypes.c_wchar_p)
|
||||||
SHGetFolderPath.restype = ctypes.c_uint32
|
SHGetFolderPath.restype = ctypes.c_uint32
|
||||||
|
|
||||||
CSIDL_LOCAL_APPDATA = 0x001c
|
CSIDL_LOCAL_APPDATA = 0x001c
|
||||||
@ -307,13 +311,13 @@ def win32_portable_main(argv=None):
|
|||||||
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
|
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
|
||||||
if res != 0:
|
if res != 0:
|
||||||
raise Exception("Could not deterime APPDATA path")
|
raise Exception("Could not deterime APPDATA path")
|
||||||
default_settings = os.path.join(buf.value, "openslides",
|
default_settings = os.path.join(
|
||||||
"openslides_personal_settings.py")
|
buf.value, "openslides", "openslides_personal_settings.py")
|
||||||
database_path = os.path.join(buf.value, "openslides",
|
database_path = os.path.join(
|
||||||
"database.sqlite")
|
buf.value, "openslides", "database.sqlite")
|
||||||
|
|
||||||
main(argv, opt_defaults={ "settings": default_settings },
|
main(argv, opt_defaults={"settings": default_settings},
|
||||||
database_path=database_path)
|
database_path=database_path)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openslides.utils.forms import CssClassMixin
|
from openslides.utils.forms import CssClassMixin
|
||||||
from openslides.utils.person import PersonFormField, MultiplePersonFormField
|
from openslides.utils.person import PersonFormField, MultiplePersonFormField
|
||||||
@ -21,18 +21,18 @@ from openslides.motion.models import Motion
|
|||||||
class MotionForm(forms.Form, CssClassMixin):
|
class MotionForm(forms.Form, CssClassMixin):
|
||||||
title = forms.CharField(widget=forms.TextInput(), label=_("Title"))
|
title = forms.CharField(widget=forms.TextInput(), label=_("Title"))
|
||||||
text = forms.CharField(widget=forms.Textarea(), label=_("Text"))
|
text = forms.CharField(widget=forms.Textarea(), label=_("Text"))
|
||||||
reason = forms.CharField(widget=forms.Textarea(), required=False,
|
reason = forms.CharField(
|
||||||
label=_("Reason"))
|
widget=forms.Textarea(), required=False, label=_("Reason"))
|
||||||
|
|
||||||
|
|
||||||
class MotionFormTrivialChanges(MotionForm):
|
class MotionFormTrivialChanges(MotionForm):
|
||||||
trivial_change = forms.BooleanField(required=False,
|
trivial_change = forms.BooleanField(
|
||||||
label=_("Trivial change"),
|
required=False, label=_("Trivial change"),
|
||||||
help_text=_("Trivial changes don't create a new version."))
|
help_text=_("Trivial changes don't create a new version."))
|
||||||
|
|
||||||
|
|
||||||
class MotionManagerForm(forms.ModelForm, CssClassMixin):
|
class MotionManagerForm(forms.ModelForm, CssClassMixin):
|
||||||
submitter = PersonFormField(label = _("Submitter"))
|
submitter = PersonFormField(label=_("Submitter"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Motion
|
model = Motion
|
||||||
@ -46,20 +46,20 @@ class MotionManagerFormSupporter(MotionManagerForm):
|
|||||||
|
|
||||||
class MotionImportForm(forms.Form, CssClassMixin):
|
class MotionImportForm(forms.Form, CssClassMixin):
|
||||||
csvfile = forms.FileField(
|
csvfile = forms.FileField(
|
||||||
widget=forms.FileInput(attrs={'size':'50'}),
|
widget=forms.FileInput(attrs={'size': '50'}),
|
||||||
label=_("CSV File"),
|
label=_("CSV File"),
|
||||||
)
|
)
|
||||||
import_permitted = forms.BooleanField(
|
import_permitted = forms.BooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Import motions with status \"authorized\""),
|
label=_("Import motions with status \"authorized\""),
|
||||||
help_text=_('Set the initial status for each motion to '
|
help_text=_('Set the initial status for each motion to '
|
||||||
'"authorized"'),
|
'"authorized"'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConfigForm(forms.Form, CssClassMixin):
|
class ConfigForm(forms.Form, CssClassMixin):
|
||||||
motion_min_supporters = forms.IntegerField(
|
motion_min_supporters = forms.IntegerField(
|
||||||
widget=forms.TextInput(attrs={'class':'small-input'}),
|
widget=forms.TextInput(attrs={'class': 'small-input'}),
|
||||||
label=_("Number of (minimum) required supporters for a motion"),
|
label=_("Number of (minimum) required supporters for a motion"),
|
||||||
initial=4,
|
initial=4,
|
||||||
min_value=0,
|
min_value=0,
|
||||||
@ -82,7 +82,7 @@ class ConfigForm(forms.Form, CssClassMixin):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
motion_pdf_ballot_papers_number = forms.IntegerField(
|
motion_pdf_ballot_papers_number = forms.IntegerField(
|
||||||
widget=forms.TextInput(attrs={'class':'small-input'}),
|
widget=forms.TextInput(attrs={'class': 'small-input'}),
|
||||||
required=False,
|
required=False,
|
||||||
min_value=1,
|
min_value=1,
|
||||||
label=_("Custom number of ballot papers")
|
label=_("Custom number of ballot papers")
|
||||||
@ -101,6 +101,6 @@ class ConfigForm(forms.Form, CssClassMixin):
|
|||||||
motion_allow_trivial_change = forms.BooleanField(
|
motion_allow_trivial_change = forms.BooleanField(
|
||||||
label=_("Allow trivial changes"),
|
label=_("Allow trivial changes"),
|
||||||
help_text=_('Warning: Trivial changes undermine the motions '
|
help_text=_('Warning: Trivial changes undermine the motions '
|
||||||
'autorisation system.'),
|
'autorisation system.'),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
@ -21,18 +21,13 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext
|
|||||||
|
|
||||||
from openslides.utils.utils import _propper_unicode
|
from openslides.utils.utils import _propper_unicode
|
||||||
from openslides.utils.person import PersonField
|
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.poll.models import (
|
||||||
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
BaseOption, BasePoll, CountVotesCast, CountInvalid, BaseVote)
|
||||||
CountInvalid, BaseVote)
|
from openslides.participant.models import User
|
||||||
|
|
||||||
from openslides.participant.models import User, Group
|
|
||||||
|
|
||||||
from openslides.projector.api import register_slidemodel
|
from openslides.projector.api import register_slidemodel
|
||||||
from openslides.projector.models import SlideMixin
|
from openslides.projector.models import SlideMixin
|
||||||
|
|
||||||
from openslides.agenda.models import Item
|
from openslides.agenda.models import Item
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +48,7 @@ class Motion(models.Model, SlideMixin):
|
|||||||
('noc', _('Not Concerned')),
|
('noc', _('Not Concerned')),
|
||||||
('com', _('Commited a bill')),
|
('com', _('Commited a bill')),
|
||||||
('nop', _('Rejected (not authorized)')),
|
('nop', _('Rejected (not authorized)')),
|
||||||
('rev', _('Needs Review')), # Where is this status used?
|
('rev', _('Needs Review')), # Where is this status used?
|
||||||
#additional actions:
|
#additional actions:
|
||||||
# edit
|
# edit
|
||||||
# delete
|
# delete
|
||||||
@ -67,9 +62,9 @@ class Motion(models.Model, SlideMixin):
|
|||||||
|
|
||||||
submitter = PersonField(verbose_name=_("Submitter"))
|
submitter = PersonField(verbose_name=_("Submitter"))
|
||||||
number = models.PositiveSmallIntegerField(blank=True, null=True,
|
number = models.PositiveSmallIntegerField(blank=True, null=True,
|
||||||
unique=True)
|
unique=True)
|
||||||
status = models.CharField(max_length=3, choices=STATUS, default='pub')
|
status = models.CharField(max_length=3, choices=STATUS, default='pub')
|
||||||
permitted = models.ForeignKey('AVersion', related_name='permitted', \
|
permitted = models.ForeignKey('AVersion', related_name='permitted',
|
||||||
null=True, blank=True)
|
null=True, blank=True)
|
||||||
log = models.TextField(blank=True, null=True)
|
log = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
@ -94,7 +89,7 @@ class Motion(models.Model, SlideMixin):
|
|||||||
else:
|
else:
|
||||||
return self.last_version
|
return self.last_version
|
||||||
|
|
||||||
def accept_version(self, version, user = None):
|
def accept_version(self, version, user=None):
|
||||||
"""
|
"""
|
||||||
accept a Version
|
accept a Version
|
||||||
"""
|
"""
|
||||||
@ -102,15 +97,15 @@ class Motion(models.Model, SlideMixin):
|
|||||||
self.save(nonewversion=True)
|
self.save(nonewversion=True)
|
||||||
version.rejected = False
|
version.rejected = False
|
||||||
version.save()
|
version.save()
|
||||||
self.writelog(_("Version %d authorized") % (version.aid, ),
|
self.writelog(_("Version %d authorized") % version.aid, user)
|
||||||
user)
|
|
||||||
|
|
||||||
def reject_version(self, version, user = None):
|
def reject_version(self, version, user=None):
|
||||||
if version.id > self.permitted.id:
|
if version.id > self.permitted.id:
|
||||||
version.rejected = True
|
version.rejected = True
|
||||||
version.save()
|
version.save()
|
||||||
self.writelog(pgettext("Rejected means not authorized", "Version %d rejected")
|
self.writelog(pgettext(
|
||||||
% (version.aid, ), user)
|
"Rejected means not authorized", "Version %d rejected")
|
||||||
|
% version.aid, user)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -154,8 +149,8 @@ class Motion(models.Model, SlideMixin):
|
|||||||
is not the lastone and the lastone is not rejected.
|
is not the lastone and the lastone is not rejected.
|
||||||
TODO: rename the property in unchecked__changes
|
TODO: rename the property in unchecked__changes
|
||||||
"""
|
"""
|
||||||
if (self.last_version != self.permitted
|
if (self.last_version != self.permitted and
|
||||||
and not self.last_version.rejected):
|
not self.last_version.rejected):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -207,7 +202,8 @@ class Motion(models.Model, SlideMixin):
|
|||||||
last_version = self.last_version
|
last_version = self.last_version
|
||||||
fields = ["text", "title", "reason"]
|
fields = ["text", "title", "reason"]
|
||||||
if last_version is not None:
|
if last_version is not None:
|
||||||
changed_fields = [f for f in fields
|
changed_fields = [
|
||||||
|
f for f in fields
|
||||||
if getattr(last_version, f) != getattr(self, f)]
|
if getattr(last_version, f) != getattr(self, f)]
|
||||||
if not changed_fields:
|
if not changed_fields:
|
||||||
return # No changes
|
return # No changes
|
||||||
@ -219,19 +215,22 @@ class Motion(models.Model, SlideMixin):
|
|||||||
last_version.save()
|
last_version.save()
|
||||||
|
|
||||||
meta = AVersion._meta
|
meta = AVersion._meta
|
||||||
field_names = [unicode(meta.get_field(f).verbose_name)
|
field_names = [
|
||||||
|
unicode(meta.get_field(f).verbose_name)
|
||||||
for f in changed_fields]
|
for f in changed_fields]
|
||||||
|
|
||||||
self.writelog(_("Trivial changes to version %(version)d; "
|
self.writelog(
|
||||||
"changed fields: %(changed_fields)s")
|
_("Trivial changes to version %(version)d; "
|
||||||
% dict(version = last_version.aid,
|
"changed fields: %(changed_fields)s")
|
||||||
changed_fields = ", ".join(field_names)))
|
% dict(version=last_version.aid,
|
||||||
return # Done
|
changed_fields=", ".join(field_names)))
|
||||||
|
return # Done
|
||||||
|
|
||||||
version = AVersion(title=getattr(self, 'title', ''),
|
version = AVersion(
|
||||||
text=getattr(self, 'text', ''),
|
title=getattr(self, 'title', ''),
|
||||||
reason=getattr(self, 'reason', ''),
|
text=getattr(self, 'text', ''),
|
||||||
motion=self)
|
reason=getattr(self, 'reason', ''),
|
||||||
|
motion=self)
|
||||||
version.save()
|
version.save()
|
||||||
self.writelog(_("Version %s created") % version.aid, user)
|
self.writelog(_("Version %s created") % version.aid, user)
|
||||||
is_manager = user.has_perm('motion.can_manage_motion')
|
is_manager = user.has_perm('motion.can_manage_motion')
|
||||||
@ -239,9 +238,8 @@ class Motion(models.Model, SlideMixin):
|
|||||||
is_manager = False
|
is_manager = False
|
||||||
|
|
||||||
supporters = self.motionsupporter_set.all()
|
supporters = self.motionsupporter_set.all()
|
||||||
if (self.status == "pub"
|
if (self.status == "pub" and
|
||||||
and supporters
|
supporters and not is_manager):
|
||||||
and not is_manager):
|
|
||||||
supporters.delete()
|
supporters.delete()
|
||||||
self.writelog(_("Supporters removed"), user)
|
self.writelog(_("Supporters removed"), user)
|
||||||
|
|
||||||
@ -272,7 +270,7 @@ class Motion(models.Model, SlideMixin):
|
|||||||
remove a supporter from the list of supporters of the motion
|
remove a supporter from the list of supporters of the motion
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
object = self.motionsupporter_set.get(person=person).delete()
|
self.motionsupporter_set.get(person=person).delete()
|
||||||
except MotionSupporter.DoesNotExist:
|
except MotionSupporter.DoesNotExist:
|
||||||
# TODO: Don't do nothing but raise a precise exception for the view
|
# TODO: Don't do nothing but raise a precise exception for the view
|
||||||
pass
|
pass
|
||||||
@ -288,8 +286,7 @@ class Motion(models.Model, SlideMixin):
|
|||||||
raise NameError('This motion has already a number.')
|
raise NameError('This motion has already a number.')
|
||||||
if number is None:
|
if number is None:
|
||||||
try:
|
try:
|
||||||
number = Motion.objects.aggregate(Max('number')) \
|
number = Motion.objects.aggregate(Max('number'))['number__max'] + 1
|
||||||
['number__max'] + 1
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
number = 1
|
number = 1
|
||||||
self.number = number
|
self.number = number
|
||||||
@ -316,8 +313,6 @@ class Motion(models.Model, SlideMixin):
|
|||||||
"""
|
"""
|
||||||
self.set_status(user, "nop")
|
self.set_status(user, "nop")
|
||||||
#TODO: reject last version
|
#TODO: reject last version
|
||||||
aversion = self.last_version
|
|
||||||
#self.permitted = aversion
|
|
||||||
if self.number is None:
|
if self.number is None:
|
||||||
self.set_number()
|
self.set_number()
|
||||||
self.save()
|
self.save()
|
||||||
@ -333,11 +328,11 @@ class Motion(models.Model, SlideMixin):
|
|||||||
error = False
|
error = False
|
||||||
break
|
break
|
||||||
if error:
|
if error:
|
||||||
#TODO: Use the Right Error
|
# TODO: Use the Right Error
|
||||||
raise NameError(_('%s is not a valid status.') % status)
|
raise NameError(_('%s is not a valid status.') % status)
|
||||||
if self.status == status:
|
if self.status == status:
|
||||||
#TODO: Use the Right Error
|
# TODO: Use the Right Error
|
||||||
raise NameError(_('The motion status is already \'%s.\'') \
|
raise NameError(_('The motion status is already \'%s.\'')
|
||||||
% self.status)
|
% self.status)
|
||||||
|
|
||||||
actions = []
|
actions = []
|
||||||
@ -353,7 +348,7 @@ class Motion(models.Model, SlideMixin):
|
|||||||
oldstatus = self.get_status_display()
|
oldstatus = self.get_status_display()
|
||||||
self.status = status
|
self.status = status
|
||||||
self.save()
|
self.save()
|
||||||
self.writelog(_("Status modified")+": %s -> %s" \
|
self.writelog(_("Status modified") + ": %s -> %s"
|
||||||
% (oldstatus, self.get_status_display()), user)
|
% (oldstatus, self.get_status_display()), user)
|
||||||
|
|
||||||
def get_allowed_actions(self, user):
|
def get_allowed_actions(self, user):
|
||||||
@ -432,10 +427,9 @@ class Motion(models.Model, SlideMixin):
|
|||||||
allready a number
|
allready a number
|
||||||
"""
|
"""
|
||||||
if self.number and not force:
|
if self.number and not force:
|
||||||
raise NameError('The motion has already a number. ' \
|
raise NameError('The motion has already a number. '
|
||||||
'You can not delete it.')
|
'You can not delete it.')
|
||||||
|
|
||||||
|
|
||||||
for item in Item.objects.filter(related_sid=self.sid):
|
for item in Item.objects.filter(related_sid=self.sid):
|
||||||
item.delete()
|
item.delete()
|
||||||
super(Motion, self).delete()
|
super(Motion, self).delete()
|
||||||
@ -501,12 +495,12 @@ class Motion(models.Model, SlideMixin):
|
|||||||
for poll in self.polls:
|
for poll in self.polls:
|
||||||
for option in poll.get_options():
|
for option in poll.get_options():
|
||||||
if option.get_votes().exists():
|
if option.get_votes().exists():
|
||||||
results.append((option['Yes'], option['No'],
|
results.append((
|
||||||
|
option['Yes'], option['No'],
|
||||||
option['Abstain'], poll.print_votesinvalid(),
|
option['Abstain'], poll.print_votesinvalid(),
|
||||||
poll.print_votescast()))
|
poll.print_votescast()))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def slide(self):
|
def slide(self):
|
||||||
"""
|
"""
|
||||||
return the slide dict
|
return the slide dict
|
||||||
@ -542,10 +536,10 @@ class Motion(models.Model, SlideMixin):
|
|||||||
|
|
||||||
|
|
||||||
class AVersion(models.Model):
|
class AVersion(models.Model):
|
||||||
title = models.CharField(max_length=100, verbose_name = _("Title"))
|
title = models.CharField(max_length=100, verbose_name=_("Title"))
|
||||||
text = models.TextField(verbose_name = _("Text"))
|
text = models.TextField(verbose_name=_("Text"))
|
||||||
reason = models.TextField(null=True, blank=True, verbose_name = _("Reason"))
|
reason = models.TextField(null=True, blank=True, verbose_name=_("Reason"))
|
||||||
rejected = models.BooleanField() # = Not Permitted
|
rejected = models.BooleanField() # = Not Permitted
|
||||||
time = models.DateTimeField(auto_now=True)
|
time = models.DateTimeField(auto_now=True)
|
||||||
motion = models.ForeignKey(Motion)
|
motion = models.ForeignKey(Motion)
|
||||||
|
|
||||||
@ -576,8 +570,8 @@ class MotionOption(BaseOption):
|
|||||||
|
|
||||||
class MotionPoll(BasePoll, CountInvalid, CountVotesCast):
|
class MotionPoll(BasePoll, CountInvalid, CountVotesCast):
|
||||||
option_class = MotionOption
|
option_class = MotionOption
|
||||||
vote_values = [ugettext_noop('Yes'), ugettext_noop('No'),
|
vote_values = [
|
||||||
ugettext_noop('Abstain')]
|
ugettext_noop('Yes'), ugettext_noop('No'), ugettext_noop('Abstain')]
|
||||||
|
|
||||||
motion = models.ForeignKey(Motion)
|
motion = models.ForeignKey(Motion)
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
|
||||||
|
|
||||||
from openslides.participant.models import User
|
from openslides.participant.models import User
|
||||||
from openslides.motion.models import Motion, AVersion
|
from openslides.motion.models import Motion
|
||||||
|
|
||||||
|
|
||||||
class MotionTest(TestCase):
|
class MotionTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -39,4 +39,3 @@ class MotionTest(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(self.app1.versions.count(), 2)
|
self.assertEqual(self.app1.versions.count(), 2)
|
||||||
self.assertEqual(self.app1.last_version, self.app1.versions[1])
|
self.assertEqual(self.app1.last_version, self.app1.versions[1])
|
||||||
|
|
||||||
|
@ -18,19 +18,17 @@ import os
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
from urlparse import parse_qs
|
from urlparse import parse_qs
|
||||||
except ImportError: # python <= 2.5
|
except ImportError: # python <= 2.5
|
||||||
from cgi import parse_qs
|
from cgi import parse_qs
|
||||||
|
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
from reportlab.lib.units import cm
|
from reportlab.lib.units import cm
|
||||||
from reportlab.platypus import (SimpleDocTemplate, PageBreak, Paragraph, Spacer,
|
from reportlab.platypus import (
|
||||||
Table, TableStyle)
|
SimpleDocTemplate, PageBreak, Paragraph, Spacer, Table, TableStyle)
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.context_processors import csrf
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
@ -39,26 +37,21 @@ from django.utils.translation import ugettext as _, ungettext
|
|||||||
from openslides.utils import csv_ext
|
from openslides.utils import csv_ext
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.template import Tab
|
from openslides.utils.template import Tab
|
||||||
from openslides.utils.utils import (template, permission_required,
|
from openslides.utils.utils import (
|
||||||
del_confirm_form, gen_confirm_form)
|
template, permission_required, del_confirm_form, gen_confirm_form)
|
||||||
from openslides.utils.views import (PDFView, RedirectView, DeleteView,
|
from openslides.utils.views import (
|
||||||
FormView, SingleObjectMixin, QuestionMixin)
|
PDFView, RedirectView, DeleteView, FormView, SingleObjectMixin,
|
||||||
|
QuestionMixin)
|
||||||
from openslides.utils.person import get_person
|
from openslides.utils.person import get_person
|
||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
|
||||||
from openslides.projector.projector import Widget
|
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 User, Group
|
from openslides.participant.models import User, Group
|
||||||
|
|
||||||
from openslides.agenda.models import Item
|
from openslides.agenda.models import Item
|
||||||
|
|
||||||
from openslides.motion.models import Motion, AVersion, MotionPoll
|
from openslides.motion.models import Motion, AVersion, MotionPoll
|
||||||
from openslides.motion.forms import (MotionForm,
|
from openslides.motion.forms import (
|
||||||
MotionFormTrivialChanges, MotionManagerForm,
|
MotionForm, MotionFormTrivialChanges, MotionManagerForm,
|
||||||
MotionManagerFormSupporter, MotionImportForm, ConfigForm)
|
MotionManagerFormSupporter, MotionImportForm, ConfigForm)
|
||||||
|
|
||||||
|
|
||||||
@ -124,14 +117,14 @@ def overview(request):
|
|||||||
for (i, motion) in enumerate(motions):
|
for (i, motion) in enumerate(motions):
|
||||||
try:
|
try:
|
||||||
motions[i] = {
|
motions[i] = {
|
||||||
'actions' : motion.get_allowed_actions(request.user),
|
'actions': motion.get_allowed_actions(request.user),
|
||||||
'motion' : motion
|
'motion': motion
|
||||||
}
|
}
|
||||||
except:
|
except:
|
||||||
# todo: except what?
|
# todo: except what?
|
||||||
motions[i] = {
|
motions[i] = {
|
||||||
'actions' : [],
|
'actions': [],
|
||||||
'motion' : motion
|
'motion': motion
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -210,12 +203,7 @@ def edit(request, motion_id=None):
|
|||||||
managerform = None
|
managerform = None
|
||||||
|
|
||||||
if valid:
|
if valid:
|
||||||
del_supporters = True
|
|
||||||
if is_manager:
|
if is_manager:
|
||||||
if motion: # Edit motion
|
|
||||||
original_supporters = list(motion.supporters)
|
|
||||||
else:
|
|
||||||
original_supporters = []
|
|
||||||
motion = managerform.save(commit=False)
|
motion = managerform.save(commit=False)
|
||||||
elif motion_id is None:
|
elif motion_id is None:
|
||||||
motion = Motion(submitter=request.user)
|
motion = Motion(submitter=request.user)
|
||||||
@ -611,7 +599,7 @@ def motion_import(request):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if is_group:
|
if is_group:
|
||||||
# fetch existing groups or issue an error message
|
# fetch existing groups or issue an error message
|
||||||
try:
|
try:
|
||||||
@ -694,7 +682,7 @@ def motion_import(request):
|
|||||||
return redirect(reverse('motion_overview'))
|
return redirect(reverse('motion_overview'))
|
||||||
|
|
||||||
except csv.Error:
|
except csv.Error:
|
||||||
message.error(request, _('Import aborted because of severe errors in the input file.'))
|
messages.error(request, _('Import aborted because of severe errors in the input file.'))
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
messages.error(request, _('Import file has wrong character encoding, only UTF-8 is supported!'))
|
messages.error(request, _('Import file has wrong character encoding, only UTF-8 is supported!'))
|
||||||
else:
|
else:
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
from random import choice
|
from random import choice
|
||||||
import string
|
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from openslides.utils import csv_ext
|
from openslides.utils import csv_ext
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ def import_users(csv_file):
|
|||||||
try:
|
try:
|
||||||
(first_name, last_name, gender, structure_level, type, committee, comment) = line[:7]
|
(first_name, last_name, gender, structure_level, type, committee, comment) = line[:7]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
|
error_messages.append(_('Ignoring malformed line %d in import file.') % (line_no + 1))
|
||||||
continue
|
continue
|
||||||
user = User()
|
user = User()
|
||||||
user.last_name = last_name
|
user.last_name = last_name
|
||||||
@ -105,7 +105,7 @@ def get_or_create_registered_group():
|
|||||||
name__iexact='Registered', defaults={'name': 'Registered'})
|
name__iexact='Registered', defaults={'name': 'Registered'})
|
||||||
if created:
|
if created:
|
||||||
registered.permissions = Permission.objects.filter(
|
registered.permissions = Permission.objects.filter(
|
||||||
codename__in=DEFAULT_PERMS)
|
codename__in=DEFAULT_PERMS)
|
||||||
registered.save()
|
registered.save()
|
||||||
return registered
|
return registered
|
||||||
|
|
||||||
@ -115,6 +115,6 @@ def get_or_create_anonymous_group():
|
|||||||
name__iexact='Anonymous', defaults={'name': 'Anonymous'})
|
name__iexact='Anonymous', defaults={'name': 'Anonymous'})
|
||||||
if created:
|
if created:
|
||||||
anonymous.permissions = Permission.objects.filter(
|
anonymous.permissions = Permission.objects.filter(
|
||||||
codename__in=DEFAULT_PERMS)
|
codename__in=DEFAULT_PERMS)
|
||||||
anonymous.save()
|
anonymous.save()
|
||||||
return anonymous
|
return anonymous
|
||||||
|
@ -66,12 +66,13 @@ class GroupForm(forms.ModelForm, CssClassMixin):
|
|||||||
instance = forms.ModelForm.save(self, False)
|
instance = forms.ModelForm.save(self, False)
|
||||||
|
|
||||||
old_save_m2m = self.save_m2m
|
old_save_m2m = self.save_m2m
|
||||||
def save_m2m():
|
|
||||||
old_save_m2m()
|
|
||||||
|
|
||||||
instance.user_set.clear()
|
def save_m2m():
|
||||||
for user in self.cleaned_data['users']:
|
old_save_m2m()
|
||||||
instance.user_set.add(user)
|
|
||||||
|
instance.user_set.clear()
|
||||||
|
for user in self.cleaned_data['users']:
|
||||||
|
instance.user_set.add(user)
|
||||||
self.save_m2m = save_m2m
|
self.save_m2m = save_m2m
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
@ -102,7 +103,7 @@ class GroupForm(forms.ModelForm, CssClassMixin):
|
|||||||
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ('username', 'first_name', 'last_name', 'gender', 'email', 'committee', 'about_me' )
|
fields = ('username', 'first_name', 'last_name', 'gender', 'email', 'committee', 'about_me')
|
||||||
|
|
||||||
|
|
||||||
class UserImportForm(forms.Form, CssClassMixin):
|
class UserImportForm(forms.Form, CssClassMixin):
|
||||||
|
@ -25,8 +25,9 @@ from openslides.config.signals import default_config_value
|
|||||||
from openslides.projector.api import register_slidemodel
|
from openslides.projector.api import register_slidemodel
|
||||||
from openslides.projector.projector import SlideMixin
|
from openslides.projector.projector import SlideMixin
|
||||||
|
|
||||||
|
|
||||||
class User(DjangoUser, PersonMixin, Person, SlideMixin):
|
class User(DjangoUser, PersonMixin, Person, SlideMixin):
|
||||||
prefix = 'user' # This is for the slides
|
prefix = 'user' # This is for the slides
|
||||||
person_prefix = 'user'
|
person_prefix = 'user'
|
||||||
GENDER_CHOICES = (
|
GENDER_CHOICES = (
|
||||||
('male', _('Male')),
|
('male', _('Male')),
|
||||||
@ -131,8 +132,9 @@ class User(DjangoUser, PersonMixin, Person, SlideMixin):
|
|||||||
|
|
||||||
register_slidemodel(User)
|
register_slidemodel(User)
|
||||||
|
|
||||||
|
|
||||||
class Group(DjangoGroup, PersonMixin, Person, SlideMixin):
|
class Group(DjangoGroup, PersonMixin, Person, SlideMixin):
|
||||||
prefix = 'group' # This is for the slides
|
prefix = 'group' # This is for the slides
|
||||||
person_prefix = 'group'
|
person_prefix = 'group'
|
||||||
|
|
||||||
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)
|
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)
|
||||||
@ -173,6 +175,7 @@ class Group(DjangoGroup, PersonMixin, Person, SlideMixin):
|
|||||||
|
|
||||||
register_slidemodel(Group)
|
register_slidemodel(Group)
|
||||||
|
|
||||||
|
|
||||||
class UsersAndGroupsToPersons(object):
|
class UsersAndGroupsToPersons(object):
|
||||||
"""
|
"""
|
||||||
Object to send all Users and Groups or a special User or Group to
|
Object to send all Users and Groups or a special User or Group to
|
||||||
@ -216,8 +219,9 @@ def receive_persons(sender, **kwargs):
|
|||||||
"""
|
"""
|
||||||
Answers to the Person-API
|
Answers to the Person-API
|
||||||
"""
|
"""
|
||||||
return UsersAndGroupsToPersons(person_prefix_filter=kwargs['person_prefix_filter'],
|
return UsersAndGroupsToPersons(
|
||||||
id_filter=kwargs['id_filter'])
|
person_prefix_filter=kwargs['person_prefix_filter'],
|
||||||
|
id_filter=kwargs['id_filter'])
|
||||||
|
|
||||||
|
|
||||||
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
|
||||||
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
|
||||||
@ -38,9 +36,9 @@ class UserTest(TestCase):
|
|||||||
self.assertEqual(unicode(self.user1), 'Max Mustermann')
|
self.assertEqual(unicode(self.user1), 'Max Mustermann')
|
||||||
|
|
||||||
def test_name_suffix(self):
|
def test_name_suffix(self):
|
||||||
self.user1.structure_level = 'München'
|
self.user1.structure_level = u'München'
|
||||||
self.user1.save()
|
self.user1.save()
|
||||||
self.assertEqual(unicode(self.user1), '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.user1.default_password, basestring)
|
self.assertIsInstance(self.user1.default_password, basestring)
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf.urls.defaults import url, patterns
|
from django.conf.urls.defaults import url, patterns
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
from openslides.participant.views import (
|
from openslides.participant.views import (
|
||||||
UserOverview, UserCreateView, UserDetailView, UserUpdateView,
|
UserOverview, UserCreateView, UserDetailView, UserUpdateView,
|
||||||
|
@ -28,7 +28,6 @@ from reportlab.platypus import (
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.forms import PasswordChangeForm
|
from django.contrib.auth.forms import PasswordChangeForm
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.contrib.auth.views import login as django_login
|
from django.contrib.auth.views import login as django_login
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
@ -39,16 +38,12 @@ from openslides.utils.template import Tab
|
|||||||
from openslides.utils.utils import (
|
from openslides.utils.utils import (
|
||||||
template, decodedict, encodedict, delete_default_permissions, html_strong)
|
template, decodedict, encodedict, delete_default_permissions, html_strong)
|
||||||
from openslides.utils.views import (
|
from openslides.utils.views import (
|
||||||
FormView, PDFView, CreateView, UpdateView, DeleteView,
|
FormView, PDFView, CreateView, UpdateView, DeleteView, PermissionMixin,
|
||||||
RedirectView, SingleObjectMixin, ListView, QuestionMixin)
|
RedirectView, SingleObjectMixin, ListView, QuestionMixin, DetailView)
|
||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
|
||||||
from openslides.projector.projector import Widget
|
from openslides.projector.projector import Widget
|
||||||
|
|
||||||
from openslides.motion.models import Motion
|
from openslides.motion.models import Motion
|
||||||
from openslides.assignment.models import Assignment
|
from openslides.assignment.models import Assignment
|
||||||
|
|
||||||
from openslides.participant.api import gen_username, gen_password, import_users
|
from openslides.participant.api import gen_username, gen_password, import_users
|
||||||
from openslides.participant.forms import (
|
from openslides.participant.forms import (
|
||||||
UserCreateForm, UserUpdateForm, UsersettingsForm,
|
UserCreateForm, UserUpdateForm, UsersettingsForm,
|
||||||
@ -125,11 +120,13 @@ class UserOverview(ListView):
|
|||||||
percent = 0
|
percent = 0
|
||||||
|
|
||||||
# list of all existing categories
|
# list of all existing categories
|
||||||
structure_levels = [p['structure_level'] for p in User.objects.values('structure_level')
|
structure_levels = [
|
||||||
.exclude(structure_level='').distinct()]
|
p['structure_level'] for p in
|
||||||
|
User.objects.values('structure_level').exclude(structure_level='').distinct()]
|
||||||
# list of all existing committees
|
# list of all existing committees
|
||||||
committees = [p['committee'] for p in User.objects.values('committee')
|
committees = [
|
||||||
.exclude(committee='').distinct()]
|
p['committee'] for p in
|
||||||
|
User.objects.values('committee').exclude(committee='').distinct()]
|
||||||
# context vars
|
# context vars
|
||||||
context.update({
|
context.update({
|
||||||
'allusers': all_users,
|
'allusers': all_users,
|
||||||
@ -137,13 +134,13 @@ class UserOverview(ListView):
|
|||||||
'percent': round(percent, 1),
|
'percent': round(percent, 1),
|
||||||
'structure_levels': structure_levels,
|
'structure_levels': structure_levels,
|
||||||
'committees': committees,
|
'committees': committees,
|
||||||
'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
|
'cookie': [
|
||||||
|
'participant_sortfilter', urlencode(decodedict(self.sortfilter),
|
||||||
doseq=True)],
|
doseq=True)],
|
||||||
'sortfilter': self.sortfilter})
|
'sortfilter': self.sortfilter})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
from openslides.utils.views import DetailView, PermissionMixin
|
|
||||||
class UserDetailView(DetailView, PermissionMixin):
|
class UserDetailView(DetailView, PermissionMixin):
|
||||||
"""
|
"""
|
||||||
Classed based view to show a specific user in the interface.
|
Classed based view to show a specific user in the interface.
|
||||||
@ -177,8 +174,8 @@ class UserCreateView(CreateView):
|
|||||||
apply_url = 'user_edit'
|
apply_url = 'user_edit'
|
||||||
|
|
||||||
def manipulate_object(self, form):
|
def manipulate_object(self, form):
|
||||||
self.object.username = gen_username(form.cleaned_data['first_name'],
|
self.object.username = gen_username(
|
||||||
form.cleaned_data['last_name'])
|
form.cleaned_data['first_name'], form.cleaned_data['last_name'])
|
||||||
if not self.object.default_password:
|
if not self.object.default_password:
|
||||||
self.object.default_password = gen_password()
|
self.object.default_password = gen_password()
|
||||||
self.object.set_password(self.object.default_password)
|
self.object.set_password(self.object.default_password)
|
||||||
@ -211,6 +208,7 @@ class UserDeleteView(DeleteView):
|
|||||||
else:
|
else:
|
||||||
super(UserDeleteView, self).pre_redirect(request, *args, **kwargs)
|
super(UserDeleteView, self).pre_redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SetUserStatusView(RedirectView, SingleObjectMixin):
|
class SetUserStatusView(RedirectView, SingleObjectMixin):
|
||||||
"""
|
"""
|
||||||
Activate or deactivate an user.
|
Activate or deactivate an user.
|
||||||
@ -547,8 +545,9 @@ def register_tab(request):
|
|||||||
return Tab(
|
return Tab(
|
||||||
title=_('Participants'),
|
title=_('Participants'),
|
||||||
url=reverse('user_overview'),
|
url=reverse('user_overview'),
|
||||||
permission=request.user.has_perm('participant.can_see_participant') or
|
permission=(
|
||||||
request.user.has_perm('participant.can_manage_participant'),
|
request.user.has_perm('participant.can_see_participant') or
|
||||||
|
request.user.has_perm('participant.can_manage_participant')),
|
||||||
selected=selected)
|
selected=selected)
|
||||||
|
|
||||||
|
|
||||||
@ -569,12 +568,12 @@ def get_personal_info_widget(request):
|
|||||||
and where you are supporter or candidate.
|
and where you are supporter or candidate.
|
||||||
"""
|
"""
|
||||||
personal_info_context = {
|
personal_info_context = {
|
||||||
'submitted_motions': Motion.objects.filter(submitter=request.user),
|
'submitted_motions': Motion.objects.filter(submitter=request.user),
|
||||||
'config_motion_min_supporters': config['motion_min_supporters'],
|
'config_motion_min_supporters': config['motion_min_supporters'],
|
||||||
'supported_motions': Motion.objects.filter(motionsupporter=request.user),
|
'supported_motions': Motion.objects.filter(motionsupporter=request.user),
|
||||||
'assignments': Assignment.objects.filter(
|
'assignments': Assignment.objects.filter(
|
||||||
assignmentcandidate__person=request.user,
|
assignmentcandidate__person=request.user,
|
||||||
assignmentcandidate__blocked=False),}
|
assignmentcandidate__blocked=False)}
|
||||||
return Widget(
|
return Widget(
|
||||||
name='personal_info',
|
name='personal_info',
|
||||||
display_name=_('My motions and elections'),
|
display_name=_('My motions and elections'),
|
||||||
@ -593,7 +592,7 @@ def get_user_widget(request):
|
|||||||
name='user',
|
name='user',
|
||||||
display_name=_('Participants'),
|
display_name=_('Participants'),
|
||||||
template='participant/user_widget.html',
|
template='participant/user_widget.html',
|
||||||
context={'users': User.objects.all(),},
|
context={'users': User.objects.all()},
|
||||||
permission_required='projector.can_manage_projector',
|
permission_required='projector.can_manage_projector',
|
||||||
default_column=1)
|
default_column=1)
|
||||||
|
|
||||||
@ -607,6 +606,6 @@ def get_group_widget(request):
|
|||||||
name='group',
|
name='group',
|
||||||
display_name=_('Groups'),
|
display_name=_('Groups'),
|
||||||
template='participant/group_widget.html',
|
template='participant/group_widget.html',
|
||||||
context={'groups': Group.objects.all(),},
|
context={'groups': Group.objects.all()},
|
||||||
permission_required='projector.can_manage_projector',
|
permission_required='projector.can_manage_projector',
|
||||||
default_column=1)
|
default_column=1)
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from openslides.utils.forms import CssClassMixin
|
from openslides.utils.forms import CssClassMixin
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class BaseVote(models.Model):
|
|||||||
Subclasses have to define a option-field, which are a subclass of
|
Subclasses have to define a option-field, which are a subclass of
|
||||||
BaseOption.
|
BaseOption.
|
||||||
"""
|
"""
|
||||||
weight = models.IntegerField(default=1, null=True) # Use MinMaxIntegerField
|
weight = models.IntegerField(default=1, null=True) # Use MinMaxIntegerField
|
||||||
value = models.CharField(max_length=255, null=True)
|
value = models.CharField(max_length=255, null=True)
|
||||||
|
|
||||||
def print_weight(self, raw=False):
|
def print_weight(self, raw=False):
|
||||||
@ -73,7 +73,7 @@ class BaseVote(models.Model):
|
|||||||
|
|
||||||
class CountVotesCast(models.Model):
|
class CountVotesCast(models.Model):
|
||||||
votescast = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
votescast = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
||||||
verbose_name=_("Votes cast"))
|
verbose_name=_("Votes cast"))
|
||||||
|
|
||||||
def append_pollform_fields(self, fields):
|
def append_pollform_fields(self, fields):
|
||||||
fields.append('votescast')
|
fields.append('votescast')
|
||||||
@ -92,7 +92,7 @@ class CountVotesCast(models.Model):
|
|||||||
|
|
||||||
class CountInvalid(models.Model):
|
class CountInvalid(models.Model):
|
||||||
votesinvalid = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
votesinvalid = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
||||||
verbose_name=_("Votes invalid"))
|
verbose_name=_("Votes invalid"))
|
||||||
|
|
||||||
def append_pollform_fields(self, fields):
|
def append_pollform_fields(self, fields):
|
||||||
fields.append('votesinvalid')
|
fields.append('votesinvalid')
|
||||||
@ -164,7 +164,6 @@ class BasePoll(models.Model):
|
|||||||
"""
|
"""
|
||||||
return self.vote_values
|
return self.vote_values
|
||||||
|
|
||||||
|
|
||||||
def get_vote_class(self):
|
def get_vote_class(self):
|
||||||
"""
|
"""
|
||||||
Return the releatet vote class.
|
Return the releatet vote class.
|
||||||
@ -212,7 +211,7 @@ class BasePoll(models.Model):
|
|||||||
"""
|
"""
|
||||||
from openslides.poll.forms import OptionForm
|
from openslides.poll.forms import OptionForm
|
||||||
return OptionForm(extra=self.get_form_values(kwargs['formid']),
|
return OptionForm(extra=self.get_form_values(kwargs['formid']),
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def get_vote_forms(self, **kwargs):
|
def get_vote_forms(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -35,7 +35,7 @@ class PollFormView(TemplateView):
|
|||||||
context['forms'] = self.poll.get_vote_forms()
|
context['forms'] = self.poll.get_vote_forms()
|
||||||
FormClass = self.get_modelform_class()
|
FormClass = self.get_modelform_class()
|
||||||
context['pollform'] = FormClass(instance=self.poll,
|
context['pollform'] = FormClass(instance=self.poll,
|
||||||
prefix='pollform')
|
prefix='pollform')
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@ -52,7 +52,7 @@ class PollFormView(TemplateView):
|
|||||||
|
|
||||||
FormClass = self.get_modelform_class()
|
FormClass = self.get_modelform_class()
|
||||||
pollform = FormClass(data=self.request.POST, instance=self.poll,
|
pollform = FormClass(data=self.request.POST, instance=self.poll,
|
||||||
prefix='pollform')
|
prefix='pollform')
|
||||||
|
|
||||||
error = False
|
error = False
|
||||||
for form in option_forms:
|
for form in option_forms:
|
||||||
|
@ -12,12 +12,11 @@
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.template.loader import render_to_string
|
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
from openslides.projector.projector import SLIDE, Slide, Widget
|
from openslides.projector.projector import SLIDE, Slide
|
||||||
|
|
||||||
|
|
||||||
def split_sid(sid):
|
def split_sid(sid):
|
||||||
@ -95,27 +94,18 @@ def clear_projector_cache():
|
|||||||
cache.delete('projector_data')
|
cache.delete('projector_data')
|
||||||
|
|
||||||
|
|
||||||
def register_slidemodel(model, model_name=None, control_template=None,
|
def register_slidemodel(model, model_name=None, control_template=None, weight=0):
|
||||||
weight=0):
|
|
||||||
"""
|
"""
|
||||||
Register a Model as a slide.
|
Register a Model as a slide.
|
||||||
"""
|
"""
|
||||||
|
# TODO: control_template should never be None
|
||||||
if model_name is None:
|
if model_name is None:
|
||||||
model_name = model.prefix
|
model_name = model.prefix
|
||||||
|
|
||||||
if control_template is None:
|
|
||||||
control_template = 'projector/default_control_slidemodel.html'
|
|
||||||
|
|
||||||
category = model.__module__.split('.')[0]
|
category = model.__module__.split('.')[0]
|
||||||
SLIDE[model_name] = Slide(
|
SLIDE[model_name] = Slide(model_slide=True, model=model, category=category,
|
||||||
model_slide=True,
|
key=model.prefix, model_name=model_name,
|
||||||
model=model,
|
control_template=control_template, weight=weight)
|
||||||
category=category,
|
|
||||||
key=model.prefix,
|
|
||||||
model_name=model_name,
|
|
||||||
control_template=control_template,
|
|
||||||
weight=weight,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def register_slidefunc(key, func, control_template=None, weight=0, name=''):
|
def register_slidefunc(key, func, control_template=None, weight=0, name=''):
|
||||||
@ -125,15 +115,9 @@ def register_slidefunc(key, func, control_template=None, weight=0, name=''):
|
|||||||
if control_template is None:
|
if control_template is None:
|
||||||
control_template = 'projector/default_control_slidefunc.html'
|
control_template = 'projector/default_control_slidefunc.html'
|
||||||
category = func.__module__.split('.')[0]
|
category = func.__module__.split('.')[0]
|
||||||
SLIDE[key] = Slide(
|
SLIDE[key] = Slide(model_slide=False, func=func, category=category,
|
||||||
model_slide=False,
|
key=key, control_template=control_template, weight=weight,
|
||||||
func=func,
|
name=name,)
|
||||||
category=category,
|
|
||||||
key=key,
|
|
||||||
control_template=control_template,
|
|
||||||
weight=weight,
|
|
||||||
name=name,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def projector_message_set(message, sid=None):
|
def projector_message_set(message, sid=None):
|
||||||
@ -147,7 +131,7 @@ def projector_message_set(message, sid=None):
|
|||||||
overlay = ProjectorOverlay.objects.get(def_name='Message')
|
overlay = ProjectorOverlay.objects.get(def_name='Message')
|
||||||
except ProjectorOverlay.DoesNotExist:
|
except ProjectorOverlay.DoesNotExist:
|
||||||
overlay = ProjectorOverlay(def_name='Message', active=False)
|
overlay = ProjectorOverlay(def_name='Message', active=False)
|
||||||
overlay.sid=sid
|
overlay.sid = sid
|
||||||
overlay.save()
|
overlay.save()
|
||||||
|
|
||||||
|
|
||||||
@ -166,7 +150,6 @@ def get_all_widgets(request, session=False):
|
|||||||
mod = import_module(app + '.views')
|
mod = import_module(app + '.views')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
continue
|
continue
|
||||||
appname = mod.__name__.split('.')[0]
|
|
||||||
try:
|
try:
|
||||||
modul_widgets = mod.get_widgets(request)
|
modul_widgets = mod.get_widgets(request)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from openslides.utils.forms import CssClassMixin
|
from openslides.utils.forms import CssClassMixin
|
||||||
|
|
||||||
|
@ -19,9 +19,6 @@ from openslides.config.signals import default_config_value
|
|||||||
from openslides.projector.api import register_slidemodel
|
from openslides.projector.api import register_slidemodel
|
||||||
from openslides.projector.projector import SlideMixin
|
from openslides.projector.projector import SlideMixin
|
||||||
|
|
||||||
from openslides.config.models import config
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectorSlide(models.Model, SlideMixin):
|
class ProjectorSlide(models.Model, SlideMixin):
|
||||||
"""
|
"""
|
||||||
@ -56,8 +53,7 @@ class ProjectorSlide(models.Model, SlideMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
register_slidemodel(ProjectorSlide,
|
register_slidemodel(ProjectorSlide, control_template='projector/control_customslide.html')
|
||||||
control_template='projector/control_customslide.html')
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectorOverlay(models.Model):
|
class ProjectorOverlay(models.Model):
|
||||||
|
@ -19,9 +19,9 @@ from openslides.config.models import config
|
|||||||
|
|
||||||
from openslides.projector.signals import projector_overlays
|
from openslides.projector.signals import projector_overlays
|
||||||
|
|
||||||
|
|
||||||
SLIDE = {}
|
SLIDE = {}
|
||||||
|
|
||||||
|
|
||||||
class SlideMixin(object):
|
class SlideMixin(object):
|
||||||
"""
|
"""
|
||||||
A Mixin for a Django-Model, for making the model a slide.
|
A Mixin for a Django-Model, for making the model a slide.
|
||||||
@ -49,13 +49,14 @@ class SlideMixin(object):
|
|||||||
"""
|
"""
|
||||||
Return True, if the the slide is the active slide.
|
Return True, if the the slide is the active slide.
|
||||||
"""
|
"""
|
||||||
from api import get_active_slide
|
from openslides.projector.api import get_active_slide
|
||||||
return get_active_slide(only_sid=True) == self.sid
|
return get_active_slide(only_sid=True) == self.sid
|
||||||
|
|
||||||
def set_active(self):
|
def set_active(self):
|
||||||
"""
|
"""
|
||||||
Appoint this item as the active slide.
|
Appoint this item as the active slide.
|
||||||
"""
|
"""
|
||||||
|
from openslides.projector.api import set_active_slide
|
||||||
set_active_slide(self.sid)
|
set_active_slide(self.sid)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
@ -112,7 +113,7 @@ class Widget(object):
|
|||||||
Class for a Widget for the Projector-Tab.
|
Class for a Widget for the Projector-Tab.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, html=None, template=None, context={},
|
def __init__(self, name, html=None, template=None, context={},
|
||||||
permission_required=None, display_name=None, default_column=1):
|
permission_required=None, display_name=None, default_column=1):
|
||||||
self.name = name
|
self.name = name
|
||||||
if display_name is None:
|
if display_name is None:
|
||||||
self.display_name = name.capitalize()
|
self.display_name = name.capitalize()
|
||||||
|
@ -13,34 +13,28 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.context_processors import csrf
|
from django.core.context_processors import csrf
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.dispatch import receiver
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.utils.datastructures import SortedDict
|
|
||||||
from django.utils.importlib import import_module
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openslides.utils.template import render_block_to_string, Tab
|
from openslides.utils.template import render_block_to_string, Tab
|
||||||
from openslides.utils.utils import html_strong
|
from openslides.utils.views import (
|
||||||
from openslides.utils.views import (TemplateView, RedirectView, CreateView,
|
TemplateView, RedirectView, CreateView, UpdateView, DeleteView, AjaxMixin)
|
||||||
UpdateView, DeleteView, AjaxMixin)
|
|
||||||
|
|
||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
from .api import (
|
||||||
from openslides.projector.api import (get_active_slide, set_active_slide,
|
get_active_slide, set_active_slide, projector_message_set,
|
||||||
projector_message_set, projector_message_delete, get_slide_from_sid,
|
projector_message_delete, get_slide_from_sid, get_all_widgets,
|
||||||
get_all_widgets, clear_projector_cache)
|
clear_projector_cache)
|
||||||
from openslides.projector.forms import SelectWidgetsForm
|
from .forms import SelectWidgetsForm
|
||||||
from openslides.projector.models import ProjectorOverlay, ProjectorSlide
|
from .models import ProjectorOverlay, ProjectorSlide
|
||||||
from openslides.projector.projector import SLIDE, Widget
|
from .projector import Widget
|
||||||
from openslides.projector.signals import projector_overlays
|
from .signals import projector_overlays
|
||||||
|
|
||||||
|
|
||||||
class DashboardView(TemplateView, AjaxMixin):
|
class DashboardView(TemplateView, AjaxMixin):
|
||||||
@ -73,7 +67,7 @@ class Projector(TemplateView, AjaxMixin):
|
|||||||
if sid is None:
|
if sid is None:
|
||||||
try:
|
try:
|
||||||
data = get_active_slide()
|
data = get_active_slide()
|
||||||
except AttributeError: #TODO: It has to be an Slide.DoesNotExist
|
except AttributeError: # TODO: It has to be an Slide.DoesNotExist
|
||||||
data = None
|
data = None
|
||||||
ajax = 'on'
|
ajax = 'on'
|
||||||
active_sid = get_active_slide(True)
|
active_sid = get_active_slide(True)
|
||||||
@ -92,10 +86,10 @@ class Projector(TemplateView, AjaxMixin):
|
|||||||
# Projector Overlays
|
# Projector Overlays
|
||||||
if self.kwargs['sid'] is None:
|
if self.kwargs['sid'] is None:
|
||||||
active_defs = ProjectorOverlay.objects.filter(active=True) \
|
active_defs = ProjectorOverlay.objects.filter(active=True) \
|
||||||
.filter(Q(sid=active_sid) | Q(sid=None)).values_list('def_name',
|
.filter(Q(sid=active_sid) | Q(sid=None)).values_list(
|
||||||
flat=True)
|
'def_name', flat=True)
|
||||||
for receiver, response in projector_overlays.send(sender=sid,
|
for receiver, response in projector_overlays.send(
|
||||||
register=False, call=active_defs):
|
sender=sid, register=False, call=active_defs):
|
||||||
if response is not None:
|
if response is not None:
|
||||||
data['overlays'].append(response)
|
data['overlays'].append(response)
|
||||||
self._data = data
|
self._data = data
|
||||||
@ -124,7 +118,6 @@ class Projector(TemplateView, AjaxMixin):
|
|||||||
'scrollcontent', self.data)
|
'scrollcontent', self.data)
|
||||||
cache.set('projector_scrollcontent', scrollcontent, 1)
|
cache.set('projector_scrollcontent', scrollcontent, 1)
|
||||||
|
|
||||||
|
|
||||||
# TODO: do not call the hole data-methode, if we only need some vars
|
# TODO: do not call the hole data-methode, if we only need some vars
|
||||||
data = cache.get('projector_data')
|
data = cache.get('projector_data')
|
||||||
if not data:
|
if not data:
|
||||||
@ -301,7 +294,6 @@ class OverlayMessageView(RedirectView):
|
|||||||
elif 'message-clean' in request.POST:
|
elif 'message-clean' in request.POST:
|
||||||
projector_message_delete()
|
projector_message_delete()
|
||||||
|
|
||||||
|
|
||||||
def get_ajax_context(self, **kwargs):
|
def get_ajax_context(self, **kwargs):
|
||||||
clear_projector_cache()
|
clear_projector_cache()
|
||||||
return {
|
return {
|
||||||
@ -309,7 +301,6 @@ class OverlayMessageView(RedirectView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ActivateOverlay(RedirectView):
|
class ActivateOverlay(RedirectView):
|
||||||
"""
|
"""
|
||||||
Activate or deactivate an overlay.
|
Activate or deactivate an overlay.
|
||||||
@ -379,12 +370,11 @@ def register_tab(request):
|
|||||||
"""
|
"""
|
||||||
Register the projector tab.
|
Register the projector tab.
|
||||||
"""
|
"""
|
||||||
selected = True if request.path.startswith('/projector/') else False
|
selected = request.path.startswith('/projector/')
|
||||||
return Tab(
|
return Tab(
|
||||||
title=_('Dashboard'),
|
title=_('Dashboard'),
|
||||||
url=reverse('dashboard'),
|
url=reverse('dashboard'),
|
||||||
permission=request.user.has_perm('projector.can_manage_projector') or
|
permission=request.user.has_perm('projector.can_see_dashboard'),
|
||||||
request.user.has_perm('projector.can_see_dashboard'),
|
|
||||||
selected=selected,
|
selected=selected,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -411,7 +401,7 @@ def get_widgets(request):
|
|||||||
name='live_view',
|
name='live_view',
|
||||||
display_name=_('Projector live view'),
|
display_name=_('Projector live view'),
|
||||||
template='projector/live_view_widget.html',
|
template='projector/live_view_widget.html',
|
||||||
context = RequestContext(request, {}),
|
context=RequestContext(request, {}),
|
||||||
permission_required='projector.can_see_projector',
|
permission_required='projector.can_see_projector',
|
||||||
default_column=2))
|
default_column=2))
|
||||||
|
|
||||||
@ -424,15 +414,14 @@ def get_widgets(request):
|
|||||||
projector_overlay = ProjectorOverlay.objects.get(
|
projector_overlay = ProjectorOverlay.objects.get(
|
||||||
def_name=name)
|
def_name=name)
|
||||||
except ProjectorOverlay.DoesNotExist:
|
except ProjectorOverlay.DoesNotExist:
|
||||||
projector_overlay = ProjectorOverlay(def_name=name,
|
projector_overlay = ProjectorOverlay(def_name=name, active=False)
|
||||||
active=False)
|
|
||||||
projector_overlay.save()
|
projector_overlay.save()
|
||||||
overlays.append(projector_overlay)
|
overlays.append(projector_overlay)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'overlays':overlays,
|
'overlays': overlays,
|
||||||
'countdown_time': config['countdown_time'],
|
'countdown_time': config['countdown_time'],
|
||||||
'countdown_state' : config['countdown_state']}
|
'countdown_state': config['countdown_state']}
|
||||||
context.update(csrf(request))
|
context.update(csrf(request))
|
||||||
widgets.append(Widget(
|
widgets.append(Widget(
|
||||||
name='overlays',
|
name='overlays',
|
||||||
@ -442,7 +431,6 @@ def get_widgets(request):
|
|||||||
default_column=2,
|
default_column=2,
|
||||||
context=context))
|
context=context))
|
||||||
|
|
||||||
|
|
||||||
# Custom slide widget
|
# Custom slide widget
|
||||||
context = {
|
context = {
|
||||||
'slides': ProjectorSlide.objects.all().order_by('weight'),
|
'slides': ProjectorSlide.objects.all().order_by('weight'),
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.defaults import patterns, url, include
|
from django.conf.urls.defaults import patterns, url, include
|
||||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
|
||||||
from django.shortcuts import redirect
|
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
from openslides.utils.views import RedirectView
|
from openslides.utils.views import RedirectView
|
||||||
@ -34,7 +32,7 @@ urlpatterns = patterns('',
|
|||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns += patterns('django.contrib.staticfiles.views',
|
urlpatterns += patterns('django.contrib.staticfiles.views',
|
||||||
url(r'^static/(?P<path>.*)$', 'serve', {'insecure':True}),
|
url(r'^static/(?P<path>.*)$', 'serve', {'insecure': True}),
|
||||||
)
|
)
|
||||||
|
|
||||||
js_info_dict = {
|
js_info_dict = {
|
||||||
|
@ -37,8 +37,8 @@ class AnonymousAuth(object):
|
|||||||
|
|
||||||
- try to return the permissions for the 'Anonymous' group
|
- try to return the permissions for the 'Anonymous' group
|
||||||
"""
|
"""
|
||||||
if not user_obj.is_anonymous() or obj is not None or \
|
if (not user_obj.is_anonymous() or obj is not None or
|
||||||
not config['system_enable_anonymous']:
|
not config['system_enable_anonymous']):
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
perms = Permission.objects.filter(group__name='Anonymous')
|
perms = Permission.objects.filter(group__name='Anonymous')
|
||||||
@ -60,8 +60,8 @@ class AnonymousAuth(object):
|
|||||||
"""
|
"""
|
||||||
Check if the user as a specific permission
|
Check if the user as a specific permission
|
||||||
"""
|
"""
|
||||||
if not user_obj.is_anonymous() or obj is not None or \
|
if (not user_obj.is_anonymous() or obj is not None or
|
||||||
not config['system_enable_anonymous']:
|
not config['system_enable_anonymous']):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return (perm in self.get_all_permissions(user_obj))
|
return (perm in self.get_all_permissions(user_obj))
|
||||||
@ -70,8 +70,8 @@ class AnonymousAuth(object):
|
|||||||
"""
|
"""
|
||||||
Check if the user has permissions on the module app_label
|
Check if the user has permissions on the module app_label
|
||||||
"""
|
"""
|
||||||
if not user_obj.is_anonymous() or \
|
if (not user_obj.is_anonymous() or
|
||||||
not config['system_enable_anonymous']:
|
not config['system_enable_anonymous']):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for perm in self.get_all_permissions(user_obj):
|
for perm in self.get_all_permissions(user_obj):
|
||||||
@ -87,10 +87,10 @@ class AnonymousAuth(object):
|
|||||||
"""
|
"""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def anonymous_context_additions(RequestContext):
|
def anonymous_context_additions(RequestContext):
|
||||||
"""
|
"""
|
||||||
Add a variable to the request context that will indicate
|
Add a variable to the request context that will indicate
|
||||||
if anonymous login is possible at all.
|
if anonymous login is possible at all.
|
||||||
"""
|
"""
|
||||||
return {'os_enable_anonymous_login' : config['system_enable_anonymous']}
|
return {'os_enable_anonymous_login': config['system_enable_anonymous']}
|
||||||
|
|
||||||
|
@ -25,10 +25,9 @@ class excel_semikolon(Dialect):
|
|||||||
def patchup(dialect):
|
def patchup(dialect):
|
||||||
if dialect:
|
if dialect:
|
||||||
if dialect.delimiter in [excel_semikolon.delimiter, excel.delimiter] and \
|
if dialect.delimiter in [excel_semikolon.delimiter, excel.delimiter] and \
|
||||||
dialect.quotechar == excel_semikolon.quotechar:
|
dialect.quotechar == excel_semikolon.quotechar:
|
||||||
# walks like a duck and talks like a duck.. must be one
|
# walks like a duck and talks like a duck.. must be one
|
||||||
dialect.doublequote = True
|
dialect.doublequote = True
|
||||||
return dialect
|
return dialect
|
||||||
|
|
||||||
register_dialect("excel_semikolon", excel_semikolon)
|
register_dialect("excel_semikolon", excel_semikolon)
|
||||||
|
|
||||||
|
@ -1 +1,3 @@
|
|||||||
from fields import JSONField
|
from fields import JSONField
|
||||||
|
|
||||||
|
__all__ = ['JSONField']
|
||||||
|
@ -6,6 +6,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from django.forms.fields import Field
|
from django.forms.fields import Field
|
||||||
from django.forms.util import ValidationError as FormValidationError
|
from django.forms.util import ValidationError as FormValidationError
|
||||||
|
|
||||||
|
|
||||||
class JSONFormField(Field):
|
class JSONFormField(Field):
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ class JSONFormField(Field):
|
|||||||
raise FormValidationError(_("Enter valid JSON"))
|
raise FormValidationError(_("Enter valid JSON"))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class JSONField(models.TextField):
|
class JSONField(models.TextField):
|
||||||
"""JSONField is a generic textfield that serializes/unserializes JSON objects"""
|
"""JSONField is a generic textfield that serializes/unserializes JSON objects"""
|
||||||
|
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class MinMaxIntegerField(models.IntegerField):
|
class MinMaxIntegerField(models.IntegerField):
|
||||||
def __init__(self, min_value=None, max_value=None, *args, **kwargs):
|
def __init__(self, min_value=None, max_value=None, *args, **kwargs):
|
||||||
self.min_value, self.max_value = min_value, max_value
|
self.min_value, self.max_value = min_value, max_value
|
||||||
super(MinMaxIntegerField, self).__init__(*args, **kwargs)
|
super(MinMaxIntegerField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'min_value': self.min_value, 'max_value' : self.max_value}
|
defaults = {'min_value': self.min_value, 'max_value': self.max_value}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(MinMaxIntegerField, self).formfield(**defaults)
|
return super(MinMaxIntegerField, self).formfield(**defaults)
|
||||||
|
@ -28,16 +28,16 @@ from openslides.config.models import config
|
|||||||
|
|
||||||
|
|
||||||
# register new truetype fonts
|
# register new truetype fonts
|
||||||
pdfmetrics.registerFont(TTFont('Ubuntu', path_join(settings.SITE_ROOT,
|
pdfmetrics.registerFont(TTFont(
|
||||||
'static/fonts/Ubuntu-R.ttf')))
|
'Ubuntu', path_join(settings.SITE_ROOT, 'static/fonts/Ubuntu-R.ttf')))
|
||||||
pdfmetrics.registerFont(TTFont('Ubuntu-Bold', path_join(settings.SITE_ROOT,
|
pdfmetrics.registerFont(TTFont(
|
||||||
'static/fonts/Ubuntu-B.ttf')))
|
'Ubuntu-Bold', path_join(settings.SITE_ROOT, 'static/fonts/Ubuntu-B.ttf')))
|
||||||
pdfmetrics.registerFont(TTFont('Ubuntu-Italic', path_join(settings.SITE_ROOT,
|
pdfmetrics.registerFont(TTFont(
|
||||||
'static/fonts/Ubuntu-RI.ttf')))
|
'Ubuntu-Italic', path_join(settings.SITE_ROOT, 'static/fonts/Ubuntu-RI.ttf')))
|
||||||
|
|
||||||
|
|
||||||
# set style information
|
# set style information
|
||||||
PAGE_HEIGHT = defaultPageSize[1];
|
PAGE_HEIGHT = defaultPageSize[1]
|
||||||
PAGE_WIDTH = defaultPageSize[0]
|
PAGE_WIDTH = defaultPageSize[0]
|
||||||
|
|
||||||
|
|
||||||
@ -105,17 +105,17 @@ stylesheet.add(ParagraphStyle(
|
|||||||
leftIndent=0,
|
leftIndent=0,
|
||||||
spaceAfter=15,
|
spaceAfter=15,
|
||||||
))
|
))
|
||||||
stylesheet.add(ParagraphStyle(name = 'Subitem',
|
stylesheet.add(ParagraphStyle(
|
||||||
parent = stylesheet['Normal'],
|
name='Subitem',
|
||||||
fontSize = 10,
|
parent=stylesheet['Normal'],
|
||||||
leading = 10,
|
fontSize=10,
|
||||||
leftIndent = 20,
|
leading=10,
|
||||||
spaceAfter = 15)
|
leftIndent=20,
|
||||||
)
|
spaceAfter=15))
|
||||||
stylesheet.add(ParagraphStyle(name = 'Tablecell',
|
stylesheet.add(ParagraphStyle(
|
||||||
parent = stylesheet['Normal'],
|
name='Tablecell',
|
||||||
fontSize = 9)
|
parent=stylesheet['Normal'],
|
||||||
)
|
fontSize=9))
|
||||||
stylesheet.add(ParagraphStyle(name = 'Signaturefield',
|
stylesheet.add(ParagraphStyle(name = 'Signaturefield',
|
||||||
parent = stylesheet['Normal'],
|
parent = stylesheet['Normal'],
|
||||||
spaceBefore = 15)
|
spaceBefore = 15)
|
||||||
|
@ -11,11 +11,15 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from openslides.utils.person.signals import receive_persons
|
from openslides.utils.person.signals import receive_persons
|
||||||
from openslides.utils.person.api import (generate_person_id, get_person,
|
from openslides.utils.person.api import (
|
||||||
Person, Persons)
|
generate_person_id, get_person, 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
|
||||||
|
|
||||||
|
__all__ = ['receive_persons', 'generate_person_id', 'get_person', 'Person',
|
||||||
|
'Persons', 'PersonFormField', 'MultiplePersonFormField',
|
||||||
|
'PersonField', 'PersonMixin', 'EmptyPerson']
|
||||||
|
|
||||||
|
|
||||||
class EmptyPerson(PersonMixin):
|
class EmptyPerson(PersonMixin):
|
||||||
@property
|
@property
|
||||||
|
@ -61,8 +61,8 @@ class MultiplePersonFormField(PersonFormField):
|
|||||||
widget = forms.widgets.SelectMultiple
|
widget = forms.widgets.SelectMultiple
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(MultiplePersonFormField, self).__init__(empty_label=None,
|
super(MultiplePersonFormField, self).__init__(
|
||||||
*args, **kwargs)
|
empty_label=None, *args, **kwargs)
|
||||||
|
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
if hasattr(value, '__iter__'):
|
if hasattr(value, '__iter__'):
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.http import HttpResponse
|
from django.template import loader, Context
|
||||||
from django.template import loader, Context, RequestContext, TextNode
|
|
||||||
from django.template.loader_tags import BlockNode, ExtendsNode
|
from django.template.loader_tags import BlockNode, ExtendsNode
|
||||||
|
|
||||||
|
|
||||||
@ -53,22 +52,22 @@ def render_template_block_nodelist(nodelist, block, context):
|
|||||||
for key in ('nodelist', 'nodelist_true', 'nodelist_false'):
|
for key in ('nodelist', 'nodelist_true', 'nodelist_false'):
|
||||||
if hasattr(node, key):
|
if hasattr(node, key):
|
||||||
try:
|
try:
|
||||||
return render_template_block_nodelist(getattr(node, key),
|
return render_template_block_nodelist(
|
||||||
block, context)
|
getattr(node, key), block, context)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
for node in nodelist:
|
for node in nodelist:
|
||||||
if isinstance(node, ExtendsNode):
|
if isinstance(node, ExtendsNode):
|
||||||
try:
|
try:
|
||||||
return render_template_block(node.get_parent(context), block,
|
return render_template_block(
|
||||||
context)
|
node.get_parent(context), block, context)
|
||||||
except BlockNotFound:
|
except BlockNotFound:
|
||||||
pass
|
pass
|
||||||
raise BlockNotFound
|
raise BlockNotFound
|
||||||
|
|
||||||
|
|
||||||
def render_block_to_string(template_name, block, dictionary=None,
|
def render_block_to_string(template_name, block, dictionary=None,
|
||||||
context_instance=None):
|
context_instance=None):
|
||||||
"""
|
"""
|
||||||
Loads the given template_name and renders the given block with the given
|
Loads the given template_name and renders the given block with the given
|
||||||
dictionary as context. Returns a string.
|
dictionary as context. Returns a string.
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
except ImportError: # For python 2.5 support
|
except ImportError: # For python 2.5 support
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.core.context_processors import csrf
|
from django.core.context_processors import csrf
|
||||||
@ -41,16 +42,17 @@ def gen_confirm_form(request, message, url):
|
|||||||
|
|
||||||
Deprecated. Use Class base Views instead.
|
Deprecated. Use Class base Views instead.
|
||||||
"""
|
"""
|
||||||
messages.warning(request,
|
messages.warning(
|
||||||
"""
|
request,
|
||||||
%s
|
"""
|
||||||
<form action="%s" method="post">
|
%s
|
||||||
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
|
<form action="%s" method="post">
|
||||||
<input type="submit" value="%s">
|
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
|
||||||
<input type="button" value="%s">
|
<input type="submit" value="%s">
|
||||||
</form>
|
<input type="button" value="%s">
|
||||||
"""
|
</form>
|
||||||
% (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
|
"""
|
||||||
|
% (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
|
||||||
|
|
||||||
|
|
||||||
def del_confirm_form(request, object, name=None, delete_link=None):
|
def del_confirm_form(request, object, name=None, delete_link=None):
|
||||||
@ -63,7 +65,8 @@ def del_confirm_form(request, object, name=None, delete_link=None):
|
|||||||
name = object
|
name = object
|
||||||
if delete_link is None:
|
if delete_link is None:
|
||||||
delete_link = object.get_absolute_url('delete')
|
delete_link = object.get_absolute_url('delete')
|
||||||
gen_confirm_form(request, _('Do you really want to delete %s?')
|
gen_confirm_form(
|
||||||
|
request, _('Do you really want to delete %s?')
|
||||||
% html_strong(name), delete_link)
|
% html_strong(name), delete_link)
|
||||||
|
|
||||||
|
|
||||||
@ -79,11 +82,11 @@ def template(template_name):
|
|||||||
if not isinstance(output, dict):
|
if not isinstance(output, dict):
|
||||||
return output
|
return output
|
||||||
context = {}
|
context = {}
|
||||||
template_manipulation.send(sender='utils_template', request=request,
|
template_manipulation.send(
|
||||||
context=context)
|
sender='utils_template', request=request, context=context)
|
||||||
output.update(context)
|
output.update(context)
|
||||||
response = render_to_response(template_name, output,
|
response = render_to_response(
|
||||||
context_instance=RequestContext(request))
|
template_name, output, context_instance=RequestContext(request))
|
||||||
if 'cookie' in output:
|
if 'cookie' in output:
|
||||||
response.set_cookie(output['cookie'][0], output['cookie'][1])
|
response.set_cookie(output['cookie'][0], output['cookie'][1])
|
||||||
return response
|
return response
|
||||||
@ -109,12 +112,12 @@ def permission_required(perm, login_url=None):
|
|||||||
return renderer
|
return renderer
|
||||||
|
|
||||||
|
|
||||||
def render_to_forbidden(request, error=
|
def render_to_forbidden(request,
|
||||||
ugettext_lazy("Sorry, you have no rights to see this page.")):
|
error=ugettext_lazy("Sorry, you have no rights to see this page.")):
|
||||||
# TODO: Integrate this function into the PermissionMixin once the
|
# TODO: Integrate this function into the PermissionMixin once the
|
||||||
# above function is deleted.
|
# above function is deleted.
|
||||||
return HttpResponseForbidden(render_to_string('403.html',
|
return HttpResponseForbidden(render_to_string(
|
||||||
{'error': error}, context_instance=RequestContext(request)))
|
'403.html', {'error': error}, context_instance=RequestContext(request)))
|
||||||
|
|
||||||
|
|
||||||
def delete_default_permissions(**kwargs):
|
def delete_default_permissions(**kwargs):
|
||||||
@ -122,9 +125,9 @@ def delete_default_permissions(**kwargs):
|
|||||||
Deletes the permissions, django creates by default for the admin.
|
Deletes the permissions, django creates by default for the admin.
|
||||||
"""
|
"""
|
||||||
for p in Permission.objects.all():
|
for p in Permission.objects.all():
|
||||||
if p.codename.startswith('add') \
|
if (p.codename.startswith('add') or
|
||||||
or p.codename.startswith('delete') \
|
p.codename.startswith('delete') or
|
||||||
or p.codename.startswith('change'):
|
p.codename.startswith('change')):
|
||||||
p.delete()
|
p.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,8 +22,7 @@ except ImportError:
|
|||||||
# Is this exception realy necessary?
|
# Is this exception realy necessary?
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Frame, PageBreak,
|
from reportlab.platypus import SimpleDocTemplate, Spacer
|
||||||
Spacer, Table, LongTable, TableStyle, Image)
|
|
||||||
from reportlab.lib.units import cm
|
from reportlab.lib.units import cm
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
@ -34,9 +33,9 @@ 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 _, ugettext_noop, ugettext_lazy
|
from django.utils.translation import ugettext as _, 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 RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.views.generic import (
|
from django.views.generic import (
|
||||||
TemplateView as _TemplateView,
|
TemplateView as _TemplateView,
|
||||||
@ -50,8 +49,6 @@ from django.views.generic import (
|
|||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
from django.views.generic.list import TemplateResponseMixin
|
from django.views.generic.list import TemplateResponseMixin
|
||||||
|
|
||||||
from openslides.config.models import config
|
|
||||||
|
|
||||||
from openslides.utils.utils import render_to_forbidden, html_strong
|
from openslides.utils.utils import render_to_forbidden, html_strong
|
||||||
from openslides.utils.signals import template_manipulation
|
from openslides.utils.signals import template_manipulation
|
||||||
from openslides.utils.pdf import firstPage, laterPages
|
from openslides.utils.pdf import firstPage, laterPages
|
||||||
@ -64,8 +61,8 @@ View = _View
|
|||||||
|
|
||||||
class SetCookieMixin(object):
|
class SetCookieMixin(object):
|
||||||
def render_to_response(self, context, **response_kwargs):
|
def render_to_response(self, context, **response_kwargs):
|
||||||
response = TemplateResponseMixin.render_to_response(self, context,
|
response = TemplateResponseMixin.render_to_response(
|
||||||
**response_kwargs)
|
self, context, **response_kwargs)
|
||||||
if 'cookie' in context:
|
if 'cookie' in context:
|
||||||
response.set_cookie(context['cookie'][0], context['cookie'][1])
|
response.set_cookie(context['cookie'][0], context['cookie'][1])
|
||||||
return response
|
return response
|
||||||
@ -90,8 +87,8 @@ class PermissionMixin(object):
|
|||||||
if not self.has_permission(request, *args, **kwargs):
|
if not self.has_permission(request, *args, **kwargs):
|
||||||
if not request.user.is_authenticated():
|
if not request.user.is_authenticated():
|
||||||
path = request.get_full_path()
|
path = request.get_full_path()
|
||||||
return HttpResponseRedirect("%s?next=%s" % (settings.LOGIN_URL,
|
return HttpResponseRedirect(
|
||||||
path))
|
"%s?next=%s" % (settings.LOGIN_URL, path))
|
||||||
else:
|
else:
|
||||||
return render_to_forbidden(request)
|
return render_to_forbidden(request)
|
||||||
return _View.dispatch(self, request, *args, **kwargs)
|
return _View.dispatch(self, request, *args, **kwargs)
|
||||||
@ -130,18 +127,18 @@ class QuestionMixin(object):
|
|||||||
option_fields = "\n".join([
|
option_fields = "\n".join([
|
||||||
'<input type="submit" name="%s" value="%s">' % (option[0], unicode(option[1]))
|
'<input type="submit" name="%s" value="%s">' % (option[0], unicode(option[1]))
|
||||||
for option in self.get_answer_options()])
|
for option in self.get_answer_options()])
|
||||||
messages.warning(self.request,
|
messages.warning(
|
||||||
|
self.request,
|
||||||
"""
|
"""
|
||||||
%(message)s
|
%(message)s
|
||||||
<form action="%(url)s" method="post">
|
<form action="%(url)s" method="post">
|
||||||
<input type="hidden" value="%(csrf)s" name="csrfmiddlewaretoken">
|
<input type="hidden" value="%(csrf)s" name="csrfmiddlewaretoken">
|
||||||
%(option_fields)s
|
%(option_fields)s
|
||||||
</form>
|
</form>
|
||||||
""" % {
|
""" % {'message': self.get_question(),
|
||||||
'message': self.get_question(),
|
'url': self.get_answer_url(),
|
||||||
'url': self.get_answer_url(),
|
'csrf': csrf(self.request)['csrf_token'],
|
||||||
'csrf': csrf(self.request)['csrf_token'],
|
'option_fields': option_fields})
|
||||||
'option_fields': option_fields})
|
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def pre_post_redirect(self, request, *args, **kwargs):
|
||||||
# Reacts on the response of the user in a POST-request.
|
# Reacts on the response of the user in a POST-request.
|
||||||
@ -167,16 +164,16 @@ class QuestionMixin(object):
|
|||||||
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)
|
||||||
template_manipulation.send(sender=self.__class__, request=self.request,
|
template_manipulation.send(
|
||||||
context=context)
|
sender=self.__class__, request=self.request, context=context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ListView(PermissionMixin, SetCookieMixin, _ListView):
|
class ListView(PermissionMixin, SetCookieMixin, _ListView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(ListView, self).get_context_data(**kwargs)
|
context = super(ListView, self).get_context_data(**kwargs)
|
||||||
template_manipulation.send(sender=self.__class__, request=self.request,
|
template_manipulation.send(
|
||||||
context=context)
|
sender=self.__class__, request=self.request, context=context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@ -217,8 +214,8 @@ class FormView(PermissionMixin, _FormView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(FormView, self).get_context_data(**kwargs)
|
context = super(FormView, self).get_context_data(**kwargs)
|
||||||
template_manipulation.send(sender=self.__class__, request=self.request,
|
template_manipulation.send(
|
||||||
context=context)
|
sender=self.__class__, request=self.request, context=context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
@ -235,8 +232,8 @@ class UpdateView(PermissionMixin, _UpdateView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||||
template_manipulation.send(sender=self.__class__, request=self.request,
|
template_manipulation.send(
|
||||||
context=context)
|
sender=self.__class__, request=self.request, context=context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
@ -256,8 +253,8 @@ class CreateView(PermissionMixin, _CreateView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(CreateView, self).get_context_data(**kwargs)
|
context = super(CreateView, self).get_context_data(**kwargs)
|
||||||
template_manipulation.send(sender=self.__class__, request=self.request,
|
template_manipulation.send(
|
||||||
context=context)
|
sender=self.__class__, request=self.request, context=context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_apply_url(self):
|
def get_apply_url(self):
|
||||||
@ -299,7 +296,6 @@ class DeleteView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
class DetailView(TemplateView, SingleObjectMixin):
|
class DetailView(TemplateView, SingleObjectMixin):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
context = self.get_context_data(object=self.object)
|
|
||||||
return super(DetailView, self).get(request, *args, **kwargs)
|
return super(DetailView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
@ -329,8 +325,8 @@ class PDFView(PermissionMixin, View):
|
|||||||
return SimpleDocTemplate(buffer)
|
return SimpleDocTemplate(buffer)
|
||||||
|
|
||||||
def build_document(self, pdf_document, story):
|
def build_document(self, pdf_document, story):
|
||||||
pdf_document.build(story, onFirstPage=firstPage,
|
pdf_document.build(
|
||||||
onLaterPages=laterPages)
|
story, onFirstPage=firstPage, onLaterPages=laterPages)
|
||||||
|
|
||||||
def render_to_response(self, filename):
|
def render_to_response(self, filename):
|
||||||
response = HttpResponse(mimetype='application/pdf')
|
response = HttpResponse(mimetype='application/pdf')
|
||||||
@ -340,7 +336,7 @@ class PDFView(PermissionMixin, View):
|
|||||||
buffer = StringIO()
|
buffer = StringIO()
|
||||||
pdf_document = self.get_template(buffer)
|
pdf_document = self.get_template(buffer)
|
||||||
pdf_document.title = self.get_document_title()
|
pdf_document.title = self.get_document_title()
|
||||||
story = [Spacer(1, self.get_top_space()*cm)]
|
story = [Spacer(1, self.get_top_space() * cm)]
|
||||||
|
|
||||||
self.append_to_pdf(story)
|
self.append_to_pdf(story)
|
||||||
|
|
||||||
@ -351,9 +347,6 @@ class PDFView(PermissionMixin, View):
|
|||||||
response.write(pdf)
|
response.write(pdf)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def get_filename(self):
|
|
||||||
return self.filename
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
return self.render_to_response(self.get_filename())
|
return self.render_to_response(self.get_filename())
|
||||||
|
|
||||||
@ -364,9 +357,8 @@ def server_error(request, template_name='500.html'):
|
|||||||
|
|
||||||
Templates: `500.html`
|
Templates: `500.html`
|
||||||
"""
|
"""
|
||||||
t = loader.get_template("500.html")
|
return HttpResponseServerError(render_to_string(
|
||||||
return HttpResponseServerError(render_to_string('500.html',
|
template_name, context_instance=RequestContext(request)))
|
||||||
context_instance=RequestContext(request)))
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(template_manipulation, dispatch_uid="send_register_tab")
|
@receiver(template_manipulation, dispatch_uid="send_register_tab")
|
||||||
|
Loading…
Reference in New Issue
Block a user