Ejemplo n.º 1
0
class Voter(HeliosModel):
    election = models.ForeignKey(Election)

    # let's link directly to the user now
    # FIXME: delete this as soon as migrations are set up
    #name = models.CharField(max_length = 200, null=True)
    #voter_type = models.CharField(max_length = 100)
    #voter_id = models.CharField(max_length = 100)

    uuid = models.CharField(max_length=50)

    # for users of type password, no user object is created
    # but a dynamic user object is created automatically
    user = models.ForeignKey('helios_auth.User', null=True)

    # if user is null, then you need a voter login ID and password
    voter_login_id = models.CharField(max_length=100, null=True)
    voter_password = models.CharField(max_length=100, null=True)
    voter_name = models.CharField(max_length=200, null=True)
    voter_email = models.CharField(max_length=250, null=True)

    # if election uses aliases
    alias = models.CharField(max_length=100, null=True)

    # we keep a copy here for easy tallying
    vote = LDObjectField(type_hint='legacy/EncryptedVote', null=True)
    vote_hash = models.CharField(max_length=100, null=True)
    cast_at = models.DateTimeField(auto_now_add=False, null=True)

    class Meta:
        unique_together = (('election', 'voter_login_id'))

    def __init__(self, *args, **kwargs):
        super(Voter, self).__init__(*args, **kwargs)

        # stub the user so code is not full of IF statements
        if not self.user:
            self.user = User(user_type='password',
                             user_id=self.voter_email,
                             name=self.voter_name)

    @classmethod
    @transaction.atomic
    def register_user_in_election(cls, user, election):
        voter_uuid = str(uuid.uuid4())
        voter = Voter(uuid=voter_uuid, user=user, election=election)

        # do we need to generate an alias?
        if election.use_voter_aliases:
            heliosutils.lock_row(Election, election.id)
            alias_num = election.last_alias_num + 1
            voter.alias = "V%s" % alias_num

        voter.save()
        return voter

    @classmethod
    def get_by_election(cls,
                        election,
                        cast=None,
                        order_by='voter_login_id',
                        after=None,
                        limit=None):
        """
    FIXME: review this for non-GAE?
    """
        query = cls.objects.filter(election=election)

        # the boolean check is not stupid, this is ternary logic
        # none means don't care if it's cast or not
        if cast == True:
            query = query.exclude(cast_at=None)
        elif cast == False:
            query = query.filter(cast_at=None)

        # little trick to get around GAE limitation
        # order by uuid only when no inequality has been added
        if cast == None or order_by == 'cast_at' or order_by == '-cast_at':
            query = query.order_by(order_by)

            # if we want the list after a certain UUID, add the inequality here
            if after:
                if order_by[0] == '-':
                    field_name = "%s__gt" % order_by[1:]
                else:
                    field_name = "%s__gt" % order_by
                conditions = {field_name: after}
                query = query.filter(**conditions)

        if limit:
            query = query[:limit]

        return query

    @classmethod
    def get_all_by_election_in_chunks(cls, election, cast=None, chunk=100):
        return cls.get_by_election(election)

    @classmethod
    def get_by_election_and_voter_id(cls, election, voter_id):
        try:
            return cls.objects.get(election=election, voter_login_id=voter_id)
        except cls.DoesNotExist:
            return None

    @classmethod
    def get_by_election_and_user(cls, election, user):
        try:
            return cls.objects.get(election=election, user=user)
        except cls.DoesNotExist:
            return None

    @classmethod
    def get_by_election_and_uuid(cls, election, uuid):
        query = cls.objects.filter(election=election, uuid=uuid)

        try:
            return query[0]
        except:
            return None

    @classmethod
    def get_by_user(cls, user):
        return cls.objects.select_related().filter(
            user=user).order_by('-cast_at')

    @property
    def datatype(self):
        return self.election.datatype.replace('Election', 'Voter')

    @property
    def vote_tinyhash(self):
        """
    get the tinyhash of the latest castvote
    """
        if not self.vote_hash:
            return None

        return CastVote.objects.get(vote_hash=self.vote_hash).vote_tinyhash

    @property
    def election_uuid(self):
        return self.election.uuid

    @property
    def name(self):
        return self.user.name

    @property
    def voter_id(self):
        return self.user.user_id

    @property
    def voter_id_hash(self):
        if self.voter_login_id:
            # for backwards compatibility with v3.0, and since it doesn't matter
            # too much if we hash the email or the unique login ID here.
            value_to_hash = self.voter_login_id
        else:
            value_to_hash = self.voter_id

        try:
            return utils.hash_b64(value_to_hash)
        except:
            try:
                return utils.hash_b64(value_to_hash.encode('latin-1'))
            except:
                return utils.hash_b64(value_to_hash.encode('utf-8'))

    @property
    def voter_type(self):
        return self.user.user_type

    @property
    def display_html_big(self):
        return self.user.display_html_big

    def send_message(self, subject, body):
        self.user.send_message(subject, body)

    def generate_password(self, length=10):
        if self.voter_password:
            raise Exception("password already exists")

        self.voter_password = heliosutils.random_string(
            length,
            alphabet='abcdefghjkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
        )

    def store_vote(self, cast_vote):
        # only store the vote if it's cast later than the current one
        if self.cast_at and cast_vote.cast_at < self.cast_at:
            return

        self.vote = cast_vote.vote
        self.vote_hash = cast_vote.vote_hash
        self.cast_at = cast_vote.cast_at
        self.save()

    def last_cast_vote(self):
        return CastVote(vote=self.vote,
                        vote_hash=self.vote_hash,
                        cast_at=self.cast_at,
                        voter=self)
