#!/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 not 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 %s 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: %s.") % 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 %s.") % application) continue title = application.title application.delete(force=True) messages.success(request, _("Motion %s 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 %s.") % self.object) else: title = self.object.title self.object.delete(force=True) messages.success(request, _("Motion %s 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 %s accepted.") % (aversion.aid)) else: gen_confirm_form(request, _('Do you really want to authorize version %s?') % 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 %s rejected.") % (aversion.aid)) else: messages.error(request, _("ERROR by rejecting the version.") ) else: gen_confirm_form(request, _('Do you really want to reject version %s?') % 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','
'), 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("%s:" % _("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("%s:" % _("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("%s:" % _("Supporters"), stylesheet['Heading4'])) for supporter in application.supporters: cell3b.append(Paragraph(".  %s" % supporter, stylesheet['Signaturefield'])) if application.status == "pub": for x in range(application.missing_supporters): cell3b.append(Paragraph(".  __________________________________________",stylesheet['Signaturefield'])) cell3b.append(Spacer(0, 0.2 * cm)) data.append([cell3a, cell3b]) # status cell4a = [] cell4b = [] note = " ".join(application.notes) cell4a.append(Paragraph("%s:" % _("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("%s:" % _("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("%s:" % _("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
%s: %s
%s: %s
%s: %s
%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','
'), 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','
'), 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 = "  " % 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')]