<commit_before>from django.db import transaction
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext as _
from rest_framework import mixins
from rest_framework import status
from rest_framework import viewsets
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response

from adhocracy4.api.permissions import ViewSetRulesPermission

from .models import Answer
from .models import Choice
from .models import OtherVote
from .models import Poll
from .models import Question
from .models import Vote
from .serializers import PollSerializer
from .serializers import QuestionSerializer
from .validators import choice_belongs_to_question


class PollViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
                  viewsets.GenericViewSet):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer
    permission_classes = (ViewSetRulesPermission,)

    def get_permission_object(self):
        poll = self.get_object()
        return poll.module


class VoteViewSet(viewsets.ViewSet):

    permission_classes = (ViewSetRulesPermission,)

    def create(self, request, *args, **kwargs):
        choices, other_choice_answer, open_answer = self.get_data(request)

        if not self.question.is_open:
            self.validate_choices(choices)

        with transaction.atomic():
            if self.question.is_open:
                self.clear_open_answer()
                if open_answer:
                    Answer.objects.create(
                        question=self.question,
                        answer=open_answer,
                        creator=self.request.user
                    )
            else:
                self.clear_current_choices()
                for choice in choices:
                    vote = Vote.objects.create(
                        choice_id=choice.id,
                        creator=self.request.user
                    )
                    if choice.is_other_choice:
                        if other_choice_answer:
                            OtherVote.objects.create(
                                vote=vote,
                                answer=other_choice_answer
                            )
                        else:
                            raise ValidationError({
                                'choice': _('Please specify your answer.')
                            })

        question_serializer = self.get_question_serializer()
        return Response({'question': question_serializer.data},
                        status=status.HTTP_201_CREATED)

    def get_data(self, request):
        try:
            choices = [get_object_or_404(Choice, pk=choice_pk)
                       for choice_pk
                       in request.data['choices']]
        except (ValueError, AttributeError):
            raise ValidationError()

        other_choice_answer = request.data['other_choice_answer']

        open_answer = request.data['open_answer']

        return choices, other_choice_answer, open_answer

    def validate_choices(self, choices):
        question = self.question

        if len(choices) > len(set(choices)):
            raise ValidationError('duplicate choices detected')

        if len(choices) == 0:
            raise ValidationError('empty choices detected')
        elif len(choices) > 1 and not question.multiple_choice:
            raise ValidationError('multiple choice disabled for question')

        for choice in choices:
            choice_belongs_to_question(choice, question.pk)

    def clear_current_choices(self):
        Vote.objects\
            .filter(choice__question_id=self.question.id,
                    creator=self.request.user)\
            .delete()

    def clear_open_answer(self):
        Answer.objects\
            .filter(question_id=self.question.id,
                    creator=self.request.user)\
            .delete()<commit_msg>polls/api/VoteViewSet: catch errors<commit_after>from django.db import transaction
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext as _
from rest_framework import mixins
from rest_framework import status
from rest_framework import viewsets
from rest_framework.exceptions import NotFound
from rest_framework.exceptions import ParseError
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response

from adhocracy4.api.permissions import ViewSetRulesPermission

from .models import Answer
from .models import Choice
from .models import OtherVote
from .models import Poll
from .models import Question
from .models import Vote
from .serializers import PollSerializer
from .serializers import QuestionSerializer
from .validators import choice_belongs_to_question


class PollViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
                  viewsets.GenericViewSet):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer
    permission_classes = (ViewSetRulesPermission,)

    def get_permission_object(self):
        poll = self.get_object()
        return poll.module


class VoteViewSet(viewsets.ViewSet):

    permission_classes = (ViewSetRulesPermission,)

    def create(self, request, *args, **kwargs):
        choices, other_choice_answer, open_answer = self.get_data(request)

        if not self.question.is_open:
            self.validate_choices(choices)

        with transaction.atomic():
            if self.question.is_open:
                self.clear_open_answer()
                if open_answer:
                    Answer.objects.create(
                        question=self.question,
                        answer=open_answer,
                        creator=self.request.user
                    )
            else:
                self.clear_current_choices()
                for choice in choices:
                    vote = Vote.objects.create(
                        choice_id=choice.id,
                        creator=self.request.user
                    )
                    if choice.is_other_choice:
                        if other_choice_answer:
                            OtherVote.objects.create(
                                vote=vote,
                                answer=other_choice_answer
                            )
                        else:
                            raise ValidationError({
                                'choice': _('Please specify your answer.')
                            })

        question_serializer = self.get_question_serializer()
        return Response({'question': question_serializer.data},
                        status=status.HTTP_201_CREATED)

    def get_data(self, request):
        try:
            choices = [get_object_or_404(Choice, pk=choice_pk)
                       for choice_pk
                       in request.data['choices']]
            other_choice_answer = request.data['other_choice_answer']
            open_answer = request.data['open_answer']
        except (ValueError, AttributeError):
            raise ValidationError()
        except KeyError as error:
            raise ParseError(detail=_('Key error for {}').format(str(error)))
        except Http404:
            raise NotFound(detail=_('Choice not found.'))

        return choices, other_choice_answer, open_answer

    def validate_choices(self, choices):
        question = self.question

        if len(choices) > len(set(choices)):
            raise ValidationError(detail=_('Duplicate choices detected.'))

        if len(choices) == 0:
            raise ValidationError(detail=_('Empty choices detected.'))
        elif len(choices) > 1 and not question.multiple_choice:
            raise ValidationError(detail=_('Multiple choice disabled for '
                                           'question.'))

        for choice in choices:
            choice_belongs_to_question(choice, question.pk)

    def clear_current_choices(self):
        Vote.objects\
            .filter(choice__question_id=self.question.id,
                    creator=self.request.user)\
            .delete()

    def clear_open_answer(self):
        Answer.objects\
            .filter(question_id=self.question.id,
                    creator=self.request.user)\
            .delete()
{'fraction_non_alphanumeric': 0.06951935754524752, 'fraction_numerical': 0.003595828838547285, 'mean_word_length': 1.9421720733427363, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '478119', 'n_tokens_mistral': 2101, 'n_tokens_neox': 1987, 'n_words': 470}