Ejemplo n.º 2
0
class Voter(HeliosModel):
  election = models.ForeignKey(Election)
  
  # let's link directly to the user now
  # FIXME: delete this as soon as migrations are set up
  #name = models.CharField(max_length = 200, null=True)
  #voter_type = models.CharField(max_length = 100)
  #voter_id = models.CharField(max_length = 100)

  uuid = models.CharField(max_length = 50)

  # for users of type password, no user object is created
  # but a dynamic user object is created automatically
  user = models.ForeignKey('helios_auth.User', null=True)

  # if user is null, then you need a voter login ID and password
  voter_login_id = models.CharField(max_length = 100, null=True)
  voter_password = models.CharField(max_length = 100, null=True)
  voter_name = models.CharField(max_length = 200, null=True)
  voter_email = models.CharField(max_length = 250, null=True)

  voter_group = models.ForeignKey(VoterGroup, null=True)
  
  # if election uses aliases
  alias = models.CharField(max_length = 100, null=True)
  
  # we keep a copy here for easy tallying
  vote = LDObjectField(type_hint = 'legacy/EncryptedVote',
                       null=True)
  vote_hash = models.CharField(max_length = 100, null=True)
  cast_at = models.DateTimeField(auto_now_add=False, null=True)

  class Meta:
    unique_together = (('election', 'voter_login_id'))

  def __init__(self, *args, **kwargs):
    super(Voter, self).__init__(*args, **kwargs)

    # stub the user so code is not full of IF statements
    if not self.user:
      self.user = User(user_type='password', user_id=self.voter_email, name=self.voter_name)

  @classmethod
  @transaction.commit_on_success
  def register_user_in_election(cls, user, election):
    voter_uuid = str(uuid.uuid4())
    voter = Voter(uuid= voter_uuid, user = user, election = election)

    # do we need to generate an alias?
    if election.use_voter_aliases:
      heliosutils.lock_row(Election, election.id)
      alias_num = election.last_alias_num + 1
      voter.alias = "V%s" % alias_num

    voter.save()
    return voter

  @classmethod
  def get_by_election(cls, election, cast=None, order_by='voter_login_id', after=None, limit=None):
    """
    FIXME: review this for non-GAE?
    """
    query = cls.objects.filter(election = election)
    
    # the boolean check is not stupid, this is ternary logic
    # none means don't care if it's cast or not
    if cast == True:
      query = query.exclude(cast_at = None)
    elif cast == False:
      query = query.filter(cast_at = None)

    # little trick to get around GAE limitation
    # order by uuid only when no inequality has been added
    if cast == None or order_by == 'cast_at' or order_by =='-cast_at':
      query = query.order_by(order_by)
      
      # if we want the list after a certain UUID, add the inequality here
      if after:
        if order_by[0] == '-':
          field_name = "%s__gt" % order_by[1:]
        else:
          field_name = "%s__gt" % order_by
        conditions = {field_name : after}
        query = query.filter (**conditions)
    
    if limit:
      query = query[:limit]
      
    return query
  
  @classmethod
  def get_all_by_election_in_chunks(cls, election, cast=None, chunk=100):
    return cls.get_by_election(election)

  @classmethod
  def get_by_election_and_voter_id(cls, election, voter_id):
    try:
      return cls.objects.get(election = election, voter_login_id = voter_id)
    except cls.DoesNotExist:
      return None
    
  @classmethod
  def get_by_election_and_user(cls, election, user):
    try:
      return cls.objects.get(election = election, user = user)
    except cls.DoesNotExist:
      return None
      
  @classmethod
  def get_by_election_and_uuid(cls, election, uuid):
    query = cls.objects.filter(election = election, uuid = uuid)

    try:
      return query[0]
    except:
      return None

  @classmethod
  def get_by_user(cls, user):
    return cls.objects.select_related().filter(user = user).order_by('-cast_at')

  @property
  def datatype(self):
    return self.election.datatype.replace('Election', 'Voter')

  @property
  def vote_tinyhash(self):
    """
    get the tinyhash of the latest castvote
    """
    if not self.vote_hash:
      return None
    
    return CastVote.objects.get(vote_hash = self.vote_hash).vote_tinyhash

  @property
  def election_uuid(self):
    return self.election.uuid

  @property
  def name(self):
    return self.user.name

  @property
  def voter_id(self):
    return self.user.user_id

  @property
  def voter_id_hash(self):
    if self.voter_login_id:
      # for backwards compatibility with v3.0, and since it doesn't matter
      # too much if we hash the email or the unique login ID here.
      value_to_hash = self.voter_login_id
    else:
      value_to_hash = self.voter_id

    try:
      return utils.hash_b64(value_to_hash)
    except:
      try:
        return utils.hash_b64(value_to_hash.encode('latin-1'))
      except:
        return utils.hash_b64(value_to_hash.encode('utf-8'))        

  @property
  def voter_type(self):
    return self.user.user_type

  @property
  def display_html_big(self):
    return self.user.display_html_big
      
  def send_message(self, subject, body):
    self.user.send_message(subject, body)

  def generate_password(self, length=10):
    if self.voter_password:
      raise Exception("password already exists")
    
    self.voter_password = heliosutils.random_string(length)

  def store_vote(self, cast_vote):
    # only store the vote if it's cast later than the current one
    if self.cast_at and cast_vote.cast_at < self.cast_at:
      return

    self.vote = cast_vote.vote
    self.vote_hash = cast_vote.vote_hash
    self.cast_at = cast_vote.cast_at
    self.save()
  
  def last_cast_vote(self):
    return CastVote(vote = self.vote, vote_hash = self.vote_hash, cast_at = self.cast_at, voter=self)
