Merge pull request #1602 from normanjaeckel/MotionPoll
Added views to create, update and delete MotionPoll objects.
This commit is contained in:
commit
ec50b6e67f
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user