Many improvements for application and assignment poll system.

This commit is contained in:
Emanuel Schuetze 2011-09-03 10:52:29 +02:00
parent b1b5d9cb70
commit ca0c50caef
14 changed files with 77 additions and 65 deletions

View File

@ -10,7 +10,7 @@
<h4>{% trans "Status" %}:</h4> <h4>{% trans "Status" %}:</h4>
{% trans item.assignment.get_status_display %} {% trans item.assignment.get_status_display %}
<h4>{% trans "Number of available posts" %}:</h4> <h4>{% trans "Number of available posts" %}:</h4>
{{ item.assignment.assignment_number }} {{ item.assignment.posts }}
</div> </div>
</div> </div>
{% endif %} {% endif %}

View File

@ -351,14 +351,8 @@ class Application(models.Model):
Generates a poll object for the application Generates a poll object for the application
""" """
from poll.models import Poll from poll.models import Poll
if pollcount > 1: poll = Poll(optiondecision=True, \
description = _("%s. poll") % pollcount application=self)
else:
description = _("Poll")
poll = Poll(title=_("Application #%s") % self.number, \
optiondecision=True, \
application=self,
description=description)
poll.save() poll.save()
poll.add_option(self) poll.add_option(self)
self.writelog(_("Poll created"), user) self.writelog(_("Poll created"), user)

View File

@ -1,25 +1,25 @@
{% extends 'application/base_application.html' %} {% extends 'application/base_application.html' %}
{% block title %}{{ block.super }} - {{ poll.title }}{% endblock %} {% block title %}{{ block.super }} - {{ poll }}{% endblock %}
{% if perms.poll.can_manage_poll %} {% if perms.application.can_manage_application %}
{% block submenu %} {% block submenu %}
{{ block.super }} {{ block.super }}
<br> <br>
<h3>{%trans "Application" %} #{{ poll.application.number }}</h3> <h3>{%trans "Application" %} #{{ poll.application.number }}</h3>
<ul> <ul>
<li><a href="{% url print_application_poll poll.id %}"><img src="/static/images/icons/application-pdf.png"> {%trans 'Print Poll' %}</a></li> <li><a href="{% url print_application_poll poll.id %}"><img src="/static/images/icons/application-pdf.png"> {%trans 'Print vote' %}</a></li>
</ul> </ul>
{% endblock %} {% endblock %}
{% endif %} {% endif %}
{% block content %} {% block content %}
<h1>{{ poll.title }}</h1> <h1>{%trans "Application" %} #{{ poll.application.number }} - {%trans "Vote" %}</h1>
<h4>Title: "{{ poll.application.title }}"</h4> <h4>{{ poll.application.title }}</h4>
{% if perms.poll.can_manage_poll %} {% if perms.poll.can_manage_poll %}
<form action="" method="post">{% csrf_token %} <form action="" method="post">{% csrf_token %}
<fieldset> <fieldset>
<legend>{{ poll.description }}</legend> <legend>{%trans "Results" %}: {{ ballot }}. {%trans "Vote" %}</legend>
<p><nobr><label>{%trans "Votes in favour" %}:</label></nobr> <p><nobr><label>{%trans "Votes in favour" %}:</label></nobr>
{{ options.0.form.yes.errors }}{{ options.0.form.yes }} {{ options.0.form.yes.errors }}{{ options.0.form.yes }}
</p> </p>

View File

@ -149,7 +149,7 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% else %} {% else %}
<a href="{% url application_poll_view poll.id %}">{% trans "Enter vote result!" %}</a> <a href="{% url application_poll_view poll.id %}">{% trans "Enter vote results!" %}</a>
{% endif %} {% endif %}
{% if not forloop.last %}<br>{% endif %} {% if not forloop.last %}<br>{% endif %}
{% empty %} {% empty %}
@ -206,13 +206,13 @@
<div> <div>
<p>{% trans "Application" %} <h1>{% trans "Application" %}
{% if application.number != None %} {% if application.number != None %}
#{{ application.number }} #{{ application.number }}
{% else %} {% else %}
<i>[no number]</i> <i>[no number]</i>
{% endif %}</p> {% endif %}</h1>
<h1>{{ application.title }}</h1> <h2>{{ application.title }}</h2>
{{ application.text|linebreaks }} {{ application.text|linebreaks }}