Ejemplo n.º 3
0
class Voter(HeliosModel):
  election = models.ForeignKey(Election)
  
  # let's link directly to the user now
  # FIXME: delete this as soon as migrations are set up
  #name = models.CharField(max_length = 200, null=True)
  #voter_type = models.CharField(max_length = 100)
  #voter_id = models.CharField(max_length = 100)

  uuid = models.CharField(max_length = 50)

  # for users of type password, no user object is created
  # but a dynamic user object is created automatically
  user = models.ForeignKey('helios_auth.User', null=True)

  # if user is null, then you need a voter login ID and password
  voter_login_id = models.CharField(max_length = 100, null=True)
  voter_password = models.CharField(max_length = 100, null=True)
  voter_name = models.CharField(max_length = 200, null=True)
  voter_email = models.CharField(max_length = 250, null=True)
  
  # if election uses aliases
  alias = models.CharField(max_length = 100, null=True)
  
  # we keep a copy here for easy tallying
  vote = LDObjectField(type_hint = 'legacy/EncryptedVote',
                       null=True)
  vote_hash = models.CharField(max_length = 100, null=True)
  cast_at = models.DateTimeField(auto_now_add=False, null=True)


  class Meta:
    unique_together = (('election', 'voter_login_id'))

  def __init__(self, *args, **kwargs):
    super(Voter, self).__init__(*args, **kwargs)

    # stub the user so code is not full of IF statements
    if not self.user:
      self.user = User(user_type='password', user_id=self.voter_email, name=self.voter_name)

  def __unicode__(self):
    return self.user.name

  # DENIS - ultimo upload sobrescreve demais. Registros em helios_voter devem ser apagados de forma a constar somente os usuarios indicados no CSV carregado por
  # ultimo. Atualiza helios_electionlog.
  # TODO  - na view acrescentar informacao: apagado(s) X eleitor(es), antes de informar novo processamento de CSV.
  @classmethod
  @transaction.commit_on_success
  def unregister_voters_in_election(cls, election):
    amount_voters = 0
    if not election:
      raise Exception("Eleicao nula, nao posso apagar eleitores do(s) arquivo(s) CSV previo(s) se existir(em)!")
    else:
      amount_voters = cls.objects.filter(election_id = election.id).count()
      voters_to_del = cls.objects.filter(election_id = election.id)
      voters_to_del.delete()
      election.append_log(ElectionLog.PREVIOUS_VOTERS_REMOVED)

    return amount_voters
    
  @classmethod
  @transaction.commit_on_success
  def register_user_in_election(cls, user, election):
    voter_uuid = str(uuid.uuid4())
    voter = Voter(uuid= voter_uuid, user = user, election = election)

    # do we need to generate an alias?
    if election.use_voter_aliases:
      heliosutils.lock_row(Election, election.id)
      alias_num = election.last_alias_num + 1
      voter.alias = "V%s" % alias_num

    voter.save()
    return voter

  @classmethod
  def get_by_election(cls, election, cast=None, order_by='voter_login_id', after=None, limit=None):
    """
    FIXME: review this for non-GAE?
    """
    query = cls.objects.filter(election = election)
    
    # the boolean check is not stupid, this is ternary logic
    # none means don't care if it's cast or not
    if cast == True:
      query = query.exclude(cast_at = None)
    elif cast == False:
      query = query.filter(cast_at = None)

    # little trick to get around GAE limitation
    # order by uuid only when no inequality has been added
    if cast == None or order_by == 'cast_at' or order_by =='-cast_at':
      query = query.order_by(order_by)
      
      # if we want the list after a certain UUID, add the inequality here
      if after:
        if order_by[0] == '-':
          field_name = "%s__gt" % order_by[1:]
        else:
          field_name = "%s__gt" % order_by
        conditions = {field_name : after}
        query = query.filter (**conditions)
    
    if limit:
      query = query[:limit]
      
    return query
  
  @classmethod
  def get_all_by_election_in_chunks(cls, election, cast=None, chunk=100):
    return cls.get_by_election(election)

  @classmethod
  def get_by_election_and_voter_id(cls, election, voter_id):
    try:
      return cls.objects.get(election = election, voter_login_id = voter_id.strip())
    except cls.DoesNotExist:
      return None
    
  @classmethod
  def get_by_election_and_user(cls, election, user):
    try:
      return cls.objects.get(election = election, user = user)
    except cls.DoesNotExist:
      return None
      
  @classmethod
  def get_by_election_and_uuid(cls, election, uuid):
    query = cls.objects.filter(election = election, uuid = uuid)

    try:
      return query[0]
    except:
      return None

  @classmethod
  def get_by_user(cls, user):
    return cls.objects.select_related().filter(user = user).order_by('-cast_at')

  @property
  def datatype(self):
    return self.election.datatype.replace('Election', 'Voter')

  @property
  def vote_tinyhash(self):
    """
    get the tinyhash of the latest castvote
    """
    if not self.vote_hash:
      return None
    
    return CastVote.objects.get(vote_hash = self.vote_hash).vote_tinyhash

  @property
  def election_uuid(self):
    return self.election.uuid

  @property
  def name(self):
    return self.user.name

  @property
  def voter_id(self):
    return self.user.user_id

  @property
  def voter_id_hash(self):
    if self.voter_login_id:
      # for backwards compatibility with v3.0, and since it doesn't matter
      # too much if we hash the email or the unique login ID here.
      value_to_hash = self.voter_login_id.strip()
    else:
      value_to_hash = self.voter_id.strip()

    try:
      return utils.hash_b64(value_to_hash)
    except:
      try:
        return utils.hash_b64(value_to_hash.encode('latin-1'))
      except:
        return utils.hash_b64(value_to_hash.encode('utf-8'))        

  @property
  def voter_type(self):
    return self.user.user_type

  @property
  def display_html_big(self):
    return self.user.display_html_big
      
  def send_message(self, subject, body):
    self.user.send_message(subject, body)

  def generate_password(self, length=10):
    if self.voter_password:
      raise Exception(_('password already exists'))

    # CSV_VOTERS_PASSWORD_SIMPLIFIED means password generated with 6 letters and just in lowercase.
    if settings.CSV_VOTERS_PASSWORD_SIMPLIFIED:
      length = 06
      self.voter_password = heliosutils.random_string(length, alphabet='abcdefghijkmnopqrstuvwxyz').strip()
    else:
      self.voter_password = heliosutils.random_string(length, alphabet='abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789').strip()

  # metadata for the election
  @property
  def metadata(self):
    return {
      'voter_email': self.voter_email,
      'uuid': self.uuid,
      'voter_name': self.voter_name,
      'vote_hash': self.vote_hash,
      'cast_at': self.cast_at,
      'alias': self.alias,
      'user_id': self.user.user_id,
      'election id': self.election.id,
      'election name': self.election.name,
      'election url': self.election.url

      }

  def store_vote(self, cast_vote):
    # only store the vote if it's cast later than the current one
    if self.cast_at and cast_vote.cast_at < self.cast_at:
      return

    self.vote = cast_vote.vote
    self.vote_hash = cast_vote.vote_hash
    self.cast_at = cast_vote.cast_at
    self.save()
  
  def last_cast_vote(self):
    return CastVote(vote = self.vote, vote_hash = self.vote_hash, cast_at = self.cast_at, voter=self)