Motion poll PDF
This commit is contained in:
parent
4f9041df65
commit
02d1025346
@ -11,6 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
import os
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
@ -18,15 +19,21 @@ from reportlab.lib.units import cm
|
|||||||
from reportlab.platypus import (
|
from reportlab.platypus import (
|
||||||
SimpleDocTemplate, PageBreak, Paragraph, Spacer, Table, TableStyle)
|
SimpleDocTemplate, PageBreak, Paragraph, Spacer, Table, TableStyle)
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from openslides.config.api import config
|
from openslides.config.api import config
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from .models import Motion
|
from .models import Motion
|
||||||
|
|
||||||
|
# Needed to count the delegates
|
||||||
|
# TODO: find another way to do this.
|
||||||
|
from openslides.participant.models import User
|
||||||
|
|
||||||
|
|
||||||
def motions_to_pdf(pdf):
|
def motions_to_pdf(pdf):
|
||||||
"""Create a PDF with all motions."""
|
"""
|
||||||
|
Create a PDF with all motions.
|
||||||
|
"""
|
||||||
motions = Motion.objects.all()
|
motions = Motion.objects.all()
|
||||||
all_motion_cover(pdf, motions)
|
all_motion_cover(pdf, motions)
|
||||||
for motion in motions:
|
for motion in motions:
|
||||||
@ -35,8 +42,9 @@ def motions_to_pdf(pdf):
|
|||||||
|
|
||||||
|
|
||||||
def motion_to_pdf(pdf, motion):
|
def motion_to_pdf(pdf, motion):
|
||||||
"""Create a PDF for one motion."""
|
"""
|
||||||
|
Create a PDF for one motion.
|
||||||
|
"""
|
||||||
pdf.append(Paragraph(_("Motion: %s") % motion.title, stylesheet['Heading1']))
|
pdf.append(Paragraph(_("Motion: %s") % motion.title, stylesheet['Heading1']))
|
||||||
|
|
||||||
motion_data = []
|
motion_data = []
|
||||||
@ -231,7 +239,9 @@ def convert_html_to_reportlab(pdf, text):
|
|||||||
|
|
||||||
|
|
||||||
def all_motion_cover(pdf, motions):
|
def all_motion_cover(pdf, motions):
|
||||||
"""Create a coverpage for all motions."""
|
"""
|
||||||
|
Create a coverpage for all motions.
|
||||||
|
"""
|
||||||
pdf.append(Paragraph(config["motion_pdf_title"], stylesheet['Heading1']))
|
pdf.append(Paragraph(config["motion_pdf_title"], stylesheet['Heading1']))
|
||||||
|
|
||||||
preamble = config["motion_pdf_preamble"]
|
preamble = config["motion_pdf_preamble"]
|
||||||
@ -245,3 +255,46 @@ def all_motion_cover(pdf, motions):
|
|||||||
else:
|
else:
|
||||||
for motion in motions:
|
for motion in motions:
|
||||||
pdf.append(Paragraph(motion.title, stylesheet['Heading3']))
|
pdf.append(Paragraph(motion.title, stylesheet['Heading3']))
|
||||||
|
|
||||||
|
|
||||||
|
def motion_poll_to_pdf(pdf, poll):
|
||||||
|
imgpath = os.path.join(settings.SITE_ROOT, 'static/img/circle.png')
|
||||||
|
circle = "<img src='%s' width='15' height='15'/> " % imgpath
|
||||||
|
cell = []
|
||||||
|
cell.append(Spacer(0, 0.8 * cm))
|
||||||
|
cell.append(Paragraph(_("Motion No. %s") % poll.motion.identifier, stylesheet['Ballot_title']))
|
||||||
|
cell.append(Paragraph(poll.motion.title, stylesheet['Ballot_subtitle']))
|
||||||
|
cell.append(Paragraph(_("%d. Vote") % poll.poll_number, stylesheet['Ballot_description']))
|
||||||
|
cell.append(Spacer(0, 0.5 * cm))
|
||||||
|
cell.append(Paragraph(circle + unicode(_("Yes")), stylesheet['Ballot_option']))
|
||||||
|
cell.append(Paragraph(circle + unicode(_("No")), stylesheet['Ballot_option']))
|
||||||
|
cell.append(Paragraph(circle + unicode(_("Abstention")), stylesheet['Ballot_option']))
|
||||||
|
data = []
|
||||||
|
# get ballot papers config values
|
||||||
|
ballot_papers_selection = config["motion_pdf_ballot_papers_selection"]
|
||||||
|
ballot_papers_number = config["motion_pdf_ballot_papers_number"]
|
||||||
|
|
||||||
|
# set number of ballot papers
|
||||||
|
if ballot_papers_selection == "NUMBER_OF_DELEGATES":
|
||||||
|
# TODO: get this number from persons
|
||||||
|
number = User.objects.filter(type__iexact="delegate").count()
|
||||||
|
elif ballot_papers_selection == "NUMBER_OF_ALL_PARTICIPANTS":
|
||||||
|
# TODO: get the number from the persons
|
||||||
|
number = int(User.objects.count())
|
||||||
|
else: # ballot_papers_selection == "CUSTOM_NUMBER"
|
||||||
|
number = int(ballot_papers_number)
|
||||||
|
number = max(1, number)
|
||||||
|
|
||||||
|
# print ballot papers
|
||||||
|
if number > 0:
|
||||||
|
# TODO: try [cell, cell] * (number / 2)
|
||||||
|
for user in xrange(number / 2):
|
||||||
|
data.append([cell, cell])
|
||||||
|
rest = number % 2
|
||||||
|
if rest:
|
||||||
|
data.append([cell, ''])
|
||||||
|
t = Table(data, 10.5 * cm, 7.42 * cm)
|
||||||
|
t.setStyle(TableStyle(
|
||||||
|
[('GRID', (0, 0), (-1, -1), 0.25, colors.grey),
|
||||||
|
('VALIGN', (0, 0), (-1, -1), 'TOP')]))
|
||||||
|
pdf.append(t)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{ block.super }} - {% trans "Motion" %} {{ motion.identifier }}, {{ ballot }}. {% trans "Vote" %}
|
{{ block.super }} - {% trans "Motion" %} {{ motion.identifier }}, {{ poll }}. {% trans "Vote" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -11,7 +11,7 @@
|
|||||||
{{ motion }}
|
{{ motion }}
|
||||||
<br>
|
<br>
|
||||||
<small>
|
<small>
|
||||||
{% trans "Motion" %} {{ motion.identifier }}, {{ ballot }}. {% trans "Vote" %}
|
{% trans "Motion" %} {{ motion.identifier }}, {{ poll }}. {% trans "Vote" %}
|
||||||
</small>
|
</small>
|
||||||
<small class="pull-right">
|
<small class="pull-right">
|
||||||
<div class="btn-toolbar">
|
<div class="btn-toolbar">
|
||||||
@ -57,8 +57,7 @@
|
|||||||
|
|
||||||
<!-- ballot paper button -->
|
<!-- ballot paper button -->
|
||||||
<p>
|
<p>
|
||||||
{# TODO: create ballot paper instead of motion_detail_pdf ! #}
|
<a href="{% url 'motion_poll_pdf' motion.id poll.poll_number %}" class="btn">
|
||||||
<a href="{% url 'motion_detail_pdf' motion.id %}" class="btn">
|
|
||||||
<i class="icon-print"></i> {% trans 'Ballot paper as PDF' %}
|
<i class="icon-print"></i> {% trans 'Ballot paper as PDF' %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -90,6 +90,11 @@ urlpatterns = patterns('openslides.motion.views',
|
|||||||
name='motion_poll_delete',
|
name='motion_poll_delete',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
url(r'^(?P<pk>\d+)/poll/(?P<poll_number>\d+)/pdf/$',
|
||||||
|
'poll_pdf',
|
||||||
|
name='motion_poll_pdf',
|
||||||
|
),
|
||||||
|
|
||||||
url(r'^(?P<pk>\d+)/set_state/(?P<state>\d+)/$',
|
url(r'^(?P<pk>\d+)/set_state/(?P<state>\d+)/$',
|
||||||
'set_state',
|
'set_state',
|
||||||
name='motion_set_state',
|
name='motion_set_state',
|
||||||
|
@ -37,7 +37,7 @@ from .models import (Motion, MotionSubmitter, MotionSupporter, MotionPoll,
|
|||||||
from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin,
|
from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin,
|
||||||
MotionDisableVersioningMixin, MotionCategoryMixin,
|
MotionDisableVersioningMixin, MotionCategoryMixin,
|
||||||
MotionIdentifierMixin)
|
MotionIdentifierMixin)
|
||||||
from .pdf import motions_to_pdf, motion_to_pdf
|
from .pdf import motions_to_pdf, motion_to_pdf, motion_poll_to_pdf
|
||||||
|
|
||||||
|
|
||||||
class MotionListView(ListView):
|
class MotionListView(ListView):
|
||||||
@ -422,12 +422,16 @@ poll_create = PollCreateView.as_view()
|
|||||||
|
|
||||||
|
|
||||||
class PollMixin(object):
|
class PollMixin(object):
|
||||||
"""Mixin for the PollUpdateView and the PollDeleteView."""
|
"""
|
||||||
|
Mixin for the PollUpdateView and the PollDeleteView.
|
||||||
|
"""
|
||||||
|
|
||||||
permission_required = 'motion.can_manage_motion'
|
permission_required = 'motion.can_manage_motion'
|
||||||
success_url_name = 'motion_detail'
|
success_url_name = 'motion_detail'
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""Return a MotionPoll object.
|
"""
|
||||||
|
Return a MotionPoll object.
|
||||||
|
|
||||||
Use the motion id and the poll_number from the url kwargs to get the
|
Use the motion id and the poll_number from the url kwargs to get the
|
||||||
object.
|
object.
|
||||||
@ -437,30 +441,40 @@ class PollMixin(object):
|
|||||||
poll_number=self.kwargs['poll_number']).get()
|
poll_number=self.kwargs['poll_number']).get()
|
||||||
|
|
||||||
def get_url_name_args(self):
|
def get_url_name_args(self):
|
||||||
"""Return the arguments to create the url to the success_url"""
|
"""
|
||||||
|
Return the arguments to create the url to the success_url.
|
||||||
|
"""
|
||||||
return [self.object.motion.pk]
|
return [self.object.motion.pk]
|
||||||
|
|
||||||
|
|
||||||
class PollUpdateView(PollMixin, PollFormView):
|
class PollUpdateView(PollMixin, PollFormView):
|
||||||
"""View to update a MotionPoll."""
|
"""
|
||||||
|
View to update a MotionPoll.
|
||||||
|
"""
|
||||||
|
|
||||||
poll_class = MotionPoll
|
poll_class = MotionPoll
|
||||||
"""Poll Class to use for this view."""
|
"""
|
||||||
|
Poll Class to use for this view.
|
||||||
|
"""
|
||||||
|
|
||||||
template_name = 'motion/poll_form.html'
|
template_name = 'motion/poll_form.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""Return the template context.
|
"""
|
||||||
|
Return the template context.
|
||||||
|
|
||||||
Append the motion object to the context.
|
Append the motion object to the context.
|
||||||
"""
|
"""
|
||||||
context = super(PollUpdateView, self).get_context_data(**kwargs)
|
context = super(PollUpdateView, self).get_context_data(**kwargs)
|
||||||
context.update({
|
context.update({
|
||||||
'motion': self.poll.motion})
|
'motion': self.poll.motion,
|
||||||
|
'poll': self.poll})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""Write a log message, if the form is valid."""
|
"""
|
||||||
|
Write a log message, if the form is valid.
|
||||||
|
"""
|
||||||
value = super(PollUpdateView, self).form_valid(form)
|
value = super(PollUpdateView, self).form_valid(form)
|
||||||
self.object.write_log(ugettext_noop('Poll updated'), self.request.user)
|
self.object.write_log(ugettext_noop('Poll updated'), self.request.user)
|
||||||
return value
|
return value
|
||||||
@ -469,21 +483,54 @@ poll_edit = PollUpdateView.as_view()
|
|||||||
|
|
||||||
|
|
||||||
class PollDeleteView(PollMixin, DeleteView):
|
class PollDeleteView(PollMixin, DeleteView):
|
||||||
"""View to delete a MotionPoll."""
|
"""
|
||||||
|
View to delete a MotionPoll.
|
||||||
|
"""
|
||||||
|
|
||||||
model = MotionPoll
|
model = MotionPoll
|
||||||
|
|
||||||
def case_yes(self):
|
def case_yes(self):
|
||||||
"""Write a log message, if the form is valid."""
|
"""
|
||||||
|
Write a log message, if the form is valid.
|
||||||
|
"""
|
||||||
super(PollDeleteView, self).case_yes()
|
super(PollDeleteView, self).case_yes()
|
||||||
self.object.write_log(ugettext_noop('Poll deleted'), self.request.user)
|
self.object.write_log(ugettext_noop('Poll deleted'), self.request.user)
|
||||||
|
|
||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
"""Return the URL to the DetailView of the motion."""
|
"""
|
||||||
|
Return the URL to the DetailView of the motion.
|
||||||
|
"""
|
||||||
return reverse('motion_detail', args=[self.object.motion.pk])
|
return reverse('motion_detail', args=[self.object.motion.pk])
|
||||||
|
|
||||||
poll_delete = PollDeleteView.as_view()
|
poll_delete = PollDeleteView.as_view()
|
||||||
|
|
||||||
|
|
||||||
|
class PollPDFView(PollMixin, PDFView):
|
||||||
|
"""
|
||||||
|
Generates a ballotpaper.
|
||||||
|
"""
|
||||||
|
|
||||||
|
permission_required = 'motion.can_manage_motion'
|
||||||
|
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
return super(PollPDFView, self).get(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_filename(self):
|
||||||
|
"""
|
||||||
|
Return the filename for the PDF.
|
||||||
|
"""
|
||||||
|
return u'%s%s_%s' % (_("Motion"), str(self.object.poll_number), _("Poll"))
|
||||||
|
|
||||||
|
def append_to_pdf(self, pdf):
|
||||||
|
"""
|
||||||
|
Append PDF objects.
|
||||||
|
"""
|
||||||
|
motion_poll_to_pdf(pdf, self.object)
|
||||||
|
|
||||||
|
poll_pdf = PollPDFView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class MotionSetStateView(SingleObjectMixin, RedirectView):
|
class MotionSetStateView(SingleObjectMixin, RedirectView):
|
||||||
"""View to set the state of a motion.
|
"""View to set the state of a motion.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user