Added views to create, update and delete MotionPoll objects.

This commit is contained in:
Norman Jäckel 2015-07-22 15:23:57 +02:00
parent 6b747c8cef
commit a1f1cfed1f
4 changed files with 79 additions and 5 deletions

View File

@ -216,7 +216,7 @@ class AssignmentViewSet(ModelViewSet):
raise ValidationError({'detail': _('Can not create poll because there are no candidates.')}) raise ValidationError({'detail': _('Can not create poll because there are no candidates.')})
with transaction.atomic(): with transaction.atomic():
assignment.create_poll() assignment.create_poll()
return Response({'detail': _(' Poll created successfully.')}) return Response({'detail': _('Poll created successfully.')})
class AssignmentPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet): class AssignmentPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):

View File

@ -18,7 +18,7 @@ class MotionsAppConfig(AppConfig):
from openslides.core.signals import config_signal from openslides.core.signals import config_signal
from openslides.utils.rest_api import router from openslides.utils.rest_api import router
from .signals import create_builtin_workflows, setup_motion_config from .signals import create_builtin_workflows, setup_motion_config
from .views import CategoryViewSet, MotionViewSet, WorkflowViewSet from .views import CategoryViewSet, MotionViewSet, MotionPollViewSet, WorkflowViewSet
# Connect signals. # Connect signals.
config_signal.connect(setup_motion_config, dispatch_uid='setup_motion_config') config_signal.connect(setup_motion_config, dispatch_uid='setup_motion_config')
@ -27,4 +27,5 @@ class MotionsAppConfig(AppConfig):
# Register viewsets. # Register viewsets.
router.register('motions/category', CategoryViewSet) router.register('motions/category', CategoryViewSet)
router.register('motions/motion', MotionViewSet) router.register('motions/motion', MotionViewSet)
router.register('motions/motionpoll', MotionPollViewSet)
router.register('motions/workflow', WorkflowViewSet) router.register('motions/workflow', WorkflowViewSet)

View File

@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _
from openslides.core.config import config from openslides.core.config import config
from openslides.utils.rest_api import ( from openslides.utils.rest_api import (
CharField, CharField,
DictField,
IntegerField, IntegerField,
ModelSerializer, ModelSerializer,
PrimaryKeyRelatedField, PrimaryKeyRelatedField,
@ -107,15 +108,50 @@ class MotionPollSerializer(ModelSerializer):
Serializer for motion.models.MotionPoll objects. Serializer for motion.models.MotionPoll objects.
""" """
motionoption_set = MotionOptionSerializer(many=True, read_only=True) motionoption_set = MotionOptionSerializer(many=True, read_only=True)
votes = DictField(
child=IntegerField(min_value=-2),
write_only=True)
class Meta: class Meta:
model = MotionPoll model = MotionPoll
fields = ( fields = (
'id',
'poll_number', 'poll_number',
'motionoption_set', 'motionoption_set',
'votesvalid', 'votesvalid',
'votesinvalid', 'votesinvalid',
'votescast',) 'votescast',
'votes',)
read_only_fields = ('poll_number',)
@transaction.atomic
def update(self, instance, validated_data):
"""
Customized update method for polls. To update votes use the write
only field 'votes'.
Example data:
"votes": {"Yes": 10, "No": 4, "Abstain": -2}
"""
# Update votes.
votes = validated_data.get('votes')
if votes:
if len(votes) != len(instance.get_vote_values()):
raise ValidationError({
'detail': _('You have to submit data for %d vote values.') % len(instance.get_vote_values())})
for vote_value, vote_weight in votes.items():
if vote_value not in instance.get_vote_values():
raise ValidationError({
'detail': _('Vote value %s is invalid.') % vote_value})
instance.set_vote_objects_with_values(instance.get_options().get(), votes)
# Update remaining writeable fields.
instance.votesvalid = validated_data.get('votesvalid', instance.votesvalid)
instance.votesinvalid = validated_data.get('votesinvalid', instance.votesinvalid)
instance.votescast = validated_data.get('votescast', instance.votescast)
instance.save()
return instance
class MotionVersionSerializer(ModelSerializer): class MotionVersionSerializer(ModelSerializer):

View File

@ -1,3 +1,4 @@
from django.db import transaction
from django.http import Http404 from django.http import Http404
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.text import slugify from django.utils.text import slugify
@ -8,17 +9,22 @@ from rest_framework import status
from openslides.core.config import config from openslides.core.config import config
from openslides.utils.rest_api import ( from openslides.utils.rest_api import (
DestroyModelMixin,
GenericViewSet,
ModelViewSet, ModelViewSet,
Response, Response,
UpdateModelMixin,
ValidationError, ValidationError,
detail_route, detail_route,
) )
from openslides.utils.views import PDFView, SingleObjectMixin from openslides.utils.views import PDFView, SingleObjectMixin
from .exceptions import WorkflowError
from .models import Category, Motion, MotionPoll, MotionVersion, Workflow from .models import Category, Motion, MotionPoll, MotionVersion, Workflow
from .pdf import motion_poll_to_pdf, motion_to_pdf, motions_to_pdf from .pdf import motion_poll_to_pdf, motion_to_pdf, motions_to_pdf
from .serializers import ( from .serializers import (
CategorySerializer, CategorySerializer,
MotionPollSerializer,
MotionSerializer, MotionSerializer,
WorkflowSerializer, WorkflowSerializer,
) )
@ -31,7 +37,8 @@ class MotionViewSet(ModelViewSet):
API endpoint for motions. API endpoint for motions.
There are the following views: metadata, list, retrieve, create, There are the following views: metadata, list, retrieve, create,
partial_update, update, destroy, manage_version, support and set_state. partial_update, update, destroy, manage_version, support, set_state and
create_poll.
""" """
queryset = Motion.objects.all() queryset = Motion.objects.all()
serializer_class = MotionSerializer serializer_class = MotionSerializer
@ -49,7 +56,7 @@ class MotionViewSet(ModelViewSet):
self.request.user.has_perm('motions.can_create') and self.request.user.has_perm('motions.can_create') and
(not config['motions_stop_submitting'] or (not config['motions_stop_submitting'] or
self.request.user.has_perm('motions.can_manage'))) self.request.user.has_perm('motions.can_manage')))
elif self.action in ('destroy', 'manage_version', 'set_state'): elif self.action in ('destroy', 'manage_version', 'set_state', 'create_poll'):
result = (self.request.user.has_perm('motions.can_see') and result = (self.request.user.has_perm('motions.can_see') and
self.request.user.has_perm('motions.can_manage')) self.request.user.has_perm('motions.can_manage'))
elif self.action == 'support': elif self.action == 'support':
@ -231,6 +238,36 @@ class MotionViewSet(ModelViewSet):
person=request.user) person=request.user)
return Response({'detail': message}) return Response({'detail': message})
@detail_route(methods=['post'])
def create_poll(self, request, pk=None):
"""
View to create a poll. It is a POST request without any data.
"""
motion = self.get_object()
try:
with transaction.atomic():
motion.create_poll()
except WorkflowError as e:
raise ValidationError({'detail': e})
return Response({'detail': _('Poll created successfully.')})
class MotionPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):
"""
API endpoint for motion polls.
There are the following views: update and destroy.
"""
queryset = MotionPoll.objects.all()
serializer_class = MotionPollSerializer
def check_view_permissions(self):
"""
Returns True if the user has required permissions.
"""
return (self.request.user.has_perm('motions.can_see') and
self.request.user.has_perm('motions.can_manage'))
class CategoryViewSet(ModelViewSet): class CategoryViewSet(ModelViewSet):
""" """