start to rewrite the poll-api

This commit is contained in:
Oskar Hahn 2012-02-14 16:31:21 +01:00
parent a54ff100d1
commit 0957de83a9
11 changed files with 245 additions and 270 deletions

View File

@ -137,29 +137,7 @@
</td>
{% if perms.agenda.can_manage_agenda %}
<td>
{% ifequal item.type 'ItemApplication' %}
<a href="{% url application_view item.cast.application.id %}">{% trans "Application" %} {{ item.cast.application.number }}</a>
{% endifequal %}
{% ifequal item.type 'ItemPoll' %}
{% if item.cast.poll.application %}
<a href="{% url poll_view item.cast.poll.id %}">{% trans "Poll of Application" %}</a>
{% endif %}
{% if item.cast.poll.assignment %}
<a href="{% url poll_view item.cast.poll.id %}">{% trans "Poll of Election" %}</a>
{% endif %}
{% endifequal %}
{% ifequal item.type 'ItemAssignment' %}
<a href="{% url assignment_view item.cast.assignment.id %}">{% trans "Election" %}</a>
{% endifequal %}
{% ifequal item.type 'ItemText' %}
Text
{% endifequal %}
{% if item.hidden %}
({% trans 'hidden' %})
{% endif %}
Text
</td>
{% endif %}
<td><span style="width: 1px;white-space: nowrap;">

View File

@ -23,6 +23,8 @@ from projector.models import Slide
from participant.models import Profile
from system.api import config_get
from utils.utils import _propper_unicode
from poll import ChoicePoll
from poll.models import BaseOption, BasePoll
class Application(models.Model, Slide):
@ -410,24 +412,28 @@ class Application(models.Model, Slide):
"""
Generates a poll object for the application
"""
from poll.models import Poll
poll = Poll(optiondecision=True, \
application=self)
poll = ApplicationPoll()
poll.save()
poll.add_option(self)
poll.set_options([{'application': self}])
self.writelog(_("Poll created"), user)
return poll
@property
def polls(self):
#todo: return an query_set
return [option.poll for option in self.applicationoption_set.all()]
@property
def results(self):
"""
Return a list of voting results
"""
# TODO: This will propably not work
results = []
for poll in self.poll_set.all():
for option in poll.options:
if poll.votesinvalid != None and poll.votescast != None:
results.append([option.yes, option.no, option.undesided, poll.votesinvalidf, poll.votescastf])
for poll in self.polls:
for option in poll.get_options():
#if poll.votesinvalid != None and poll.votescast != None:
results.append([option.yes, option.no, option.undesided, poll.votesinvalidf, poll.votescastf])
return results
def slide(self):
@ -484,3 +490,14 @@ class AVersion(models.Model):
return self._aid
register_slidemodel(Application)
class ApplicationOption(BaseOption):
application = models.ForeignKey(Application)
def __unicode__(self):
return unicode(self.application)
class ApplicationPoll(BasePoll):
option_class = ApplicationOption

View File

