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