OpenSlides/openslides/motion/views.py

904 lines
31 KiB
Python
Raw Normal View History

2013-01-06 12:07:37 +01:00
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import Http404, HttpResponseRedirect
from django.utils.text import slugify
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy, ugettext_noop
2013-09-25 12:53:44 +02:00
from reportlab.platypus import SimpleDocTemplate
from django.shortcuts import get_object_or_404
from openslides.agenda.views import CreateRelatedAgendaItemView as _CreateRelatedAgendaItemView
from openslides.config.api import config
2013-09-25 12:53:44 +02:00
from openslides.poll.views import PollFormView
from openslides.utils.rest_api import ModelViewSet
from openslides.utils.utils import html_strong, htmldiff
from openslides.utils.views import (CreateView, CSVImportView, DeleteView, DetailView,
ListView, PDFView, QuestionView,
RedirectView, SingleObjectMixin, UpdateView)
2013-02-03 18:18:29 +01:00
from .csv_import import import_motions
from .forms import (BaseMotionForm, MotionCategoryMixin,
MotionDisableVersioningMixin, MotionIdentifierMixin,
MotionCSVImportForm, MotionSubmitterMixin,
MotionSupporterMixin, MotionWorkflowMixin)
from .models import (Category, Motion, MotionPoll, MotionSubmitter,
MotionSupporter, MotionVersion, State, Workflow)
from .pdf import motion_poll_to_pdf, motion_to_pdf, motions_to_pdf
from .serializers import CategorySerializer, MotionSerializer, WorkflowSerializer
2011-07-31 10:46:29 +02:00
2013-02-02 00:37:43 +01:00
2013-01-06 12:07:37 +01:00
class MotionListView(ListView):
"""
View, to list all motions.
"""
model = Motion
required_permission = 'motion.can_see_motion'
# The template name must be set explicitly because the overridden method
# get_queryset() does not return a QuerySet any more so that Django can't
# generate the template name from the name of the model.
template_name = 'motion/motion_list.html'
# The attribute context_object_name must be set explicitly because the
# overridden method get_queryset() does not return a QuerySet any more so
# that Django can't generate the context_object_name from the name of the
# model.
context_object_name = 'motion_list'
def get_queryset(self, *args, **kwargs):
"""
Returns not a QuerySet but a filtered list of motions. Excludes motions
that the user is not allowed to see.
"""
queryset = super().get_queryset(*args, **kwargs)
motions = []
for motion in queryset:
if (not motion.state.required_permission_to_see or
self.request.user.has_perm(motion.state.required_permission_to_see)):
motions.append(motion)
return motions
2011-07-31 10:46:29 +02:00
class MotionDetailView(DetailView):
"""
Show one motion.
"""
model = Motion
2013-02-05 18:46:46 +01:00
def check_permission(self, request, *args, **kwargs):
"""
Check if the request.user has the permission to see the motion.
"""
return self.get_object().get_allowed_actions(request.user)['see']
def get_context_data(self, **kwargs):
"""
Return the template context.
Append the allowed actions for the motion, the shown version and its
data to the context.
"""
2013-02-03 13:24:29 +01:00
version_number = self.kwargs.get('version_number', None)
if version_number is not None:
try:
version = self.get_object().versions.get(version_number=int(version_number))
2013-02-03 13:24:29 +01:00
except MotionVersion.DoesNotExist:
raise Http404('Version %s not found' % version_number)
else:
version = self.get_object().get_active_version()
2013-02-03 13:24:29 +01:00
kwargs.update({
'allowed_actions': self.get_object().get_allowed_actions(self.request.user),
'version': version,
'title': version.title,
'text': version.text,
'reason': version.reason})
return super().get_context_data(**kwargs)
class MotionEditMixin(object):
2013-04-19 16:02:16 +02:00
"""
Mixin for motion views classes to save the version data.
2013-04-19 16:02:16 +02:00
"""
2013-02-05 18:46:46 +01:00
def form_valid(self, form):
2013-04-19 16:02:16 +02:00
"""
Saves the CreateForm or UpdateForm into a motion object.
2013-04-19 16:02:16 +02:00
"""
self.object = form.save(commit=False)
2013-03-12 23:35:08 +01:00
try:
self.object.category = form.cleaned_data['category']
except KeyError:
pass
try:
self.object.identifier = form.cleaned_data['identifier']
except KeyError:
pass
self.manipulate_object(form)
for attr in ['title', 'text', 'reason']:
setattr(self.version, attr, form.cleaned_data[attr])
self.object.save(use_version=self.version)
# Save the submitter an the supporter so the motion.
# TODO: Only delete and save neccessary submitters and supporters
2013-02-01 12:51:54 +01:00
if 'submitter' in form.cleaned_data:
self.object.submitter.all().delete()
MotionSubmitter.objects.bulk_create(
[MotionSubmitter(motion=self.object, person=person)
for person in form.cleaned_data['submitter']])
if 'supporter' in form.cleaned_data:
self.object.supporter.all().delete()
MotionSupporter.objects.bulk_create(
[MotionSupporter(motion=self.object, person=person)
for person in form.cleaned_data['supporter']])
# Save the attachments
self.object.attachments.clear()
self.object.attachments.add(*form.cleaned_data['attachments'])
# Save the tags
self.object.tags.clear()
self.object.tags.add(*form.cleaned_data['tags'])
2013-09-07 22:57:29 +02:00
messages.success(self.request, self.get_success_message())
return HttpResponseRedirect(self.get_success_url())
2013-01-26 15:25:54 +01:00
def get_form_class(self):
"""
Return the FormClass to create or update the motion.
2013-02-05 18:46:46 +01:00
forms.BaseMotionForm is the base for the Class, and some FormMixins
will be mixed in dependence of some config values. See motion.forms
for more information on the mixins.
"""
form_classes = []
if (self.request.user.has_perm('motion.can_manage_motion') and
(config['motion_identifier'] == 'manually' or type(self) == MotionUpdateView)):
form_classes.append(MotionIdentifierMixin)
form_classes.append(BaseMotionForm)
2013-02-05 18:46:46 +01:00
2013-01-26 15:25:54 +01:00
if self.request.user.has_perm('motion.can_manage_motion'):
form_classes.append(MotionSubmitterMixin)
form_classes.append(MotionCategoryMixin)
2013-01-26 15:25:54 +01:00
if config['motion_min_supporters'] > 0:
form_classes.append(MotionSupporterMixin)
form_classes.append(MotionWorkflowMixin)
if self.object:
if config['motion_allow_disable_versioning'] and self.object.state.versioning:
form_classes.append(MotionDisableVersioningMixin)
2013-01-26 15:25:54 +01:00
return type('MotionForm', tuple(form_classes), {})
2012-02-14 16:31:21 +01:00
class MotionCreateView(MotionEditMixin, CreateView):
"""
View to create a motion.
"""
2013-01-06 12:07:37 +01:00
model = Motion
2012-03-18 17:11:58 +01:00
def check_permission(self, request, *args, **kwargs):
"""
Checks whether the requesting user can submit a new motion. He needs
at least the permission 'motion.can_create_motion'. If the submitting
of new motions by non-staff users is stopped via config variable
'motion_stop_submitting', the requesting user needs also to have
'motion.can_manage_motion'.
"""
if request.user.has_perm('motion.can_create_motion'):
return not config['motion_stop_submitting'] or request.user.has_perm('motion.can_manage_motion')
return False
def form_valid(self, form):
"""
2014-12-25 10:58:52 +01:00
Write a log message and set the submitter if necessary.
"""
2014-12-25 10:58:52 +01:00
# First, validate and process the form and create the motion
response = super().form_valid(form)
2014-12-25 10:58:52 +01:00
# Write the log message
self.object.write_log([ugettext_noop('Motion created')], self.request.user)
2014-12-25 10:58:52 +01:00
# Set submitter to request.user if no submitter is set yet
2014-03-27 20:38:13 +01:00
if ('submitter' not in form.cleaned_data or
not form.cleaned_data['submitter']):
2013-03-15 11:35:03 +01:00
self.object.add_submitter(self.request.user)
return response
2013-03-15 11:35:03 +01:00
def get_initial(self):
2014-12-25 10:58:52 +01:00
"""
Sets the initial data for the MotionCreateForm.
"""
initial = super().get_initial()
2014-12-25 10:58:52 +01:00
initial['text'] = config['motion_preamble']
if self.request.user.has_perm('motion.can_manage_motion'):
initial['workflow'] = config['motion_workflow']
return initial
def manipulate_object(self, form):
"""
Sets first state according to given or default workflow and initiates
a new version.
"""
2014-05-28 00:20:13 +02:00
workflow = form.cleaned_data.get('workflow', int(config['motion_workflow']))
self.object.reset_state(workflow)
self.version = self.object.get_new_version()
2014-12-25 10:58:52 +01:00
class MotionCreateAmendmentView(MotionCreateView):
"""
Create an amendment.
"""
def dispatch(self, *args, **kwargs):
if not config['motion_amendments_enabled']:
raise Http404('Amendments are disabled in the config.')
return super().dispatch(*args, **kwargs)
2014-12-25 10:58:52 +01:00
def get_parent_motion(self):
"""
Gets the parent motion from the url.
Caches the value.
"""
try:
parent = self._object_parent
except AttributeError:
# self.get_object() is the django method, which does not cache the
# object. For now this is not a problem, because get_object() is only
# called once.
parent = self._object_parent = self.get_object()
return parent
def manipulate_object(self, form):
"""
Sets the parent to the motion to which this amendment refers.
"""
self.object.parent = self.get_parent_motion()
super().manipulate_object(form)
2014-12-25 10:58:52 +01:00
def get_initial(self):
"""
Sets the initial values to the form.
This are the values for title, text and reason which are set to the
values from the parent motion.
"""
initial = super().get_initial()
2014-12-25 10:58:52 +01:00
parent = self.get_parent_motion()
initial['title'] = parent.title
initial['text'] = parent.text
initial['reason'] = parent.reason
initial['category'] = parent.category
return initial
2012-03-18 17:11:58 +01:00
2012-06-11 13:43:48 +02:00
class MotionUpdateView(MotionEditMixin, UpdateView):
"""
View to update a motion.
"""
2013-01-06 12:07:37 +01:00
model = Motion
2012-06-11 13:43:48 +02:00
def check_permission(self, request, *args, **kwargs):
"""
Check if the request.user has the permission to edit the motion.
"""
return self.get_object().get_allowed_actions(request.user)['update']
2013-02-02 10:59:07 +01:00
def form_valid(self, form):
"""
Writes a log message and removes supports in some cases if the form is valid.
"""
response = super().form_valid(form)
self.write_log()
if (config['motion_remove_supporters'] and self.object.state.allow_support and
not self.request.user.has_perm('motion.can_manage_motion')):
self.object.clear_supporters()
self.object.write_log([ugettext_noop('All supporters removed')], self.request.user)
return response
def write_log(self):
"""
Writes a log message. Distinguishs whether a version was created or updated.
"""
if self.version.id is None:
number = self.object.get_last_version().version_number
created = False
else:
number = self.version.version_number
created = self.used_new_version
self.object.write_log(
2013-06-25 00:59:16 +02:00
[ugettext_noop('Motion version'),
' %d ' % number,
ugettext_noop('created') if created else ugettext_noop('updated')],
self.request.user)
def get_initial(self):
initial = super().get_initial()
if self.request.user.has_perm('motion.can_manage_motion'):
initial['workflow'] = self.object.state.workflow
return initial
def manipulate_object(self, form):
"""
Resets state if the workflow should change and decides whether to use a
new version or the last version.
"""
workflow = form.cleaned_data.get('workflow', None)
if (workflow is not None and
workflow != self.object.state.workflow):
self.object.reset_state(workflow)
# Decide if a new version is saved to the database
if (self.object.state.versioning and
not form.cleaned_data.get('disable_versioning', False)):
self.version = self.object.get_new_version()
self.used_new_version = True
else:
self.version = self.object.get_last_version()
self.used_new_version = False
2013-01-26 15:25:54 +01:00
class MotionDeleteView(DeleteView):
"""
View to delete a motion.
"""
model = Motion
success_url_name = 'motion_list'
2013-02-02 10:59:07 +01:00
def check_permission(self, request, *args, **kwargs):
"""
Check if the request.user has the permission to delete the motion.
"""
2013-02-02 10:59:07 +01:00
return self.get_object().get_allowed_actions(request.user)['delete']
2013-09-25 12:53:44 +02:00
def get_final_message(self):
return _('%s was successfully deleted.') % _('Motion')
class VersionDeleteView(DeleteView):
"""
View to delete a motion version.
"""
model = MotionVersion
required_permission = 'motion.can_manage_motion'
success_url_name = 'motion_detail'
def get_object(self):
try:
version = self._object
except AttributeError:
try:
motion = Motion.objects.get(pk=int(self.kwargs.get('pk')))
except Motion.DoesNotExist:
raise Http404('Motion %s not found.' % self.kwargs.get('pk'))
try:
version = MotionVersion.objects.get(
motion=motion,
version_number=int(self.kwargs.get('version_number')))
except MotionVersion.DoesNotExist:
raise Http404('Version %s not found.' % self.kwargs.get('version_number'))
if version == motion.active_version:
raise Http404('You can not delete the active version of a motion.')
self._object = version
return version
2013-09-25 12:53:44 +02:00
def get_url_name_args(self):
return (self.get_object().motion_id, )
2013-09-25 12:53:44 +02:00
class VersionPermitView(SingleObjectMixin, QuestionView):
2013-04-19 16:02:16 +02:00
"""
View to permit a version of a motion.
"""
2013-02-03 13:24:29 +01:00
model = Motion
2013-09-25 12:53:44 +02:00
final_message = ugettext_lazy('Version successfully permitted.')
required_permission = 'motion.can_manage_motion'
2013-09-25 12:53:44 +02:00
question_url_name = 'motion_version_detail'
2013-02-03 13:24:29 +01:00
def get(self, *args, **kwargs):
2013-04-19 16:02:16 +02:00
"""
Sets self.version to a motion version.
2013-04-19 16:02:16 +02:00
"""
version_number = self.kwargs.get('version_number', None)
try:
self.version = self.get_object().versions.get(version_number=int(version_number))
except MotionVersion.DoesNotExist:
raise Http404('Version %s not found.' % version_number)
return super().get(*args, **kwargs)
2013-02-03 13:24:29 +01:00
def get_url_name_args(self):
2013-04-19 16:02:16 +02:00
"""
Returns a list with arguments to create the success- and question_url.
2013-04-19 16:02:16 +02:00
"""
return [self.get_object().pk, self.version.version_number]
2013-02-03 13:24:29 +01:00
2013-09-25 12:53:44 +02:00
def get_question_message(self):
2013-04-19 16:02:16 +02:00
"""
Return a string, shown to the user as question to permit the version.
"""
return _('Are you sure you want permit version %s?') % self.version.version_number
2013-02-03 13:24:29 +01:00
2013-09-25 12:53:44 +02:00
def on_clicked_yes(self):
2013-04-19 16:02:16 +02:00
"""
Activate the version, if the user chooses 'yes'.
"""
self.get_object().active_version = self.version
self.get_object().save(update_fields=['active_version'])
self.get_object().write_log(
2013-06-25 00:59:16 +02:00
message_list=[ugettext_noop('Version'),
' %d ' % self.version.version_number,
ugettext_noop('permitted')],
person=self.request.user)
2013-02-03 13:24:29 +01:00
class VersionDiffView(DetailView):
"""
Show diff between two versions of a motion.
"""
model = Motion
template_name = 'motion/motion_diff.html'
def check_permission(self, request, *args, **kwargs):
"""
Check if the request.user has the permission to see the motion.
"""
return self.get_object().get_allowed_actions(request.user)['see']
def get_context_data(self, **kwargs):
"""
Return the template context with versions and html diff strings.
"""
try:
rev1 = int(self.request.GET['rev1'])
rev2 = int(self.request.GET['rev2'])
version_rev1 = self.get_object().versions.get(version_number=rev1)
version_rev2 = self.get_object().versions.get(version_number=rev2)
diff_text = htmldiff(version_rev1.text, version_rev2.text)
diff_reason = htmldiff(version_rev1.reason, version_rev2.reason)
except (KeyError, ValueError, MotionVersion.DoesNotExist):
messages.error(self.request, _('At least one version number is not valid.'))
version_rev1 = None
version_rev2 = None
diff_text = None
diff_reason = None
context = super().get_context_data(**kwargs)
context.update({
'version_rev1': version_rev1,
'version_rev2': version_rev2,
'diff_text': diff_text,
'diff_reason': diff_reason,
})
return context
2013-09-25 12:53:44 +02:00
class SupportView(SingleObjectMixin, QuestionView):
"""
View to support or unsupport a motion.
2013-02-05 18:46:46 +01:00
If self.support is True, the view will append a request.user to the supporter list.
If self.support is False, the view will remove a request.user from the supporter list.
"""
2013-02-05 18:46:46 +01:00
required_permission = 'motion.can_support_motion'
model = Motion
support = True
2013-02-02 10:59:07 +01:00
def check_permission(self, request):
"""
Return True if the user can support or unsupport the motion. Else: False.
"""
allowed_actions = self.get_object().get_allowed_actions(request.user)
2013-02-02 10:59:07 +01:00
if self.support and not allowed_actions['support']:
messages.error(request, _('You can not support this motion.'))
return False
2013-02-02 10:59:07 +01:00
elif not self.support and not allowed_actions['unsupport']:
messages.error(request, _('You can not unsupport this motion.'))
return False
else:
return True
2013-09-25 12:53:44 +02:00
def get_question_message(self):
"""
Return the question string.
"""
2013-03-15 02:14:15 +01:00
if self.support:
return _('Do you really want to support this motion?')
else:
return _('Do you really want to unsupport this motion?')
2013-09-25 12:53:44 +02:00
def on_clicked_yes(self):
"""
Append or remove the request.user from the motion.
2013-02-05 18:46:46 +01:00
First the method checks the permissions, and writes a log message after
2013-02-05 18:46:46 +01:00
appending or removing the user.
"""
2013-02-02 10:59:07 +01:00
if self.check_permission(self.request):
2013-02-03 10:02:06 +01:00
user = self.request.user
if self.support:
self.get_object().support(person=user)
self.get_object().write_log([ugettext_noop('Motion supported')], user)
else:
self.get_object().unsupport(person=user)
self.get_object().write_log([ugettext_noop('Motion unsupported')], user)
2013-09-25 12:53:44 +02:00
def get_final_message(self):
"""
Return the success message.
"""
if self.support:
return _("You have supported this motion successfully.")
else:
return _("You have unsupported this motion successfully.")
class MotionViewSet(ModelViewSet):
"""
API endpoint to list, retrieve, create, update and destroy motions.
"""
queryset = Motion.objects.all()
serializer_class = MotionSerializer
def check_permissions(self, request):
"""
Calls self.permission_denied() if the requesting user has not the
permission to see motions and in case of create, update or
destroy requests the permission to manage motions.
"""
# TODO: Use motion.can_create_motion permission and
# motion.can_support_motion permission to create and update some
# objects but restricted concerning the requesting user.
if (not request.user.has_perm('motion.can_see_motion') or
(self.action in ('create', 'update', 'destroy') and not
request.user.has_perm('motion.can_manage_motion'))):
self.permission_denied(request)
2013-02-01 12:51:54 +01:00
class PollCreateView(SingleObjectMixin, RedirectView):
"""
View to create a poll for a motion.
"""
required_permission = 'motion.can_manage_motion'
2013-02-01 12:51:54 +01:00
model = Motion
url_name = 'motionpoll_detail'
2013-02-01 12:51:54 +01:00
def pre_redirect(self, request, *args, **kwargs):
"""
Create the poll for the motion.
"""
self.poll = self.get_object().create_poll()
self.get_object().write_log([ugettext_noop("Poll created")], request.user)
2013-02-01 12:51:54 +01:00
messages.success(request, _("New vote was successfully created."))
def get_redirect_url(self, **kwargs):
"""
Return the URL to the UpdateView of the poll.
"""
return reverse('motionpoll_update', args=[self.get_object().pk, self.poll.poll_number])
2013-02-01 12:51:54 +01:00
class PollMixin(object):
2013-04-21 19:12:50 +02:00
"""
Mixin for the PollUpdateView and the PollDeleteView.
"""
required_permission = 'motion.can_manage_motion'
2013-02-01 12:51:54 +01:00
success_url_name = 'motion_detail'
def get_object(self):
2013-04-21 19:12:50 +02:00
"""
Return a MotionPoll object.
2013-02-05 18:46:46 +01:00
Use the motion id and the poll_number from the url kwargs to get the
object.
"""
try:
obj = self._object
except AttributeError:
queryset = MotionPoll.objects.filter(
motion=self.kwargs['pk'],
poll_number=self.kwargs['poll_number'])
obj = get_object_or_404(queryset)
self._object = obj
return obj
2013-02-01 12:51:54 +01:00
def get_url_name_args(self):
2013-04-21 19:12:50 +02:00
"""
Return the arguments to create the url to the success_url.
"""
return [self.get_object().motion.pk]
class PollUpdateView(PollMixin, PollFormView):
2013-04-21 19:12:50 +02:00
"""
View to update a MotionPoll.
"""
2013-09-25 12:53:44 +02:00
poll_class = MotionPoll
2013-04-21 19:12:50 +02:00
"""
Poll Class to use for this view.
"""
2013-02-05 18:46:46 +01:00
template_name = 'motion/motionpoll_form.html'
2013-02-01 12:51:54 +01:00
def get_context_data(self, **kwargs):
2013-04-21 19:12:50 +02:00
"""
Return the template context.
2013-02-05 18:46:46 +01:00
Append the motion object to the context.
"""
context = super().get_context_data(**kwargs)
2013-02-01 12:51:54 +01:00
context.update({
2013-04-21 19:12:50 +02:00
'motion': self.poll.motion,
'poll': self.poll})
2013-02-01 12:51:54 +01:00
return context
2013-02-03 10:02:06 +01:00
def form_valid(self, form):
2013-04-21 19:12:50 +02:00
"""
Write a log message, if the form is valid.
"""
value = super().form_valid(form)
self.get_object().write_log([ugettext_noop('Poll updated')], self.request.user)
2013-02-03 10:02:06 +01:00
return value
2013-02-01 12:51:54 +01:00
class PollDeleteView(PollMixin, DeleteView):
2013-04-21 19:12:50 +02:00
"""
View to delete a MotionPoll.
"""
model = MotionPoll
2013-09-25 12:53:44 +02:00
def on_clicked_yes(self):
2013-04-21 19:12:50 +02:00
"""
Write a log message, if the form is valid.
"""
super().on_clicked_yes()
self.get_object().motion.write_log([ugettext_noop('Poll deleted')], self.request.user)
2013-02-03 10:02:06 +01:00
def get_redirect_url(self, **kwargs):
2013-04-21 19:12:50 +02:00
"""
Return the URL to the DetailView of the motion.
"""
return reverse('motion_detail', args=[self.get_object().motion.pk])
2013-04-21 19:12:50 +02:00
class PollPDFView(PollMixin, PDFView):
"""
Generates a ballotpaper.
"""
required_permission = 'motion.can_manage_motion'
top_space = 0
2013-04-21 19:12:50 +02:00
def get_filename(self):
"""
Return the filename for the PDF.
"""
return u'%s%s_%s' % (_("Motion"), str(self.get_object().poll_number), _("Poll"))
2013-04-21 19:12:50 +02:00
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)
2013-04-21 19:12:50 +02:00
def append_to_pdf(self, pdf):
"""
Append PDF objects.
"""
motion_poll_to_pdf(pdf, self.get_object())
2013-04-21 19:12:50 +02:00
class MotionSetStateView(SingleObjectMixin, RedirectView):
"""
View to set the state of a motion.
2013-02-05 18:46:46 +01:00
If self.reset is False, the new state is taken from url.
If self.reset is True, the default state is taken.
"""
required_permission = 'motion.can_manage_motion'
url_name = 'motion_detail'
model = Motion
reset = False
def pre_redirect(self, request, *args, **kwargs):
"""
Save the new state and write a log message.
"""
success = False
if self.reset:
self.get_object().reset_state()
success = True
elif self.get_object().state.id == int(kwargs['state']):
messages.error(request, _('You can not set the state of the motion. It is already done.'))
elif int(kwargs['state']) not in [state.id for state in self.get_object().state.next_states.all()]:
messages.error(request, _('You can not set the state of the motion to %s.') % _(State.objects.get(pk=int(kwargs['state'])).name))
else:
self.get_object().set_state(int(kwargs['state']))
success = True
if success:
self.get_object().save(update_fields=['state', 'identifier'])
self.get_object().write_log(
message_list=[ugettext_noop('State changed to'), ' ', self.get_object().state.name], # TODO: Change string to 'State set to ...'
person=self.request.user)
2013-05-16 23:44:07 +02:00
messages.success(request,
_('The state of the motion was set to %s.')
% html_strong(_(self.get_object().state.name)))
class CreateRelatedAgendaItemView(_CreateRelatedAgendaItemView):
"""
View to create and agenda item for a motion.
"""
2013-02-02 00:51:08 +01:00
model = Motion
def pre_redirect(self, request, *args, **kwargs):
"""
Create the agenda item.
"""
super().pre_redirect(request, *args, **kwargs)
self.get_object().write_log([ugettext_noop('Agenda item created')], self.request.user)
2013-02-02 00:51:08 +01:00
2013-02-03 18:18:29 +01:00
class MotionPDFView(SingleObjectMixin, PDFView):
"""
Create the PDF for one or for all motions.
2013-02-05 18:46:46 +01:00
If self.print_all_motions is True, the view returns a PDF with all motions.
If self.print_all_motions is False, the view returns a PDF with only one
motion.
"""
2013-02-03 18:18:29 +01:00
model = Motion
top_space = 0
print_all_motions = False
def check_permission(self, request, *args, **kwargs):
"""
Checks if the requesting user has the permission to see the motion as
PDF.
"""
if self.print_all_motions:
is_allowed = request.user.has_perm('motion.can_see_motion')
else:
is_allowed = self.get_object().get_allowed_actions(request.user)['see']
return is_allowed
def get_object(self, *args, **kwargs):
if self.print_all_motions:
obj = None
else:
obj = super().get_object(*args, **kwargs)
return obj
2013-02-03 18:18:29 +01:00
def get_filename(self):
"""
Return the filename for the PDF.
"""
2013-02-03 18:18:29 +01:00
if self.print_all_motions:
return _("Motions")
else:
if self.get_object().identifier:
suffix = self.get_object().identifier.replace(' ', '')
else:
suffix = self.get_object().title.replace(' ', '_')
suffix = slugify(suffix)
return '%s-%s' % (_("Motion"), suffix)
2013-02-03 18:18:29 +01:00
def append_to_pdf(self, pdf):
"""
Append PDF objects.
"""
2013-02-03 18:18:29 +01:00
if self.print_all_motions:
motions = []
for motion in Motion.objects.all():
if (not motion.state.required_permission_to_see or
self.request.user.has_perm(motion.state.required_permission_to_see)):
motions.append(motion)
motions_to_pdf(pdf, motions)
2013-02-03 18:18:29 +01:00
else:
motion_to_pdf(pdf, self.get_object())
2013-02-03 18:18:29 +01:00
2013-03-11 20:17:19 +01:00
class CategoryListView(ListView):
required_permission = 'motion.can_manage_motion'
2013-03-11 20:17:19 +01:00
model = Category
class CategoryCreateView(CreateView):
fields = ("name", "prefix",)
required_permission = 'motion.can_manage_motion'
2013-03-11 20:17:19 +01:00
model = Category
2013-03-11 21:29:56 +01:00
success_url_name = 'motion_category_list'
url_name_args = []
2013-03-11 20:17:19 +01:00
class CategoryUpdateView(UpdateView):
fields = ("name", "prefix",)
required_permission = 'motion.can_manage_motion'
2013-03-11 20:17:19 +01:00
model = Category
2013-03-11 21:29:56 +01:00
success_url_name = 'motion_category_list'
url_name_args = []
2013-03-11 20:17:19 +01:00
2013-03-11 21:38:07 +01:00
class CategoryDeleteView(DeleteView):
required_permission = 'motion.can_manage_motion'
2013-03-11 21:38:07 +01:00
model = Category
question_url_name = 'motion_category_list'
url_name_args = []
2013-03-11 21:38:07 +01:00
success_url_name = 'motion_category_list'
class CategoryViewSet(ModelViewSet):
"""
API endpoint to list, retrieve, create, update and destroy categories.
"""
queryset = Category.objects.all()
serializer_class = CategorySerializer
def check_permissions(self, request):
"""
Calls self.permission_denied() if the requesting user has not the
permission to see motions and in case of create, update or destroy
requests the permission to manage motions.
"""
if (not request.user.has_perm('motion.can_see_motion') or
(self.action in ('create', 'update', 'destroy') and not
request.user.has_perm('motion.can_manage_motion'))):
self.permission_denied(request)
class MotionCSVImportView(CSVImportView):
2013-05-08 18:07:09 +02:00
"""
Imports motions from an uploaded csv file.
2013-05-08 18:07:09 +02:00
"""
form_class = MotionCSVImportForm
required_permission = 'motion.can_manage_motion'
2013-05-08 18:07:09 +02:00
success_url_name = 'motion_list'
template_name = 'motion/motion_form_csv_import.html'
2013-05-08 18:07:09 +02:00
2013-05-12 00:47:49 +02:00
def get_initial(self, *args, **kwargs):
"""
Sets the request user as initial for the default submitter.
"""
return_value = super().get_initial(*args, **kwargs)
2013-05-12 00:47:49 +02:00
return_value.update({'default_submitter': self.request.user.person_id})
return return_value
2013-05-08 18:07:09 +02:00
def form_valid(self, form):
success, warning, error = import_motions(importing_person=self.request.user, **form.cleaned_data)
messages.success(self.request, success)
messages.warning(self.request, warning)
messages.error(self.request, error)
# Overleap method of CSVImportView
return super(CSVImportView, self).form_valid(form)
class WorkflowViewSet(ModelViewSet):
"""
API endpoint to list, retrieve, create, update and destroy workflows.
"""
queryset = Workflow.objects.all()
serializer_class = WorkflowSerializer
def check_permissions(self, request):
"""
Calls self.permission_denied() if the requesting user has not the
permission to see motions and in case of create, update or destroy
requests the permission to manage motions.
"""
if (not request.user.has_perm('motion.can_see_motion') or
(self.action in ('create', 'update', 'destroy') and not
request.user.has_perm('motion.can_manage_motion'))):
self.permission_denied(request)