@ -6,60 +6,45 @@
{% if perms.application.can_manage_application %}
{% block submenu %}
{{ block.super }}
<br>
<h3>{%trans "Application No." %} {{ poll.application.number }}</h3>
<ul>
<li><a href="{% url print_application_poll poll.id %}"><img src="/static/images/icons/application-pdf.png"> {%trans 'Print vote' %}</a></li>
</ul>
{{ block.super }}
<br>
<h3>{%trans "Application No." %} {{ poll.application.number }}</h3>
<ul>
<li><a href="{% url print_application_poll poll.id %}"><img src="/static/images/icons/application-pdf.png"> {%trans 'Print vote' %}</a></li>
</ul>
{% endblock %}
{% endif %}
{% block content %}
<h1>{%trans "Application No." %} {{ poll.application.number }} - {%trans "Vote" %}</h1>
<h3>{{ poll.application.title }}</h3>
<h1>{%trans "Application No." %} {{ application.number }} - {%trans "Vote" %}</h1>
<h3>{{ application.title }}</h3>
<p>{%trans "Results of" %} {{ ballot }}. {%trans "Vote" %}</p>
<i>-1 := {% trans 'majority' %}, -2 := {% trans 'undocumented' %}</i>
<form action="" method="post">{% csrf_token %}
<table class="table" style="width: auto;">
<tr>
<th>{%trans "Option" %}</th>
<th>{%trans "Votes" %}</th>
</tr>
<tr>
<td>{%trans "Yes" %}</td>
<td>{{ options.0.form.yes.errors }}{{ options.0.form.yes }}</td>
</tr>
<tr class="odd">
<td>{%trans "No" %}</label></td>
<td>{{ options.0.form.no.errors }}{{ options.0.form.no }}</td>
</tr>
<tr>
<td>{%trans "Abstentions" %}</td>
<td>{{ options.0.form.undesided.errors }}{{ options.0.form.undesided }}</td>
</tr>
<tr class="odd">
<td>{%trans "Invalid votes" %}</td>
<td>{{ form.invalid.errors }}{{ form.invalid }}</td>
</tr>
<tr class="total">
<td style="white-space: nowrap;"><b>{%trans "Votes cast" %}</b></td>
<td>{{ form.votescast.errors }}{{ form.votescast }}</td>
</tr>
</table>
<p>
<button class="button" type="submit">
<span class="icon ok">{%trans 'Save' %}</span>
</button>
<button class="button" type="submit" name="apply">
<span class="icon apply">{%trans 'Apply' %}</span>
</button>
<a href='{% url application_view poll.application.id %}'>
<button class="button" type="button" onclick="window.location='{% url application_view poll.application.id %}'">
<span class="icon cancel">{%trans 'Cancel' %}</span>
</button>
</a>
<table class="table" style="width: auto;">
<tr>
<th>{% trans "Option" %}</th>
<th>{% trans "Votes" %}</th>
</tr>
{% for value in forms.0 %}
<tr>
<td>{{ value.label }}</td>
<td>{{ value.errors }}{{ value }}</td>
</tr>
{% endfor %}
</table>
<p>
<button class="button" type="submit">
<span class="icon ok">{%trans 'Save' %}</span>
</button>
<button class="button" type="submit" name="apply">
<span class="icon apply">{%trans 'Apply' %}</span>
</button>
<a href='{% url application_view application.id %}'>
<button class="button" type="button" onclick="window.location='{% url application_view application.id %}'">
<span class="icon cancel">{%trans 'Cancel' %}</span>
</button>
</a>
</form>
{% endblock %}

View File

@ -47,7 +47,7 @@
{% endfor %}
<h4>{% trans "Vote results" %}:</h4>
{% with application.poll_set.all as polls %}
{% with application.polls as polls %}
{% if polls|length == 0 %}
{% if perms.application.can_manage_application %}
{% if "genpoll" in actions %}

View File