View File

@ -318,6 +318,7 @@ def view_poll(request, poll_id):
view a poll for this application. view a poll for this application.
""" """
poll = Poll.objects.get(pk=poll_id) poll = Poll.objects.get(pk=poll_id)
ballot = poll.ballot
options = poll.options options = poll.options
if request.user.has_perm('application.can_manage_applications'): if request.user.has_perm('application.can_manage_applications'):
if request.method == 'POST': if request.method == 'POST':
@ -347,4 +348,5 @@ def view_poll(request, poll_id):
'poll': poll, 'poll': poll,
'form': form, 'form': form,
'options': options, 'options': options,
'ballot': ballot,
} }

View File

@ -17,7 +17,7 @@ from participant.models import Profile
from assignment.models import Assignment from assignment.models import Assignment
class AssigmentForm(ModelForm): class AssignmentForm(ModelForm):
error_css_class = 'error' error_css_class = 'error'
required_css_class = 'required' required_css_class = 'required'
@ -26,7 +26,7 @@ class AssigmentForm(ModelForm):
exclude = ('status', 'profile') exclude = ('status', 'profile')
class AssigmentRunForm(Form): class AssignmentRunForm(Form):
error_css_class = 'error' error_css_class = 'error'
candidate = ModelChoiceField( candidate = ModelChoiceField(

View File

@ -25,7 +25,7 @@ class Assignment(models.Model):
name = models.CharField(max_length=100, verbose_name = _("Name")) name = models.CharField(max_length=100, verbose_name = _("Name"))
description = models.TextField(null=True, blank=True, verbose_name = _("Description")) description = models.TextField(null=True, blank=True, verbose_name = _("Description"))
assignment_number = models.PositiveSmallIntegerField(verbose_name = _("Number of available posts")) posts = models.PositiveSmallIntegerField(verbose_name = _("Number of available posts"))
polldescription = models.CharField(max_length=50, null=True, blank=True, verbose_name = _("Short description (for ballot paper)")) polldescription = models.CharField(max_length=50, null=True, blank=True, verbose_name = _("Short description (for ballot paper)"))
profile = models.ManyToManyField(Profile, null=True, blank=True) profile = models.ManyToManyField(Profile, null=True, blank=True)
status = models.CharField(max_length=1, choices=STATUS, default='sea') status = models.CharField(max_length=1, choices=STATUS, default='sea')
@ -69,10 +69,9 @@ class Assignment(models.Model):
def gen_poll(self): def gen_poll(self):
from poll.models import Poll from poll.models import Poll
poll = Poll() poll = Poll()
poll.title = _("Election for %s") % self.name
# Option A: candidates <= available posts -> yes/no/abstention # Option A: candidates <= available posts -> yes/no/abstention
if self.profile.count() <= self.assignment_number: if self.profile.count() <= self.posts:
poll.optiondecision = True poll.optiondecision = True
else: else:
poll.optiondecision = False poll.optiondecision = False

View File

@ -27,7 +27,7 @@
{% for assignment in assignments %} {% for assignment in assignments %}
<tr class="{% cycle '' 'odd' %}"> <tr class="{% cycle '' 'odd' %}">
<td><a href="{% url assignment_view assignment.id %}">{{ assignment }}</a></td> <td><a href="{% url assignment_view assignment.id %}">{{ assignment }}</a></td>
<td>{{ assignment.profile.count }} / {{ assignment.assignment_number }}</td> <td>{{ assignment.profile.count }} / {{ assignment.posts }}</td>
<td>{{ assignment.get_status_display }}</td> <td>{{ assignment.get_status_display }}</td>
{% if perms.assignment.can_manage_assignment %} {% if perms.assignment.can_manage_assignment %}
<td><a href="{% url assignment_edit assignment.id %}"><img src="/static/images/icons/document-edit.png" title="{%trans 'Edit assignment' %}"></a> <td><a href="{% url assignment_edit assignment.id %}"><img src="/static/images/icons/document-edit.png" title="{%trans 'Edit assignment' %}"></a>

View File

@ -1,8 +1,8 @@
{% extends 'assignment/base_assignment.html' %} {% extends 'assignment/base_assignment.html' %}
{% block title %}{{ block.super }} - {%trans "Poll" %} "{{ poll.title }}"{% endblock %} {% block title %}{{ block.super }} - {%trans "Poll" %} "{{ poll }}"{% endblock %}
{% block content %} {% block content %}
<h1>{{ poll.title }}</h1> <h1>{{ poll }}</h1>
<p>{{ ballotnumber }}. {%trans "ballot" %}: {{options.count}} <p>{{ ballotnumber }}. {%trans "ballot" %}: {{options.count}}
{% blocktrans count counter=options|length %}candidate{% plural %}candidates{% endblocktrans %} {% blocktrans count counter=options|length %}candidate{% plural %}candidates{% endblocktrans %}
</p> </p>
@ -46,7 +46,7 @@
<span class="icon previous">{%trans 'Back to election' %}</span> <span class="icon previous">{%trans 'Back to election' %}</span>
</button> </button>
</a> </a>
<a href='{% url print_assignment_poll poll.id ballotnumber poll.assignment.assignment_number %}'> <a href='{% url print_assignment_poll poll.id %}'>
<button type="button"> <button type="button">
<span class="icon pdf">{%trans 'Print ballot' %}</span> <span class="icon pdf">{%trans 'Print ballot' %}</span>
</button> </button>

View File

@ -9,7 +9,7 @@
{% trans assignment.get_status_display %} {% trans assignment.get_status_display %}
<h4>{% trans "Number of available posts" %}:</h4> <h4>{% trans "Number of available posts" %}:</h4>
{{ assignment.assignment_number }} {{ assignment.posts }}
</div> </div>
<br><br> <br><br>
@ -122,7 +122,7 @@
<tr> <tr>
<th>{% trans "Candidates" %}</th> <th>{% trans "Candidates" %}</th>
{% for poll in assignment.poll_set.all %} {% for poll in assignment.poll_set.all %}
<th style="vertical-align: top; white-space:nowrap;">{% if perms.assignment.can_manage_assignment %}<a href="{% url assignment_poll_view poll.id forloop.counter %}">{% endif %} <th style="vertical-align: top; white-space:nowrap;">{% if perms.assignment.can_manage_assignment %}<a href="{% url assignment_poll_view poll.id %}">{% endif %}
{{forloop.counter}}. {{forloop.counter}}.
{% if perms.assignment.can_manage_assignment %} {% if perms.assignment.can_manage_assignment %}
</a> </a>
@ -132,13 +132,11 @@
{% endfor %} {% endfor %}
{% if assignment.profile.count > 0 and perms.assignment.can_manage_assignment and assignment.status == "vot" %} {% if assignment.profile.count > 0 and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
<th> <th>
{% with ballotnumber=assignment.poll_set.all.count %} <a href='{% url assignment_gen_poll assignment.id %}'>
<a href='{% url assignment_gen_poll assignment.id ballotnumber|add:'1' %}'>
<button type="button"> <button type="button">
<span class="icon poll">{%trans 'New ballot' %}</span> <span class="icon poll">{%trans 'New ballot' %}</span>
</button> </button>
</a> </a>
{% endwith %}
</th> </th>
{% endif %} {% endif %}
</tr> </tr>
@ -169,13 +167,11 @@
<i>{% trans "No ballots available." %}</i> <i>{% trans "No ballots available." %}</i>
{% if assignment.profile.count > 0 and perms.assignment.can_manage_assignment and assignment.status == "vot" %} {% if assignment.profile.count > 0 and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
{% with ballotnumber=assignment.poll_set.all.count %} <p><a href='{% url assignment_gen_poll assignment.id %}'>
<p><a href='{% url assignment_gen_poll assignment.id ballotnumber|add:'1' %}'>
<button type="button"> <button type="button">
<span class="icon poll">{%trans 'New ballot' %}</span> <span class="icon poll">{%trans 'New ballot' %}</span>
</button> </button>
</a></p> </a></p>
{% endwith %}
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@ -40,13 +40,13 @@ urlpatterns = patterns('assignment.views',
url(r'^assignment/(?P<assignment_id>\d+)/delother/(?P<profile_id>\d+)$', 'delother', \ url(r'^assignment/(?P<assignment_id>\d+)/delother/(?P<profile_id>\d+)$', 'delother', \
name='assignment_delother'), name='assignment_delother'),
url(r'^assignment/poll/(?P<poll_id>\d+)/print/(?P<ballotnumber>\d+)/(?P<posts>\d+)$', 'print_assignment_poll', \ url(r'^assignment/poll/(?P<poll_id>\d+)/print$', 'print_assignment_poll', \
name='print_assignment_poll'), name='print_assignment_poll'),
url(r'^assignment/(?P<assignment_id>\d+)/gen_poll/(?P<ballotnumber>\d+)$', 'gen_poll', \ url(r'^assignment/(?P<assignment_id>\d+)/gen_poll$', 'gen_poll', \
name='assignment_gen_poll'), name='assignment_gen_poll'),
url(r'^assignment/poll/(?P<poll_id>\d+)/(?P<ballotnumber>\d+)$', 'poll_view', \ url(r'^assignment/poll/(?P<poll_id>\d+)$', 'poll_view', \
name='assignment_poll_view'), name='assignment_poll_view'),
url(r'^assignment/poll/(?P<poll_id>\d+)/del$', 'delete_poll', \ url(r'^assignment/poll/(?P<poll_id>\d+)/del$', 'delete_poll', \

View File

@ -19,7 +19,7 @@ from django.utils.translation import ugettext as _
from poll.models import Poll, Option from poll.models import Poll, Option
from poll.forms import OptionResultForm, PollInvalidForm from poll.forms import OptionResultForm, PollInvalidForm
from assignment.models import Assignment from assignment.models import Assignment
from assignment.forms import AssigmentForm, AssigmentRunForm from assignment.forms import AssignmentForm, AssignmentRunForm
from utils.utils import template, permission_required, gen_confirm_form, del_confirm_form from utils.utils import template, permission_required, gen_confirm_form, del_confirm_form
from utils.pdf import print_assignment_poll from utils.pdf import print_assignment_poll
from participant.models import Profile from participant.models import Profile
@ -53,7 +53,7 @@ def view(request, assignment_id=None):
assignment = Assignment.objects.get(pk=assignment_id) assignment = Assignment.objects.get(pk=assignment_id)
if request.method == 'POST': if request.method == 'POST':
if request.user.has_perm('assignment.can_nominate_other'): if request.user.has_perm('assignment.can_nominate_other'):
form = AssigmentRunForm(request.POST) form = AssignmentRunForm(request.POST)
if form.is_valid(): if form.is_valid():
user = form.cleaned_data['candidate'] user = form.cleaned_data['candidate']
try: try:
@ -63,7 +63,7 @@ def view(request, assignment_id=None):
messages.error(request, e) messages.error(request, e)
else: else:
if request.user.has_perm('assignment.can_nominate_other'): if request.user.has_perm('assignment.can_nominate_other'):
form = AssigmentRunForm() form = AssignmentRunForm()
# list of candidates # list of candidates
candidates = set() candidates = set()
@ -102,7 +102,7 @@ def edit(request, assignment_id=None):
assignment = None assignment = None
if request.method == 'POST': if request.method == 'POST':
form = AssigmentForm(request.POST, instance=assignment) form = AssignmentForm(request.POST, instance=assignment)
if form.is_valid(): if form.is_valid():
form.save() form.save()
if assignment_id is None: if assignment_id is None:
@ -111,7 +111,7 @@ def edit(request, assignment_id=None):
messages.success(request, _('Election was successfully modified.')) messages.success(request, _('Election was successfully modified.'))
return redirect(reverse("assignment_overview")) return redirect(reverse("assignment_overview"))
else: else:
form = AssigmentForm(instance=assignment) form = AssignmentForm(instance=assignment)
return { return {
'form': form, 'form': form,
'assignment': assignment, 'assignment': assignment,
@ -180,19 +180,20 @@ def delother(request, assignment_id, profile_id):
@permission_required('assignment.can_manage_assignment') @permission_required('assignment.can_manage_assignment')
def gen_poll(request, assignment_id, ballotnumber): def gen_poll(request, assignment_id):
try: try:
poll = Assignment.objects.get(pk=assignment_id).gen_poll() poll = Assignment.objects.get(pk=assignment_id).gen_poll()
messages.success(request, _("New ballot was successfully created.") ) messages.success(request, _("New ballot was successfully created.") )
except Assignment.DoesNotExist: except Assignment.DoesNotExist:
pass pass
return redirect(reverse('assignment_poll_view', args=[poll.id, ballotnumber])) return redirect(reverse('assignment_poll_view', args=[poll.id]))
@permission_required('assignment.can_view_assignment') @permission_required('assignment.can_view_assignment')
@template('assignment/poll_view.html') @template('assignment/poll_view.html')
def poll_view(request, poll_id, ballotnumber=1): def poll_view(request, poll_id):
poll = Poll.objects.get(pk=poll_id) poll = Poll.objects.get(pk=poll_id)
ballotnumber = poll.ballot
options = poll.options.order_by('user__user__first_name') options = poll.options.order_by('user__user__first_name')
assignment = poll.assignment assignment = poll.assignment
if request.user.has_perm('assignment.can_manage_assignment'): if request.user.has_perm('assignment.can_manage_assignment'):

View File

@ -19,8 +19,6 @@ from participant.models import Profile
class Poll(models.Model): class Poll(models.Model):
#TODO: Mehrheit in den Zahlen festmachen
title = models.CharField(max_length=100, verbose_name = _("Title"))
optiondecision = models.BooleanField(default=True, verbose_name = _("Poll of decision (yes, no, abstention)")) optiondecision = models.BooleanField(default=True, verbose_name = _("Poll of decision (yes, no, abstention)"))
application = models.ForeignKey(Application, null=True, blank=True, verbose_name = _("Application")) application = models.ForeignKey(Application, null=True, blank=True, verbose_name = _("Application"))
assignment = models.ForeignKey(Assignment, null=True, blank=True, verbose_name = _("Election")) assignment = models.ForeignKey(Assignment, null=True, blank=True, verbose_name = _("Election"))
@ -58,6 +56,30 @@ class Poll(models.Model):
def options_values(self): def options_values(self):
return [option.value for option in self.options] return [option.value for option in self.options]
@property
def count_ballots(self):
if self.application:
return Poll.objects.filter(application=self.application).count()
if self.assignment:
return Poll.objects.filter(assignment=self.assignment).count()
return None
@property
def ballot(self):
if self.application:
counter = 0
for poll in Poll.objects.filter(application=self.application):
counter = counter + 1
if self == poll:
return counter
if self.assignment:
counter = 0
for poll in Poll.objects.filter(assignment=self.assignment):
counter = counter + 1
if self == poll:
return counter
return None
@models.permalink @models.permalink
def get_absolute_url(self, link='view'): def get_absolute_url(self, link='view'):
if self.application: if self.application:
@ -76,7 +98,10 @@ class Poll(models.Model):
return ('poll_delete', [str(self.id)]) return ('poll_delete', [str(self.id)])
def __unicode__(self): def __unicode__(self):
return self.title if self.application:
return self.application.title
if self.assignment:
return self.assignment.name
class Option(models.Model): class Option(models.Model):

View File

@ -320,10 +320,10 @@ def print_application_poll(request, poll_id=None):
circle = "<img src='openslides/static/images/circle.png' width='15' height='15'/>&nbsp;&nbsp;" circle = "<img src='openslides/static/images/circle.png' width='15' height='15'/>&nbsp;&nbsp;"
cell = [] cell = []
cell.append(Spacer(0,0.8*cm)) cell.append(Spacer(0,0.8*cm))
cell.append(Paragraph(poll.title, stylesheet['Ballot_title'])) cell.append(Paragraph(_("Application")+" #"+str(poll.application.number), stylesheet['Ballot_title']))
cell.append(Paragraph(_("Title")+": "+poll.application.title, stylesheet['Ballot_subtitle'])) cell.append(Paragraph(poll.application.title, stylesheet['Ballot_subtitle']))
if poll.description: #if poll.description:
cell.append(Paragraph(poll.description, stylesheet['Ballot_description'])) cell.append(Paragraph(str(poll.ballot)+". "+_("Vote"), stylesheet['Ballot_description']))
cell.append(Spacer(0,0.5*cm)) cell.append(Spacer(0,0.5*cm))
cell.append(Paragraph(circle+_("Yes"), stylesheet['Ballot_option'])) cell.append(Paragraph(circle+_("Yes"), stylesheet['Ballot_option']))
cell.append(Paragraph(circle+_("No"), stylesheet['Ballot_option'])) cell.append(Paragraph(circle+_("No"), stylesheet['Ballot_option']))
@ -340,10 +340,10 @@ def print_application_poll(request, poll_id=None):
doc.build(story) doc.build(story)
return response return response
def print_assignment_poll(request, poll_id=None, ballotnumber=1, posts=None): def print_assignment_poll(request, poll_id=None):
poll = Poll.objects.get(id=poll_id) poll = Poll.objects.get(id=poll_id)
response = HttpResponse(mimetype='application/pdf') response = HttpResponse(mimetype='application/pdf')
filename = u'filename=%s-%s-#%s.pdf;' % (_("Election"), poll.title.replace(' ','_'), ballotnumber) filename = u'filename=%s-%s-#%s.pdf;' % (_("Election"), poll.assignment.name.replace(' ','_'), poll.ballot)
response['Content-Disposition'] = filename.encode('utf-8') response['Content-Disposition'] = filename.encode('utf-8')
doc = SimpleDocTemplate(response, pagesize=A4, topMargin=-6, bottomMargin=-6, leftMargin=0, rightMargin=0, showBoundary=False) doc = SimpleDocTemplate(response, pagesize=A4, topMargin=-6, bottomMargin=-6, leftMargin=0, rightMargin=0, showBoundary=False)
story = [Spacer(0,0*cm)] story = [Spacer(0,0*cm)]
@ -351,18 +351,13 @@ def print_assignment_poll(request, poll_id=None, ballotnumber=1, posts=None):
circle = "<img src='openslides/static/images/circle.png' width='15' height='15'/>&nbsp;" circle = "<img src='openslides/static/images/circle.png' width='15' height='15'/>&nbsp;"
cell = [] cell = []
cell.append(Spacer(0,0.8*cm)) cell.append(Spacer(0,0.8*cm))
cell.append(Paragraph(poll.title, stylesheet['Ballot_title'])) cell.append(Paragraph(_("Election") + ": " + poll.assignment.name, stylesheet['Ballot_title']))
cell.append(Paragraph(poll.description, stylesheet['Ballot_subtitle'])) cell.append(Paragraph(poll.description, stylesheet['Ballot_subtitle']))
options = poll.get_options().order_by('user__user__first_name') options = poll.get_options().order_by('user__user__first_name')
cell.append(Paragraph(ballotnumber+". "+_("ballot")+", "+str(len(options))+" "+ ungettext("candidate", "candidates", len(options))+", "+posts+" "+_("available posts"), stylesheet['Ballot_description'])) cell.append(Paragraph(str(poll.ballot)+". "+_("ballot")+", "+str(len(options))+" "+ ungettext("candidate", "candidates", len(options))+", "+str(poll.assignment.posts)+" "+_("available posts"), stylesheet['Ballot_description']))
cell.append(Spacer(0,0.4*cm)) cell.append(Spacer(0,0.4*cm))
if len(options) <= int(posts): if poll.optiondecision:
optiondecision = True
else:
optiondecision = False
if optiondecision:
for option in options: for option in options:
o = str(option).rsplit("(",1) o = str(option).rsplit("(",1)
cell.append(Paragraph(o[0], stylesheet['Ballot_option_name'])) cell.append(Paragraph(o[0], stylesheet['Ballot_option_name']))