904 lines
38 KiB
Python
904 lines
38 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
openslides.application.views
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Views for the application app.
|
|
|
|
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
|
:license: GNU GPL, see LICENSE for more details.
|
|
"""
|
|
|
|
# for python 2.5 support
|
|
from __future__ import with_statement
|
|
|
|
import csv
|
|
import os
|
|
|
|
try:
|
|
from urlparse import parse_qs
|
|
except ImportError: # python <= 2.5
|
|
from cgi import parse_qs
|
|
|
|
from reportlab.lib import colors
|
|
from reportlab.lib.units import cm
|
|
from reportlab.platypus import (SimpleDocTemplate, PageBreak, Paragraph, Spacer,
|
|
Table, TableStyle)
|
|
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth.models import User
|
|
from django.core.context_processors import csrf
|
|
from django.core.urlresolvers import reverse
|
|
from django.db import transaction
|
|
from django.shortcuts import redirect
|
|
from django.utils.translation import ugettext as _, ungettext
|
|
|
|
from openslides.utils import csv_ext
|
|
from openslides.utils.pdf import stylesheet
|
|
from openslides.utils.template import Tab
|
|
from openslides.utils.utils import (template, permission_required,
|
|
del_confirm_form, gen_confirm_form)
|
|
from openslides.utils.views import PDFView, RedirectView, DeleteView, FormView
|
|
from openslides.utils.person import get_person
|
|
|
|
from openslides.config.models import config
|
|
|
|
from openslides.projector.projector import Widget
|
|
|
|
from openslides.poll.views import PollFormView
|
|
|
|
from openslides.participant.api import gen_username, gen_password
|
|
from openslides.participant.models import User
|
|
|
|
from openslides.agenda.models import Item
|
|
|
|
from openslides.application.models import Application, AVersion, ApplicationPoll
|
|
from openslides.application.forms import (ApplicationForm,
|
|
ApplicationFormTrivialChanges, ApplicationManagerForm,
|
|
ApplicationManagerFormSupporter, ApplicationImportForm, ConfigForm)
|
|
|
|
|
|
@permission_required('application.can_see_application')
|
|
@template('application/overview.html')
|
|
def overview(request):
|
|
"""
|
|
View all applications
|
|
"""
|
|
try:
|
|
sortfilter = parse_qs(request.COOKIES['votecollector_sortfilter'])
|
|
for value in sortfilter:
|
|
sortfilter[value] = sortfilter[value][0]
|
|
except KeyError:
|
|
sortfilter = {}
|
|
|
|
for value in [u'sort', u'reverse', u'number', u'status', u'needsup', u'statusvalue']:
|
|
if value in request.REQUEST:
|
|
if request.REQUEST[value] == '0':
|
|
try:
|
|
del sortfilter[value]
|
|
except KeyError:
|
|
pass
|
|
else:
|
|
sortfilter[value] = request.REQUEST[value]
|
|
|
|
query = Application.objects.all()
|
|
if 'number' in sortfilter:
|
|
query = query.filter(number=None)
|
|
if 'status' in sortfilter:
|
|
if 'statusvalue' in sortfilter and 'on' in sortfilter['status']:
|
|
query = query.filter(status__iexact=sortfilter['statusvalue'])
|
|
|
|
if 'sort' in sortfilter:
|
|
if sortfilter['sort'] == 'title':
|
|
sort = 'aversion__title'
|
|
elif sortfilter['sort'] == 'time':
|
|
sort = 'aversion__time'
|
|
else:
|
|
sort = sortfilter['sort']
|
|
query = query.order_by(sort)
|
|
if sort.startswith('aversion_'):
|
|
# limit result to last version of an application
|
|
query = query.filter(aversion__id__in=[x.last_version.id for x in Application.objects.all()])
|
|
else:
|
|
pass
|
|
|
|
if 'reverse' in sortfilter:
|
|
query = query.reverse()
|
|
|
|
# todo: rewrite this with a .filter()
|
|
if 'needsup' in sortfilter:
|
|
applications = []
|
|
for application in query.all():
|
|
if not application.enough_supporters:
|
|
applications.append(application)
|
|
else:
|
|
applications = query
|
|
|
|
if type(applications) is not list:
|
|
applications = list(query.all())
|
|
|
|
# not the most efficient way to do this but 'get_allowed_actions'
|
|
# is not callable from within djangos templates..
|
|
for (i, application) in enumerate(applications):
|
|
try:
|
|
applications[i] = {
|
|
'actions' : application.get_allowed_actions(request.user),
|
|
'application' : application
|
|
}
|
|
except:
|
|
# todo: except what?
|
|
applications[i] = {
|
|
'actions' : [],
|
|
'application' : application
|
|
}
|
|
|
|
return {
|
|
'applications': applications,
|
|
'min_supporters': int(config['application_min_supporters']),
|
|
}
|
|
|
|
|
|
@permission_required('application.can_see_application')
|
|
@template('application/view.html')
|
|
def view(request, application_id, newest=False):
|
|
"""
|
|
View one application.
|
|
"""
|
|
application = Application.objects.get(pk=application_id)
|
|
if newest:
|
|
version = application.last_version
|
|
else:
|
|
version = application.public_version
|
|
revisions = application.versions
|
|
actions = application.get_allowed_actions(user=request.user)
|
|
|
|
return {
|
|
'application': application,
|
|
'revisions': revisions,
|
|
'actions': actions,
|
|
'min_supporters': int(config['application_min_supporters']),
|
|
'version': version,
|
|
#'results': application.results
|
|
}
|
|
|
|
|
|
@login_required
|
|
@template('application/edit.html')
|
|
def edit(request, application_id=None):
|
|
"""
|
|
View a form to edit or create a application.
|
|
"""
|
|
if request.user.has_perm('application.can_manage_application'):
|
|
is_manager = True
|
|
else:
|
|
is_manager = False
|
|
|
|
if not is_manager \
|
|
and not request.user.has_perm('application.can_create_application'):
|
|
messages.error(request, _("You have not the necessary rights to create or edit motions."))
|
|
return redirect(reverse('application_overview'))
|
|
if application_id is not None:
|
|
application = Application.objects.get(id=application_id)
|
|
if not 'edit' in application.get_allowed_actions(request.user):
|
|
messages.error(request, _("You can not edit this motion."))
|
|
return redirect(reverse('application_view', args=[application.id]))
|
|
actions = application.get_allowed_actions(user=request.user)
|
|
else:
|
|
application = None
|
|
actions = None
|
|
|
|
formclass = ApplicationFormTrivialChanges \
|
|
if config['application_allow_trivial_change'] and application_id \
|
|
else ApplicationForm
|
|
|
|
managerformclass = ApplicationManagerFormSupporter \
|
|
if config['application_min_supporters'] \
|
|
else ApplicationManagerForm
|
|
|
|
if request.method == 'POST':
|
|
dataform = formclass(request.POST, prefix="data")
|
|
valid = dataform.is_valid()
|
|
|
|
if is_manager:
|
|
managerform = managerformclass(request.POST,
|
|
instance=application,
|
|
prefix="manager")
|
|
valid = valid and managerform.is_valid()
|
|
else:
|
|
managerform = None
|
|
|
|
if valid:
|
|
del_supporters = True
|
|
if is_manager:
|
|
if application: # Edit application
|
|
original_supporters = list(application.supporters)
|
|
else:
|
|
original_supporters = []
|
|
application = managerform.save(commit=False)
|
|
elif application_id is None:
|
|
application = Application(submitter=request.user)
|
|
application.title = dataform.cleaned_data['title']
|
|
application.text = dataform.cleaned_data['text']
|
|
application.reason = dataform.cleaned_data['reason']
|
|
|
|
try:
|
|
trivial_change = config['application_allow_trivial_change'] \
|
|
and dataform.cleaned_data['trivial_change']
|
|
except KeyError:
|
|
trivial_change = False
|
|
application.save(request.user, trivial_change=trivial_change)
|
|
if is_manager:
|
|
try:
|
|
new_supporters = set(managerform.cleaned_data['supporter'])
|
|
except KeyError:
|
|
# The managerform has no field for the supporters
|
|
pass
|
|
else:
|
|
old_supporters = set(application.supporters)
|
|
# add new supporters
|
|
for supporter in new_supporters.difference(old_supporters):
|
|
application.support(supporter)
|
|
# remove old supporters
|
|
for supporter in old_supporters.difference(new_supporters):
|
|
application.unsupport(supporter)
|
|
|
|
if application_id is None:
|
|
messages.success(request, _('New motion was successfully created.'))
|
|
else:
|
|
messages.success(request, _('Motion was successfully modified.'))
|
|
|
|
if not 'apply' in request.POST:
|
|
return redirect(reverse('application_view', args=[application.id]))
|
|
if application_id is None:
|
|
return redirect(reverse('application_edit', args=[application.id]))
|
|
else:
|
|
messages.error(request, _('Please check the form for errors.'))
|
|
else:
|
|
if application_id is None:
|
|
initial = {'text': config['application_preamble']}
|
|
else:
|
|
if application.status == "pub" and application.supporters:
|
|
if request.user.has_perm('application.can_manage_application'):
|
|
messages.warning(request, _("Attention: Do you really want to edit this motion? The supporters will <b>not</b> be removed automatically because you can manage motions. Please check if the supports are valid after your changing!"))
|
|
else:
|
|
messages.warning(request, _("Attention: Do you really want to edit this motion? All <b>%s</b> supporters will be removed! Try to convince the supporters again.") % application.count_supporters() )
|
|
initial = {'title': application.title,
|
|
'text': application.text,
|
|
'reason': application.reason}
|
|
|
|
dataform = formclass(initial=initial, prefix="data")
|
|
if is_manager:
|
|
if application_id is None:
|
|
initial = {'submitter': request.user.person_id}
|
|
else:
|
|
initial = {'submitter': application.submitter.person_id,
|
|
'supporter': [supporter.person_id for supporter in application.supporters]}
|
|
managerform = managerformclass(initial=initial,
|
|
instance=application, prefix="manager")
|
|
else:
|
|
managerform = None
|
|
return {
|
|
'form': dataform,
|
|
'managerform': managerform,
|
|
'application': application,
|
|
'actions': actions,
|
|
}
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
@template('application/view.html')
|
|
def set_number(request, application_id):
|
|
"""
|
|
set a number for an application.
|
|
"""
|
|
try:
|
|
Application.objects.get(pk=application_id).set_number(user=request.user)
|
|
messages.success(request, _("Motion number was successfully set."))
|
|
except Application.DoesNotExist:
|
|
pass
|
|
except NameError:
|
|
pass
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
@template('application/view.html')
|
|
def permit(request, application_id):
|
|
"""
|
|
permit an application.
|
|
"""
|
|
try:
|
|
Application.objects.get(pk=application_id).permit(user=request.user)
|
|
messages.success(request, _("Motion was successfully authorized."))
|
|
except Application.DoesNotExist:
|
|
pass
|
|
except NameError, e:
|
|
messages.error(request, e)
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
@permission_required('application.can_manage_application')
|
|
@template('application/view.html')
|
|
def notpermit(request, application_id):
|
|
"""
|
|
reject (not permit) an application.
|
|
"""
|
|
try:
|
|
Application.objects.get(pk=application_id).notpermit(user=request.user)
|
|
messages.success(request, _("Motion was successfully rejected."))
|
|
except Application.DoesNotExist:
|
|
pass
|
|
except NameError, e:
|
|
messages.error(request, e)
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
@template('application/view.html')
|
|
def set_status(request, application_id=None, status=None):
|
|
"""
|
|
set a status of an application.
|
|
"""
|
|
try:
|
|
if status is not None:
|
|
application = Application.objects.get(pk=application_id)
|
|
application.set_status(user=request.user, status=status)
|
|
messages.success(request, _("Motion status was set to: <b>%s</b>.") % application.get_status_display())
|
|
except Application.DoesNotExist:
|
|
pass
|
|
except NameError, e:
|
|
messages.error(request, e)
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
@template('application/view.html')
|
|
def reset(request, application_id):
|
|
"""
|
|
reset an application.
|
|
"""
|
|
try:
|
|
Application.objects.get(pk=application_id).reset(user=request.user)
|
|
messages.success(request, _("Motion status was reset.") )
|
|
except Application.DoesNotExist:
|
|
pass
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
|
|
@permission_required('application.can_support_application')
|
|
@template('application/view.html')
|
|
def support(request, application_id):
|
|
"""
|
|
support an application.
|
|
"""
|
|
try:
|
|
Application.objects.get(pk=application_id).support(person=request.user)
|
|
messages.success(request, _("You have support the motion successfully.") )
|
|
except Application.DoesNotExist:
|
|
pass
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
|
|
@permission_required('application.can_support_application')
|
|
@template('application/view.html')
|
|
def unsupport(request, application_id):
|
|
"""
|
|
unsupport an application.
|
|
"""
|
|
try:
|
|
Application.objects.get(pk=application_id).unsupport(person=request.user)
|
|
messages.success(request, _("You have unsupport the motion successfully.") )
|
|
except Application.DoesNotExist:
|
|
pass
|
|
return redirect(reverse('application_view', args=[application_id]))
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
@template('application/view.html')
|
|
def gen_poll(request, application_id):
|
|
"""
|
|
gen a poll for this application.
|
|
"""
|
|
try:
|
|
poll = Application.objects.get(pk=application_id).gen_poll(user=request.user)
|
|
messages.success(request, _("New vote was successfully created.") )
|
|
except Application.DoesNotExist:
|
|
pass # TODO: do not call poll after this excaption
|
|
return redirect(reverse('application_poll_view', args=[poll.id]))
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
def delete_poll(request, poll_id):
|
|
"""
|
|
delete a poll from this application
|
|
"""
|
|
poll = ApplicationPoll.objects.get(pk=poll_id)
|
|
application = poll.application
|
|
count = application.polls.filter(id__lte=poll_id).count()
|
|
if request.method == 'POST':
|
|
poll.delete()
|
|
application.writelog(_("Poll deleted"), request.user)
|
|
messages.success(request, _('Poll was successfully deleted.'))
|
|
else:
|
|
del_confirm_form(request, poll, name=_("the %s. poll") % count, delete_link=reverse('application_poll_delete', args=[poll_id]))
|
|
return redirect(reverse('application_view', args=[application.id]))
|
|
|
|
|
|
class ApplicationDelete(DeleteView):
|
|
"""
|
|
Delete one or more Applications.
|
|
"""
|
|
permission_required = 'application.can_manage_application'
|
|
model = Application
|
|
url = 'application_overview'
|
|
|
|
def get_object(self):
|
|
self.applications = []
|
|
|
|
if self.kwargs.get('application_id', None):
|
|
try:
|
|
return Application.objects.get(id=int(self.kwargs['application_id']))
|
|
except Application.DoesNotExist:
|
|
return None
|
|
|
|
if self.kwargs.get('application_ids', []):
|
|
for appid in self.kwargs['application_ids']:
|
|
try:
|
|
self.applications.append(Application.objects.get(id=int(appid)))
|
|
except Application.DoesNotExist:
|
|
pass
|
|
|
|
if self.applications:
|
|
return self.applications[0]
|
|
return None
|
|
|
|
def pre_post_redirect(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
|
|
if len(self.applications):
|
|
for application in self.applications:
|
|
if not 'delete' in application.get_allowed_actions(user=request.user):
|
|
messages.error(request, _("You can not delete motion <b>%s</b>.") % application)
|
|
continue
|
|
|
|
title = application.title
|
|
application.delete(force=True)
|
|
messages.success(request, _("Motion <b>%s</b> was successfully deleted.") % title)
|
|
|
|
elif self.object:
|
|
if not 'delete' in self.object.get_allowed_actions(user=request.user):
|
|
messages.error(request, _("You can not delete motion <b>%s</b>.") % self.object)
|
|
else:
|
|
title = self.object.title
|
|
self.object.delete(force=True)
|
|
messages.success(request, _("Motion <b>%s</b> was successfully deleted.") % title)
|
|
else:
|
|
messages.error(request, _("Invalid request"))
|
|
|
|
|
|
class ViewPoll(PollFormView):
|
|
permission_required = 'application.can_manage_application'
|
|
poll_class = ApplicationPoll
|
|
template_name = 'application/poll_view.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ViewPoll, self).get_context_data(**kwargs)
|
|
self.application = self.poll.get_application()
|
|
context['application'] = self.application
|
|
context['ballot'] = self.poll.get_ballot()
|
|
context['actions'] = self.application.get_allowed_actions(user=self.request.user)
|
|
return context
|
|
|
|
def get_modelform_class(self):
|
|
cls = super(ViewPoll, self).get_modelform_class()
|
|
user = self.request.user
|
|
|
|
class ViewPollFormClass(cls):
|
|
def save(self, commit = True):
|
|
instance = super(ViewPollFormClass, self).save(commit)
|
|
application = instance.application
|
|
application.writelog(_("Poll was updated"), user)
|
|
return instance
|
|
|
|
return ViewPollFormClass
|
|
|
|
def get_success_url(self):
|
|
if not 'apply' in self.request.POST:
|
|
return reverse('application_view', args=[self.poll.application.id])
|
|
return ''
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
def permit_version(request, aversion_id):
|
|
aversion = AVersion.objects.get(pk=aversion_id)
|
|
application = aversion.application
|
|
if request.method == 'POST':
|
|
application.accept_version(aversion, user=request.user)
|
|
messages.success(request, _("Version <b>%s</b> accepted.") % (aversion.aid))
|
|
else:
|
|
gen_confirm_form(request, _('Do you really want to authorize version <b>%s</b>?') % aversion.aid, reverse('application_version_permit', args=[aversion.id]))
|
|
return redirect(reverse('application_view', args=[application.id]))
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
def reject_version(request, aversion_id):
|
|
aversion = AVersion.objects.get(pk=aversion_id)
|
|
application = aversion.application
|
|
if request.method == 'POST':
|
|
if application.reject_version(aversion, user=request.user):
|
|
messages.success(request, _("Version <b>%s</b> rejected.") % (aversion.aid))
|
|
else:
|
|
messages.error(request, _("ERROR by rejecting the version.") )
|
|
else:
|
|
gen_confirm_form(request, _('Do you really want to reject version <b>%s</b>?') % aversion.aid, reverse('application_version_reject', args=[aversion.id]))
|
|
return redirect(reverse('application_view', args=[application.id]))
|
|
|
|
|
|
@permission_required('application.can_manage_application')
|
|
@template('application/import.html')
|
|
def application_import(request):
|
|
if request.method == 'POST':
|
|
form = ApplicationImportForm(request.POST, request.FILES)
|
|
if form.is_valid():
|
|
import_permitted = form.cleaned_data['import_permitted']
|
|
try:
|
|
# check for valid encoding (will raise UnicodeDecodeError if not)
|
|
request.FILES['csvfile'].read().decode('utf-8')
|
|
request.FILES['csvfile'].seek(0)
|
|
|
|
users_generated = 0
|
|
applications_generated = 0
|
|
applications_modified = 0
|
|
with transaction.commit_on_success():
|
|
dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
|
|
dialect = csv_ext.patchup(dialect)
|
|
request.FILES['csvfile'].seek(0)
|
|
for (lno, line) in enumerate(csv.reader(request.FILES['csvfile'], dialect=dialect)):
|
|
# basic input verification
|
|
if lno < 1:
|
|
continue
|
|
try:
|
|
(number, title, text, reason, first_name, last_name) = line[:6]
|
|
except ValueError:
|
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
|
continue
|
|
form = ApplicationForm({'title': title, 'text': text, 'reason': reason})
|
|
if not form.is_valid():
|
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
|
continue
|
|
if number:
|
|
try:
|
|
number = abs(long(number))
|
|
if number < 1:
|
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
|
continue
|
|
except ValueError:
|
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
|
continue
|
|
# fetch existing users or create new users as needed
|
|
try:
|
|
user = User.objects.get(first_name=first_name, last_name=last_name)
|
|
except User.DoesNotExist:
|
|
user = None
|
|
if user is None:
|
|
user = User()
|
|
user.last_name = last_name
|
|
user.first_name = first_name
|
|
user.username = gen_username(first_name, last_name)
|
|
user.save()
|
|
profile = Profile()
|
|
profile.user = user
|
|
profile.group = ''
|
|
profile.committee = ''
|
|
profile.gender = 'none'
|
|
profile.type = 'guest'
|
|
profile.firstpassword = gen_password()
|
|
profile.user.set_password(profile.firstpassword)
|
|
profile.save()
|
|
users_generated += 1
|
|
# create / modify the application
|
|
application = None
|
|
if number:
|
|
try:
|
|
application = Application.objects.get(number=number)
|
|
applications_modified += 1
|
|
except Application.DoesNotExist:
|
|
application = None
|
|
if application is None:
|
|
application = Application(submitter=user)
|
|
if number:
|
|
application.number = number
|
|
applications_generated += 1
|
|
|
|
application.title = form.cleaned_data['title']
|
|
application.text = form.cleaned_data['text']
|
|
application.reason = form.cleaned_data['reason']
|
|
if import_permitted:
|
|
application.status = 'per'
|
|
|
|
application.save(user, trivial_change=True)
|
|
|
|
if applications_generated:
|
|
messages.success(request, ungettext('%d motion was successfully imported.',
|
|
'%d motions were successfully imported.', applications_generated) % applications_generated)
|
|
if applications_modified:
|
|
messages.success(request, ungettext('%d motion was successfully modified.',
|
|
'%d motions were successfully modified.', applications_modified) % applications_modified)
|
|
if users_generated:
|
|
messages.success(request, ungettext('%d new user was added.', '%d new users were added.', users_generated) % users_generated)
|
|
return redirect(reverse('application_overview'))
|
|
|
|
except csv.Error:
|
|
message.error(request, _('Import aborted because of severe errors in the input file.'))
|
|
except UnicodeDecodeError:
|
|
messages.error(request, _('Import file has wrong character encoding, only UTF-8 is supported!'))
|
|
else:
|
|
messages.error(request, _('Please check the form for errors.'))
|
|
else:
|
|
messages.warning(request, _("Attention: Existing motions will be modified if you import new motions with the same number."))
|
|
messages.warning(request, _("Attention: Importing an motions without a number multiple times will create duplicates."))
|
|
form = ApplicationImportForm()
|
|
return {
|
|
'form': form,
|
|
}
|
|
|
|
|
|
class CreateAgendaItem(RedirectView):
|
|
permission_required = 'agenda.can_manage_agenda'
|
|
|
|
def pre_redirect(self, request, *args, **kwargs):
|
|
self.application = Application.objects.get(pk=kwargs['application_id'])
|
|
self.item = Item(related_sid=self.application.sid)
|
|
self.item.save()
|
|
|
|
def get_redirect_url(self, **kwargs):
|
|
return reverse('item_overview')
|
|
|
|
|
|
class ApplicationPDF(PDFView):
|
|
permission_required = 'application.can_see_application'
|
|
top_space = 0
|
|
|
|
def get_filename(self):
|
|
application_id = self.kwargs['application_id']
|
|
if application_id is None:
|
|
filename = _("Applications")
|
|
else:
|
|
application = Application.objects.get(id=application_id)
|
|
if application.number:
|
|
number = application.number
|
|
else:
|
|
number = ""
|
|
filename = u'%s%s' % (_("Application"), str(number))
|
|
return filename
|
|
|
|
def append_to_pdf(self, story):
|
|
application_id = self.kwargs['application_id']
|
|
if application_id is None: #print all applications
|
|
title = config["application_pdf_title"]
|
|
story.append(Paragraph(title, stylesheet['Heading1']))
|
|
preamble = config["application_pdf_preamble"]
|
|
if preamble:
|
|
story.append(Paragraph("%s" % preamble.replace('\r\n','<br/>'), stylesheet['Paragraph']))
|
|
story.append(Spacer(0,0.75*cm))
|
|
applications = Application.objects.all()
|
|
if not applications: # No applications existing
|
|
story.append(Paragraph(_("No motions available."), stylesheet['Heading3']))
|
|
else: # Print all Applications
|
|
# List of applications
|
|
for application in applications:
|
|
if application.number:
|
|
story.append(Paragraph(_("Motion No.")+" %s: %s" % (application.number, application.title), stylesheet['Heading3']))
|
|
else:
|
|
story.append(Paragraph(_("Motion No.")+" : %s" % (application.title), stylesheet['Heading3']))
|
|
# Applications details (each application on single page)
|
|
for application in applications:
|
|
story.append(PageBreak())
|
|
story = self.get_application(application, story)
|
|
else: # print selected application
|
|
application = Application.objects.get(id=application_id)
|
|
story = self.get_application(application, story)
|
|
|
|
def get_application(self, application, story):
|
|
# Preparing Table
|
|
data = []
|
|
|
|
# application number
|
|
if application.number:
|
|
story.append(Paragraph(_("Motion No.")+" %s" % application.number, stylesheet['Heading1']))
|
|
else:
|
|
story.append(Paragraph(_("Motion No."), stylesheet['Heading1']))
|
|
|
|
# submitter
|
|
cell1a = []
|
|
cell1a.append(Spacer(0, 0.2 * cm))
|
|
cell1a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font>" % _("Submitter"), stylesheet['Heading4']))
|
|
cell1b = []
|
|
cell1b.append(Spacer(0, 0.2 * cm))
|
|
cell1b.append(Paragraph("%s" % application.submitter, stylesheet['Normal']))
|
|
data.append([cell1a, cell1b])
|
|
|
|
if application.status == "pub":
|
|
# Cell for the signature
|
|
cell2a = []
|
|
cell2b = []
|
|
cell2a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font>" % _("Signature"), stylesheet['Heading4']))
|
|
cell2b.append(Paragraph("__________________________________________", stylesheet['Signaturefield']))
|
|
cell2b.append(Spacer(0, 0.1 * cm))
|
|
cell2b.append(Spacer(0,0.2*cm))
|
|
data.append([cell2a, cell2b])
|
|
|
|
# supporters
|
|
if config['application_min_supporters']:
|
|
cell3a = []
|
|
cell3b = []
|
|
cell3a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font><seqreset id='counter'>" % _("Supporters"), stylesheet['Heading4']))
|
|
for supporter in application.supporters:
|
|
cell3b.append(Paragraph("<seq id='counter'/>. %s" % supporter, stylesheet['Signaturefield']))
|
|
if application.status == "pub":
|
|
for x in range(application.missing_supporters):
|
|
cell3b.append(Paragraph("<seq id='counter'/>. __________________________________________",stylesheet['Signaturefield']))
|
|
cell3b.append(Spacer(0, 0.2 * cm))
|
|
data.append([cell3a, cell3b])
|
|
|
|
# status
|
|
cell4a = []
|
|
cell4b = []
|
|
note = " ".join(application.notes)
|
|
cell4a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font>" % _("Status"), stylesheet['Heading4']))
|
|
if note != "":
|
|
if application.status == "pub":
|
|
cell4b.append(Paragraph(note, stylesheet['Normal']))
|
|
else:
|
|
cell4b.append(Paragraph("%s | %s" % (application.get_status_display(), note), stylesheet['Normal']))
|
|
else:
|
|
cell4b.append(Paragraph("%s" % application.get_status_display(), stylesheet['Normal']))
|
|
data.append([cell4a, cell4b])
|
|
|
|
# Version number (aid)
|
|
if application.public_version.aid > 1:
|
|
cell5a = []
|
|
cell5b = []
|
|
cell5a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font>" % _("Version"), stylesheet['Heading4']))
|
|
cell5b.append(Paragraph("%s" % application.public_version.aid, stylesheet['Normal']))
|
|
data.append([cell5a, cell5b])
|
|
|
|
# voting results
|
|
poll_results = application.get_poll_results()
|
|
if poll_results:
|
|
cell6a = []
|
|
cell6a.append(Paragraph("<font name='Ubuntu-Bold'>%s:</font>" % _("Vote results"), stylesheet['Heading4']))
|
|
cell6b = []
|
|
ballotcounter = 0
|
|
for result in poll_results:
|
|
ballotcounter += 1
|
|
if len(poll_results) > 1:
|
|
cell6b.append(Paragraph("%s. %s" % (ballotcounter, _("Vote")), stylesheet['Bold']))
|
|
cell6b.append(Paragraph("%s: %s <br/> %s: %s <br/> %s: %s <br/> %s: %s <br/> %s: %s" % (_("Yes"), result[0], _("No"), result[1], _("Abstention"), result[2], _("Invalid"), result[3], _("Votes cast"), result[4]), stylesheet['Normal']))
|
|
cell6b.append(Spacer(0, 0.2*cm))
|
|
data.append([cell6a, cell6b])
|
|
|
|
# Creating Table
|
|
t = Table(data)
|
|
t._argW[0] = 4.5 * cm
|
|
t._argW[1] = 11 * cm
|
|
t.setStyle(TableStyle([('BOX', (0, 0), (-1, -1), 1, colors.black),
|
|
('VALIGN', (0,0), (-1,-1), 'TOP')]))
|
|
story.append(t)
|
|
story.append(Spacer(0, 1 * cm))
|
|
|
|
# title
|
|
story.append(Paragraph(application.public_version.title, stylesheet['Heading3']))
|
|
# text
|
|
story.append(Paragraph("%s" % application.public_version.text.replace('\r\n','<br/>'), stylesheet['Paragraph']))
|
|
# reason
|
|
if application.public_version.reason:
|
|
story.append(Paragraph(_("Reason")+":", stylesheet['Heading3']))
|
|
story.append(Paragraph("%s" % application.public_version.reason.replace('\r\n','<br/>'), stylesheet['Paragraph']))
|
|
return story
|
|
|
|
|
|
class ApplicationPollPDF(PDFView):
|
|
permission_required = 'application.can_manage_application'
|
|
top_space = 0
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
self.poll = ApplicationPoll.objects.get(id=self.kwargs['poll_id'])
|
|
return super(ApplicationPollPDF, self).get(request, *args, **kwargs)
|
|
|
|
def get_filename(self):
|
|
filename = u'%s%s_%s' % (_("Application"), str(self.poll.application.number), _("Poll"))
|
|
return filename
|
|
|
|
def get_template(self, buffer):
|
|
return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6, leftMargin=0, rightMargin=0, showBoundary=False)
|
|
|
|
def build_document(self, pdf_document, story):
|
|
pdf_document.build(story)
|
|
|
|
def append_to_pdf(self, story):
|
|
imgpath = os.path.join(settings.SITE_ROOT, 'static/images/circle.png')
|
|
circle = "<img src='%s' width='15' height='15'/> " % imgpath
|
|
cell = []
|
|
cell.append(Spacer(0,0.8*cm))
|
|
cell.append(Paragraph(_("Application No. %s") % self.poll.application.number, stylesheet['Ballot_title']))
|
|
cell.append(Paragraph(self.poll.application.title, stylesheet['Ballot_subtitle']))
|
|
cell.append(Paragraph(_("%d. Vote") % self.poll.get_ballot(), 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["application_pdf_ballot_papers_selection"]
|
|
ballot_papers_number = config["application_pdf_ballot_papers_number"]
|
|
|
|
# set number of ballot papers
|
|
if ballot_papers_selection == "NUMBER_OF_DELEGATES":
|
|
number = User.objects.filter(profile__type__iexact="delegate").count()
|
|
elif ballot_papers_selection == "NUMBER_OF_ALL_PARTICIPANTS":
|
|
number = int(Profile.objects.count())
|
|
else: # ballot_papers_selection == "CUSTOM_NUMBER"
|
|
number = int(ballot_papers_number)
|
|
number = max(1, number)
|
|
|
|
# print ballot papers
|
|
if number > 0:
|
|
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'),
|
|
]))
|
|
story.append(t)
|
|
|
|
|
|
class Config(FormView):
|
|
permission_required = 'config.can_manage_config'
|
|
form_class = ConfigForm
|
|
template_name = 'application/config.html'
|
|
|
|
def get_initial(self):
|
|
return {
|
|
'application_min_supporters': config['application_min_supporters'],
|
|
'application_preamble': config['application_preamble'],
|
|
'application_pdf_ballot_papers_selection': config['application_pdf_ballot_papers_selection'],
|
|
'application_pdf_ballot_papers_number': config['application_pdf_ballot_papers_number'],
|
|
'application_pdf_title': config['application_pdf_title'],
|
|
'application_pdf_preamble': config['application_pdf_preamble'],
|
|
'application_allow_trivial_change': config['application_allow_trivial_change'],
|
|
}
|
|
|
|
def form_valid(self, form):
|
|
config['application_min_supporters'] = form.cleaned_data['application_min_supporters']
|
|
config['application_preamble'] = form.cleaned_data['application_preamble']
|
|
config['application_pdf_ballot_papers_selection'] = form.cleaned_data['application_pdf_ballot_papers_selection']
|
|
config['application_pdf_ballot_papers_number'] = form.cleaned_data['application_pdf_ballot_papers_number']
|
|
config['application_pdf_title'] = form.cleaned_data['application_pdf_title']
|
|
config['application_pdf_preamble'] = form.cleaned_data['application_pdf_preamble']
|
|
config['application_allow_trivial_change'] = form.cleaned_data['application_allow_trivial_change']
|
|
messages.success(self.request, _('Motion settings successfully saved.'))
|
|
return super(Config, self).form_valid(form)
|
|
|
|
|
|
def register_tab(request):
|
|
selected = True if request.path.startswith('/application/') else False
|
|
return Tab(
|
|
title=_('Applications'),
|
|
url=reverse('application_overview'),
|
|
permission=request.user.has_perm('application.can_see_application') or request.user.has_perm('application.can_support_application') or request.user.has_perm('application.can_support_application') or request.user.has_perm('application.can_manage_application'),
|
|
selected=selected,
|
|
)
|
|
|
|
|
|
def get_widgets(request):
|
|
return [
|
|
Widget(
|
|
name='applications',
|
|
template='application/widget.html',
|
|
context={'applications': Application.objects.all()},
|
|
permission_required='application.can_manage_application')]
|