Exemple #1
0
    def post(self, request):

        logging_dict = {
            'client_ip': get_client_ip(request),
            'user': request.user,
            'body': request.body[:1024],
            'election': '-1',
        }

        serialized_data = AddVoteSerializer(data=request.body)

        if serialized_data.is_valid():
            election = self._get_next_election()

            if not election:
                logger.error('User has no valid election left',
                             extra=logging_dict)
                messages.add_message(
                    request, messages.ERROR,
                    'You\'ve no active election. This incident is logged',
                    AlertTags.DANGER)
                return self.get(request)

            logging_dict['election'] = election.id

            votes_for_this_ip = None

            if election.votes_per_ip > 0:
                votes_for_this_ip = election.vote_ips.filter(
                    ip=logging_dict['client_ip']).first()
                if votes_for_this_ip:
                    if votes_for_this_ip.votes >= election.votes_per_ip:
                        logger.error('User is voting for extra votes',
                                     extra=logging_dict)
                        messages.add_message(
                            request, messages.ERROR,
                            'Only {} vote(s) are allowed per IP'.format(
                                election.votes_per_ip), AlertTags.DANGER)
                        request.method = 'POST'
                        return VoterLogoutView.as_view()(request)

            # Validate is valid voter
            voters = election.voter
            voter = voters[0]
            if len(voters) != 1:
                logger.error('User is not a valid voter', extra=logging_dict)
                messages.add_message(request, messages.ERROR,
                                     'You\'re not a voter.', AlertTags.DANGER)
                return self.get(request)

            # Validate key
            if election.is_key_required:
                key = serialized_data.validated_data['key']
                if not key or key.upper() != voter.key.upper():
                    logger.error('User has entered invalid key',
                                 extra=logging_dict)
                    messages.add_message(
                        request, messages.ERROR,
                        'Invalid Key. This incident is logged',
                        AlertTags.DANGER)
                    return self.get(request)

            # Validate votes
            votes = serialized_data.validated_data['votes']
            keys = dict()
            for key, value in votes.items():
                keys[key] = (False, value)

            # Checks that there is a vote for all candidate in election that are visible to voter
            # Like it checks for posts for which voter should be allowed to vote (UG/PG)
            # It also checks if number of non-neutral votes for a post are less then total posts.
            for post in election.posts.all():
                non_neutral_nota_votes = 0

                candidate_count = len(post.human_candidates)

                post_processed = False

                for candidate in post.auto_candidates:
                    if candidate.id in keys:
                        if post_processed:
                            logger.error(
                                'Multiple entries for non auto candidates',
                                extra=logging_dict)
                            messages.add_message(
                                request, messages.ERROR,
                                'Found invalid data. Attempt is logged',
                                AlertTags.DANGER)
                            return self.get(request)

                        keys[candidate.id] = (True, keys[candidate.id][1])

                        # Checking if NO is voted for neutral and NOTA
                        if keys[candidate.id][1] == VoteTypes.NO:
                            logger.log(
                                'User voted for NO for auto accounts. User is stupid',
                                extra=logging_dict)
                            messages.add_message(
                                request, messages.ERROR,
                                'Found invalid data. Attempt is logged',
                                AlertTags.DANGER)
                            return self.get(request)

                        post_processed = True

                for candidate in post.human_candidates:
                    if candidate.id in keys:
                        if post_processed:
                            logger.error(
                                'Entries for normal candidates is present when with auto candidates',
                                extra=logging_dict)

                            messages.add_message(
                                request, messages.ERROR,
                                'Found invalid data. Attempt is logged',
                                AlertTags.DANGER)
                            return self.get(request)

                        keys[candidate.id] = (True, keys[candidate.id][1])

                        if keys[candidate.id][1] == VoteTypes.NO:
                            """
                            Checking if NO vote is casted for a post where candidates > post
                            """
                            if candidate_count > post.number:
                                logger.error(
                                    'Voted NO for a post where candidates > post',
                                    extra=logging_dict)
                                messages.add_message(
                                    request, messages.ERROR,
                                    'Found invalid data. Attempt is logged',
                                    AlertTags.DANGER)
                                return self.get(request)

                        non_neutral_nota_votes += 1

                if non_neutral_nota_votes > post.number:
                    logger.error(
                        'Number of non-neutral votes are greater than number of posts',
                        extra=logging_dict)
                    messages.add_message(
                        request, messages.ERROR,
                        'Found invalid data. Attempt is logged',
                        AlertTags.DANGER)
                    return self.get(request)

            # Check if there is an entry present which are not pk for candidates in election available
            # To person
            for key, value in keys.items():
                if not value[0]:
                    logger.error(
                        'User has entered a candidate id %s which is not a valid value',
                        key,
                        extra=logging_dict)
                    messages.add_message(
                        request, messages.ERROR,
                        'Found corrupted data. Incident will be reported',
                        AlertTags.DANGER)
                    return self.get(request)

            # create votes

            with transaction.atomic():
                # Create Session. Each vote will be associated with a session
                vote_session = VoteSession.objects.create(election=election)

                if not votes_for_this_ip:
                    votes_for_this_ip = VoteIPMap(
                        election=election,
                        votes=1,
                        ip=logging_dict['client_ip'],
                    )
                else:
                    votes_for_this_ip.votes += 1

                votes_for_this_ip.save()

                vote_list = []
                for key, value in keys.items():
                    vote = Vote(candidate_id=key, session=vote_session)
                    vote.vote = value[1]
                    vote_list.append(vote)

                # Add votes to server
                Vote.objects.bulk_create(vote_list)
                voter.voted = True
                voter.save()

            messages.add_message(request, messages.INFO,
                                 'Your vote has been recorded',
                                 AlertTags.SUCCESS)
            return self.get(request, new_session=True)
        else:
            logger.error('Request data is invalidated by serializer',
                         extra=logging_dict)
            messages.add_message(
                request, messages.INFO,
                'Received corrupted data. Incident is recorded',
                AlertTags.DANGER)
            return self.get(request)