def election_questions_validator(questions): ''' Validates a list of questions checking the voting method used, etc ''' error = django_forms.ValidationError(_('Invalid questions format')) # we need at least one question if not isinstance(questions, list) or len(questions) < 1: raise error for question in questions: # check type if not isinstance(question, dict): raise error # check it contains the valid elements if not list_contains_all(['a', 'answers', 'max', 'min', 'question', 'randomize_answer_order', 'tally_type', 'layout'], question.keys()): raise error # let the voting system check the rest voting_system = get_voting_system_by_id(question['tally_type']) if not voting_system: raise error voting_system.validate_question(question)
def election_questions_validator(questions): """ Validates a list of questions checking the voting method used, etc """ error = django_forms.ValidationError(_("Invalid questions format")) # we need at least one question if not isinstance(questions, list) or len(questions) < 1: raise error for question in questions: # check type if not isinstance(question, dict): raise error # check it contains the valid elements if not list_contains_all( ["a", "answers", "max", "min", "question", "randomize_answer_order", "tally_type"], question.keys() ): raise error # let the voting system check the rest voting_system = get_voting_system_by_id(question["tally_type"]) if not voting_system: raise error voting_system.validate_question(question)
def election_questions_validator(questions): ''' Validates a list of questions checking the voting method used, etc ''' error = django_forms.ValidationError(_('Invalid questions format')) # we need at least one question if not isinstance(questions, list) or len(questions) < 1: raise error for question in questions: # check type if not isinstance(question, dict): raise error # check it contains the valid elements if not list_contains_all([ 'a', 'answers', 'max', 'min', 'question', 'randomize_answer_order', 'tally_type' ], question.keys()): raise error # let the voting system check the rest voting_system = get_voting_system_by_id(question['tally_type']) if not voting_system: raise error voting_system.validate_question(question)
def __init__(self, request, election, *args, **kwargs): super(VoteForm, self).__init__(*args, **kwargs) self.election = election self.request = request i = 0 for question in election.questions: voting_system = get_voting_system_by_id(question['tally_type']) field = voting_system.get_question_field(election, question) self.fields.insert(0, 'question%d' % i, field) i += 1
def __init__(self, request, election, *args, **kwargs): super(VoteForm, self).__init__(*args, **kwargs) self.election = election self.request = request i = 0 for question in election.questions: voting_system = get_voting_system_by_id(question['tally_type']) field = voting_system.get_question_field(election, question) self.fields.insert(0, 'question%d' % i, field) i += 1
def get_winning_option(self): """ Returns data of the winning option for the first question or throw an exception """ if not self.result: raise Exception("Election not tallied yet") elif len(self.result["counts"]) == 0 or not get_voting_system_by_id(self.result["counts"][0]["tally_type"]): raise Exception("Unknown election result type: %s" % self.result["counts"][0]["tally_type"]) winner = dict(value="", total_count=0.0, total_count_percentage=0.0) for answer in self.result["counts"][0]["answers"]: if answer["value"] == self.result["counts"][0]["winners"][0]: winner = answer return winner
def get_winning_option(self): ''' Returns data of the winning option for the first question or throw an exception ''' if not self.result: raise Exception('Election not tallied yet') elif len(self.result['counts']) == 0 or\ not get_voting_system_by_id(self.result['counts'][0]['tally_type']): raise Exception('Unknown election result type: %s' % self.result['counts'][0]['tally_type']) winner = dict(value='', total_count=0.0, total_count_percentage=0.0) for answer in self.result['counts'][0]['answers']: if answer['value'] == self.result['counts'][0]['winners'][0]: winner = answer return winner
def get_winning_option(self): ''' Returns data of the winning option for the first question or throw an exception ''' if not self.result: raise Exception('Election not tallied yet') elif len(self.result['counts']) == 0 or\ not get_voting_system_by_id(self.result['counts'][0]['tally_type']): raise Exception('Unknown election result type: %s' % self.result['counts'][0]['tally_type']) winner = dict(value='', total_count=0.0, total_count_percentage=0.0) for answer in self.result['counts'][0]['answers']: if answer['value'] == self.result['counts'][0]['winners'][0]: winner = answer return winner
def compute_result(self): ''' Computes the result of the election ''' from agora_site.agora_core.models import CastVote # Query with the direct votes in this election q=self.cast_votes.filter( is_counted=True, invalidated_at_date=None ).values('voter__id').query # Query with the delegated votes self.delegated_votes = CastVote.objects.filter( election=self.agora.delegation_election, is_direct=False, is_counted=True, invalidated_at_date=None # we exclude from this query the people who voted directly so that # you cannot vote twice ).exclude( is_direct=False, voter__id__in=q ) # These are all the people that can vote in this election self.electorate = self.agora.members.all() # These are all the direct votes, even from those who are not elegible # to vote in this election nodes = self.cast_votes.filter(is_direct=True, #is_counted=True, FIXME invalidated_at_date=None) # These are all the delegation votes, i.e. those that point to a delegate #edges = self.agora.delegation_election.cast_votes.filter( #is_direct=False, invalidated_at_date=None) edges = self.delegated_votes # list of saved paths. A path represent a list of users who delegate # into a given vote. # A path has the following format: #{ #user_ids: [id1, id2, ...], #answers: [ question1_plaintext_answer, question2_plaintext_answer, ..], #is_broken_loop: True|False #} # note that the user_ids do NOT include the last user in the chain # also note that is_broken_loop is set to true if either the loop is # closed (infinite) or does not end in a leaf (=node) paths = [] # A dictionary where the number of delegated voted per delegate is # stored. This dict is used only for recording the number of delegated # votes a delegate has. # # The keys are the user_ids of the delegates, and the values are # the number of delegated votes. # Note that because of chains of delegations, the same vote can be # counted multiple times. delegation_counts = dict() def update_delegation_counts(vote): ''' function used to update the delegation counts, for each valid vote. it basically goes deep in the delegation chain, updating the count for each delegate. NOTE: Calling to this function assumes a valid path for the vote, which means for example that the delegation chain is public. ''' # if there is no vote we have nothing to do if not vote: return def increment_delegate(delegate_id): ''' Increments the delegate count or sets it to one if doesn't it exist ''' if delegate_id in delegation_counts: delegation_counts[delegate_id] += 1 else: delegation_counts[delegate_id] = 1 i = 0 while not vote.is_direct: i += 1 next_delegate = vote.get_delegate() if nodes.filter(voter=next_delegate).count() == 1: increment_delegate(next_delegate.id) return elif edges.filter(voter=next_delegate).count() == 1: increment_delegate(next_delegate.id) vote = edges.filter(voter=next_delegate)[0] else: raise Exception('Broken delegation chain') def get_path_for_user(user_id): ''' Given an user id, checks if it's already in any known path, and return it if that path is found. Returns None otherwise. ''' for path in paths: if user_id in path["user_ids"]: return path return None def get_vote_for_voter(voter_id): ''' Given a voter (an User), returns the vote of the vote of this voter on the election. It will be either a proxy or a direct vote ''' if nodes.filter(voter_id=voter_id).count() == 1: return nodes.filter(voter_id=voter_id)[0] elif edges.filter(voter_id=voter_id).count() == 1: return edges.filter(voter_id=voter_id)[0] else: return None if self.election_type not in dict(parse_voting_methods()): raise Exception('do not know how to count this type of voting') voting_systems = [] tallies = [] import copy # result is in the same format as get_result_pretty(). Initialized here result = copy.deepcopy(self.questions) # setup the initial data common to all voting system i = 0 for question in result: tally_type = self.election_type if 'tally_type' in question: tally_type = question['tally_type'] voting_system = get_voting_system_by_id(tally_type) tally = voting_system.create_tally(self, i) voting_systems.append(voting_system) tallies.append(tally) i += 1 question['a'] = "question/result/" + voting_system.get_id() question['winners'] = [] question['total_votes'] = 0 for answer in question['answers']: answer['a'] = "answer/result/" + voting_system.get_id() answer['total_count'] = 0 answer['total_count_percentage'] = 0 # prepare the tally tally.pre_tally(result) num_delegated_votes = 0 def add_vote(user_answers, is_delegated): ''' Given the answers of a vote, update the result ''' for tally in tallies: tally.add_vote(voter_answers=user_answers, result=result, is_delegated=is_delegated) # Here we go! for each voter, we try to find it in the paths, or in # the proxy vote chain, or in the direct votes pool for voter in self.electorate.all(): path_for_user = get_path_for_user(voter.id) # Found the user in a known path if path_for_user and not path_for_user['is_broken_loop']: # found a path to which the user belongs # update delegation counts num_delegated_votes += 1 add_vote(path_for_user['answers'], is_delegated=True) update_delegation_counts(get_vote_for_voter(voter.id)) # found the user in a direct vote elif nodes.filter(voter=voter).count() == 1: vote = nodes.filter(voter=voter)[0] add_vote(vote.data["answers"], is_delegated=False) # found the user in an edge (delegated vote), but not yet in a path elif edges.filter(voter=voter).count() == 1: path = dict( user_ids=[voter.id], answers=[], is_broken_loop=False ) current_edge = edges.filter(voter=voter)[0] loop = True i = 0 while loop: i += 1 delegate = current_edge.get_delegate() path_for_user = get_path_for_user(delegate.id) if delegate.id in path['user_ids']: # wrong path! loop found, vote won't be counted path['is_broken_loop'] = True paths += [path] loop = False elif path_for_user and not path_for_user['is_broken_loop']: # extend the found path and count a new vote path_for_user['user_ids'] += path['user_ids'] # Count the vote num_delegated_votes += 1 add_vote(path_for_user['answers'], is_delegated=True) update_delegation_counts(get_vote_for_voter(voter.id)) loop = False elif nodes.filter(voter=delegate).count() == 1: # The delegate voted directly vote = nodes.filter(voter=delegate)[0] # if the vote of the delegate is not public, then # it doesn't count, we have finished if not vote.is_public: # wrong path! loop found, vote won't be counted path['is_broken_loop'] = True paths += [path] loop = False break # add the path and count the vote path["answers"] = vote.data['answers'] paths += [path] num_delegated_votes += 1 add_vote(vote.data['answers'], is_delegated=True) update_delegation_counts(get_vote_for_voter(voter.id)) loop = False elif edges.filter(voter=delegate).count() == 1: # the delegate also delegated vote = edges.filter(voter=delegate)[0] # if the vote of the delegate is not public, then # it doesn't count, we have finished if not vote.is_public: # wrong path! loop found, vote won't be counted path['is_broken_loop'] = True paths += [path] loop = False break # vote is public, so continue looping path['user_ids'] += [delegate.id] current_edge = vote else: # broken path! we cannot continue path['is_broken_loop'] = True paths += [path] loop = False if not self.extra_data: self.extra_data = dict() # post process the tally for tally in tallies: tally.post_tally(result) self.result = dict( a= "result", counts = result, total_votes = result[0]['total_votes'] + result[0]['dirty_votes'], electorate_count = self.electorate.count(), total_delegated_votes = num_delegated_votes ) tally_log = [] for tally in tallies: tally_log.append(tally.get_log()) self.extra_data['tally_log'] = tally_log def rank_delegate(delegate_count, delegation_counts): if delegate_count == 0: return None count = 0 for key, value in delegation_counts.iteritems(): if delegate_count <= value: count += 1 return count # refresh DelegateElectionCount items from agora_site.agora_core.models.delegateelectioncount import DelegateElectionCount DelegateElectionCount.objects.filter(election=self).delete() for key, value in delegation_counts.iteritems(): dec = DelegateElectionCount(election=self, count=value) dec.rank = rank_delegate(value, delegation_counts) dec.count_percentage = value * 100.0 / self.result['total_votes'] dec.delegate_vote = get_vote_for_voter(int(key)) dec.delegate_id = int(key) dec.save() self.delegated_votes_frozen_at_date = self.voters_frozen_at_date =\ self.result_tallied_at_date = timezone.now() # TODO: update result_hash self.save()
def compute_result(self): ''' Computes the result of the election ''' from agora_site.agora_core.models import CastVote # Query with the direct votes in this election q = self.cast_votes.filter( is_counted=True, invalidated_at_date=None).values('voter__id').query # Query with the delegated votes self.delegated_votes = CastVote.objects.filter( election=self.agora.delegation_election, is_direct=False, is_counted=True, invalidated_at_date=None # we exclude from this query the people who voted directly so that # you cannot vote twice ).exclude(is_direct=False, voter__id__in=q) # These are all the people that can vote in this election self.electorate = self.agora.members.all() # These are all the direct votes, even from those who are not elegible # to vote in this election nodes = self.cast_votes.filter( is_direct=True, #is_counted=True, FIXME invalidated_at_date=None) # These are all the delegation votes, i.e. those that point to a delegate #edges = self.agora.delegation_election.cast_votes.filter( #is_direct=False, invalidated_at_date=None) edges = self.delegated_votes # list of saved paths. A path represent a list of users who delegate # into a given vote. # A path has the following format: #{ #user_ids: [id1, id2, ...], #answers: [ question1_plaintext_answer, question2_plaintext_answer, ..], #is_broken_loop: True|False #} # note that the user_ids do NOT include the last user in the chain # also note that is_broken_loop is set to true if either the loop is # closed (infinite) or does not end in a leaf (=node) paths = [] # A dictionary where the number of delegated voted per delegate is # stored. This dict is used only for recording the number of delegated # votes a delegate has. # # The keys are the user_ids of the delegates, and the values are # the number of delegated votes. # Note that because of chains of delegations, the same vote can be # counted multiple times. delegation_counts = dict() def update_delegation_counts(vote): ''' function used to update the delegation counts, for each valid vote. it basically goes deep in the delegation chain, updating the count for each delegate. NOTE: Calling to this function assumes a valid path for the vote, which means for example that the delegation chain is public. ''' # if there is no vote we have nothing to do if not vote: return def increment_delegate(delegate_id): ''' Increments the delegate count or sets it to one if doesn't it exist ''' if delegate_id in delegation_counts: delegation_counts[delegate_id] += 1 else: delegation_counts[delegate_id] = 1 i = 0 while not vote.is_direct: i += 1 next_delegate = vote.get_delegate() if nodes.filter(voter=next_delegate).count() == 1: increment_delegate(next_delegate.id) return elif edges.filter(voter=next_delegate).count() == 1: increment_delegate(next_delegate.id) vote = edges.filter(voter=next_delegate)[0] else: raise Exception('Broken delegation chain') def get_path_for_user(user_id): ''' Given an user id, checks if it's already in any known path, and return it if that path is found. Returns None otherwise. ''' for path in paths: if user_id in path["user_ids"]: return path return None def get_vote_for_voter(voter_id): ''' Given a voter (an User), returns the vote of the vote of this voter on the election. It will be either a proxy or a direct vote ''' if nodes.filter(voter_id=voter_id).count() == 1: return nodes.filter(voter_id=voter_id)[0] elif edges.filter(voter_id=voter_id).count() == 1: return edges.filter(voter_id=voter_id)[0] else: return None if self.election_type not in dict(parse_voting_methods()): raise Exception('do not know how to count this type of voting') voting_systems = [] tallies = [] import copy # result is in the same format as get_result_pretty(). Initialized here result = copy.deepcopy(self.questions) # setup the initial data common to all voting system i = 0 for question in result: tally_type = self.election_type if 'tally_type' in question: tally_type = question['tally_type'] voting_system = get_voting_system_by_id(tally_type) tally = voting_system.create_tally(self, i) voting_systems.append(voting_system) tallies.append(tally) i += 1 question['a'] = "question/result/" + voting_system.get_id() question['winners'] = [] question['total_votes'] = 0 for answer in question['answers']: answer['a'] = "answer/result/" + voting_system.get_id() answer['total_count'] = 0 answer['total_count_percentage'] = 0 # prepare the tally tally.pre_tally(result) num_delegated_votes = 0 def add_vote(user_answers, is_delegated): ''' Given the answers of a vote, update the result ''' for tally in tallies: tally.add_vote(voter_answers=user_answers, result=result, is_delegated=is_delegated) # Here we go! for each voter, we try to find it in the paths, or in # the proxy vote chain, or in the direct votes pool for voter in self.electorate.all(): path_for_user = get_path_for_user(voter.id) # Found the user in a known path if path_for_user and not path_for_user['is_broken_loop']: # found a path to which the user belongs # update delegation counts num_delegated_votes += 1 add_vote(path_for_user['answers'], is_delegated=True) update_delegation_counts(get_vote_for_voter(voter.id)) # found the user in a direct vote elif nodes.filter(voter=voter).count() == 1: vote = nodes.filter(voter=voter)[0] add_vote(vote.data["answers"], is_delegated=False) # found the user in an edge (delegated vote), but not yet in a path elif edges.filter(voter=voter).count() == 1: path = dict(user_ids=[voter.id], answers=[], is_broken_loop=False) current_edge = edges.filter(voter=voter)[0] loop = True i = 0 while loop: i += 1 delegate = current_edge.get_delegate() path_for_user = get_path_for_user(delegate.id) if delegate.id in path['user_ids']: # wrong path! loop found, vote won't be counted path['is_broken_loop'] = True paths += [path] loop = False elif path_for_user and not path_for_user['is_broken_loop']: # extend the found path and count a new vote path_for_user['user_ids'] += path['user_ids'] # Count the vote num_delegated_votes += 1 add_vote(path_for_user['answers'], is_delegated=True) update_delegation_counts(get_vote_for_voter(voter.id)) loop = False elif nodes.filter(voter=delegate).count() == 1: # The delegate voted directly vote = nodes.filter(voter=delegate)[0] # if the vote of the delegate is not public, then # it doesn't count, we have finished if not vote.is_public: # wrong path! loop found, vote won't be counted path['is_broken_loop'] = True paths += [path] loop = False break # add the path and count the vote path["answers"] = vote.data['answers'] paths += [path] num_delegated_votes += 1 add_vote(vote.data['answers'], is_delegated=True) update_delegation_counts(get_vote_for_voter(voter.id)) loop = False elif edges.filter(voter=delegate).count() == 1: # the delegate also delegated vote = edges.filter(voter=delegate)[0] # if the vote of the delegate is not public, then # it doesn't count, we have finished if not vote.is_public: # wrong path! loop found, vote won't be counted path['is_broken_loop'] = True paths += [path] loop = False break # vote is public, so continue looping path['user_ids'] += [delegate.id] current_edge = vote else: # broken path! we cannot continue path['is_broken_loop'] = True paths += [path] loop = False if not self.extra_data: self.extra_data = dict() # post process the tally for tally in tallies: tally.post_tally(result) self.result = dict(a="result", counts=result, total_votes=result[0]['total_votes'] + result[0]['dirty_votes'], electorate_count=self.electorate.count(), total_delegated_votes=num_delegated_votes) tally_log = [] for tally in tallies: tally_log.append(tally.get_log()) self.extra_data['tally_log'] = tally_log def rank_delegate(delegate_count, delegation_counts): if delegate_count == 0: return None count = 0 for key, value in delegation_counts.iteritems(): if delegate_count <= value: count += 1 return count # refresh DelegateElectionCount items from agora_site.agora_core.models.delegateelectioncount import DelegateElectionCount DelegateElectionCount.objects.filter(election=self).delete() for key, value in delegation_counts.iteritems(): dec = DelegateElectionCount(election=self, count=value) dec.rank = rank_delegate(value, delegation_counts) dec.count_percentage = value * 100.0 / self.result['total_votes'] dec.delegate_vote = get_vote_for_voter(int(key)) dec.delegate_id = int(key) dec.save() self.delegated_votes_frozen_at_date = self.voters_frozen_at_date =\ self.result_tallied_at_date = timezone.now() # TODO: update result_hash self.save()
def compute_result(self): """ Computes the result of the election """ from agora_site.agora_core.models import CastVote # maximum delegation depth, so that we don't enter in near-infinite loops MAX_DELEGATION_DEPTH = 20 # Query with the direct votes in this election q = self.cast_votes.filter(is_counted=True, invalidated_at_date=None).values("voter__id").query # Query with the delegated votes self.delegated_votes = CastVote.objects.filter( election=self.agora.delegation_election, is_direct=False, is_counted=True, invalidated_at_date=None # we exclude from this query the people who voted directly so that # you cannot vote twice ).exclude(is_direct=False, voter__id__in=q) # These are all the people that can vote in this election self.electorate = self.agora.members.all() # These are all the direct votes, even from those who are not elegible # to vote in this election nodes = self.cast_votes.filter( is_direct=True, # is_counted=True, FIXME invalidated_at_date=None, ) # These are all the delegation votes, i.e. those that point to a delegate # edges = self.agora.delegation_election.cast_votes.filter( # is_direct=False, invalidated_at_date=None) edges = self.delegated_votes # list of saved paths. A path represent a list of users who delegate # into a given vote. # A path has the following format: # { # user_ids: [id1, id2, ...], # answers: [ question1_plaintext_answer, question2_plaintext_answer, ..], # is_broken_loop: True|False # } # note that the user_ids do NOT include the last user in the chain # also note that is_broken_loop is set to true if either the loop is # closed (infinite) or does not end in a leaf (=node) paths = [] # A dictionary where the number of delegated voted per delegate is # stored. This dict is used only for recording the number of delegated # votes a delegate has. # # The keys are the user_ids of the delegates, and the values are # the number of delegated votes. # Note that because of chains of delegations, the same vote can be # counted multiple times. delegation_counts = dict() def update_delegation_counts(vote): """ function used to update the delegation counts, for each valid vote. it basically goes deep in the delegation chain, updating the count for each delegate """ # if there is no vote we have nothing to do if not vote: return def increment_delegate(delegate_id): """ Increments the delegate count or sets it to one if doesn't it exist """ if delegate_id in delegation_counts: delegation_counts[delegate_id] += 1 else: delegation_counts[delegate_id] = 1 i = 0 while not vote.is_direct and i < MAX_DELEGATION_DEPTH: i += 1 next_delegate = vote.get_delegate() if nodes.filter(voter=next_delegate).count() == 1: increment_delegate(next_delegate.id) return elif edges.filter(voter=next_delegate).count() == 1: increment_delegate(next_delegate.id) vote = edges.filter(voter=next_delegate)[0] else: raise Exception("Broken delegation chain") def get_path_for_user(user_id): """ Given an user id, checks if it's already in any known path, and return it if that path is found. Returns None otherwise. """ for path in paths: if user_id in path["user_ids"]: return path return None def get_vote_for_voter(voter): """ Given a voter (an User), returns the vote of the vote of this voter on the election. It will be either a proxy or a direct vote """ if nodes.filter(voter=voter).count() == 1: return nodes.filter(voter=voter)[0] elif edges.filter(voter=voter) == 1: return edges.filter(voter=voter)[0] else: return None if self.election_type not in dict(parse_voting_methods()): raise Exception("do not know how to count this type of voting") voting_systems = [] tallies = [] import copy # result is in the same format as get_result_pretty(). Initialized here result = copy.deepcopy(self.questions) # setup the initial data common to all voting system i = 0 for question in result: voting_system = get_voting_system_by_id(self.election_type) tally = voting_system.create_tally(self, i) voting_systems.append(voting_system) tallies.append(tally) i += 1 question["a"] = "question/result/" + voting_system.get_id() question["winners"] = [] question["total_votes"] = 0 for answer in question["answers"]: answer["a"] = "answer/result/" + voting_system.get_id() answer["total_count"] = 0 answer["total_count_percentage"] = 0 # prepare the tally tally.pre_tally(result) def add_vote(user_answers, is_delegated): """ Given the answers of a vote, update the result """ for tally in tallies: tally.add_vote(voter_answers=user_answers, result=result, is_delegated=is_delegated) # Here we go! for each voter, we try to find it in the paths, or in # the proxy vote chain, or in the direct votes pool for voter in self.electorate.all(): path_for_user = get_path_for_user(voter.id) # Found the user in a known path if path_for_user and not path_for_user["is_broken_loop"]: # found a path to which the user belongs # update delegation counts update_delegation_counts(get_vote_for_voter(voter)) add_vote(path_for_user["answers"], is_delegated=True) # found the user in a direct vote elif nodes.filter(voter=voter).count() == 1: vote = nodes.filter(voter=voter)[0] add_vote(vote.data["answers"], is_delegated=False) # found the user in an edge (delegated vote), but not yet in a path elif edges.filter(voter=voter).count() == 1: path = dict(user_ids=[voter.id], answers=[], is_broken_loop=False) current_edge = edges.filter(voter=voter)[0] loop = True i = 0 while loop and i < MAX_DELEGATION_DEPTH: i += 1 delegate = current_edge.get_delegate() path_for_user = get_path_for_user(delegate.id) check_depth = i < MAX_DELEGATION_DEPTH if check_depth and delegate in path["user_ids"]: # wrong path! loop found, vote won't be counted path["is_broken_loop"] = True paths += [path] loop = False elif check_depth and path_for_user and not path_for_user["is_broken_loop"]: # extend the found path and count a new vote path_for_user["user_ids"] += path["user_ids"] # Count the vote add_vote(path_for_user["answers"], is_delegated=True) update_delegation_counts(current_edge) loop = False elif check_depth and nodes.filter(voter=delegate).count() == 1: # The delegate voted directly, add the path and count # the vote vote = nodes.filter(voter=delegate)[0] path["answers"] = vote.data["answers"] paths += [path] add_vote(vote.data["answers"], is_delegated=True) update_delegation_counts(current_edge) loop = False elif check_depth and edges.filter(voter=delegate).count() == 1: # the delegate also delegated, so continue looping path["user_ids"] += [delegate.id] current_edge = edges.filter(voter=delegate)[0] else: # broken path! we cannot continue path["is_broken_loop"] = True paths += [path] loop = False # post process the tally for tally in tallies: tally.post_tally(result) self.result = dict(a="result", counts=result, delegation_counts=delegation_counts) tally_log = [] for tally in tallies: tally_log.append(tally.get_log()) self.extra_data["tally_log"] = tally_log self.delegated_votes_frozen_at_date = ( self.voters_frozen_at_date ) = self.result_tallied_at_date = datetime.datetime.now() # TODO: update result_hash self.save()
def do_tally(tally_path, election): import copy # result is in the same format as get_result_pretty(). Initialized here result = copy.deepcopy(election.questions) base_vote =[dict(choices=[]) for q in result] # setup the initial data common to all voting system i = 0 tallies = [] for question in result: tally_type = election.election_type if 'tally_type' in question: tally_type = question['tally_type'] voting_system = get_voting_system_by_id(tally_type) tally = voting_system.create_tally(election, i) tallies.append(tally) question['a'] = "question/result/" + voting_system.get_id() question['winners'] = [] question['total_votes'] = 0 for answer in question['answers']: answer['a'] = "answer/result/" + voting_system.get_id() answer['total_count'] = 0 answer['total_count_percentage'] = 0 tally.pre_tally(result) plaintexts_path = os.path.join(settings.PRIVATE_DATA_ROOT, 'elections', str(election.id), "%d_plaintexts_json" % i) with codecs.open(plaintexts_path, encoding='utf-8', mode='r') as plaintexts_file: for line in plaintexts_file.readlines(): voter_answers = base_vote choices = [] try: # Note line starts with " (1 character) and ends with # "\n (2 characters). It contains the index of the # option selected by the user but starting with 1 # because number 0 cannot be encrypted with elgammal # so we trim beginning and end, parse the int and # substract one number = int(line[1:-2]) - 1 choices = tally.parse_vote(number, question) # craft the voter_answers in the format admitted by # tally.add_vote voter_answers[i]['choices'] = choices except: print "invalid/blank vote: " + line tally.add_vote(voter_answers=voter_answers, result=result, is_delegated=False) i += 1 if not election.extra_data: election.extra_data = dict() # post process the tally for tally in tallies: tally.post_tally(result) election.electorate = election.agora.members.all() election.result = dict( a= "result", counts = result, total_votes = result[0]['total_votes'] + result[0]['dirty_votes'], electorate_count = election.electorate.count(), total_delegated_votes = 0 ) tally_log = [] for tally in tallies: tally_log.append(tally.get_log()) election.extra_data['tally_log'] = tally_log election.delegated_votes_frozen_at_date = election.voters_frozen_at_date =\ election.result_tallied_at_date = timezone.now()