2015-01-21 12:58:46 +01:00
|
|
|
from cgi import escape
|
2012-02-21 13:17:42 +01:00
|
|
|
|
2015-05-26 18:21:30 +02:00
|
|
|
from django.contrib.auth import get_user_model
|
2013-09-25 10:01:01 +02:00
|
|
|
from django.utils.translation import ugettext as _
|
|
|
|
from django.utils.translation import ugettext_lazy
|
|
|
|
from reportlab.platypus import Paragraph
|
2012-02-20 17:46:45 +01:00
|
|
|
|
2015-05-26 18:21:30 +02:00
|
|
|
from openslides.utils.exceptions import OpenSlidesError
|
2013-09-25 10:01:01 +02:00
|
|
|
from openslides.utils.pdf import stylesheet
|
2015-05-26 18:21:30 +02:00
|
|
|
from openslides.utils.rest_api import (
|
|
|
|
ModelViewSet,
|
|
|
|
Response,
|
|
|
|
ValidationError,
|
|
|
|
detail_route,
|
|
|
|
list_route,
|
|
|
|
)
|
2015-06-16 10:37:23 +02:00
|
|
|
from openslides.utils.views import PDFView
|
2014-03-27 20:30:15 +01:00
|
|
|
|
2015-05-26 18:21:30 +02:00
|
|
|
from .models import Item, Speaker
|
2015-01-06 00:14:49 +01:00
|
|
|
from .serializers import ItemSerializer
|
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.
|
|
|
|
"""
|
2015-03-26 05:36:10 +01:00
|
|
|
required_permission = 'agenda.can_see'
|
2012-07-23 12:57:47 +02:00
|
|
|
filename = ugettext_lazy('Agenda')
|
|
|
|
document_title = ugettext_lazy('Agenda')
|
2012-02-21 13:17:42 +01:00
|
|
|
|
|
|
|
def append_to_pdf(self, story):
|
2015-06-25 09:53:55 +02:00
|
|
|
tree = Item.objects.get_tree(only_agenda_items=True, include_content=True)
|
|
|
|
|
|
|
|
def walk_tree(tree, ancestors=0):
|
|
|
|
"""
|
|
|
|
Generator that yields a two-element-tuple. The first element is an
|
|
|
|
agenda-item and the second a number for steps to the root element.
|
|
|
|
"""
|
|
|
|
for element in tree:
|
|
|
|
yield element['item'], ancestors
|
|
|
|
yield from walk_tree(element['children'], ancestors + 1)
|
|
|
|
|
|
|
|
for item, ancestors in walk_tree(tree):
|
2012-02-21 13:17:42 +01:00
|
|
|
if ancestors:
|
2015-06-25 09:53:55 +02:00
|
|
|
space = " " * 6 * ancestors
|
2012-11-24 14:01:21 +01:00
|
|
|
story.append(Paragraph(
|
2015-01-21 12:58:46 +01:00
|
|
|
"%s%s" % (space, escape(item.get_title())),
|
2012-07-04 12:50:33 +02:00
|
|
|
stylesheet['Subitem']))
|
2012-02-21 13:17:42 +01:00
|
|
|
else:
|
2015-01-21 12:58:46 +01:00
|
|
|
story.append(Paragraph(escape(item.get_title()), stylesheet['Item']))
|
2012-03-16 14:31:59 +01:00
|
|
|
|
2013-02-16 10:41:22 +01:00
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class ItemViewSet(ModelViewSet):
|
2015-01-06 00:14:49 +01:00
|
|
|
"""
|
2015-01-24 16:35:50 +01:00
|
|
|
API endpoint to list, retrieve, create, update and destroy agenda items.
|
2015-01-06 00:14:49 +01:00
|
|
|
"""
|
2015-02-12 18:48:14 +01:00
|
|
|
queryset = Item.objects.all()
|
2015-01-06 00:14:49 +01:00
|
|
|
serializer_class = ItemSerializer
|
|
|
|
|
|
|
|
def check_permissions(self, request):
|
|
|
|
"""
|
|
|
|
Calls self.permission_denied() if the requesting user has not the
|
2015-01-24 16:35:50 +01:00
|
|
|
permission to see the agenda and in case of create, update or destroy
|
|
|
|
requests the permission to manage the agenda and to see organizational
|
|
|
|
items.
|
2015-01-06 00:14:49 +01:00
|
|
|
"""
|
2015-03-26 05:36:10 +01:00
|
|
|
if (not request.user.has_perm('agenda.can_see') or
|
2015-01-17 14:25:05 +01:00
|
|
|
(self.action in ('create', 'update', 'destroy') and not
|
2015-03-26 05:36:10 +01:00
|
|
|
(request.user.has_perm('agenda.can_manage') and
|
2015-01-17 14:25:05 +01:00
|
|
|
request.user.has_perm('agenda.can_see_orga_items')))):
|
2015-01-06 00:14:49 +01:00
|
|
|
self.permission_denied(request)
|
|
|
|
|
|
|
|
def check_object_permissions(self, request, obj):
|
|
|
|
"""
|
|
|
|
Checks if the requesting user has permission to see also an
|
|
|
|
organizational item if it is one.
|
|
|
|
"""
|
|
|
|
if obj.type == obj.ORGANIZATIONAL_ITEM and not request.user.has_perm('agenda.can_see_orga_items'):
|
|
|
|
self.permission_denied(request)
|
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
"""
|
2015-01-24 16:35:50 +01:00
|
|
|
Filters organizational items if the user has no permission to see them.
|
2015-01-06 00:14:49 +01:00
|
|
|
"""
|
2015-02-12 18:48:14 +01:00
|
|
|
queryset = super().get_queryset()
|
2015-01-17 14:25:05 +01:00
|
|
|
if not self.request.user.has_perm('agenda.can_see_orga_items'):
|
2015-01-06 00:14:49 +01:00
|
|
|
queryset = queryset.exclude(type__exact=Item.ORGANIZATIONAL_ITEM)
|
|
|
|
return queryset
|
2015-03-29 14:42:27 +02:00
|
|
|
|
2015-05-26 18:21:30 +02:00
|
|
|
@detail_route(methods=['POST', 'DELETE'])
|
|
|
|
def manage_speaker(self, request, pk=None):
|
|
|
|
"""
|
|
|
|
Special view endpoint to add users to the list of speakers or remove
|
|
|
|
them. Send POST {'user': <user_id>} to add a new speaker. Omit
|
|
|
|
data to add yourself. Send DELETE {'speaker': <speaker_id>} to remove
|
|
|
|
someone from the list of speakers. Omit data to remove yourself.
|
|
|
|
|
|
|
|
Checks also whether the requesting user can do this. He needs at
|
|
|
|
least the permissions 'agenda.can_see' (see
|
|
|
|
self.check_permission()). In case of adding himself the permission
|
|
|
|
'agenda.can_be_speaker' is required. In case of adding someone else
|
|
|
|
the permission 'agenda.can_manage' is required. In case of removing
|
|
|
|
someone else 'agenda.can_manage' is required. In case of removing
|
|
|
|
himself no other permission is required.
|
|
|
|
"""
|
|
|
|
# Retrieve item.
|
|
|
|
item = self.get_object()
|
|
|
|
|
|
|
|
if request.method == 'POST':
|
|
|
|
# Retrieve user_id
|
|
|
|
user_id = request.data.get('user')
|
|
|
|
|
|
|
|
# Check permissions and other conditions. Get user instance.
|
|
|
|
if user_id is None:
|
|
|
|
# Add oneself
|
|
|
|
if not self.request.user.has_perm('agenda.can_be_speaker'):
|
|
|
|
self.permission_denied(request)
|
|
|
|
if item.speaker_list_closed:
|
|
|
|
raise ValidationError({'detail': _('The list of speakers is closed.')})
|
|
|
|
user = self.request.user
|
|
|
|
else:
|
|
|
|
# Add someone else.
|
|
|
|
if not self.request.user.has_perm('agenda.can_manage'):
|
|
|
|
self.permission_denied(request)
|
|
|
|
try:
|
|
|
|
user = get_user_model().objects.get(pk=int(user_id))
|
|
|
|
except (ValueError, get_user_model().DoesNotExist):
|
|
|
|
raise ValidationError({'detail': _('User does not exist.')})
|
|
|
|
|
|
|
|
# Try to add the user. This ensurse that a user is not twice in the
|
|
|
|
# list of coming speakers.
|
|
|
|
try:
|
|
|
|
Speaker.objects.add(user, item)
|
|
|
|
except OpenSlidesError as e:
|
|
|
|
raise ValidationError({'detail': e})
|
2015-05-27 15:42:32 +02:00
|
|
|
message = _('User %s was successfully added to the list of speakers.') % user
|
2015-05-26 18:21:30 +02:00
|
|
|
|
|
|
|
else:
|
|
|
|
# request.method == 'DELETE'
|
|
|
|
# Retrieve speaker_id
|
|
|
|
speaker_id = request.data.get('speaker')
|
|
|
|
|
|
|
|
# Check permissions and other conditions. Get speaker instance.
|
|
|
|
if speaker_id is None:
|
|
|
|
# Remove oneself
|
|
|
|
queryset = Speaker.objects.filter(
|
|
|
|
item=item, user=self.request.user).exclude(weight=None)
|
|
|
|
try:
|
|
|
|
# We assume that there aren't multiple entries because this
|
|
|
|
# is forbidden by the Manager's add method. We assume that
|
|
|
|
# there is only one speaker instance or none.
|
|
|
|
speaker = queryset.get()
|
|
|
|
except Speaker.DoesNotExist:
|
|
|
|
raise ValidationError({'detail': _('You are not on the list of speakers.')})
|
|
|
|
else:
|
|
|
|
# Remove someone else.
|
|
|
|
if not self.request.user.has_perm('agenda.can_manage'):
|
|
|
|
self.permission_denied(request)
|
|
|
|
try:
|
2015-05-27 15:42:32 +02:00
|
|
|
speaker = Speaker.objects.get(pk=int(speaker_id))
|
|
|
|
except (ValueError, Speaker.DoesNotExist):
|
2015-05-26 18:21:30 +02:00
|
|
|
raise ValidationError({'detail': _('Speaker does not exist.')})
|
|
|
|
|
|
|
|
# Delete the speaker.
|
|
|
|
speaker.delete()
|
2015-05-27 15:42:32 +02:00
|
|
|
message = _('Speaker %s was successfully removed from the list of speakers.') % speaker
|
|
|
|
|
|
|
|
# Initiate response.
|
|
|
|
return Response({'detail': message})
|
|
|
|
|
|
|
|
@detail_route(methods=['PUT', 'DELETE'])
|
|
|
|
def speak(self, request, pk=None):
|
|
|
|
"""
|
|
|
|
Special view endpoint to begin and end speach of speakers. Send PUT
|
|
|
|
{'speaker': <speaker_id>} to begin speach. Omit data to begin speach of
|
|
|
|
the next speaker. Send DELETE to end speach of current speaker.
|
|
|
|
|
|
|
|
Checks also whether the requesting user can do this. He needs at
|
|
|
|
least the permissions 'agenda.can_see' (see
|
|
|
|
self.check_permission()). Also the permission 'agenda.can_manage'
|
|
|
|
is required.
|
|
|
|
"""
|
|
|
|
# Check permission.
|
|
|
|
if not self.request.user.has_perm('agenda.can_manage'):
|
|
|
|
self.permission_denied(request)
|
|
|
|
|
|
|
|
# Retrieve item.
|
|
|
|
item = self.get_object()
|
|
|
|
|
|
|
|
if request.method == 'PUT':
|
|
|
|
# Retrieve speaker_id
|
|
|
|
speaker_id = request.data.get('speaker')
|
|
|
|
if speaker_id is None:
|
|
|
|
speaker = item.get_next_speaker()
|
|
|
|
if speaker is None:
|
|
|
|
raise ValidationError({'detail': _('The list of speakers is empty.')})
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
speaker = Speaker.objects.get(pk=int(speaker_id))
|
|
|
|
except (ValueError, Speaker.DoesNotExist):
|
|
|
|
raise ValidationError({'detail': _('Speaker does not exist.')})
|
|
|
|
speaker.begin_speach()
|
|
|
|
message = _('User is now speaking.')
|
|
|
|
|
|
|
|
else:
|
|
|
|
# request.method == 'DELETE'
|
|
|
|
try:
|
|
|
|
# We assume that there aren't multiple entries because this
|
|
|
|
# is forbidden by the Model's begin_speach method. We assume that
|
|
|
|
# there is only one speaker instance or none.
|
|
|
|
current_speaker = Speaker.objects.filter(item=item, end_time=None).exclude(begin_time=None).get()
|
|
|
|
except Speaker.DoesNotExist:
|
|
|
|
raise ValidationError(
|
|
|
|
{'detail': _('There is no one speaking at the moment according to %(item)s.') % {'item': item}})
|
|
|
|
current_speaker.end_speach()
|
|
|
|
message = _('The speach is finished now.')
|
2015-05-26 18:21:30 +02:00
|
|
|
|
|
|
|
# Initiate response.
|
|
|
|
return Response({'detail': message})
|
|
|
|
|
2015-03-29 14:42:27 +02:00
|
|
|
@list_route(methods=['get', 'put'])
|
|
|
|
def tree(self, request):
|
|
|
|
"""
|
|
|
|
Returns or sets the agenda tree.
|
|
|
|
"""
|
|
|
|
if request.method == 'PUT':
|
|
|
|
if not (request.user.has_perm('agenda.can_manage') and
|
|
|
|
request.user.has_perm('agenda.can_see_orga_items')):
|
|
|
|
self.permission_denied(request)
|
2015-06-25 09:53:55 +02:00
|
|
|
try:
|
|
|
|
Item.objects.set_tree(request.data['tree'])
|
|
|
|
except ValueError as error:
|
|
|
|
return Response({'detail': str(error)}, status=400)
|
|
|
|
else:
|
|
|
|
return Response({'detail': 'Agenda tree successfully updated.'})
|
|
|
|
return Response(Item.objects.get_tree())
|