@ -11,6 +11,10 @@
"""
from django.conf.urls.defaults import *
from django.utils.translation import ugettext as _
from application.views import ViewPoll
urlpatterns = patterns('application.views',
url(r'^application/$', 'overview', \
@ -77,8 +81,10 @@ urlpatterns = patterns('application.views',
url(r'^application/poll/(?P<poll_id>\d+)/print$', 'print_application_poll', \
name='print_application_poll'),
url(r'^application/poll/(?P<poll_id>\d+)$', 'view_poll', \
name='application_poll_view'),
url(r'^application/poll/(?P<poll_id>\d+)$',
ViewPoll.as_view(),
name='application_poll_view'
),
url(r'^application/poll/(?P<poll_id>\d+)/del$', 'delete_poll', \
name='application_poll_delete'),

View File

@ -23,14 +23,15 @@ from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
from django.db import transaction
from openslides.agenda.models import Item
from openslides.application.models import Application, AVersion
from openslides.application.forms import ApplicationForm, \
from agenda.models import Item
from application.models import Application, AVersion, ApplicationPoll
from application.forms import ApplicationForm, \
ApplicationManagerForm, \
ApplicationImportForm
from openslides.participant.models import Profile
from openslides.poll.models import Poll
from openslides.poll.forms import OptionResultForm, PollForm
from poll.models import PollFormView
from openslides.utils.utils import template, permission_required, \
render_to_forbitten, del_confirm_form, gen_confirm_form
from openslides.utils.pdf import print_application, print_application_poll
@ -92,7 +93,7 @@ def view(request, application_id, newest=False):
'actions': actions,
'min_supporters': int(config_get('application_min_supporters')),
'version': version,
'results': application.results
#'results': application.results
}
@ -347,7 +348,7 @@ def gen_poll(request, application_id):
poll = Application.objects.get(pk=application_id).gen_poll(user=request.user)
messages.success(request, _("New vote was successfully created.") )
except Application.DoesNotExist:
pass
pass # TODO: do not call poll after this excaption
return redirect(reverse('application_poll_view', args=[poll.id]))
@ -373,9 +374,9 @@ def view_poll(request, poll_id):
"""
view a poll for this application.
"""
poll = Poll.objects.get(pk=poll_id)
ballot = poll.ballot
options = poll.options
poll = ApplicationPoll.objects.get(pk=poll_id)
#ballot = poll.ballot
options = poll.get_options()
if request.user.has_perm('application.can_manage_application'):
if request.method == 'POST':
form = PollForm(request.POST, prefix="poll")
@ -408,9 +409,27 @@ def view_poll(request, poll_id):
'poll': poll,
'form': form,
'options': options,
'ballot': ballot,
#'ballot': ballot,
}
class ViewPoll(PollFormView):
poll_class = ApplicationPoll
vote_values = [_('yes'), _('no'), _('contained')]
template_name = 'application/poll_view.html'
def get_context_data(self, **kwargs):
context = super(ViewPoll, self).get_context_data()
self.application = self.poll.get_options()[0].application
context['application'] = self.application
return context
def get_success_url(self):
if not 'apply' in self.request.POST:
return reverse('application_view', args=[self.application.id])
return ''
@permission_required('application.can_manage_application')
def permit_version(request, aversion_id):
aversion = AVersion.objects.get(pk=aversion_id)

View File

@ -17,8 +17,8 @@ from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
from openslides.agenda.models import Item
from poll.models import Poll, Option
from poll.forms import OptionResultForm, PollForm
#from poll.models import Poll, Option
#from poll.forms import OptionResultForm, PollForm
from assignment.models import Assignment
from assignment.forms import AssignmentForm, AssignmentRunForm
from utils.utils import template, permission_required, gen_confirm_form, del_confirm_form, ajax_request

View File

@ -52,3 +52,4 @@ class Profile(models.Model):
('can_see_participant', "Can see participant"),
('can_manage_participant', "Can manage participant"),
)

View File

@ -0,0 +1,12 @@
from django.utils.translation import ugettext as _
from models import PollFormView, BasePoll
class DesicionPoll(PollFormView):
vote_values = [_('yes'), _('no'), _('contained')]
poll_class = BasePoll
class ChoicePoll(PollFormView):
poll_class = BasePoll

View File

@ -12,185 +12,142 @@
from django.db import models
from django.utils.translation import ugettext as _
from application.models import Application
from assignment.models import Assignment
from participant.models import Profile
from django import forms
from django.views.generic import TemplateView
from django.http import HttpResponseRedirect
class Poll(models.Model):
optiondecision = models.BooleanField(default=True, verbose_name = _("Poll of decision (yes, no, abstention)"))
application = models.ForeignKey(Application, null=True, blank=True, verbose_name = _("Application"))
assignment = models.ForeignKey(Assignment, null=True, blank=True, verbose_name = _("Election"))
class OptionForm(forms.Form):
def __init__(self, *args, **kwargs):
extra = kwargs.pop('extra')
formid = kwargs.pop('formid')
kwargs['prefix'] = "option-%s" % formid
super(OptionForm, self).__init__(*args, **kwargs)
for key, value in extra:
self.fields[key] = forms.IntegerField(
widget=forms.TextInput(attrs={'class': 'small-input'}),
label=_(key),
initial=value,
)
class BaseOption(models.Model):
poll = models.ForeignKey('BasePoll')
@property
def votes(self):
count = 0
for vote in Vote.objects.filter(option=self):
count += vote.weight
return weight
class TextOption(BaseOption):
text = models.CharField(max_length=255)
def __unicode__(self):
return self.text
class Vote(models.Model):
option = models.ForeignKey(BaseOption)
#profile = models.ForeignKey(Profile) # TODO: we need a person+ here
weight = models.IntegerField(default=1)
value = models.CharField(max_length=255, null=True)
class BasePoll(models.Model):
description = models.TextField(null=True, blank=True, verbose_name = _("Description"))
votescast = models.IntegerField(null=True, blank=True, verbose_name = _("Votes cast"))
votesinvalid = models.IntegerField(null=True, blank=True, verbose_name = _("Votes invalid"))
published = models.BooleanField(default=False)
def add_option(self, option):
self.save()
optionc = Option()
optionc.poll = self
if isinstance(option, Application):
optionc.application = option
elif isinstance(option, Profile):
optionc.user = option
else:
optionc.text = str(option)
optionc.save()
return optionc
option_class = TextOption
vote_values = [_('votes')]
@property
def votescastf(self):
if self.votescast == -2:
return _('undocumented')
elif self.votescast:
return self.votescast
return '0'
@property
def votesinvalidf(self):
if self.votesinvalid == -2:
return _('undocumented')
elif self.votesinvalid:
if self.votescast > 0:
percentage = round(float(self.votesinvalid) / float(self.votescast) * 100,1)
invalid = "%s (%s %%)" % (str(self.votesinvalid), str(percentage))
return invalid
return self.votesinvalid
return '0'
def has_vote(self):
for option in self.options:
if option.voteyes or option.voteno or option.voteundesided:
return True
return False
def set_options(self, options_data):
for option_data in options_data:
option = self.option_class(**option_data)
option.poll = self
option.save()
def get_options(self):
return self.option_set.all()
return self.get_option_class().objects.filter(poll=self)
@property
def options(self):
return self.option_set.all()
def get_option_class(self):
return self.option_class
@property
def options_values(self):
return [option.value for option in self.options]
def get_vote_values(self):
return self.vote_values
def set_published(self, published=True):
"""
Changes the published-status of the poll.
"""
self.published = published
self.save()
@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
def get_absolute_url(self, link='view'):
if self.application:
if link == 'view':
return ('application_poll_view', [str(self.id), 0])
if link == 'delete':
return ('application_poll_delete', [str(self.id)])
if self.assignment:
if link == 'view':
return ('assignment_poll_view', [str(self.id), 0])
if link == 'delete':
return ('assignment_poll_delete', [str(self.id)])
if link == 'view':
return ('poll_view', [str(self.id)])
if link == 'delete':
return ('poll_delete', [str(self.id)])
def __unicode__(self):
if self.application:
return self.application.title
if self.assignment:
return self.assignment.name
def set_form_values(self, option, data):
for value in self.get_vote_values():
try:
vote = Vote.objects.filter(option=option).get(value=value)
except Vote.DoesNotExist:
vote = Vote(option=option, value=value)
vote.weight = data[value]
vote.save()
class Option(models.Model):
text = models.CharField(max_length=100, null=True, blank=True, verbose_name = _("Text"))
user = models.ForeignKey(Profile, null=True, blank=True, verbose_name = _("Participant"))
application = models.ForeignKey(Application, null=True, blank=True, verbose_name = _("Application"))
poll = models.ForeignKey(Poll, verbose_name = _("Poll"))
voteyes = models.IntegerField(null=True, blank=True)
voteno = models.IntegerField(null=True, blank=True)
voteundesided = models.IntegerField(null=True, blank=True)
def get_form_values(self, option_id):
values = []
for value in self.get_vote_values():
try:
vote = Vote.objects.filter(option=option_id).get(value=value)
weight = vote.weight
except Vote.DoesNotExist:
weight = None
values.append((value, weight))
return values
@property
def yes(self):
if self.voteyes == -1:
return _('majority')
if self.voteyes == -2:
return _('undocumented')
if self.voteyes:
if self.poll.votescast > 0 and self.voteyes > 0:
percentage = round(float(self.voteyes) / float(self.poll.votescast) * 100,1)
return "%s (%s %%)" % (str(self.voteyes), str(percentage))
return self.voteyes
return '0'
def get_vote_form(self, **kwargs):
return OptionForm(extra=self.get_form_values(kwargs['formid']), **kwargs)
@property
def no(self):
if self.voteno == -1:
return _('majority')
if self.voteno == -2:
return _('undocumented')
if self.voteno:
if self.poll.votescast > 0 and self.voteno > 0:
percentage = round(float(self.voteno) / float(self.poll.votescast) * 100,1)
return "%s (%s %%)" % (str(self.voteno), str(percentage))
return self.voteno
return '0'
def get_vote_forms(self, **kwargs):
forms = []
for option in self.get_options():
form = self.get_vote_form(formid=option.id, **kwargs)
form.option = option
forms.append(form)
@property
def undesided(self):
if self.voteundesided == -1:
return _('majority')
if self.voteundesided == -2:
return _('undocumented')
if self.voteundesided:
if self.poll.votescast > 0 and self.voteundesided > 0:
percentage = round(float(self.voteundesided) / float(self.poll.votescast) * 100,1)
return "%s (%s %%)" % (str(self.voteundesided), str(percentage))
return self.voteundesided
return '0'
return forms
@property
def value(self):
if self.text != "" and self.text is not None:
return self.text
if self.user is not None:
return self.user
if self.application is not None:
return self.application
return None
def __unicode__(self):
if self.value:
return unicode(self.value)
return _("No options")
class PollFormView(TemplateView):
template_name = 'poll/poll.html'
poll_argument = 'poll_id'
def set_poll(self, poll_id):
poll_id = poll_id
self.poll = self.poll_class.objects.get(pk=poll_id)
self.poll.vote_values = self.vote_values
def get_context_data(self, **kwargs):
context = super(PollFormView, self).get_context_data(**kwargs)
self.set_poll(self.kwargs['poll_id'])
context['poll'] = self.poll
if not 'forms' in context:
context['forms'] = context['poll'].get_vote_forms()
return context
def get_success_url(self):
return self.success_url
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
forms = self.poll.get_vote_forms(data=self.request.POST)
error = False
for form in forms:
if not form.is_valid():
error = True
if error:
return self.render_to_response(self.get_context_data(forms=forms))
for form in forms:
data = {}
for value in self.poll.vote_values:
data[value] = form.cleaned_data[value]
print data
self.poll.set_form_values(form.option, data)
return HttpResponseRedirect(self.get_success_url())

View File

@ -36,7 +36,7 @@ from openslides.agenda.models import Item
from openslides.agenda.api import children_list
from openslides.application.models import Application
from openslides.assignment.models import Assignment
from openslides.poll.models import Poll, Option
#from openslides.poll.models import Poll, Option
from openslides.participant.models import Profile
from openslides.system.api import config_get
from openslides.settings import SITE_ROOT
@ -343,7 +343,7 @@ def get_application(application, story):
else:
story.append(Paragraph(_("Application No."), stylesheet['Heading1']))
# submitter
cell1a = []
cell1a.append(Spacer(0,0.2*cm))
@ -357,7 +357,7 @@ def get_application(application, story):
cell1b.append(Spacer(0,0.2*cm))
else:
cell1b.append(Paragraph(unicode(application.submitter.profile), stylesheet['Normal']))
# supporters
cell2a = []
cell2a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font><seqreset id='counter'>" % _("Supporters"), stylesheet['Heading4']))
@ -368,7 +368,7 @@ def get_application(application, story):
for x in range(0,application.missing_supporters):
cell2b.append(Paragraph("<seq id='counter'/>.&nbsp; __________________________________________",stylesheet['Signaturefield']))
cell2b.append(Spacer(0,0.2*cm))
# status
note = ""
for n in application.notes:
@ -389,7 +389,7 @@ def get_application(application, story):
data.append([cell1a,cell1b])
data.append([cell2a,cell2b])
data.append([cell3a,cell3b])
# voting results
if len(application.results) > 0:
cell4a = []
@ -412,7 +412,7 @@ def get_application(application, story):
]))
story.append(t)
story.append(Spacer(0,1*cm))
# title
story.append(Paragraph(application.title, stylesheet['Heading3']))
# text
@ -431,7 +431,7 @@ def print_application(request, application_id=None):
doc = SimpleDocTemplate(response)
doc.title = None
story = []
if application_id is None: #print all applications
title = config_get("application_pdf_title")
story.append(Paragraph(title, stylesheet['Heading1']))
@ -614,7 +614,7 @@ def get_assignment(assignment, story):
('LINEBELOW',(0,-1),(-1,-1),2,colors.black),
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9))),
]))
# table
data = []
data.append([cell1a,cell1b])
@ -635,7 +635,7 @@ def get_assignment(assignment, story):
# text
story.append(Paragraph("%s" % assignment.description.replace('\r\n','<br/>'), stylesheet['Paragraph']))
return story
@permission_required('application.can_see_application')
def print_assignment(request, assignment_id=None):
response = HttpResponse(mimetype='application/pdf')
@ -644,7 +644,7 @@ def print_assignment(request, assignment_id=None):
doc = SimpleDocTemplate(response)
doc.title = None
story = []
if assignment_id is None: #print all applications
title = config_get("assignment_pdf_title")
story.append(Paragraph(title, stylesheet['Heading1']))
@ -667,7 +667,7 @@ def print_assignment(request, assignment_id=None):
doc.build(story, onFirstPage=firstPage, onLaterPages=firstPage)
return response
@permission_required('application.can_manage_application')
def print_assignment_poll(request, poll_id=None):
poll = Poll.objects.get(id=poll_id)
@ -714,7 +714,7 @@ def print_assignment_poll(request, poll_id=None):
rest = number % 2
if rest:
data.append([cell,''])
if len(options) <= 2:
t=Table(data, 10.5*cm, 7.42*cm)
elif len(options) <= 5:
@ -742,7 +742,7 @@ def print_assignment_poll(request, poll_id=None):
rest = number % 2
if rest:
data.append([cell,''])
if len(options) <= 4:
t=Table(data, 10.5*cm, 7.42*cm)
elif len(options) <= 8: