Merge remote branch 'upstream/master'

This commit is contained in:
Emanuel Schuetze 2012-10-30 20:03:17 +01:00
commit 0c797aa476
44 changed files with 2009 additions and 1929 deletions

View File

@ -11,14 +11,14 @@
"item" "item"
], ],
[ [
"can_create_application", "can_create_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_see_application", "can_see_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_nominate_other", "can_nominate_other",
@ -44,6 +44,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }
@ -60,19 +65,19 @@
"item" "item"
], ],
[ [
"can_create_application", "can_create_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_see_application", "can_see_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_support_application", "can_support_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_nominate_other", "can_nominate_other",
@ -98,6 +103,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }
@ -119,19 +129,19 @@
"item" "item"
], ],
[ [
"can_create_application", "can_create_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_manage_application", "can_manage_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_see_application", "can_see_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_manage_assignment", "can_manage_assignment",
@ -177,6 +187,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }
@ -206,6 +221,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }

View File

@ -5,11 +5,14 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
VERSION = (1, 2, 0, 'final', 1) VERSION = (1, 3, 0, 'alpha', 1)
def get_version(version=None): def get_version(version=None):
"""Derives a PEP386-compliant version number from VERSION.""" """
# TODO: Get the Version Hash from GIT. Derives a PEP386-compliant version number from VERSION. Adds id of
the current git commit.
"""
if version is None: if version is None:
version = VERSION version = VERSION
assert len(version) == 5 assert len(version) == 5
@ -17,67 +20,24 @@ def get_version(version=None):
# Now build the two parts of the version number: # Now build the two parts of the version number:
# main = X.Y[.Z] # main = X.Y[.Z]
# sub = .devN - for pre-alpha releases # sub = {a|b|c}N for alpha, beta and rc releases
# | {a|b|c}N - for alpha, beta and rc releases # git's commit id is added
parts = 2 if version[2] == 0 else 3 main_parts = 2 if version[2] == 0 else 3
main = '.'.join(str(x) for x in version[:parts]) main = '.'.join(str(x) for x in version[:main_parts])
sub = '' if version[3] != 'final':
if version[3] == 'alpha' and version[4] == 0: mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
mercurial_version = hg_version() sub = mapping[version[3]] + str(version[4])
if mercurial_version != 'unknown': try:
sub = '.dev%s' % mercurial_version git_head_path = '.git/' + open('.git/HEAD', 'r').read()[5:].rstrip()
except IOError:
git_commit_id = 'unknown'
else: else:
sub = '.dev' import os
git_commit_id = open(os.path.abspath(git_head_path), 'r').read().rstrip()
elif version[3] != 'final': sub = '%s commit %s' % (sub, git_commit_id)
sub = "-" + version[3] + str(version[4]) else:
sub = ''
return main + sub return main + sub
def hg_version():
import socket
import os
import sys
from os.path import realpath, join, dirname
try:
from mercurial import ui as hgui
from mercurial.localrepo import localrepository
from mercurial.node import short as shorthex
from mercurial.error import RepoError
nomercurial = False
except ImportError:
return 'unknown'
os.environ['HGRCPATH'] = ''
conts = realpath(join(dirname(__file__)))
try:
ui = hgui.ui()
repository = localrepository(ui, join(conts, '..'))
ctx = repository['.']
if ctx.tags() and ctx.tags() != ['tip']:
version = ' '.join(ctx.tags())
else:
version = '%(num)s:%(id)s' % {
'num': ctx.rev(), 'id': shorthex(ctx.node())
}
except TypeError:
version = 'unknown'
except RepoError:
return 0
# This value defines the timeout for sockets in seconds. Per default python
# sockets do never timeout and as such we have blocking workers.
# Socket timeouts are set globally within the whole application.
# The value *must* be a floating point value.
socket.setdefaulttimeout(10.0)
return version
## import os, site
##
## SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
## site.addsitedir(SITE_ROOT)

View File

@ -177,12 +177,12 @@ class ItemDelete(DeleteView):
if self.get_answer() == 'all': if self.get_answer() == 'all':
self.object.delete(with_children=True) self.object.delete(with_children=True)
messages.success(request, messages.success(request,
_("Item %s and his children were successfully deleted.") \ _("Item %s and his children were successfully deleted.")
% html_strong(self.object)) % html_strong(self.object))
elif self.get_answer() == 'yes': elif self.get_answer() == 'yes':
self.object.delete(with_children=False) self.object.delete(with_children=False)
messages.success(request, messages.success(request,
_("Item %s was successfully deleted.") \ _("Item %s was successfully deleted.")
% html_strong(self.object)) % html_strong(self.object))

View File

@ -1,66 +0,0 @@
{% extends "base.html" %}
{% load tags %}
{% load i18n %}
{% load staticfiles %}
{% block submenu %}
{% url application_overview as url_applicationoverview %}
<h4>{% trans "Motions" %}</h4>
<ul>
<li class="{% if request.path == url_applicationoverview %}selected{% endif %}"><a href="{% url application_overview %}">{% trans "All motions" %}</a></li>
{% if perms.application.can_create_application or perms.application.can_manage_application %}
<li class="{% active request '/application/new' %}"><a href="{% url application_new %}">{% trans "New motion" %}</a></li>
{% endif %}
{% if perms.application.can_manage_application %}
<li class="{% active request '/application/import' %}"><a href="{% url application_import %}">{% trans 'Import motions' %}</a></li>
{% endif %}
<li><a href="{% url print_applications %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'All motions as PDF' %}</a></li>
</ul>
{# second submenu #}
{% if application %}
<br>
<h3>{% trans "Application No." %}
{% if application.number != None %}
{{ application.number }}
{% else %}
<i>[-]</i>
{% endif %}
</h3>
<ul>
{# view application #}
{% url application_view application.id as url_applicationview %}
<li class="{% if request.path == url_applicationview %}selected{% endif %}"><a href="{% url application_view application.id %}">{% trans 'View motion' %}</a></li>
{# edit application #}
{% if "edit" in actions %}
{% url application_edit application.id as url_applicationedit %}
<li class="{% if request.path == url_applicationedit %}selected{% endif %}"><a href="{% url application_edit application.id %}"><img src="{% static 'images/icons/edit.png' %}"> {% trans 'Edit motion' %}</a></li>
{% endif %}
{# delete application #}
{% if "delete" in actions %}
<li><a href="{% url application_delete application.id %}"><img src="{% static 'images/icons/delete.png' %}"> {% trans 'Delete motion' %}</a></li>
{% endif %}
{# PDF #}
<li><a href="{% url print_application application.id %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'Motion as PDF' %}</a></li>
{# activate and polls #}
{% if perms.projector.can_manage_projector %}
<li>
<a class="activate_link {% if item.active %}active{% endif %}" href="{% url projector_activate_slide application.sid %}"><img src="{% static 'images/icons/projector.png' %}"> {% trans 'Show Application' %}</a>
</li>
{% endif %}
{% if perms.application.can_manage_application %}
{% for poll in application.polls %}
{% url application_poll_view poll.id as url_applicationpollview %}
<li class="{% if request.path == url_applicationpollview %}selected{% endif %}"><a href="{% url application_poll_view poll.id %}"><img src="{% static 'images/icons/edit.png' %}"> {{ forloop.counter }}. {% trans "Vote" %}</a></li>
{% endfor %}
{% endif %}
{# Agenda Item #}
{% if perms.agenda.can_manage_agenda %}
<li>
<a href="{% url application_create_agenda application.id %}">{% trans 'New agenda item' %}</a>
</li>
{% endif %}
</ul>
{% endif %}
{% endblock %}

View File

@ -1,34 +0,0 @@
{% load staticfiles %}
{% load i18n %}
{% load tags %}
<ul style="line-height: 180%">
{% for application in applications %}
<li class="{% if application.active %}activeline{% endif %}">
<a href="{% url projector_activate_slide application.sid %}" class="activate_link {% if application.active %}active{% endif %}">
<div></div>
</a>
<a href="{% model_url application 'delete' %}" title="{% trans 'Delete' %}" class="icon delete right">
<span></span>
</a>
<a href="{% model_url application 'edit' %}" title="{% trans 'Edit' %}" class="icon edit right">
<span></span>
</a>
<a href="{% url projctor_preview_slide application.sid %}" title="{% trans 'Preview' %}" class="icon preview right">
<span></span>
</a>
<a href="{% model_url application 'view' %}">
{{ application.public_version.title }}
</a>
({% trans "motion" %}
{% if application.number %}
{{ application.number }})
{% else %}
<i>[{% trans "no number" %}]</i>)
{% endif %}
</li>
{% empty %}
<li>{% trans 'No motion available.' %}</li>
{% endfor %}
</ul>

View File

@ -1,141 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
openslides.application.urls
~~~~~~~~~~~~~~~~~~~~~~~~~~~
URL list for the application app.
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details.
"""
from django.conf.urls.defaults import url, patterns
from openslides.application.views import (ApplicationDelete, ViewPoll,
ApplicationPDF, ApplicationPollPDF, CreateAgendaItem)
urlpatterns = patterns('openslides.application.views',
url(r'^$',
'overview',
name='application_overview',
),
url(r'^(?P<application_id>\d+)/$',
'view',
name='application_view',
),
url(r'^(?P<application_id>\d+)/agenda/$',
CreateAgendaItem.as_view(),
name='application_create_agenda',
),
url(r'^(?P<application_id>\d+)/newest/$',
'view',
{'newest': True},
name='application_view_newest',
),
url(r'^new/$',
'edit',
name='application_new',
),
url(r'^import/$',
'application_import',
name='application_import',
),
url(r'^(?P<application_id>\d+)/edit/$',
'edit',
name='application_edit',
),
url(r'^(?P<application_id>\d+)/del/$',
ApplicationDelete.as_view(),
name='application_delete',
),
url(r'^del/$',
ApplicationDelete.as_view(),
{ 'application_id' : None , 'application_ids' : None },
name='application_delete',
),
url(r'^(?P<application_id>\d+)/setnumber/$',
'set_number',
name='application_set_number',
),
url(r'^(?P<application_id>\d+)/setstatus/(?P<status>[a-z]{3})/$',
'set_status',
name='application_set_status',
),
url(r'^(?P<application_id>\d+)/permit/$',
'permit',
name='application_permit',
),
url(r'^version/(?P<aversion_id>\d+)/permit/$',
'permit_version',
name='application_version_permit',
),
url(r'^version/(?P<aversion_id>\d+)/reject/$',
'reject_version',
name='application_version_reject',
),
url(r'^(?P<application_id>\d+)/notpermit/$',
'notpermit',
name='application_notpermit',
),
url(r'^(?P<application_id>\d+)/reset/$',
'reset',
name='application_reset',
),
url(r'^(?P<application_id>\d+)/support/$',
'support',
name='application_support',
),
url(r'^(?P<application_id>\d+)/unsupport/$',
'unsupport',
name='application_unsupport',
),
url(r'^(?P<application_id>\d+)/gen_poll/$',
'gen_poll',
name='application_gen_poll',
),
url(r'^print/$',
ApplicationPDF.as_view(),
{'application_id': None},
name='print_applications',
),
url(r'^(?P<application_id>\d+)/print/$',
ApplicationPDF.as_view(),
name='print_application',
),
url(r'^poll/(?P<poll_id>\d+)/print/$',
ApplicationPollPDF.as_view(),
name='print_application_poll',
),
url(r'^poll/(?P<poll_id>\d+)/$',
ViewPoll.as_view(),
name='application_poll_view',
),
url(r'^poll/(?P<poll_id>\d+)/del/$',
'delete_poll',
name='application_poll_delete',
),
)

View File

@ -218,7 +218,7 @@ class Assignment(models.Model, SlideMixin):
return self.name return self.name
def delete(self): def delete(self):
# Remove any Agenda-Item, which is related to this application. # Remove any Agenda-Item, which is related to this assignment.
for item in Item.objects.filter(related_sid=self.sid): for item in Item.objects.filter(related_sid=self.sid):
item.delete() item.delete()
super(Assignment, self).delete() super(Assignment, self).delete()

View File

@ -31,7 +31,7 @@
<div style="margin-right: 250px; min-width: 400px;"> <div style="margin-right: 250px; min-width: 400px;">
<h1>{{ assignment }}</h1> <h1>{{ assignment }}</h1>
<p>{{ assignment.description }}</p> <p>{{ assignment.description|linebreaks }}</p>
<h3>{% trans "Candidates" %}</h3> <h3>{% trans "Candidates" %}</h3>
<ol> <ol>

View File

@ -430,11 +430,11 @@ class AssignmentPDF(PDFView):
for candidate, poll_list in vote_results.iteritems(): for candidate, poll_list in vote_results.iteritems():
row = [] row = []
candidate_string = candidate.user.get_full_name() candidate_string = candidate.clean_name
if candidate in elected_candidates: if candidate in elected_candidates:
candidate_string = "* " + candidate_string candidate_string = "* " + candidate_string
if candidate.category: if candidate.name_suffix:
candidate_string += "\n(%s)" % candidate.category candidate_string += "\n(%s)" % candidate.name_suffix
row.append(candidate_string) row.append(candidate_string)
for vote in poll_list: for vote in poll_list:
if vote == None: if vote == None:
@ -565,7 +565,7 @@ class AssignmentPollPDF(PDFView):
if self.poll.yesnoabstain: if self.poll.yesnoabstain:
for option in options: for option in options:
candidate = option.candidate candidate = option.candidate
cell.append(Paragraph(candidate.user.get_full_name(), cell.append(Paragraph(candidate.clean_name,
stylesheet['Ballot_option_name'])) stylesheet['Ballot_option_name']))
if candidate.name_suffix: if candidate.name_suffix:
cell.append(Paragraph("(%s)" % candidate.name_suffix, cell.append(Paragraph("(%s)" % candidate.name_suffix,
@ -591,10 +591,10 @@ class AssignmentPollPDF(PDFView):
else: else:
for option in options: for option in options:
candidate = option.candidate candidate = option.candidate
cell.append(Paragraph(circle + candidate.user.get_full_name(), cell.append(Paragraph(circle + candidate.clean_name,
stylesheet['Ballot_option_name'])) stylesheet['Ballot_option_name']))
if candidate.category: if candidate.name_suffix:
cell.append(Paragraph("(%s)" % candidate.category, cell.append(Paragraph("(%s)" % candidate.name_suffix,
stylesheet['Ballot_option_group_right'])) stylesheet['Ballot_option_group_right']))
else: else:
cell.append(Paragraph("&nbsp;", cell.append(Paragraph("&nbsp;",

View File

@ -66,8 +66,9 @@ class GeneralConfig(FormView):
try: try:
anonymous = Group.objects.get(name='Anonymous') anonymous = Group.objects.get(name='Anonymous')
except Group.DoesNotExist: except Group.DoesNotExist:
default_perms = [u'can_see_agenda', u'can_see_projector', default_perms = ['can_see_agenda', 'can_see_projector',
u'can_see_application', u'can_see_assignment'] 'can_see_motion', 'can_see_assignment',
'can_see_dashboard']
anonymous = Group() anonymous = Group()
anonymous.name = 'Anonymous' anonymous.name = 'Anonymous'
anonymous.save() anonymous.save()

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
openslides.application.forms openslides.motion.forms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Forms for the application app. Forms for the motion app.
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS. :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
@ -15,36 +15,36 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop
from openslides.utils.forms import CssClassMixin from openslides.utils.forms import CssClassMixin
from openslides.utils.person import PersonFormField, MultiplePersonFormField from openslides.utils.person import PersonFormField, MultiplePersonFormField
from openslides.application.models import Application from openslides.motion.models import Motion
class ApplicationForm(forms.Form, CssClassMixin): class MotionForm(forms.Form, CssClassMixin):
title = forms.CharField(widget=forms.TextInput(), label=_("Title")) title = forms.CharField(widget=forms.TextInput(), label=_("Title"))
text = forms.CharField(widget=forms.Textarea(), label=_("Text")) text = forms.CharField(widget=forms.Textarea(), label=_("Text"))
reason = forms.CharField(widget=forms.Textarea(), required=False, reason = forms.CharField(widget=forms.Textarea(), required=False,
label=_("Reason")) label=_("Reason"))
class ApplicationFormTrivialChanges(ApplicationForm): class MotionFormTrivialChanges(MotionForm):
trivial_change = forms.BooleanField(required=False, trivial_change = forms.BooleanField(required=False,
label=_("Trivial change"), label=_("Trivial change"),
help_text=_("Trivial changes don't create a new version.")) help_text=_("Trivial changes don't create a new version."))
class ApplicationManagerForm(forms.ModelForm, CssClassMixin): class MotionManagerForm(forms.ModelForm, CssClassMixin):
submitter = PersonFormField() submitter = PersonFormField()
class Meta: class Meta:
model = Application model = Motion
exclude = ('number', 'status', 'permitted', 'log', 'supporter') exclude = ('number', 'status', 'permitted', 'log', 'supporter')
class ApplicationManagerFormSupporter(ApplicationManagerForm): class MotionManagerFormSupporter(MotionManagerForm):
# TODO: Do not show the submitter in the user-list # TODO: Do not show the submitter in the user-list
supporter = MultiplePersonFormField(required=False, label=_("Supporters")) supporter = MultiplePersonFormField(required=False, label=_("Supporters"))
class ApplicationImportForm(forms.Form, CssClassMixin): class MotionImportForm(forms.Form, CssClassMixin):
csvfile = forms.FileField( csvfile = forms.FileField(
widget=forms.FileInput(attrs={'size':'50'}), widget=forms.FileInput(attrs={'size':'50'}),
label=_("CSV File"), label=_("CSV File"),
@ -58,7 +58,7 @@ class ApplicationImportForm(forms.Form, CssClassMixin):
class ConfigForm(forms.Form, CssClassMixin): class ConfigForm(forms.Form, CssClassMixin):
application_min_supporters = forms.IntegerField( motion_min_supporters = forms.IntegerField(
widget=forms.TextInput(attrs={'class':'small-input'}), widget=forms.TextInput(attrs={'class':'small-input'}),
label=_("Number of (minimum) required supporters for a motion"), label=_("Number of (minimum) required supporters for a motion"),
initial=4, initial=4,
@ -66,12 +66,12 @@ class ConfigForm(forms.Form, CssClassMixin):
max_value=8, max_value=8,
help_text=_("Choose 0 to disable the supporting system"), help_text=_("Choose 0 to disable the supporting system"),
) )
application_preamble = forms.CharField( motion_preamble = forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
required=False, required=False,
label=_("Motion preamble") label=_("Motion preamble")
) )
application_pdf_ballot_papers_selection = forms.ChoiceField( motion_pdf_ballot_papers_selection = forms.ChoiceField(
widget=forms.Select(), widget=forms.Select(),
required=False, required=False,
label=_("Number of ballot papers (selection)"), label=_("Number of ballot papers (selection)"),
@ -81,24 +81,24 @@ class ConfigForm(forms.Form, CssClassMixin):
("CUSTOM_NUMBER", _("Use the following custom number")), ("CUSTOM_NUMBER", _("Use the following custom number")),
] ]
) )
application_pdf_ballot_papers_number = forms.IntegerField( motion_pdf_ballot_papers_number = forms.IntegerField(
widget=forms.TextInput(attrs={'class':'small-input'}), widget=forms.TextInput(attrs={'class':'small-input'}),
required=False, required=False,
min_value=1, min_value=1,
label=_("Custom number of ballot papers") label=_("Custom number of ballot papers")
) )
application_pdf_title = forms.CharField( motion_pdf_title = forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
required=False, required=False,
label=_("Title for PDF document (all motions)") label=_("Title for PDF document (all motions)")
) )
application_pdf_preamble = forms.CharField( motion_pdf_preamble = forms.CharField(
widget=forms.Textarea(), widget=forms.Textarea(),
required=False, required=False,
label=_("Preamble text for PDF document (all motions)") label=_("Preamble text for PDF document (all motions)")
) )
application_allow_trivial_change = forms.BooleanField( motion_allow_trivial_change = forms.BooleanField(
label=_("Allow trivial changes"), label=_("Allow trivial changes"),
help_text=_('Warning: Trivial changes undermine the motions ' help_text=_('Warning: Trivial changes undermine the motions '
'autorisation system.'), 'autorisation system.'),

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
openslides.application.models openslides.motion.models
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Models for the application app. Models for the motion app.
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS. :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
@ -34,13 +34,13 @@ from openslides.projector.models import SlideMixin
from openslides.agenda.models import Item from openslides.agenda.models import Item
class ApplicationSupporter(models.Model): class MotionSupporter(models.Model):
application = models.ForeignKey("Application") motion = models.ForeignKey("Motion")
person = PersonField() person = PersonField()
class Application(models.Model, SlideMixin): class Motion(models.Model, SlideMixin):
prefix = "application" prefix = "motion"
STATUS = ( STATUS = (
('pub', _('Published')), ('pub', _('Published')),
('per', _('Permitted')), ('per', _('Permitted')),
@ -74,10 +74,10 @@ class Application(models.Model, SlideMixin):
@property @property
def last_version(self): def last_version(self):
""" """
Return last version of the application. Return last version of the motion.
""" """
try: try:
return AVersion.objects.filter(application=self).order_by('id') \ return AVersion.objects.filter(motion=self).order_by('id') \
.reverse()[0] .reverse()[0]
except IndexError: except IndexError:
return None return None
@ -85,7 +85,7 @@ class Application(models.Model, SlideMixin):
@property @property
def public_version(self): def public_version(self):
""" """
Return permitted, if the application was permitted, else last_version Return permitted, if the motion was permitted, else last_version
""" """
if self.permitted is not None: if self.permitted is not None:
return self.permitted return self.permitted
@ -115,14 +115,14 @@ class Application(models.Model, SlideMixin):
@property @property
def versions(self): def versions(self):
""" """
Return a list of all versions of the application. Return a list of all versions of the motion.
""" """
return AVersion.objects.filter(application=self) return AVersion.objects.filter(motion=self)
@property @property
def creation_time(self): def creation_time(self):
""" """
Return the time of the creation of the application. Return the time of the creation of the motion.
""" """
try: try:
return self.versions[0].time return self.versions[0].time
@ -132,7 +132,7 @@ class Application(models.Model, SlideMixin):
@property @property
def notes(self): def notes(self):
""" """
Return some information of the application. Return some information of the motion.
""" """
note = [] note = []
if self.status == "pub" and not self.enough_supporters: if self.status == "pub" and not self.enough_supporters:
@ -146,9 +146,9 @@ class Application(models.Model, SlideMixin):
@property @property
def unpermitted_changes(self): def unpermitted_changes(self):
""" """
Return True if the application has unpermitted changes. Return True if the motion has unpermitted changes.
The application has unpermitted changes, if the permitted-version The motion has unpermitted changes, if the permitted-version
is not the lastone and the lastone is not rejected. is not the lastone and the lastone is not rejected.
TODO: rename the property in unchecked__changes TODO: rename the property in unchecked__changes
""" """
@ -160,35 +160,35 @@ class Application(models.Model, SlideMixin):
@property @property
def supporters(self): def supporters(self):
for object in self.applicationsupporter_set.all(): for object in self.motionsupporter_set.all():
yield object.person yield object.person
def is_supporter(self, person): def is_supporter(self, person):
try: try:
return self.applicationsupporter_set.filter(person=person).exists() return self.motionsupporter_set.filter(person=person).exists()
except AttributeError: except AttributeError:
return False return False
@property @property
def enough_supporters(self): def enough_supporters(self):
""" """
Return True, if the application has enough supporters Return True, if the motion has enough supporters
""" """
min_supporters = int(config['application_min_supporters']) min_supporters = int(config['motion_min_supporters'])
if self.status == "pub": if self.status == "pub":
return self.count_supporters() >= min_supporters return self.count_supporters() >= min_supporters
else: else:
return True return True
def count_supporters(self): def count_supporters(self):
return self.applicationsupporter_set.count() return self.motionsupporter_set.count()
@property @property
def missing_supporters(self): def missing_supporters(self):
""" """
Return number of missing supporters Return number of missing supporters
""" """
min_supporters = int(config['application_min_supporters']) min_supporters = int(config['motion_min_supporters'])
delta = min_supporters - self.count_supporters() delta = min_supporters - self.count_supporters()
if delta > 0: if delta > 0:
return delta return delta
@ -197,9 +197,9 @@ class Application(models.Model, SlideMixin):
def save(self, user=None, nonewversion=False, trivial_change=False): def save(self, user=None, nonewversion=False, trivial_change=False):
""" """
Save the Application, and create a new AVersion if necessary Save the Motion, and create a new AVersion if necessary
""" """
super(Application, self).save() super(Motion, self).save()
if nonewversion: if nonewversion:
return return
last_version = self.last_version last_version = self.last_version
@ -229,14 +229,14 @@ class Application(models.Model, SlideMixin):
version = AVersion(title=getattr(self, 'title', ''), version = AVersion(title=getattr(self, 'title', ''),
text=getattr(self, 'text', ''), text=getattr(self, 'text', ''),
reason=getattr(self, 'reason', ''), reason=getattr(self, 'reason', ''),
application=self) motion=self)
version.save() version.save()
self.writelog(_("Version %s created") % version.aid, user) self.writelog(_("Version %s created") % version.aid, user)
is_manager = user.has_perm('application.can_manage_application') is_manager = user.has_perm('motion.can_manage_motion')
except AttributeError: except AttributeError:
is_manager = False is_manager = False
supporters = self.applicationsupporter_set.all() supporters = self.motionsupporter_set.all()
if (self.status == "pub" if (self.status == "pub"
and supporters and supporters
and not is_manager): and not is_manager):
@ -245,7 +245,7 @@ class Application(models.Model, SlideMixin):
def reset(self, user): def reset(self, user):
""" """
Reset the application. Reset the motion.
""" """
self.status = "pub" self.status = "pub"
self.permitted = None self.permitted = None
@ -254,43 +254,39 @@ class Application(models.Model, SlideMixin):
def support(self, person): def support(self, person):
""" """
Add a Supporter to the list of supporters of the application. Add a Supporter to the list of supporters of the motion.
""" """
if person == self.submitter: if person == self.submitter:
# TODO: Use own Exception # TODO: Use own Exception
raise NameError('Supporter can not be the submitter of a ' \ raise NameError('Supporter can not be the submitter of a '
'application.') 'motion.')
if self.permitted is not None:
# TODO: Use own Exception
raise NameError('This application is already permitted.')
if not self.is_supporter(person): if not self.is_supporter(person):
ApplicationSupporter(application=self, person=person).save() MotionSupporter(motion=self, person=person).save()
self.writelog(_("Supporter: +%s") % (person)) self.writelog(_("Supporter: +%s") % (person))
# TODO: Raise a precise exception for the view in else-clause
def unsupport(self, person): def unsupport(self, person):
""" """
remove a supporter from the list of supporters of the application remove a supporter from the list of supporters of the motion
""" """
if self.permitted is not None:
# TODO: Use own Exception
raise NameError('This application is already permitted.')
try: try:
object = self.applicationsupporter_set.get(person=person).delete() object = self.motionsupporter_set.get(person=person).delete()
except ApplicationSupporter.DoesNotExist: except MotionSupporter.DoesNotExist:
# TODO: Don't do nothing but raise a precise exception for the view
pass pass
else: else:
self.writelog(_("Supporter: -%s") % (person)) self.writelog(_("Supporter: -%s") % (person))
def set_number(self, number=None, user=None): def set_number(self, number=None, user=None):
""" """
Set a number for ths application. Set a number for ths motion.
""" """
if self.number is not None: if self.number is not None:
# TODO: Use own Exception # TODO: Use own Exception
raise NameError('This application has already a number.') raise NameError('This motion has already a number.')
if number is None: if number is None:
try: try:
number = Application.objects.aggregate(Max('number')) \ number = Motion.objects.aggregate(Max('number')) \
['number__max'] + 1 ['number__max'] + 1
except TypeError: except TypeError:
number = 1 number = 1
@ -301,7 +297,7 @@ class Application(models.Model, SlideMixin):
def permit(self, user=None): def permit(self, user=None):
""" """
Change the status of this application to permit. Change the status of this motion to permit.
""" """
self.set_status(user, "per") self.set_status(user, "per")
aversion = self.last_version aversion = self.last_version
@ -314,7 +310,7 @@ class Application(models.Model, SlideMixin):
def notpermit(self, user=None): def notpermit(self, user=None):
""" """
Change the status of this application to 'not permitted (rejected)'. Change the status of this motion to 'not permitted (rejected)'.
""" """
self.set_status(user, "nop") self.set_status(user, "nop")
#TODO: reject last version #TODO: reject last version
@ -327,10 +323,10 @@ class Application(models.Model, SlideMixin):
def set_status(self, user, status, force=False): def set_status(self, user, status, force=False):
""" """
Set the status of the application. Set the status of the motion.
""" """
error = True error = True
for a, b in Application.STATUS: for a, b in Motion.STATUS:
if status == a: if status == a:
error = False error = False
break break
@ -364,25 +360,25 @@ class Application(models.Model, SlideMixin):
""" """
actions = [] actions = []
# check if user allowed to withdraw an application # check if user allowed to withdraw an motion
if ((self.status == "pub" if ((self.status == "pub"
and self.number and self.number
and user == self.submitter) and user == self.submitter)
or (self.status == "pub" or (self.status == "pub"
and self.number and self.number
and user.has_perm("application.can_manage_application")) and user.has_perm("motion.can_manage_motion"))
or (self.status == "per" or (self.status == "per"
and user == self.submitter) and user == self.submitter)
or (self.status == "per" or (self.status == "per"
and user.has_perm("application.can_manage_application"))): and user.has_perm("motion.can_manage_motion"))):
actions.append("wit") actions.append("wit")
#Check if the user can review the application #Check if the user can review the motion
if (self.status == "rev" if (self.status == "rev"
and (self.submitter == user and (self.submitter == user
or user.has_perm("application.can_manage_application"))): or user.has_perm("motion.can_manage_motion"))):
actions.append("pub") actions.append("pub")
# Check if the user can support and unspoort the application # Check if the user can support and unspoort the motion
if (self.status == "pub" if (self.status == "pub"
and user != self.submitter and user != self.submitter
and not self.is_supporter(user)): and not self.is_supporter(user)):
@ -391,22 +387,22 @@ class Application(models.Model, SlideMixin):
if self.status == "pub" and self.is_supporter(user): if self.status == "pub" and self.is_supporter(user):
actions.append("unsupport") actions.append("unsupport")
#Check if the user can edit the application #Check if the user can edit the motion
if (user == self.submitter \ if (user == self.submitter \
and (self.status in ('pub', 'per'))) \ and (self.status in ('pub', 'per'))) \
or user.has_perm("application.can_manage_application"): or user.has_perm("motion.can_manage_motion"):
actions.append("edit") actions.append("edit")
# Check if the user can delete the application (admin, manager, owner) # Check if the user can delete the motion (admin, manager, owner)
# reworked as requiered in #100 # reworked as requiered in #100
if (user.has_perm("applicatoin.can_delete_all_applications") or if (user.has_perm("motion.can_delete_all_motions") or
(user.has_perm("application.can_manage_application") and (user.has_perm("motion.can_manage_motion") and
self.number is None) or self.number is None) or
(self.submitter == user and self.number is None)): (self.submitter == user and self.number is None)):
actions.append("delete") actions.append("delete")
#For the rest, all actions need the manage permission #For the rest, all actions need the manage permission
if not user.has_perm("application.can_manage_application"): if not user.has_perm("motion.can_manage_motion"):
return actions return actions
if self.status == "pub": if self.status == "pub":
@ -430,17 +426,17 @@ class Application(models.Model, SlideMixin):
def delete(self, force=False): def delete(self, force=False):
""" """
Delete the application. It is not possible, if the application has Delete the motion. It is not possible, if the motion has
allready a number allready a number
""" """
if self.number and not force: if self.number and not force:
raise NameError('The application has already a number. ' \ raise NameError('The motion has already a number. ' \
'You can not delete it.') 'You can not delete it.')
for item in Item.objects.filter(related_sid=self.sid): for item in Item.objects.filter(related_sid=self.sid):
item.delete() item.delete()
super(Application, self).delete() super(Motion, self).delete()
def writelog(self, text, user=None): def writelog(self, text, user=None):
if not self.log: if not self.log:
@ -461,7 +457,7 @@ class Application(models.Model, SlideMixin):
def __getattr__(self, name): def __getattr__(self, name):
""" """
if name is title, text, reason or time, if name is title, text, reason or time,
Return this attribute from the newest version of the application Return this attribute from the newest version of the motion
""" """
if name in ('title', 'text', 'reason', 'time', 'aid'): if name in ('title', 'text', 'reason', 'time', 'aid'):
try: try:
@ -476,9 +472,9 @@ class Application(models.Model, SlideMixin):
def gen_poll(self, user=None): def gen_poll(self, user=None):
""" """
Generates a poll object for the application Generates a poll object for the motion
""" """
poll = ApplicationPoll(application=self) poll = MotionPoll(motion=self)
poll.save() poll.save()
poll.set_options() poll.set_options()
self.writelog(_("Poll created"), user) self.writelog(_("Poll created"), user)
@ -486,7 +482,7 @@ class Application(models.Model, SlideMixin):
@property @property
def polls(self): def polls(self):
return self.applicationpoll_set.all() return self.motionpoll_set.all()
@property @property
def results(self): def results(self):
@ -510,19 +506,19 @@ class Application(models.Model, SlideMixin):
""" """
return the slide dict return the slide dict
""" """
data = super(Application, self).slide() data = super(Motion, self).slide()
data['application'] = self data['motion'] = self
data['title'] = self.title data['title'] = self.title
data['template'] = 'projector/Application.html' data['template'] = 'projector/Motion.html'
return data return data
def get_absolute_url(self, link='view'): def get_absolute_url(self, link='view'):
if link == 'view': if link == 'view':
return reverse('application_view', args=[str(self.id)]) return reverse('motion_view', args=[str(self.id)])
if link == 'edit': if link == 'edit':
return reverse('application_edit', args=[str(self.id)]) return reverse('motion_edit', args=[str(self.id)])
if link == 'delete': if link == 'delete':
return reverse('application_delete', args=[str(self.id)]) return reverse('motion_delete', args=[str(self.id)])
def __unicode__(self): def __unicode__(self):
try: try:
@ -532,10 +528,10 @@ class Application(models.Model, SlideMixin):
class Meta: class Meta:
permissions = ( permissions = (
('can_see_application', ugettext_noop("Can see motions")), ('can_see_motion', ugettext_noop("Can see motions")),
('can_create_application', ugettext_noop("Can create motions")), ('can_create_motion', ugettext_noop("Can create motions")),
('can_support_application', ugettext_noop("Can support motions")), ('can_support_motion', ugettext_noop("Can support motions")),
('can_manage_application', ugettext_noop("Can manage motions")), ('can_manage_motion', ugettext_noop("Can manage motions")),
) )
ordering = ('number',) ordering = ('number',)
@ -546,7 +542,7 @@ class AVersion(models.Model):
reason = models.TextField(null=True, blank=True, verbose_name = _("Reason")) reason = models.TextField(null=True, blank=True, verbose_name = _("Reason"))
rejected = models.BooleanField() # = Not Permitted rejected = models.BooleanField() # = Not Permitted
time = models.DateTimeField(auto_now=True) time = models.DateTimeField(auto_now=True)
application = models.ForeignKey(Application) motion = models.ForeignKey(Motion)
def __unicode__(self): def __unicode__(self):
return "%s %s" % (self.id, self.title) return "%s %s" % (self.id, self.title)
@ -557,31 +553,31 @@ class AVersion(models.Model):
return self._aid return self._aid
except AttributeError: except AttributeError:
self._aid = AVersion.objects \ self._aid = AVersion.objects \
.filter(application=self.application) \ .filter(motion=self.motion) \
.filter(id__lte=self.id).count() .filter(id__lte=self.id).count()
return self._aid return self._aid
register_slidemodel(Application) register_slidemodel(Motion)
class ApplicationVote(BaseVote): class MotionVote(BaseVote):
option = models.ForeignKey('ApplicationOption') option = models.ForeignKey('MotionOption')
class ApplicationOption(BaseOption): class MotionOption(BaseOption):
poll = models.ForeignKey('ApplicationPoll') poll = models.ForeignKey('MotionPoll')
vote_class = ApplicationVote vote_class = MotionVote
class ApplicationPoll(BasePoll, CountInvalid, CountVotesCast): class MotionPoll(BasePoll, CountInvalid, CountVotesCast):
option_class = ApplicationOption option_class = MotionOption
vote_values = [ugettext_noop('Yes'), ugettext_noop('No'), vote_values = [ugettext_noop('Yes'), ugettext_noop('No'),
ugettext_noop('Abstain')] ugettext_noop('Abstain')]
application = models.ForeignKey(Application) motion = models.ForeignKey(Motion)
def get_application(self): def get_motion(self):
return self.application return self.motion
def set_options(self): def set_options(self):
#TODO: maybe it is possible with .create() to call this without poll=self #TODO: maybe it is possible with .create() to call this without poll=self
@ -592,20 +588,20 @@ class ApplicationPoll(BasePoll, CountInvalid, CountVotesCast):
CountVotesCast.append_pollform_fields(self, fields) CountVotesCast.append_pollform_fields(self, fields)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('application_poll_view', args=[self.id]) return reverse('motion_poll_view', args=[self.id])
def get_ballot(self): def get_ballot(self):
return self.application.applicationpoll_set.filter(id__lte=self.id).count() return self.motion.motionpoll_set.filter(id__lte=self.id).count()
@receiver(default_config_value, dispatch_uid="application_default_config") @receiver(default_config_value, dispatch_uid="motion_default_config")
def default_config(sender, key, **kwargs): def default_config(sender, key, **kwargs):
return { return {
'application_min_supporters': 0, 'motion_min_supporters': 0,
'application_preamble': _('The assembly may decide,'), 'motion_preamble': _('The assembly may decide,'),
'application_pdf_ballot_papers_selection': 'CUSTOM_NUMBER', 'motion_pdf_ballot_papers_selection': 'CUSTOM_NUMBER',
'application_pdf_ballot_papers_number': '8', 'motion_pdf_ballot_papers_number': '8',
'application_pdf_title': _('Motions'), 'motion_pdf_title': _('Motions'),
'application_pdf_preamble': '', 'motion_pdf_preamble': '',
'application_allow_trivial_change': False, 'motion_allow_trivial_change': False,
}.get(key) }.get(key)

View File

@ -0,0 +1,66 @@
{% extends "base.html" %}
{% load tags %}
{% load i18n %}
{% load staticfiles %}
{% block submenu %}
{% url motion_overview as url_motionoverview %}
<h4>{% trans "Motions" %}</h4>
<ul>
<li class="{% if request.path == url_motionoverview %}selected{% endif %}"><a href="{% url motion_overview %}">{% trans "All motions" %}</a></li>
{% if perms.motion.can_create_motion or perms.motion.can_manage_motion %}
<li class="{% active request '/motion/new' %}"><a href="{% url motion_new %}">{% trans "New motion" %}</a></li>
{% endif %}
{% if perms.motion.can_manage_motion %}
<li class="{% active request '/motion/import' %}"><a href="{% url motion_import %}">{% trans 'Import motions' %}</a></li>
{% endif %}
<li><a href="{% url print_motions %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'All motions as PDF' %}</a></li>
</ul>
{# second submenu #}
{% if motion %}
<br>
<h3>{% trans "Motion No." %}
{% if motion.number != None %}
{{ motion.number }}
{% else %}
<i>[-]</i>
{% endif %}
</h3>
<ul>
{# view motion #}
{% url motion_view motion.id as url_motionview %}
<li class="{% if request.path == url_motionview %}selected{% endif %}"><a href="{% url motion_view motion.id %}">{% trans 'View motion' %}</a></li>
{# edit motion #}
{% if "edit" in actions %}
{% url motion_edit motion.id as url_motionedit %}
<li class="{% if request.path == url_motionedit %}selected{% endif %}"><a href="{% url motion_edit motion.id %}"><img src="{% static 'images/icons/edit.png' %}"> {% trans 'Edit motion' %}</a></li>
{% endif %}
{# delete motion #}
{% if "delete" in actions %}
<li><a href="{% url motion_delete motion.id %}"><img src="{% static 'images/icons/delete.png' %}"> {% trans 'Delete motion' %}</a></li>
{% endif %}
{# PDF #}
<li><a href="{% url print_motion motion.id %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'Motion as PDF' %}</a></li>
{# activate and polls #}
{% if perms.projector.can_manage_projector %}
<li>
<a class="activate_link {% if item.active %}active{% endif %}" href="{% url projector_activate_slide motion.sid %}"><img src="{% static 'images/icons/projector.png' %}"> {% trans 'Show Motion' %}</a>
</li>
{% endif %}
{% if perms.motion.can_manage_motion %}
{% for poll in motion.polls %}
{% url motion_poll_view poll.id as url_motionpollview %}
<li class="{% if request.path == url_motionpollview %}selected{% endif %}"><a href="{% url motion_poll_view poll.id %}"><img src="{% static 'images/icons/edit.png' %}"> {{ forloop.counter }}. {% trans "Vote" %}</a></li>
{% endfor %}
{% endif %}
{# Agenda Item #}
{% if perms.agenda.can_manage_agenda %}
<li>
<a href="{% url motion_create_agenda motion.id %}">{% trans 'New agenda item' %}</a>
</li>
{% endif %}
</ul>
{% endif %}
{% endblock %}

View File

@ -2,18 +2,18 @@
{% load i18n %} {% load i18n %}
{% block title %}{{ block.super }} {% trans "Application settings" %}{% endblock %} {% block title %}{{ block.super }} {% trans "Motion settings" %}{% endblock %}
{% block content %} {% block content %}
<h1>{% trans "Application settings" %}</h1> <h1>{% trans "Motion settings" %}</h1>
<form action="" method="post">{% csrf_token %} <form action="" method="post">{% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<p> <p>
<button class="button" type="submit"> <button class="button" type="submit">
<span class="icon ok">{% trans 'Save' %}</span> <span class="icon ok">{% trans 'Save' %}</span>
</button> </button>
<a href='{% url config_application %}'> <a href='{% url config_motion %}'>
<button class="button" type="button" onclick="window.location='{% url config_application %}'"> <button class="button" type="button" onclick="window.location='{% url config_motion %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span> <span class="icon cancel">{% trans 'Cancel' %}</span>
</button> </button>
</a> </a>

View File

@ -1,10 +1,10 @@
{% extends "application/base_application.html" %} {% extends "motion/base_motion.html" %}
{% load i18n %} {% load i18n %}
{% block title %} {% block title %}
{{ block.super }} {{ block.super }}
{% if application %} {% if motion %}
{% trans "Edit motion" %} {% trans "Edit motion" %}
{% else %} {% else %}
{% trans "New motion" %} {% trans "New motion" %}
@ -12,7 +12,7 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if application %} {% if motion %}
<h1>{% trans "Edit motion" %}</h1> <h1>{% trans "Edit motion" %}</h1>
{% else %} {% else %}
<h1>{% trans "New motion" %}</h1> <h1>{% trans "New motion" %}</h1>
@ -28,8 +28,8 @@
<button class="button" type="submit" name="apply"> <button class="button" type="submit" name="apply">
<span class="icon apply">{% trans 'Apply' %}</span> <span class="icon apply">{% trans 'Apply' %}</span>
</button> </button>
<a href='{% url application_overview %}'> <a href='{% url motion_overview %}'>
<button class="button" type="button" onclick="window.location='{% url application_overview %}'"> <button class="button" type="button" onclick="window.location='{% url motion_overview %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span> <span class="icon cancel">{% trans 'Cancel' %}</span>
</button> </button>
</a> </a>

View File

@ -1,4 +1,4 @@
{% extends "application/base_application.html" %} {% extends "motion/base_motion.html" %}
{% load i18n %} {% load i18n %}
@ -22,8 +22,8 @@
<button class="button" type="submit"> <button class="button" type="submit">
<span class="icon import">{% trans 'Import' %}</span> <span class="icon import">{% trans 'Import' %}</span>
</button> </button>
<a href="{% url application_overview%}"> <a href="{% url motion_overview%}">
<button class="button" type="button" onclick="window.location='{% url application_overview %}'"> <button class="button" type="button" onclick="window.location='{% url motion_overview %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span> <span class="icon cancel">{% trans 'Cancel' %}</span>
</button> </button>
</a> </a>

View File

@ -1,4 +1,4 @@
{% extends "application/base_application.html" %} {% extends "motion/base_motion.html" %}
{% load tags %} {% load tags %}
{% load i18n %} {% load i18n %}
@ -28,8 +28,8 @@
</select> </select>
</form> </form>
</p> </p>
{{ applications|length }} {{ motions|length }}
{% blocktrans count counter=applications|length %}motion{% plural %}motions{% endblocktrans %} {% blocktrans count counter=motions|length %}motion{% plural %}motions{% endblocktrans %}
<table> <table>
<tr> <tr>
<th><a href="?sort=number{% if 'number' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Number" %}</a></th> <th><a href="?sort=number{% if 'number' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Number" %}</a></th>
@ -42,39 +42,39 @@
<th><a href="?sort=time{% if 'time' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Creation Time" %}<a></th> <th><a href="?sort=time{% if 'time' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Creation Time" %}<a></th>
<th style="width: 1px;">{% trans "Actions" %}</th> <th style="width: 1px;">{% trans "Actions" %}</th>
</tr> </tr>
{% for app_info in applications %} {% for app_info in motions %}
{% with application=app_info.application useractions=app_info.actions %} {% with motion=app_info.motion useractions=app_info.actions %}
<tr class="{% cycle '' 'odd' %} <tr class="{% cycle '' 'odd' %}
{% if application.active %}activeline{% endif %}"> {% if motion.active %}activeline{% endif %}">
<td>{% if application.number %}{{ application.number }}{% else %}-{% endif %}</td> <td>{% if motion.number %}{{ motion.number }}{% else %}-{% endif %}</td>
<td><a href="{% url application_view application.id %}">{{ application.public_version.title }}</a></td> <td><a href="{% url motion_view motion.id %}">{{ motion.public_version.title }}</a></td>
{% if min_supporters > 0 %} {% if min_supporters > 0 %}
<td>{{ application.count_supporters }}</td> <td>{{ motion.count_supporters }}</td>
{% endif %} {% endif %}
<td>{% if application.status != "pub" %} <td>{% if motion.status != "pub" %}
{{ application.get_status_display }}<br> {{ motion.get_status_display }}<br>
{% endif %} {% endif %}
{% for note in application.notes %} {% for note in motion.notes %}
{{ note }} {{ note }}
{% if not forloop.last %}<br>{%endif%} {% if not forloop.last %}<br>{%endif%}
{% endfor %} {% endfor %}
</td> </td>
<td>{{ application.submitter }}</td> <td>{{ motion.submitter }}</td>
<td>{{ application.creation_time }}</td> <td>{{ motion.creation_time }}</td>
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.projector.can_manage_projector %}
<a class="activate_link {% if application.active %}active{% endif %}" href="{% url projector_activate_slide application.sid %}" title="{% trans 'Activate motion' %}"> <a class="activate_link {% if motion.active %}active{% endif %}" href="{% url projector_activate_slide motion.sid %}" title="{% trans 'Activate motion' %}">
<span></span> <span></span>
</a> </a>
{% endif %} {% endif %}
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
<a href="{% url application_edit application.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit motion' %}"></a> <a href="{% url motion_edit motion.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit motion' %}"></a>
{% if "delete" in useractions %} {% if "delete" in useractions %}
<a href="{% url application_delete application.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete motion' %}"></a> <a href="{% url motion_delete motion.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete motion' %}"></a>
{% endif %} {% endif %}
{% endif %} {% endif %}
<a href="{% url print_application application.id %}" title="{% trans 'Motion as PDF' %}"><img src="{% static 'images/icons/pdf.png' %}"></a> <a href="{% url print_motion motion.id %}" title="{% trans 'Motion as PDF' %}"><img src="{% static 'images/icons/pdf.png' %}"></a>
</span> </span>
</td> </td>
</tr> </tr>

View File

@ -1,16 +1,16 @@
{% extends 'application/base_application.html' %} {% extends 'motion/base_motion.html' %}
{% load i18n %} {% load i18n %}
{% load staticfiles %} {% load staticfiles %}
{% block title %} {% block title %}
{{ block.super }} {% trans "Motion" %} "{{ application.public_version.title }}" {{ block.super }} {% trans "Motion" %} "{{ motion.public_version.title }}"
{{ ballot }}. {% trans "Vote" %} {{ ballot }}. {% trans "Vote" %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h1>{{ application.public_version.title }} ({% trans "Motion" %} <h1>{{ motion.public_version.title }} ({% trans "Motion" %}
{{ application.number }}) {{ ballot }}. {% trans "Vote" %}</h1> {{ motion.number }}) {{ ballot }}. {% trans "Vote" %}</h1>
<i class="helptext">{% trans "Special values" %}: -1 = {% trans 'majority' %}; -2 = {% trans 'undocumented' %}</i> <i class="helptext">{% trans "Special values" %}: -1 = {% trans 'majority' %}; -2 = {% trans 'undocumented' %}</i>
<form action="" method="post" class="small-form">{% csrf_token %} <form action="" method="post" class="small-form">{% csrf_token %}
{{ pre_form }} {{ pre_form }}
@ -40,8 +40,8 @@
{{ post_form }} {{ post_form }}
<p> <p>
<a href='{% url print_application_poll poll.id %}'> <a href='{% url print_motion_poll poll.id %}'>
<button class="button" type="button" onclick="window.location='{% url print_application_poll poll.id %}'"> <button class="button" type="button" onclick="window.location='{% url print_motion_poll poll.id %}'">
<span class="icon pdf">{% trans 'Ballot paper as PDF' %}</span> <span class="icon pdf">{% trans 'Ballot paper as PDF' %}</span>
</button> </button>
</a> </a>
@ -54,8 +54,8 @@
<button class="button" type="submit" name="apply"> <button class="button" type="submit" name="apply">
<span class="icon apply">{% trans 'Apply' %}</span> <span class="icon apply">{% trans 'Apply' %}</span>
</button> </button>
<a href='{% url application_view application.id %}'> <a href='{% url motion_view motion.id %}'>
<button class="button" type="button" onclick="window.location='{% url application_view application.id %}'"> <button class="button" type="button" onclick="window.location='{% url motion_view motion.id %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span> <span class="icon cancel">{% trans 'Cancel' %}</span>
</button> </button>
</a> </a>

View File

@ -1,4 +1,4 @@
{% extends "application/base_application.html" %} {% extends "motion/base_motion.html" %}
{% load tags %} {% load tags %}
{% load i18n %} {% load i18n %}
@ -16,15 +16,15 @@
<div id="sidebar"> <div id="sidebar">
<div class="box"> <div class="box">
<h4>{% trans "Submitter" %}:</h4> <h4>{% trans "Submitter" %}:</h4>
{{ application.submitter }} {{ motion.submitter }}
{% if min_supporters > 0 %} {% if min_supporters > 0 %}
<h4>{% trans "Supporters" %}: *</h4> <h4>{% trans "Supporters" %}: *</h4>
{% if not application.supporters %} {% if not motion.supporters %}
- -
{% else %} {% else %}
<ol> <ol>
{% for supporter in application.supporters %} {% for supporter in motion.supporters %}
<li> {{ supporter }}</li> <li> {{ supporter }}</li>
{% endfor %} {% endfor %}
</ol> </ol>
@ -32,21 +32,21 @@
{% endif %} {% endif %}
<h4>{% trans "Status" %}:</h4> <h4>{% trans "Status" %}:</h4>
{% if application.status != "pub" %} {% if motion.status != "pub" %}
{% trans application.get_status_display %} {% trans motion.get_status_display %}
<br> <br>
{% endif %} {% endif %}
{% for note in application.notes %} {% for note in motion.notes %}
{{ note }} {{ note }}
{% if not forloop.last %}<br>{% endif %} {% if not forloop.last %}<br>{% endif %}
{% endfor %} {% endfor %}
<h4>{% trans "Vote results" %}:</h4> <h4>{% trans "Vote results" %}:</h4>
{% with application.polls as polls %} {% with motion.polls as polls %}
{% if not polls.exists %} {% if not polls.exists %}
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
{% if "genpoll" in actions %} {% if "genpoll" in actions %}
<a href='{% url application_gen_poll application.id %}'> <a href='{% url motion_gen_poll motion.id %}'>
<span class="button"> <span class="button">
<span class="icon statistics">{% trans 'New vote' %}</span> <span class="icon statistics">{% trans 'New vote' %}</span>
</span> </span>
@ -60,14 +60,14 @@
{% endif %} {% endif %}
<ul class="results"> <ul class="results">
{% for poll in polls %} {% for poll in polls %}
{% if perms.application.can_manage_application or poll.has_votes %} {% if perms.motion.can_manage_motion or poll.has_votes %}
<li> <li>
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
<strong>{{ forloop.counter }}. {% trans "Vote" %} </strong> <strong>{{ forloop.counter }}. {% trans "Vote" %} </strong>
<a class="icon edit" href="{% url application_poll_view poll.id %}" title="{% trans 'Edit Vote' %}"> <a class="icon edit" href="{% url motion_poll_view poll.id %}" title="{% trans 'Edit Vote' %}">
<span></span> <span></span>
</a> </a>
<a class="icon delete" href="{% url application_poll_delete poll.id %}" title="{% trans 'Delete Vote' %}"> <a class="icon delete" href="{% url motion_poll_delete poll.id %}" title="{% trans 'Delete Vote' %}">
<span></span> <span></span>
</a> </a>
{% elif poll.has_votes %} {% elif poll.has_votes %}
@ -84,18 +84,18 @@
<img src="{% static 'images/icons/voting-total.png' %}" title="{% trans 'Votes cast' %}"> {{ poll.print_votescast }} <img src="{% static 'images/icons/voting-total.png' %}" title="{% trans 'Votes cast' %}"> {{ poll.print_votescast }}
</div> </div>
{% endwith %} {% endwith %}
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
{% if forloop.last %} {% if forloop.last %}
{% if "genpoll" in actions %} {% if "genpoll" in actions %}
<a href='{% url application_gen_poll application.id %}'> <a href='{% url motion_gen_poll motion.id %}'>
<span class="button"><span class="icon statistics">{% trans 'New vote' %}</span></span> <span class="button"><span class="icon statistics">{% trans 'New vote' %}</span></span>
</a> </a>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% else %} {% else %}
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
<a href='{% url application_poll_view poll.id %}'> <a href='{% url motion_poll_view poll.id %}'>
<span class="button"><span class="icon statistics">{% trans 'Enter result' %}</span></span> <span class="button"><span class="icon statistics">{% trans 'Enter result' %}</span></span>
</a> </a>
{% endif %} {% endif %}
@ -107,26 +107,26 @@
{% endwith %} {% endwith %}
<h4>{% trans "Creation Time" %}:</h4> <h4>{% trans "Creation Time" %}:</h4>
{{ application.creation_time }} {{ motion.creation_time }}
<p></p> <p></p>
{% if "wit" in actions and user == application.submitter.user %} {% if "wit" in actions and user == motion.submitter.user %}
<p></p> <p></p>
<a href='{% url application_set_status application.id 'wit' %}'> <a href='{% url motion_set_status motion.id 'wit' %}'>
<span class="button"><span class="icon revert">{% trans 'Withdraw' %}</span></span> <span class="button"><span class="icon revert">{% trans 'Withdraw' %}</span></span>
</a> </a>
{% endif %} {% endif %}
{% if perms.application.can_support_application and min_supporters > 0 %} {% if perms.motion.can_support_motion and min_supporters > 0 %}
{% if "unsupport" in actions %} {% if "unsupport" in actions %}
<p></p> <p></p>
<a href='{% url application_unsupport application.id %}'> <a href='{% url motion_unsupport motion.id %}'>
<span class="button"><span class="icon remove">{% trans 'Unsupport' %}</span></span> <span class="button"><span class="icon remove">{% trans 'Unsupport' %}</span></span>
</a> </a>
{% endif %} {% endif %}
{% if "support" in actions %} {% if "support" in actions %}
<p></p> <p></p>
<a href='{% url application_support application.id %}'> <a href='{% url motion_support motion.id %}'>
<span class="button"><span class="icon add">{% trans 'Support' %}</span></span> <span class="button"><span class="icon add">{% trans 'Support' %}</span></span>
</a> </a>
{% endif %} {% endif %}
@ -138,23 +138,23 @@
<br><br> <br><br>
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
<div class="box"> <div class="box">
<h4><b>{% trans "Manage motion" %}</b></h4> <h4><b>{% trans "Manage motion" %}</b></h4>
{% if "pub" in actions or "per" in actions or "nop" in actions or "setnumber" in actions %} {% if "pub" in actions or "per" in actions or "nop" in actions or "setnumber" in actions %}
<h4>{% trans "Formal validation" %}:</h4> <h4>{% trans "Formal validation" %}:</h4>
{% if "pub" in actions %} {% if "pub" in actions %}
<a href='{% url application_set_status application.id 'pub' %}'><span class="button"><span class="icon ok-blue">{% trans 'Publish' %}</span></span></a> <a href='{% url motion_set_status motion.id 'pub' %}'><span class="button"><span class="icon ok-blue">{% trans 'Publish' %}</span></span></a>
{% endif %} {% endif %}
{% if "per" in actions %} {% if "per" in actions %}
<a href='{% url application_permit application.id %}'><span class="button"><span class="icon ok-blue">{% trans 'Permit' %}</span></span></a> <a href='{% url motion_permit motion.id %}'><span class="button"><span class="icon ok-blue">{% trans 'Permit' %}</span></span></a>
{% endif %} {% endif %}
{% if "nop" in actions %} {% if "nop" in actions %}
<a href='{% url application_notpermit application.id %}'><span class="button"><span class="icon reject">{% trans 'Not permit (reject)' %}</span></span></a> <a href='{% url motion_notpermit motion.id %}'><span class="button"><span class="icon reject">{% trans 'Not permit (reject)' %}</span></span></a>
{% endif %} {% endif %}
{% if "setnumber" in actions %} {% if "setnumber" in actions %}
<a href='{% url application_set_number application.id %}'><span class="button"><span class="icon number">{% trans 'Set Number' %}</span></span></a> <a href='{% url motion_set_number motion.id %}'><span class="button"><span class="icon number">{% trans 'Set Number' %}</span></span></a>
{% endif %} {% endif %}
</p> </p>
{% endif %} {% endif %}
@ -163,12 +163,12 @@
{% if "acc" in actions or "rej" in actions %} {% if "acc" in actions or "rej" in actions %}
<h4>{% trans "Result after vote" %}:</h4> <h4>{% trans "Result after vote" %}:</h4>
{% if "acc" in actions %} {% if "acc" in actions %}
<a href='{% url application_set_status application.id 'acc' %}'> <a href='{% url motion_set_status motion.id 'acc' %}'>
<span class="button"><span class="icon done">{% trans 'Accepted' %}</span></span> <span class="button"><span class="icon done">{% trans 'Accepted' %}</span></span>
</a> </a>
{% endif %} {% endif %}
{% if "rej" in actions %} {% if "rej" in actions %}
<a href='{% url application_set_status application.id 'rej' %}'> <a href='{% url motion_set_status motion.id 'rej' %}'>
<span class="button"><span class="icon reject">{% trans 'Rejected' %}</span></span> <span class="button"><span class="icon reject">{% trans 'Rejected' %}</span></span>
</a> </a>
{% endif %} {% endif %}
@ -177,26 +177,26 @@
{% if "adj" in actions or "noc" in actions or "com" in actions or "wit" in actions %} {% if "adj" in actions or "noc" in actions or "com" in actions or "wit" in actions %}
<h4>{% trans 'Result after debate' %}:</h4> <h4>{% trans 'Result after debate' %}:</h4>
{% if "adj" in actions %} {% if "adj" in actions %}
<a href='{% url application_set_status application.id 'adj' %}'><span class="button">{% trans 'Adjourned' %}</span></a><br> <a href='{% url motion_set_status motion.id 'adj' %}'><span class="button">{% trans 'Adjourned' %}</span></a><br>
{% endif %} {% endif %}
{% if "noc" in actions %} {% if "noc" in actions %}
<a href='{% url application_set_status application.id 'noc' %}'><span class="button">{% trans 'Not Concerned' %}</span></a><br> <a href='{% url motion_set_status motion.id 'noc' %}'><span class="button">{% trans 'Not Concerned' %}</span></a><br>
{% endif %} {% endif %}
{% if "com" in actions %} {% if "com" in actions %}
<a href='{% url application_set_status application.id 'com' %}'><span class="button">{% trans 'Commited a bill' %}</span></a><br> <a href='{% url motion_set_status motion.id 'com' %}'><span class="button">{% trans 'Commited a bill' %}</span></a><br>
{% endif %} {% endif %}
{% if "wit" in actions %} {% if "wit" in actions %}
<a href='{% url application_set_status application.id 'wit' %}'><span class="button">{% trans 'Withdrawed by Submitter' %}</span></a> <a href='{% url motion_set_status motion.id 'wit' %}'><span class="button">{% trans 'Withdrawed by Submitter' %}</span></a>
{% endif %} {% endif %}
{% endif %} {% endif %}
<p></p> <p></p>
<hr> <hr>
<h4>{% trans "For Administration only:" %}</h4> <h4>{% trans "For Administration only:" %}</h4>
<a href='{% url application_reset application.id %}'> <a href='{% url motion_reset motion.id %}'>
<span class="button"><span class="icon undo">{% trans 'Reset' %}</span></span> <span class="button"><span class="icon undo">{% trans 'Reset' %}</span></span>
</a> </a>
</div> </div>
{% endif %} {# end perms.application.can_support_application #} {% endif %} {# end perms.motion.can_support_motion #}
</div> <!-- end sidebar --> </div> <!-- end sidebar -->
@ -204,8 +204,8 @@
<h1> <h1>
{{ version.title }} {{ version.title }}
({% trans "Motion" %} ({% trans "Motion" %}
{% if application.number != None %} {% if motion.number != None %}
{{ application.number }}) {{ motion.number }})
{% else %} {% else %}
<i>[{% trans "no number" %}]</i>) <i>[{% trans "no number" %}]</i>)
{% endif %} {% endif %}
@ -213,12 +213,12 @@
{% trans "Version" %} {{ version.aid }} {% trans "Version" %} {{ version.aid }}
{% if application.public_version != application.last_version %} {% if motion.public_version != motion.last_version %}
&#8901; &#8901;
{% if version == application.public_version %} {% if version == motion.public_version %}
{% trans "This is not the newest version." %} <a href="{% url application_view_newest application.id %}">{% trans "Go to version" %} {{ application.last_version.aid }}.</a> {% trans "This is not the newest version." %} <a href="{% url motion_view_newest motion.id %}">{% trans "Go to version" %} {{ motion.last_version.aid }}.</a>
{% else %} {% else %}
{% trans "This is not the authorized version." %} <a href="{% url application_view application.id %}">{% trans "Go to version" %} {{ application.public_version.aid }}.</a> {% trans "This is not the authorized version." %} <a href="{% url motion_view motion.id %}">{% trans "Go to version" %} {{ motion.public_version.aid }}.</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
@ -235,7 +235,7 @@
{% endif %} {% endif %}
{% if application.versions|length > 1 %} {% if motion.versions|length > 1 %}
<h2>{% trans "Version History" %}:</h2> <h2>{% trans "Version History" %}:</h2>
<table class="table valigntop" style="width: auto;"> <table class="table valigntop" style="width: auto;">
@ -248,18 +248,18 @@
<th>{% trans "Reason" %}</th> <th>{% trans "Reason" %}</th>
</tr> </tr>
{% for revision in application.versions %} {% for revision in motion.versions %}
<tr class="{% cycle 'odd' '' %}"> <tr class="{% cycle 'odd' '' %}">
<td style="white-space:nowrap;"> <td style="white-space:nowrap;">
{% if application.status != "pub" %} {% if motion.status != "pub" %}
{% if revision == application.permitted %} {% if revision == motion.permitted %}
<img title="{% trans 'Version authorized' %}" src="{% static 'images/icons/accept.png' %}"> <img title="{% trans 'Version authorized' %}" src="{% static 'images/icons/accept.png' %}">
{% else %} {% else %}
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
<a href="{% url application_version_permit revision.id %}"><img title="{% trans 'Permit Version' %}" src="{% static 'images/icons/accept-grey.png' %}"></a> <a href="{% url motion_version_permit revision.id %}"><img title="{% trans 'Permit Version' %}" src="{% static 'images/icons/accept-grey.png' %}"></a>
{% endif %} {% endif %}
{% if not revision.rejected and revision.id > application.permitted.id and perms.application.can_manage_application %} {% if not revision.rejected and revision.id > motion.permitted.id and perms.motion.can_manage_motion %}
<a href="{% url application_version_reject revision.id %}"><img title="{% trans 'Reject Version' %}" src="{% static 'images/icons/reject-grey.png' %}"></a> <a href="{% url motion_version_reject revision.id %}"><img title="{% trans 'Reject Version' %}" src="{% static 'images/icons/reject-grey.png' %}"></a>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if revision.rejected %} {% if revision.rejected %}
@ -295,9 +295,9 @@
</table> </table>
{% endif %} {% endif %}
{% if perms.application.can_manage_application %} {% if perms.motion.can_manage_motion %}
<h2>{% trans "Log" %}:</h2> <h2>{% trans "Log" %}:</h2>
{{ application.log|linebreaks }} {{ motion.log|linebreaks }}
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,34 @@
{% load staticfiles %}
{% load i18n %}
{% load tags %}
<ul style="line-height: 180%">
{% for motion in motions %}
<li class="{% if motion.active %}activeline{% endif %}">
<a href="{% url projector_activate_slide motion.sid %}" class="activate_link {% if motion.active %}active{% endif %}">
<div></div>
</a>
<a href="{% model_url motion 'delete' %}" title="{% trans 'Delete' %}" class="icon delete right">
<span></span>
</a>
<a href="{% model_url motion 'edit' %}" title="{% trans 'Edit' %}" class="icon edit right">
<span></span>
</a>
<a href="{% url projctor_preview_slide motion.sid %}" title="{% trans 'Preview' %}" class="icon preview right">
<span></span>
</a>
<a href="{% model_url motion 'view' %}">
{{ motion.public_version.title }}
</a>
({% trans "motion" %}
{% if motion.number %}
{{ motion.number }})
{% else %}
<i>[{% trans "no number" %}]</i>)
{% endif %}
</li>
{% empty %}
<li>{% trans 'No motion available.' %}</li>
{% endfor %}
</ul>

View File

@ -4,27 +4,27 @@
{% load i18n %} {% load i18n %}
{% load staticfiles %} {% load staticfiles %}
{% block title %}{{ block.super }} - {% trans "Motion" %} {{ application.number }}{% endblock %} {% block title %}{{ block.super }} - {% trans "Motion" %} {{ motion.number }}{% endblock %}
{% block content %} {% block content %}
<div id="sidebar"> <div id="sidebar">
<div class="box"> <div class="box">
<p><b>{% trans "Status" %}:</b><br> <p><b>{% trans "Status" %}:</b><br>
{% if application.status != "pub" %} {% if motion.status != "pub" %}
{% if application.status == "acc" %} {% if motion.status == "acc" %}
<img src="{% static 'images/icons/voting-yes.png' %}"> <img src="{% static 'images/icons/voting-yes.png' %}">
{% endif %} {% endif %}
{% if application.status == "rej" %} {% if motion.status == "rej" %}
<img src="{% static 'images/icons/voting-no.png' %}"> <img src="{% static 'images/icons/voting-no.png' %}">
{% endif %} {% endif %}
{% trans application.get_status_display %} {% trans motion.get_status_display %}
{% else %} {% else %}
{% for note in application.notes %} {% for note in motion.notes %}
{{ note }} {{ note }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>
{% with application.polls as polls %} {% with motion.polls as polls %}
{% if polls.exists and polls.0.has_votes %} {% if polls.exists and polls.0.has_votes %}
<p><b>{% trans "Poll result" %}:</b> <p><b>{% trans "Poll result" %}:</b>
{% for poll in polls %} {% for poll in polls %}
@ -53,29 +53,29 @@
{% endwith %} {% endwith %}
<p><b>{% trans "Submitter" %}:</b><br> <p><b>{% trans "Submitter" %}:</b><br>
{{ application.submitter }} {{ motion.submitter }}
</p> </p>
</div> </div>
</div> </div>
<h1> <h1>
{% if application.number != None %} {% if motion.number != None %}
{% trans "Motion No." %} {{ application.number }} {% trans "Motion No." %} {{ motion.number }}
{% else %} {% else %}
{% trans "Motion" %} <i>[{% trans "no number" %}]</i> {% trans "Motion" %} <i>[{% trans "no number" %}]</i>
{% endif %} {% endif %}
</h1> </h1>
<b>{{ application.public_version.title }}</b> <b>{{ motion.public_version.title }}</b>
<hr> <hr>
{% endblock %} {% endblock %}
{% block scrollcontent %} {% block scrollcontent %}
<p> <p>
<div class="text">{{ application.public_version.text|linebreaks }}</div> <div class="text">{{ motion.public_version.text|linebreaks }}</div>
{% if application.public_version.reason %} {% if motion.public_version.reason %}
<br> <br>
<div class="reason"><p><b>{% trans "Reason" %}:</b></p> <div class="reason"><p><b>{% trans "Reason" %}:</b></p>
{{ application.public_version.reason|linebreaks }}</div> {{ motion.public_version.reason|linebreaks }}</div>
{% endif %} {% endif %}
</p> </p>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
openslides.application.tests openslides.motion.tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unit tests for the application app. Unit tests for the motion app.
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS. :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
@ -14,19 +14,19 @@ from django.test import TestCase
from django.test.client import Client from django.test.client import Client
from openslides.participant.models import User from openslides.participant.models import User
from openslides.application.models import Application, AVersion from openslides.motion.models import Motion, AVersion
class ApplicationTest(TestCase): class MotionTest(TestCase):
def setUp(self): def setUp(self):
self.admin = User(username='testadmin') self.admin = User(username='testadmin')
self.admin.save() self.admin.save()
self.anonym = User(username='testanoym') self.anonym = User(username='testanoym')
self.anonym.save() self.anonym.save()
self.app1 = Application(submitter=self.admin) self.app1 = Motion(submitter=self.admin)
self.app1.save() self.app1.save()
def refresh(self): def refresh(self):
self.app1 = Application.objects.get(pk=self.app1.id) self.app1 = Motion.objects.get(pk=self.app1.id)
def testVersion(self): def testVersion(self):
self.assertTrue(self.app1.versions.exists()) self.assertTrue(self.app1.versions.exists())

141
openslides/motion/urls.py Normal file
View File

@ -0,0 +1,141 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
openslides.motion.urls
~~~~~~~~~~~~~~~~~~~~~~~~~~~
URL list for the motion app.
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details.
"""
from django.conf.urls.defaults import url, patterns
from openslides.motion.views import (MotionDelete, ViewPoll,
MotionPDF, MotionPollPDF, CreateAgendaItem, SupportView)
urlpatterns = patterns('openslides.motion.views',
url(r'^$',
'overview',
name='motion_overview',
),
url(r'^(?P<motion_id>\d+)/$',
'view',
name='motion_view',
),
url(r'^(?P<motion_id>\d+)/agenda/$',
CreateAgendaItem.as_view(),
name='motion_create_agenda',
),
url(r'^(?P<motion_id>\d+)/newest/$',
'view',
{'newest': True},
name='motion_view_newest',
),
url(r'^new/$',
'edit',
name='motion_new',
),
url(r'^import/$',
'motion_import',
name='motion_import',
),
url(r'^(?P<motion_id>\d+)/edit/$',
'edit',
name='motion_edit',
),
url(r'^(?P<motion_id>\d+)/del/$',
MotionDelete.as_view(),
name='motion_delete',
),
url(r'^del/$',
MotionDelete.as_view(),
{ 'motion_id' : None , 'motion_ids' : None },
name='motion_delete',
),
url(r'^(?P<motion_id>\d+)/setnumber/$',
'set_number',
name='motion_set_number',
),
url(r'^(?P<motion_id>\d+)/setstatus/(?P<status>[a-z]{3})/$',
'set_status',
name='motion_set_status',
),
url(r'^(?P<motion_id>\d+)/permit/$',
'permit',
name='motion_permit',
),
url(r'^version/(?P<aversion_id>\d+)/permit/$',
'permit_version',
name='motion_version_permit',
),
url(r'^version/(?P<aversion_id>\d+)/reject/$',
'reject_version',
name='motion_version_reject',
),
url(r'^(?P<motion_id>\d+)/notpermit/$',
'notpermit',
name='motion_notpermit',
),
url(r'^(?P<motion_id>\d+)/reset/$',
'reset',
name='motion_reset',
),
url(r'^(?P<motion_id>\d+)/support/$',
SupportView.as_view(support=True),
name='motion_support',
),
url(r'^(?P<motion_id>\d+)/unsupport/$',
SupportView.as_view(support=False),
name='motion_unsupport',
),
url(r'^(?P<motion_id>\d+)/gen_poll/$',
'gen_poll',
name='motion_gen_poll',
),
url(r'^print/$',
MotionPDF.as_view(),
{'motion_id': None},
name='print_motions',
),
url(r'^(?P<motion_id>\d+)/print/$',
MotionPDF.as_view(),
name='print_motion',
),
url(r'^poll/(?P<poll_id>\d+)/print/$',
MotionPollPDF.as_view(),
name='print_motion_poll',
),
url(r'^poll/(?P<poll_id>\d+)/$',
ViewPoll.as_view(),
name='motion_poll_view',
),
url(r'^poll/(?P<poll_id>\d+)/del/$',
'delete_poll',
name='motion_poll_delete',
),
)

View File

@ -119,7 +119,7 @@ INSTALLED_APPS = (
'openslides.poll', 'openslides.poll',
'openslides.projector', 'openslides.projector',
'openslides.agenda', 'openslides.agenda',
'openslides.application', 'openslides.motion',
'openslides.assignment', 'openslides.assignment',
'openslides.participant', 'openslides.participant',
'openslides.config', 'openslides.config',
@ -134,3 +134,10 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'openslides.utils.utils.revision', 'openslides.utils.utils.revision',
'openslides.utils.auth.anonymous_context_additions', 'openslides.utils.auth.anonymous_context_additions',
) )
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'openslidecache'
}
}

View File

@ -47,7 +47,7 @@ def gen_username(first_name, last_name):
i = 0 i = 0
while True: while True:
i += 1 i += 1
testname = "%s%s%s" % (first_name, last_name, i) testname = "%s %s %s" % (first_name, last_name, i)
try: try:
User.objects.get(username=testname) User.objects.get(username=testname)
except User.DoesNotExist: except User.DoesNotExist:

View File

@ -27,7 +27,7 @@ class UserCreateForm(forms.ModelForm, CssClassMixin):
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name', 'is_active', 'groups', 'category', fields = ('first_name', 'last_name', 'is_active', 'groups', 'detail',
'gender', 'type', 'committee', 'comment', 'default_password') 'gender', 'type', 'committee', 'comment', 'default_password')
@ -35,7 +35,7 @@ class UserUpdateForm(UserCreateForm):
class Meta: class Meta:
model = User model = User
fields = ('username', 'first_name', 'last_name', 'is_active', 'groups', fields = ('username', 'first_name', 'last_name', 'is_active', 'groups',
'category', 'gender', 'type', 'committee', 'comment', 'detail', 'gender', 'type', 'committee', 'comment',
'default_password') 'default_password')

View File

@ -16,14 +16,14 @@ from django.db.models import signals
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _, ugettext_noop from django.utils.translation import ugettext_lazy as _, ugettext_noop
from openslides.utils.person import PersonMixin from openslides.utils.person import PersonMixin, Person
from openslides.utils.person.signals import receive_persons from openslides.utils.person.signals import receive_persons
from openslides.config.models import config from openslides.config.models import config
from openslides.config.signals import default_config_value from openslides.config.signals import default_config_value
class User(DjangoUser, PersonMixin): class User(DjangoUser, PersonMixin, Person):
person_prefix = 'user' person_prefix = 'user'
GENDER_CHOICES = ( GENDER_CHOICES = (
('male', _('Male')), ('male', _('Male')),
@ -37,8 +37,8 @@ class User(DjangoUser, PersonMixin):
) )
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True) django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
category = models.CharField( detail = models.CharField(
max_length=100, null=True, blank=True, verbose_name=_("Category"), max_length=100, blank=True, default='', verbose_name=_("Detail"),
help_text=_('Will be shown behind the name.')) help_text=_('Will be shown behind the name.'))
gender = models.CharField( gender = models.CharField(
max_length=50, choices=GENDER_CHOICES, blank=True, max_length=50, choices=GENDER_CHOICES, blank=True,
@ -47,20 +47,24 @@ class User(DjangoUser, PersonMixin):
max_length=100, choices=TYPE_CHOICES, blank=True, max_length=100, choices=TYPE_CHOICES, blank=True,
verbose_name=_("Typ"), help_text=_('Only for filter the userlist.')) verbose_name=_("Typ"), help_text=_('Only for filter the userlist.'))
committee = models.CharField( committee = models.CharField(
max_length=100, null=True, blank=True, verbose_name=_("Committee"), max_length=100, blank=True, default='', verbose_name=_("Committee"),
help_text=_('Only for filter the userlist.')) help_text=_('Only for filter the userlist.'))
comment = models.TextField( comment = models.TextField(
null=True, blank=True, verbose_name=_('Comment'), blank=True, default='', verbose_name=_('Comment'),
help_text=_('Only for notes.')) help_text=_('Only for notes.'))
default_password = models.CharField( default_password = models.CharField(
max_length=100, null=True, blank=True, max_length=100, blank=True, default='',
verbose_name=_("Default password")) verbose_name=_("Default password"))
@property
def clean_name(self):
return self.get_full_name() or self.username
def get_name_suffix(self): def get_name_suffix(self):
return self.category return self.detail
def set_name_suffix(self, value): def set_name_suffix(self, value):
self.category = value self.detail = value
name_suffix = property(get_name_suffix, set_name_suffix) name_suffix = property(get_name_suffix, set_name_suffix)
@ -88,10 +92,9 @@ class User(DjangoUser, PersonMixin):
return ('user_delete', [str(self.id)]) return ('user_delete', [str(self.id)])
def __unicode__(self): def __unicode__(self):
name = self.get_full_name() or self.username
if self.name_suffix: if self.name_suffix:
return u"%s (%s)" % (name, self.name_suffix) return u"%s (%s)" % (self.clean_name, self.name_suffix)
return u"%s" % name return u"%s" % self.clean_name
class Meta: class Meta:
# Rename permissions # Rename permissions
@ -103,7 +106,7 @@ class User(DjangoUser, PersonMixin):
ordering = ('last_name',) ordering = ('last_name',)
class Group(DjangoGroup, PersonMixin): class Group(DjangoGroup, PersonMixin, Person):
person_prefix = 'group' person_prefix = 'group'
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True) django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)

