removed race condition & cleanup
This commit is contained in:
parent
7882ea1a25
commit
b7b8620153
@ -42,6 +42,6 @@ export class User extends BaseDecimalModel<User> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getDecimalFields(): string[] {
|
protected getDecimalFields(): string[] {
|
||||||
return ["vote_weight"];
|
return ['vote_weight'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ from decimal import Decimal
|
|||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.utils import IntegrityError
|
|
||||||
|
|
||||||
from openslides.poll.views import BaseOptionViewSet, BasePollViewSet, BaseVoteViewSet
|
from openslides.poll.views import BaseOptionViewSet, BasePollViewSet, BaseVoteViewSet
|
||||||
from openslides.utils.auth import has_perm
|
from openslides.utils.auth import has_perm
|
||||||
@ -526,17 +525,11 @@ class AssignmentPollViewSet(BasePollViewSet):
|
|||||||
|
|
||||||
poll.voted.add(check_user)
|
poll.voted.add(check_user)
|
||||||
|
|
||||||
|
def add_user_to_voted_array(self, user, poll):
|
||||||
|
VotedModel = AssignmentPoll.voted.through
|
||||||
|
VotedModel.objects.create(assignmentpoll=poll, user=user)
|
||||||
|
|
||||||
def handle_named_vote(self, data, poll, user):
|
def handle_named_vote(self, data, poll, user):
|
||||||
try:
|
|
||||||
with transaction.atomic():
|
|
||||||
return self.try_handle_named_vote(data, poll, user)
|
|
||||||
except IntegrityError:
|
|
||||||
raise ValidationError({"detail": "You have already voted"})
|
|
||||||
|
|
||||||
def try_handle_named_vote(self, data, poll, user):
|
|
||||||
if user in poll.voted.all():
|
|
||||||
raise ValidationError({"detail": "You have already voted"})
|
|
||||||
|
|
||||||
if poll.pollmethod == AssignmentPoll.POLLMETHOD_VOTES:
|
if poll.pollmethod == AssignmentPoll.POLLMETHOD_VOTES:
|
||||||
self.create_votes_type_votes(data, poll, user)
|
self.create_votes_type_votes(data, poll, user)
|
||||||
elif poll.pollmethod in (
|
elif poll.pollmethod in (
|
||||||
@ -546,16 +539,6 @@ class AssignmentPollViewSet(BasePollViewSet):
|
|||||||
self.create_votes_type_named_pseudoanonymous(data, poll, user, user)
|
self.create_votes_type_named_pseudoanonymous(data, poll, user, user)
|
||||||
|
|
||||||
def handle_pseudoanonymous_vote(self, data, poll, user):
|
def handle_pseudoanonymous_vote(self, data, poll, user):
|
||||||
try:
|
|
||||||
with transaction.atomic():
|
|
||||||
return self.try_handle_pseudoanonymous_vote(data, poll, user)
|
|
||||||
except IntegrityError:
|
|
||||||
raise ValidationError({"detail": "You have already voted"})
|
|
||||||
|
|
||||||
def try_handle_pseudoanonymous_vote(self, data, poll, user):
|
|
||||||
if user in poll.voted.all():
|
|
||||||
raise ValidationError({"detail": "You have already voted"})
|
|
||||||
|
|
||||||
if poll.pollmethod == AssignmentPoll.POLLMETHOD_VOTES:
|
if poll.pollmethod == AssignmentPoll.POLLMETHOD_VOTES:
|
||||||
self.create_votes_type_votes(data, poll, user)
|
self.create_votes_type_votes(data, poll, user)
|
||||||
|
|
||||||
|
@ -1176,6 +1176,10 @@ class MotionPollViewSet(BasePollViewSet):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def add_user_to_voted_array(self, user, poll):
|
||||||
|
VotedModel = MotionPoll.voted.through
|
||||||
|
VotedModel.objects.create(motionpoll=poll, user=user)
|
||||||
|
|
||||||
def handle_analog_vote(self, data, poll, user):
|
def handle_analog_vote(self, data, poll, user):
|
||||||
option = poll.options.get()
|
option = poll.options.get()
|
||||||
vote, _ = MotionVote.objects.get_or_create(option=option, value="Y")
|
vote, _ = MotionVote.objects.get_or_create(option=option, value="Y")
|
||||||
@ -1223,21 +1227,11 @@ class MotionPollViewSet(BasePollViewSet):
|
|||||||
raise ValidationError("Data must be Y or N")
|
raise ValidationError("Data must be Y or N")
|
||||||
|
|
||||||
def handle_named_vote(self, data, poll, user):
|
def handle_named_vote(self, data, poll, user):
|
||||||
if user in poll.voted.all():
|
|
||||||
raise ValidationError({"detail": "You have already voted"})
|
|
||||||
poll.voted.add(user)
|
|
||||||
poll.save()
|
|
||||||
|
|
||||||
option = poll.options.get()
|
option = poll.options.get()
|
||||||
vote = MotionVote.objects.create(user=user, option=option)
|
vote = MotionVote.objects.create(user=user, option=option)
|
||||||
self.handle_named_and_pseudoanonymous_vote(data, user, poll, option, vote)
|
self.handle_named_and_pseudoanonymous_vote(data, user, poll, option, vote)
|
||||||
|
|
||||||
def handle_pseudoanonymous_vote(self, data, poll, user):
|
def handle_pseudoanonymous_vote(self, data, poll, user):
|
||||||
if user in poll.voted.all():
|
|
||||||
raise ValidationError({"detail": "You have already voted"})
|
|
||||||
poll.voted.add(user)
|
|
||||||
poll.save()
|
|
||||||
|
|
||||||
option = poll.options.get()
|
option = poll.options.get()
|
||||||
vote = MotionVote.objects.create(user=None, option=option)
|
vote = MotionVote.objects.create(user=None, option=option)
|
||||||
self.handle_named_and_pseudoanonymous_vote(data, user, poll, option, vote)
|
self.handle_named_and_pseudoanonymous_vote(data, user, poll, option, vote)
|
||||||
|
@ -2,6 +2,7 @@ from textwrap import dedent
|
|||||||
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.db.utils import IntegrityError
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
from openslides.utils.auth import in_some_groups
|
from openslides.utils.auth import in_some_groups
|
||||||
@ -184,6 +185,7 @@ class BasePollViewSet(ModelViewSet):
|
|||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
@detail_route(methods=["POST"])
|
@detail_route(methods=["POST"])
|
||||||
|
@transaction.atomic
|
||||||
def vote(self, request, pk):
|
def vote(self, request, pk):
|
||||||
"""
|
"""
|
||||||
For motion polls: Just "Y", "N" or "A" (if pollmethod is "YNA")
|
For motion polls: Just "Y", "N" or "A" (if pollmethod is "YNA")
|
||||||
@ -219,10 +221,10 @@ class BasePollViewSet(ModelViewSet):
|
|||||||
|
|
||||||
def assert_can_vote(self, poll, request):
|
def assert_can_vote(self, poll, request):
|
||||||
"""
|
"""
|
||||||
Raises a permission denied, if the user is not allowed to vote.
|
Raises a permission denied, if the user is not allowed to vote (or has already voted).
|
||||||
|
Adds the user to the voted array, so this needs to be reverted on error!
|
||||||
Analog: has to have manage permissions
|
Analog: has to have manage permissions
|
||||||
Named & Pseudoanonymous: has to be in a poll group and present
|
Named & Pseudoanonymous: has to be in a poll group and present
|
||||||
Note: For pseudoanonymous it is *not* tested, if the user has already voted!
|
|
||||||
"""
|
"""
|
||||||
if poll.type == BasePoll.TYPE_ANALOG:
|
if poll.type == BasePoll.TYPE_ANALOG:
|
||||||
if not self.has_manage_permissions():
|
if not self.has_manage_permissions():
|
||||||
@ -231,11 +233,17 @@ class BasePollViewSet(ModelViewSet):
|
|||||||
if poll.state != BasePoll.STATE_STARTED:
|
if poll.state != BasePoll.STATE_STARTED:
|
||||||
raise ValidationError("You can only vote on a started poll.")
|
raise ValidationError("You can only vote on a started poll.")
|
||||||
if not request.user.is_present or not in_some_groups(
|
if not request.user.is_present or not in_some_groups(
|
||||||
request.user.id,
|
request.user.id,
|
||||||
list(poll.groups.values_list("pk", flat=True)),
|
list(poll.groups.values_list("pk", flat=True)),
|
||||||
exact=True,
|
exact=True,
|
||||||
):
|
):
|
||||||
self.permission_denied(request)
|
self.permission_denied(request)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.add_user_to_voted_array(request.user, poll)
|
||||||
|
inform_changed_data(poll)
|
||||||
|
except IntegrityError:
|
||||||
|
raise ValidationError({"detail": "You have already voted"})
|
||||||
|
|
||||||
def parse_vote_value(self, obj, key):
|
def parse_vote_value(self, obj, key):
|
||||||
""" Raises a ValidationError on incorrect values, including None """
|
""" Raises a ValidationError on incorrect values, including None """
|
||||||
@ -257,6 +265,13 @@ class BasePollViewSet(ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def add_user_to_voted_array(self, user, poll):
|
||||||
|
"""
|
||||||
|
To be implemented by subclass. Adds the given user to the voted array of the given poll.
|
||||||
|
Throws an IntegrityError if the user already exists in the array
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def validate_vote_data(self, data, poll, user):
|
def validate_vote_data(self, data, poll, user):
|
||||||
"""
|
"""
|
||||||
To be implemented by subclass. Validates the data according to poll type and method and fields by validated versions.
|
To be implemented by subclass. Validates the data according to poll type and method and fields by validated versions.
|
||||||
|
Loading…
Reference in New Issue
Block a user