OpenSlides/openslides/agenda/views.py

499 lines
16 KiB
Python
Raw Normal View History

2011-07-31 10:46:29 +02:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
openslides.agenda.views
~~~~~~~~~~~~~~~~~~~~~~~
Views for the agenda app.
2012-04-25 22:29:19 +02:00
:copyright: 2011, 2012 by the OpenSlides team, see AUTHORS.
2011-07-31 10:46:29 +02:00
:license: GNU GPL, see LICENSE for more details.
"""
2013-03-18 12:34:47 +01:00
# TODO: Rename all views and template names
2013-02-16 10:41:22 +01:00
from reportlab.platypus import Paragraph
2013-02-18 18:56:37 +01:00
from datetime import datetime, timedelta
2011-07-31 10:46:29 +02:00
from django.core.urlresolvers import reverse
from django.contrib import messages
2012-07-04 12:50:33 +02:00
from django.db import transaction
from django.db.models import Model
from django.utils.translation import ugettext as _, ugettext_lazy
2012-02-20 19:39:26 +01:00
from django.views.generic.detail import SingleObjectMixin
2012-02-20 17:46:45 +01:00
from openslides.config.api import config
from openslides.utils.pdf import stylesheet
2013-03-18 12:34:47 +01:00
from openslides.utils.exceptions import OpenSlidesError
from openslides.utils.views import (
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
2013-03-18 12:34:47 +01:00
DetailView, FormView, SingleObjectMixin)
from openslides.utils.template import Tab
2012-07-04 12:50:33 +02:00
from openslides.utils.utils import html_strong
2013-03-18 12:34:47 +01:00
from openslides.projector.api import get_active_slide, get_slide_from_sid
from openslides.projector.projector import Widget, SLIDE
2013-03-18 12:34:47 +01:00
from .models import Item, Speaker
from .forms import ItemOrderForm, ItemForm, AppendSpeakerForm
2012-02-20 17:46:45 +01:00
class Overview(TemplateView):
2012-07-04 12:50:33 +02:00
"""
Show all agenda items, and update there range via post.
"""
2012-02-20 17:46:45 +01:00
permission_required = 'agenda.can_see_agenda'
template_name = 'agenda/overview.html'
def get_context_data(self, **kwargs):
2012-03-18 17:11:58 +01:00
context = super(Overview, self).get_context_data(**kwargs)
2013-01-05 23:52:29 +01:00
if self.request.user.has_perm('agenda.can_see_orga_items'):
items = Item.objects.all()
else:
items = Item.objects.filter(type__exact=Item.AGENDA_ITEM)
2013-01-05 23:52:29 +01:00
2013-02-16 10:41:22 +01:00
start = config['agenda_start_event_date_time']
if start is None or len(start) == 0:
start = None
else:
start = datetime.strptime(start, '%d.%m.%Y %H:%M')
2013-01-29 14:28:42 +01:00
duration = timedelta()
for item in items:
if not item.closed and (item.duration is not None
and len(item.duration) > 0):
duration_list = item.duration.split(':')
duration += timedelta(hours=int(duration_list[0]),
minutes=int(duration_list[1]))
if not start is None:
item.tooltip = start + duration
2013-01-29 14:28:42 +01:00
2013-01-30 17:39:53 +01:00
if start is None:
end = None
else:
2013-02-16 10:41:22 +01:00
end = start + duration
2013-01-30 17:39:53 +01:00
2013-02-18 18:56:37 +01:00
duration = u'%d:%02d' % (
(duration.days * 24 + duration.seconds / 3600.0),
(duration.seconds / 60.0 % 60))
2013-01-30 17:39:53 +01:00
2012-02-20 17:46:45 +01:00
context.update({
2013-01-05 23:52:29 +01:00
'items': items,
2012-07-04 12:50:33 +02:00
'active_sid': get_active_slide(only_sid=True),
2013-01-30 17:39:53 +01:00
'duration': duration,
'start': start,
2013-02-18 18:56:37 +01:00
'end': end})
2012-02-20 17:46:45 +01:00
return context
2012-07-04 12:50:33 +02:00
@transaction.commit_manually
2012-02-20 17:46:45 +01:00
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
2012-07-04 12:50:33 +02:00
if not request.user.has_perm('agenda.can_manage_agenda'):
messages.error(
request,
_('You are not authorized to manage the agenda.'))
2012-07-04 12:50:33 +02:00
return self.render_to_response(context)
transaction.commit()
2011-07-31 10:46:29 +02:00
for item in Item.objects.all():
2012-02-06 22:22:16 +01:00
form = ItemOrderForm(request.POST, prefix="i%d" % item.id)
2011-07-31 10:46:29 +02:00
if form.is_valid():
try:
parent = Item.objects.get(id=form.cleaned_data['parent'])
2011-07-31 10:46:29 +02:00
except Item.DoesNotExist:
parent = None
2011-07-31 10:46:29 +02:00
item.weight = form.cleaned_data['weight']
item.parent = parent
Model.save(item)
2012-07-04 12:50:33 +02:00
else:
transaction.rollback()
messages.error(
request, _('Errors when reordering of the agenda'))
2012-07-04 12:50:33 +02:00
return self.render_to_response(context)
Item.objects.rebuild()
2012-07-04 12:50:33 +02:00
# TODO: assure, that it is a valid tree
transaction.commit()
2012-02-20 17:46:45 +01:00
return self.render_to_response(context)
2011-07-31 10:46:29 +02:00
2013-03-18 12:34:47 +01:00
class AgendaItemView(SingleObjectMixin, FormView):
2012-07-04 12:50:33 +02:00
"""
Show an agenda item.
"""
2013-03-18 12:34:47 +01:00
# TODO: use 'SingleObjectTemplateResponseMixin' to choose the right template name
2012-04-15 09:55:21 +02:00
permission_required = 'agenda.can_see_agenda'
template_name = 'agenda/view.html'
model = Item
context_object_name = 'item'
2013-03-18 12:34:47 +01:00
form_class = AppendSpeakerForm
def get_context_data(self, **kwargs):
self.object = self.get_object()
speakers = Speaker.objects.filter(time=None, item=self.object.pk).order_by('weight')
2013-03-18 12:34:47 +01:00
old_speakers = list(Speaker.objects.filter(item=self.object.pk)
.exclude(time=None).order_by('time'))
2013-03-18 12:34:47 +01:00
kwargs.update({
'object': self.object,
'speakers': speakers,
'old_speakers': old_speakers,
'is_speaker': Speaker.objects.filter(
time=None, person=self.request.user, item=self.object).exists(),
'show_list': config['presentation_argument'] == 'show_list_of_speakers',
2013-03-18 12:34:47 +01:00
})
return super(AgendaItemView, self).get_context_data(**kwargs)
def form_valid(self, form):
Speaker.objects.add(person=form.cleaned_data['speaker'], item=self.get_object())
return self.render_to_response(self.get_context_data(form=form))
def get_form_kwargs(self):
kwargs = super(AgendaItemView, self).get_form_kwargs()
kwargs['item'] = self.get_object()
return kwargs
2012-04-15 09:55:21 +02:00
2012-02-20 19:39:26 +01:00
class SetClosed(RedirectView, SingleObjectMixin):
2011-07-31 10:46:29 +02:00
"""
2012-07-04 12:50:33 +02:00
Close or open an item.
2011-07-31 10:46:29 +02:00
"""
2012-02-20 17:46:45 +01:00
permission_required = 'agenda.can_manage_agenda'
allow_ajax = True
url_name = 'item_overview'
2012-02-20 19:39:26 +01:00
model = Item
2011-09-02 20:46:24 +02:00
2012-02-20 17:46:45 +01:00
def get_ajax_context(self, **kwargs):
context = super(SetClosed, self).get_ajax_context(**kwargs)
closed = kwargs['closed']
2011-08-31 23:47:31 +02:00
if closed:
2012-02-20 19:39:26 +01:00
link = reverse('item_open', args=[self.object.id])
2011-08-31 23:47:31 +02:00
else:
2012-02-20 19:39:26 +01:00
link = reverse('item_close', args=[self.object.id])
2012-02-20 17:46:45 +01:00
context.update({
'closed': kwargs['closed'],
2013-02-18 18:56:37 +01:00
'link': link})
2012-02-20 17:46:45 +01:00
return context
def pre_redirect(self, request, *args, **kwargs):
2012-02-20 19:39:26 +01:00
self.object = self.get_object()
2012-02-20 17:46:45 +01:00
closed = kwargs['closed']
2012-02-20 19:39:26 +01:00
self.object.set_closed(closed)
2012-02-20 17:46:45 +01:00
return super(SetClosed, self).pre_redirect(request, *args, **kwargs)
2013-03-18 12:34:47 +01:00
def get_url_name_args(self):
return []
2011-07-31 10:46:29 +02:00
2012-02-20 17:46:45 +01:00
class ItemUpdate(UpdateView):
2012-07-04 12:50:33 +02:00
"""
Update an existing item.
"""
2012-02-20 17:46:45 +01:00
permission_required = 'agenda.can_manage_agenda'
template_name = 'agenda/edit.html'
model = Item
context_object_name = 'item'
form_class = ItemForm
success_url_name = 'item_overview'
2011-07-31 10:46:29 +02:00
2012-02-20 17:46:45 +01:00
class ItemCreate(CreateView):
2012-07-04 12:50:33 +02:00
"""
Create a new item.
"""
2012-02-20 17:46:45 +01:00
permission_required = 'agenda.can_manage_agenda'
template_name = 'agenda/edit.html'
model = Item
context_object_name = 'item'
form_class = ItemForm
success_url_name = 'item_overview'
2012-02-20 17:46:45 +01:00
class ItemDelete(DeleteView):
2011-07-31 10:46:29 +02:00
"""
2012-07-04 12:50:33 +02:00
Delete an item.
2011-07-31 10:46:29 +02:00
"""
2012-02-20 17:46:45 +01:00
permission_required = 'agenda.can_manage_agenda'
model = Item
question_url_name = 'item_overview'
success_url_name = 'item_overview'
2012-02-20 17:46:45 +01:00
def get_answer_options(self):
if self.object.children.exists():
return [('all', _("Yes, with all child items."))] + self.answer_options
else:
return self.answer_options
2012-02-09 02:29:38 +01:00
def pre_post_redirect(self, request, *args, **kwargs):
if self.get_answer() == 'all':
self.object.delete(with_children=True)
messages.success(
2013-02-16 10:41:22 +01:00
request,
_("Item %s and his children were successfully deleted.")
2012-07-04 12:50:33 +02:00
% html_strong(self.object))
elif self.get_answer() == 'yes':
self.object.delete(with_children=False)
messages.success(
2013-02-16 10:41:22 +01:00
request,
_("Item %s was successfully deleted.")
2012-07-04 12:50:33 +02:00
% html_strong(self.object))
2012-02-20 17:46:45 +01:00
2012-04-14 10:54:22 +02:00
class AgendaPDF(PDFView):
2012-07-04 12:50:33 +02:00
"""
Create a full agenda-PDF.
"""
permission_required = 'agenda.can_see_agenda'
filename = ugettext_lazy('Agenda')
document_title = ugettext_lazy('Agenda')
def append_to_pdf(self, story):
for item in Item.objects.filter(type__exact=Item.AGENDA_ITEM):
ancestors = item.get_ancestors()
if ancestors:
2012-07-04 12:50:33 +02:00
space = " " * 6 * ancestors.count()
story.append(Paragraph(
"%s%s" % (space, item.get_title()),
2012-07-04 12:50:33 +02:00
stylesheet['Subitem']))
else:
story.append(Paragraph(item.get_title(), stylesheet['Item']))
2012-03-16 14:31:59 +01:00
2013-02-16 10:41:22 +01:00
2013-03-18 12:34:47 +01:00
class SpeakerAppendView(SingleObjectMixin, RedirectView):
"""
Set the request.user to the speaker list.
"""
permission_required = 'agenda.can_be_speaker'
url_name = 'item_view'
model = Item
def pre_redirect(self, request, *args, **kwargs):
self.object = self.get_object()
if self.object.speaker_list_closed:
messages.error(request, _('The list of speakers is closed.'))
2013-03-18 12:34:47 +01:00
else:
try:
Speaker.objects.add(item=self.object, person=request.user)
except OpenSlidesError, e:
messages.error(request, e)
class SpeakerDeleteView(DeleteView):
"""
Delete the request.user or a specific user from the speaker list.
"""
success_url_name = 'item_view'
question_url_name = 'item_view'
def has_permission(self, request, *args, **kwargs):
"""
Check the permission to delete a speaker.
"""
if 'speaker' in kwargs:
return request.user.has_perm('agenda.can_manage_agenda')
else:
# Any person how is on the list of speakers can delete him self from the list
return True
def get(self, *args, **kwargs):
try:
return super(SpeakerDeleteView, self).get(*args, **kwargs)
except Speaker.DoesNotExist:
messages.error(self.request, _('You are not on the list of speakers.'))
return super(RedirectView, self).get(*args, **kwargs)
def get_object(self):
"""
Returns the speaker object.
If 'speaker' is in kwargs, this speaker object is returnd. Else, a speaker
object with the request.user as speaker.
"""
try:
return Speaker.objects.get(pk=self.kwargs['speaker'])
except KeyError:
return Speaker.objects.filter(
item=self.kwargs['pk'], person=self.request.user).exclude(weight=None).get()
def get_url_name_args(self):
return [self.kwargs['pk']]
def get_question(self):
if 'speaker' in self.kwargs:
return super(SpeakerDeleteView, self).get_question()
else:
return _('Do you really want to remove yourself from the list of speakers?')
class SpeakerSpeakView(SingleObjectMixin, RedirectView):
"""
2013-03-18 12:34:47 +01:00
Mark the speaking person.
2013-03-18 12:34:47 +01:00
"""
permission_required = 'agenda.can_manage_agenda'
url_name = 'item_view'
model = Item
def pre_redirect(self, *args, **kwargs):
self.object = self.get_object()
try:
speaker = Speaker.objects.filter(
person=kwargs['person_id'],
item=self.object.pk).exclude(
weight=None).get()
except Speaker.DoesNotExist:
messages.error(
self.request,
_('%(person)s is not on the list of %(item)s.')
% {'person': kwargs['person_id'], 'item': self.object})
2013-03-18 12:34:47 +01:00
else:
speaker.speak()
def get_url_name_args(self):
return [self.object.pk]
2013-03-18 12:34:47 +01:00
class SpeakerListCloseView(SingleObjectMixin, RedirectView):
2013-03-18 12:34:47 +01:00
"""
2013-03-18 12:34:47 +01:00
View to close and reopen a list of speakers.
2013-03-18 12:34:47 +01:00
"""
permission_required = 'agenda.can_manage_agenda'
model = Item
2013-03-18 12:34:47 +01:00
reopen = False
2013-03-18 12:34:47 +01:00
url_name = 'item_view'
def pre_redirect(self, *args, **kwargs):
self.object = self.get_object()
2013-03-18 12:34:47 +01:00
self.object.speaker_list_closed = not self.reopen
2013-03-18 12:34:47 +01:00
self.object.save()
def get_url_name_args(self):
return [self.object.pk]
class SpeakerChangeOrderView(SingleObjectMixin, RedirectView):
"""
Change the order of the speakers.
Has to be called as post-request with the new order of the speaker ids.
"""
permission_required = 'agenda.can_manage_agenda'
model = Item
url_name = 'item_view'
def pre_redirect(self, args, **kwargs):
self.object = self.get_object()
@transaction.commit_manually
def pre_post_redirect(self, request, *args, **kwargs):
"""
Reorder the list of speaker.
Take the string 'sort_order' from the post-data, and use this order.
"""
self.object = self.get_object()
transaction.commit()
for (counter, speaker) in enumerate(self.request.POST['sort_order'].split(',')):
try:
speaker_pk = int(speaker.split('_')[1])
except IndexError:
transaction.rollback()
break
try:
speaker = Speaker.objects.filter(item=self.object).get(pk=speaker_pk)
except:
transaction.rollback()
break
speaker.weight = counter + 1
speaker.save()
else:
transaction.commit()
2013-03-18 12:34:47 +01:00
return None
messages.error(request, _('Could not change order. Invalid data.'))
2013-03-18 12:34:47 +01:00
def get_url_name_args(self):
return [self.object.pk]
2013-03-18 12:34:47 +01:00
class CurrentListOfSpeakersView(RedirectView):
"""
Redirect to the current list of speakers and set the request.user on it.
"""
def get_item(self):
"""
Returns the current Item, or None, if the current Slide is not an Agenda Item.
"""
slide = get_slide_from_sid(get_active_slide(only_sid=True), element=True)
if not isinstance(slide, Item):
return None
else:
return slide
def get_redirect_url(self):
"""
Returns the URL to the item_view if:
* the current slide is an item and
* the user has the permission to see the item
in other case, it returns the URL to the dashboard.
This method also add the request.user to the list of speakers, if he
has the right permissions.
"""
item = self.get_item()
request = self.request
if item is None:
messages.error(request, _(
'There is no list of speakers for the current slide. '
'Please choose the agenda item manually from the agenda.'))
2013-03-18 12:34:47 +01:00
return reverse('dashboard')
if self.request.user.has_perm('agenda.can_be_speaker'):
try:
Speaker.objects.add(self.request.user, item)
except OpenSlidesError:
messages.error(request, _('You are already on the list of speakers.'))
else:
messages.success(request, _('You are now on the list of speakers.'))
else:
messages.error(request, _('You can not put yourself on the list of speakers.'))
if not self.request.user.has_perm('agenda.can_see_agenda'):
return reverse('dashboard')
else:
return reverse('item_view', args=[item.pk])
2012-03-18 17:11:58 +01:00
def register_tab(request):
2012-07-04 12:50:33 +02:00
"""
Registers the agenda tab.
2012-07-04 12:50:33 +02:00
"""
selected = request.path.startswith('/agenda/')
2012-03-18 17:11:58 +01:00
return Tab(
title=_('Agenda'),
app='agenda',
2012-03-18 17:11:58 +01:00
url=reverse('item_overview'),
permission=(request.user.has_perm('agenda.can_see_agenda') or
request.user.has_perm('agenda.can_manage_agenda')),
selected=selected)
2012-06-11 13:43:48 +02:00
def get_widgets(request):
2012-07-04 12:50:33 +02:00
"""
Returns the agenda widget for the projector tab.
2012-07-04 12:50:33 +02:00
"""
2013-03-18 12:34:47 +01:00
return [
Widget(
name='agenda',
display_name=_('Agenda'),
template='agenda/widget.html',
context={
'agenda': SLIDE['agenda'],
'items': Item.objects.all(),
'summary': config['presentation_argument'] == 'summary',
'speakers': config['presentation_argument'] == 'show_list_of_speakers'},
2013-03-18 12:34:47 +01:00
permission_required='projector.can_manage_projector'),
Widget(
name='append_to_list_of_speakers',
display_name=_('To the current list of speakers'),
template='agenda/speaker_widget.html',
context={},
permission_required='agenda.can_be_speaker')]