View File

@ -12,8 +12,8 @@
<button class="button" type="submit"> <button class="button" type="submit">
<span class="icon ok">{% trans 'Save' %}</span> <span class="icon ok">{% trans 'Save' %}</span>
</button> </button>
<a href='{% url config_application %}'> <a href='{% url config_participant %}'>
<button class="button" type="button" onclick="window.location='{% url config_application %}'"> <button class="button" type="button" onclick="window.location='{% url config_participant %}'">
<span class="icon cancel">{% trans 'Cancel' %}</span> <span class="icon cancel">{% trans 'Cancel' %}</span>
</button> </button>
</a> </a>

View File

@ -26,11 +26,11 @@
<option value="female"{% if 'female' in sortfilter.gender %} selected{% endif %}>{% trans "Female" %}</option> <option value="female"{% if 'female' in sortfilter.gender %} selected{% endif %}>{% trans "Female" %}</option>
<option value=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option> <option value=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option>
</select> </select>
<select class="default-input" name="category" onchange="document.forms['filter'].submit()"> <select class="default-input" name="detail" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Category" %} --</option> <option value="---">-- {% trans "Detail" %} --</option>
{% for category in categories %} {% for detail in details %}
<option value="{{ category }}"{% if category in sortfilter.category %} selected{% endif %}> <option value="{{ detail }}"{% if detail in sortfilter.detail %} selected{% endif %}>
{{ category }}</option> {{ detail }}</option>
{% endfor %} {% endfor %}
</select> </select>
<select class="default-input" name="type" onchange="document.forms['filter'].submit()"> <select class="default-input" name="type" onchange="document.forms['filter'].submit()">
@ -65,7 +65,7 @@
<tr> <tr>
<th><a href="?sort=first_name&reverse={% if 'first_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "First Name" %}</a></th> <th><a href="?sort=first_name&reverse={% if 'first_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "First Name" %}</a></th>
<th><a href="?sort=last_name&reverse={% if 'last_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Name" %}</a></th> <th><a href="?sort=last_name&reverse={% if 'last_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Name" %}</a></th>
<th><a href="?sort=category&reverse={% if 'category' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Category" %}</a></th> <th><a href="?sort=detail&reverse={% if 'detail' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Detail" %}</a></th>
<th><a href="?sort=type&reverse={% if 'type' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Type" %}</a></th> <th><a href="?sort=type&reverse={% if 'type' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Type" %}</a></th>
<th><a href="?sort=committee&reverse={% if 'committee' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Committee" %}</a></th> <th><a href="?sort=committee&reverse={% if 'committee' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Committee" %}</a></th>
{% if perms.participant.can_manage_participant %} {% if perms.participant.can_manage_participant %}
@ -78,7 +78,7 @@
<tr class="{% cycle '' 'odd' %}"> <tr class="{% cycle '' 'odd' %}">
<td>{{ user.first_name }}</td> <td>{{ user.first_name }}</td>
<td>{{ user.last_name }}</td> <td>{{ user.last_name }}</td>
<td>{{ user.category }}</td> <td>{{ user.detail }}</td>
<td>{{ user.get_type_display }}</td> <td>{{ user.get_type_display }}</td>
<td>{{ user.committee }}</td> <td>{{ user.committee }}</td>
{% if perms.participant.can_manage_participant %} {% if perms.participant.can_manage_participant %}

