OpenSlides/openslides/poll/views.py
jsangmeister 5fa8341614 added testing for named and pseudoanonymous assignment voting
added queries count tests for assignment and motion polls and votes
2020-03-17 07:24:35 +01:00

164 lines
5.2 KiB
Python

from django.contrib.auth.models import AnonymousUser
from openslides.utils.auth import in_some_groups
from openslides.utils.autoupdate import inform_changed_data
from openslides.utils.rest_api import (
DecimalField,
GenericViewSet,
ListModelMixin,
ModelViewSet,
Response,
RetrieveModelMixin,
ValidationError,
detail_route,
)
from .models import BasePoll
class BasePollViewSet(ModelViewSet):
def check_view_permissions(self):
"""
the vote view is checked seperately. For all other views manage permissions
are required.
"""
if self.action == "vote":
return True
else:
return self.has_manage_permissions()
def perform_create(self, serializer):
poll = serializer.save()
poll.create_options()
def update(self, *args, **kwargs):
"""
Customized view endpoint to update a motion poll.
"""
poll = self.get_object()
if poll.state != BasePoll.STATE_CREATED:
raise ValidationError(
{"detail": "You can just edit a poll if it was not started."}
)
return super().update(*args, **kwargs)
@detail_route(methods=["POST"])
def start(self, request, pk):
poll = self.get_object()
if poll.state != BasePoll.STATE_CREATED:
raise ValidationError({"detail": "Wrong poll state"})
poll.state = BasePoll.STATE_STARTED
poll.save()
inform_changed_data(poll.get_votes())
return Response()
@detail_route(methods=["POST"])
def stop(self, request, pk):
poll = self.get_object()
if poll.state != BasePoll.STATE_STARTED:
raise ValidationError({"detail": "Wrong poll state"})
poll.state = BasePoll.STATE_FINISHED
poll.save()
inform_changed_data(poll.get_votes())
return Response()
@detail_route(methods=["POST"])
def publish(self, request, pk):
poll = self.get_object()
if poll.state != BasePoll.STATE_FINISHED:
raise ValidationError({"detail": "Wrong poll state"})
poll.state = BasePoll.STATE_PUBLISHED
poll.save()
inform_changed_data(poll.get_votes())
return Response()
@detail_route(methods=["POST"])
def pseudoanonymize(self, request, pk):
poll = self.get_object()
if poll.state not in (BasePoll.STATE_FINISHED, BasePoll.STATE_PUBLISHED):
raise ValidationError(
{"detail": "Pseudoanonmizing can only be done after a finished poll"}
)
if poll.type != BasePoll.TYPE_NAMED:
raise ValidationError(
{"detail": "You can just pseudoanonymize named polls"}
)
poll.pseudoanonymize()
return Response()
@detail_route(methods=["POST"])
def reset(self, request, pk):
poll = self.get_object()
if poll.state not in (BasePoll.STATE_FINISHED, BasePoll.STATE_PUBLISHED):
raise ValidationError(
{"detail": "You can only reset this poll after it is finished"}
)
poll.reset()
return Response()
@detail_route(methods=["POST"])
def vote(self, request, pk):
"""
For motion polls: Just "Y", "N" or "A" (if pollmethod is "YNA")
"""
poll = self.get_object()
if poll.state != BasePoll.STATE_STARTED:
raise ValidationError({"detail": "You cannot vote for an unstarted poll"})
if isinstance(request.user, AnonymousUser):
self.permission_denied(request)
# check permissions based on poll type and handle requests
if poll.type == BasePoll.TYPE_ANALOG:
if not self.has_manage_permissions():
self.permission_denied(request)
self.handle_analog_vote(request.data, poll, request.user)
# special: change the poll state to finished.
poll.state = BasePoll.STATE_FINISHED
poll.save()
elif poll.type == BasePoll.TYPE_NAMED:
self.assert_can_vote(poll, request)
self.handle_named_vote(request.data, poll, request.user)
poll.voted.add(request.user)
elif poll.type == BasePoll.TYPE_PSEUDOANONYMOUS:
self.assert_can_vote(poll, request)
if request.user in poll.voted.all():
self.permission_denied(request)
self.handle_pseudoanonymous_vote(request.data, poll)
poll.voted.add(request.user)
inform_changed_data(poll) # needed for the changed voted relation
return Response()
def assert_can_vote(self, poll, request):
"""
Raises a permission denied, if the user is not in a poll group
and present
"""
if not request.user.is_present or not in_some_groups(
request.user.id, poll.groups.all(), exact=True
):
self.permission_denied(request)
def parse_decimal_value(self, value, min_value=None):
""" Raises a ValidationError on incorrect values """
field = DecimalField(min_value=min_value, max_digits=15, decimal_places=6)
return field.to_internal_value(value)
class BaseVoteViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
pass