View File

@ -35,12 +35,12 @@ class UserTest(TestCase):
self.assertEqual(self.django_user1, self.user1.django_user) self.assertEqual(self.django_user1, self.user1.django_user)
def test_repr(self): def test_repr(self):
self.assertEqual(unicode(self.user1), u'Max Mustermann') self.assertEqual(unicode(self.user1), 'Max Mustermann')
def test_name_surfix(self): def test_name_suffix(self):
self.user1.category = u'München' self.user1.detail = 'München'
self.user1.save() self.user1.save()
self.assertEqual(unicode(self.user1), u'Max Mustermann (München)') self.assertEqual(unicode(self.user1), 'Max Mustermann (München)')
def test_reset_password(self): def test_reset_password(self):
self.assertIsInstance(self.user1.default_password, basestring) self.assertIsInstance(self.user1.default_password, basestring)

View File

@ -66,8 +66,8 @@ class Overview(ListView):
except KeyError: except KeyError:
sortfilter = {} sortfilter = {}
for value in [u'gender', u'category', u'type', u'committee', u'status', for value in ['gender', 'detail', 'type', 'committee', 'status',
u'sort', u'reverse']: 'sort', 'reverse']:
if value in self.request.REQUEST: if value in self.request.REQUEST:
if self.request.REQUEST[value] == '---': if self.request.REQUEST[value] == '---':
try: try:
@ -80,8 +80,8 @@ class Overview(ListView):
query = User.objects query = User.objects
if 'gender' in sortfilter: if 'gender' in sortfilter:
query = query.filter(gender__iexact=sortfilter['gender'][0]) query = query.filter(gender__iexact=sortfilter['gender'][0])
if 'category' in sortfilter: if 'detail' in sortfilter:
query = query.filter(category__iexact=sortfilter['category'][0]) query = query.filter(detail__iexact=sortfilter['detail'][0])
if 'type' in sortfilter: if 'type' in sortfilter:
query = query.filter(type__iexact=sortfilter['type'][0]) query = query.filter(type__iexact=sortfilter['type'][0])
if 'committee' in sortfilter: if 'committee' in sortfilter:
@ -92,7 +92,7 @@ class Overview(ListView):
if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']: if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']:
query = query.order_by(sortfilter['sort'][0]) query = query.order_by(sortfilter['sort'][0])
elif (sortfilter['sort'][0] in elif (sortfilter['sort'][0] in
['category', 'type', 'committee', 'comment']): ['detail', 'type', 'committee', 'comment']):
query = query.order_by( query = query.order_by(
'%s' % sortfilter['sort'][0]) '%s' % sortfilter['sort'][0])
else: else:
@ -118,8 +118,8 @@ class Overview(ListView):
percent = 0 percent = 0
# list of all existing categories # list of all existing categories
categories = [p['category'] for p in User.objects.values('category') details = [p['detail'] for p in User.objects.values('detail')
.exclude(category='').distinct()] .exclude(detail='').distinct()]
# list of all existing committees # list of all existing committees
committees = [p['committee'] for p in User.objects.values('committee') committees = [p['committee'] for p in User.objects.values('committee')
@ -127,7 +127,7 @@ class Overview(ListView):
context.update({ context.update({
'allusers': all_users, 'allusers': all_users,
'percent': round(percent, 1), 'percent': round(percent, 1),
'categories': categories, 'details': details,
'committees': committees, 'committees': committees,
'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter), 'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
doseq=True)], doseq=True)],
@ -223,7 +223,7 @@ class ParticipantsListPDF(PDFView):
counter, counter,
Paragraph(user.last_name, stylesheet['Tablecell']), Paragraph(user.last_name, stylesheet['Tablecell']),
Paragraph(user.first_name, stylesheet['Tablecell']), Paragraph(user.first_name, stylesheet['Tablecell']),
Paragraph(user.category, stylesheet['Tablecell']), Paragraph(user.detail, stylesheet['Tablecell']),
Paragraph(user.type, stylesheet['Tablecell']), Paragraph(user.type, stylesheet['Tablecell']),
Paragraph(user.committee, stylesheet['Tablecell'])]) Paragraph(user.committee, stylesheet['Tablecell'])])
t = LongTable(data, style=[ t = LongTable(data, style=[
@ -320,7 +320,7 @@ class UserImportView(FormView):
return super(UserImportView, self).form_valid(form) return super(UserImportView, self).form_valid(form)
class ResetPasswordView(RedirectView, SingleObjectMixin, QuestionMixin): class ResetPasswordView(SingleObjectMixin, QuestionMixin, RedirectView):
""" """
Set the Passwort for a user to his default password. Set the Passwort for a user to his default password.
""" """
@ -336,17 +336,11 @@ class ResetPasswordView(RedirectView, SingleObjectMixin, QuestionMixin):
def get_redirect_url(self, **kwargs): def get_redirect_url(self, **kwargs):
return reverse('user_edit', args=[self.object.id]) return reverse('user_edit', args=[self.object.id])
def pre_redirect(self, request, *args, **kwargs): def case_yes(self):
self.confirm_form() self.object.reset_password()
def pre_post_redirect(self, request, *args, **kwargs): def get_success_message(self):
if self.get_answer().lower() == 'yes': return _('The Password for %s was successfully reset.') % html_strong(self.object)
self.object.reset_password()
messages.success(request,
_('The Password for %s was successfully reset.') % html_strong(self.object))
def get_answer_url(self):
return reverse('user_reset_password', args=[self.object.id])
class GroupOverviewView(ListView): class GroupOverviewView(ListView):

View File

@ -11,6 +11,7 @@
""" """
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from django.utils.importlib import import_module from django.utils.importlib import import_module
@ -85,6 +86,13 @@ def set_active_slide(sid, argument=None):
""" """
config["presentation"] = sid config["presentation"] = sid
config['presentation_argument'] = argument config['presentation_argument'] = argument
clear_projector_cache()
def clear_projector_cache():
cache.delete('projector_content')
cache.delete('projector_scrollcontent')
cache.delete('projector_data')
def register_slidemodel(model, model_name=None, control_template=None, def register_slidemodel(model, model_name=None, control_template=None,

View File

@ -58,6 +58,12 @@ class SlideMixin(object):
""" """
set_active_slide(self.sid) set_active_slide(self.sid)
def save(self, *args, **kwargs):
if self.active:
from api import clear_projector_cache
clear_projector_cache()
return super(SlideMixin, self).save(*args, **kwargs)
class Slide(object): class Slide(object):
""" """

View File

@ -15,6 +15,7 @@ from time import time
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.core.cache import cache
from django.core.context_processors import csrf from django.core.context_processors import csrf
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
@ -73,6 +74,7 @@ class Projector(TemplateView, AjaxMixin):
except AttributeError: #TODO: It has to be an Slide.DoesNotExist except AttributeError: #TODO: It has to be an Slide.DoesNotExist
data = None data = None
ajax = 'on' ajax = 'on'
active_sid = get_active_slide(True)
else: else:
data = get_slide_from_sid(sid) data = get_slide_from_sid(sid)
ajax = 'off' ajax = 'off'
@ -88,7 +90,7 @@ class Projector(TemplateView, AjaxMixin):
# Projector Overlays # Projector Overlays
if self.kwargs['sid'] is None: if self.kwargs['sid'] is None:
active_defs = ProjectorOverlay.objects.filter(active=True) \ active_defs = ProjectorOverlay.objects.filter(active=True) \
.filter(Q(sid=sid) | Q(sid=None)).values_list('def_name', .filter(Q(sid=active_sid) | Q(sid=None)).values_list('def_name',
flat=True) flat=True)
for receiver, response in projector_overlays.send(sender=sid, for receiver, response in projector_overlays.send(sender=sid,
register=False, call=active_defs): register=False, call=active_defs):
@ -106,10 +108,26 @@ class Projector(TemplateView, AjaxMixin):
return context return context
def get_ajax_context(self, **kwargs): def get_ajax_context(self, **kwargs):
content = render_block_to_string(self.get_template_names()[0], content = cache.get('projector_content')
'content', self.data) if not content:
scrollcontent = render_block_to_string(self.get_template_names()[0], content = render_block_to_string(
'scrollcontent', self.data) self.get_template_names()[0],
'content', self.data)
cache.set('projector_content', content)
scrollcontent = cache.get('projector_scrollcontent')
if not scrollcontent:
scrollcontent = render_block_to_string(
self.get_template_names()[0],
'scrollcontent', self.data)
cache.set('projector_scrollcontent', scrollcontent)
# TODO: do not call the hole data-methode, if we only need some vars
data = cache.get('projector_data')
if not data:
data = self.data
cache.set('projector_data', data)
context = super(Projector, self).get_ajax_context(**kwargs) context = super(Projector, self).get_ajax_context(**kwargs)
content_hash = hash(content) content_hash = hash(content)
@ -117,8 +135,8 @@ class Projector(TemplateView, AjaxMixin):
'content': content, 'content': content,
'scrollcontent': scrollcontent, 'scrollcontent': scrollcontent,
'time': datetime.now().strftime('%H:%M'), 'time': datetime.now().strftime('%H:%M'),
'overlays': self.data['overlays'], 'overlays': data['overlays'],
'title': self.data['title'], 'title': data['title'],
'bigger': config['bigger'], 'bigger': config['bigger'],
'up': config['up'], 'up': config['up'],
'content_hash': content_hash, 'content_hash': content_hash,

View File

@ -26,7 +26,7 @@ urlpatterns = patterns('',
(r'^$', FrontPage.as_view()), (r'^$', FrontPage.as_view()),
(r'^agenda/', include('openslides.agenda.urls')), (r'^agenda/', include('openslides.agenda.urls')),
(r'^application/', include('openslides.application.urls')), (r'^motion/', include('openslides.motion.urls')),
(r'^assignment/', include('openslides.assignment.urls')), (r'^assignment/', include('openslides.assignment.urls')),
(r'^participant/', include('openslides.participant.urls')), (r'^participant/', include('openslides.participant.urls')),
(r'^config/', include('openslides.config.urls')), (r'^config/', include('openslides.config.urls')),

View File

@ -11,7 +11,8 @@
""" """
from openslides.utils.person.signals import receive_persons from openslides.utils.person.signals import receive_persons
from openslides.utils.person.api import generate_person_id, get_person, 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.forms import PersonFormField, MultiplePersonFormField
from openslides.utils.person.models import PersonField, PersonMixin from openslides.utils.person.models import PersonField, PersonMixin

View File

@ -13,6 +13,37 @@
from openslides.utils.person.signals import receive_persons from openslides.utils.person.signals import receive_persons
class Person(object):
"""
Meta-class for all person objects
"""
def person_id(self):
"""
Return an id for representation of ths person. Has to be unique.
"""
raise NotImplementedError('Any person object needs a person_id')
def __repr__(self):
"""
Return a string for this person.
"""
return str(self.person_id)
@property
def clean_name(self):
"""
Return the name of this person without a suffix
"""
return unicode(self)
@property
def name_suffix(self):
"""
Return a suffix for the person-name.
"""
return ''
class Persons(object): class Persons(object):
""" """
A Storage for a multiplicity of different Person-Objects. A Storage for a multiplicity of different Person-Objects.

View File

@ -18,7 +18,7 @@ register = template.Library()
@register.simple_tag @register.simple_tag
def get_min_supporters(): def get_min_supporters():
return config['application_min_supporters'] return config['motion_min_supporters']
@register.simple_tag @register.simple_tag

View File

@ -101,13 +101,13 @@ def permission_required(perm, login_url=None):
if request.user.has_perm(perm): if request.user.has_perm(perm):
return func(request, *args, **kw) return func(request, *args, **kw)
if request.user.is_authenticated(): if request.user.is_authenticated():
return render_to_forbitten(request) return render_to_forbidden(request)
return redirect(reverse('user_login')) return redirect(reverse('user_login'))
return wrapper return wrapper
return renderer return renderer
def render_to_forbitten(request, error= def render_to_forbidden(request, error=
ugettext_lazy("Sorry, you have no rights to see this page.")): ugettext_lazy("Sorry, you have no rights to see this page.")):
return HttpResponseForbidden(render_to_string('403.html', return HttpResponseForbidden(render_to_string('403.html',
{'error': error}, context_instance=RequestContext(request))) {'error': error}, context_instance=RequestContext(request)))

View File

@ -52,7 +52,7 @@ from django.views.generic.list import TemplateResponseMixin
from openslides.config.models import config from openslides.config.models import config
from openslides.utils.utils import render_to_forbitten, html_strong from openslides.utils.utils import render_to_forbidden, html_strong
from openslides.utils.signals import template_manipulation from openslides.utils.signals import template_manipulation
from openslides.utils.pdf import firstPage, laterPages from openslides.utils.pdf import firstPage, laterPages
@ -80,20 +80,20 @@ class LoginMixin(object):
class PermissionMixin(object): class PermissionMixin(object):
permission_required = NO_PERMISSION_REQUIRED permission_required = NO_PERMISSION_REQUIRED
def has_permission(self, request): def has_permission(self, request, *args, **kwargs):
if self.permission_required == NO_PERMISSION_REQUIRED: if self.permission_required == NO_PERMISSION_REQUIRED:
return True return True
else: else:
return request.user.has_perm(self.permission_required) return request.user.has_perm(self.permission_required)
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not self.has_permission(request): if not self.has_permission(request, *args, **kwargs):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
path = request.get_full_path() path = request.get_full_path()
return HttpResponseRedirect("%s?next=%s" % (settings.LOGIN_URL, return HttpResponseRedirect("%s?next=%s" % (settings.LOGIN_URL,
path)) path))
else: else:
return render_to_forbitten(request) return render_to_forbidden(request)
return _View.dispatch(self, request, *args, **kwargs) return _View.dispatch(self, request, *args, **kwargs)
@ -110,20 +110,21 @@ class QuestionMixin(object):
success_message = ugettext_lazy('Thank you for your answer') success_message = ugettext_lazy('Thank you for your answer')
answer_options = [('yes', ugettext_lazy("Yes")), ('no', ugettext_lazy("No"))] answer_options = [('yes', ugettext_lazy("Yes")), ('no', ugettext_lazy("No"))]
def get_answer_options(self): def pre_redirect(self, request, *args, **kwargs):
return self.answer_options # Prints the question in a GET request
self.confirm_form()
def get_question(self): def get_question(self):
return unicode(self.question) return unicode(self.question)
def get_answer(self): def get_answer_options(self):
for option in self.get_answer_options(): return self.answer_options
if option[0] in self.request.POST:
return option[0]
return None
def get_answer_url(self): def get_answer_url(self):
return self.answer_url try:
return self.answer_url
except AttributeError:
return self.request.path
def confirm_form(self): def confirm_form(self):
option_fields = "\n".join([ option_fields = "\n".join([
@ -142,11 +143,25 @@ class QuestionMixin(object):
'csrf': csrf(self.request)['csrf_token'], 'csrf': csrf(self.request)['csrf_token'],
'option_fields': option_fields}) 'option_fields': option_fields})
def pre_redirect(self, request, *args, **kwargs):
self.confirm_form(request, self.object)
def pre_post_redirect(self, request, *args, **kwargs): def pre_post_redirect(self, request, *args, **kwargs):
messages.success(request) # Reacts on the response of the user in a POST-request.
# TODO: call the methodes for all possible answers.
if self.get_answer() == 'yes':
self.case_yes()
messages.success(request, self.get_success_message())
def get_answer(self):
for option in self.get_answer_options():
if option[0] in self.request.POST:
return option[0]
return None
def case_yes(self):
# TODO: raise a warning
pass
def get_success_message(self):
return self.success_message
class TemplateView(PermissionMixin, _TemplateView): class TemplateView(PermissionMixin, _TemplateView):
@ -266,27 +281,19 @@ class CreateView(PermissionMixin, _CreateView):
pass pass
class DeleteView(RedirectView, SingleObjectMixin, QuestionMixin): class DeleteView(SingleObjectMixin, QuestionMixin, RedirectView):
def get_question(self):
return _('Do you really want to delete %s?') % html_strong(self.object)
def get_success_message(self):
return _('%s was successfully deleted.') % html_strong(self.object)
def pre_redirect(self, request, *args, **kwargs):
self.confirm_form()
def pre_post_redirect(self, request, *args, **kwargs):
if self.get_answer().lower() == 'yes':
self.object.delete()
messages.success(request, self.get_success_message())
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
return super(DeleteView, self).get(request, *args, **kwargs) return super(DeleteView, self).get(request, *args, **kwargs)
def get_answer_url(self): def get_question(self):
return self.object.get_absolute_url('delete') return _('Do you really want to delete %s?') % html_strong(self.object)
def case_yes(self):
self.object.delete()
def get_success_message(self):
return _('%s was successfully deleted.') % html_strong(self.object)
class DetailView(TemplateView, SingleObjectMixin): class DetailView(TemplateView, SingleObjectMixin):