diff --git a/helios/crypto/electionalgs.py b/helios/crypto/electionalgs.py index c161fed7cfb8e7326c381b7df070b7f02363d3f2..609b5ad583c0712efcab93f6e6bbb881f98c3d78 100644 --- a/helios/crypto/electionalgs.py +++ b/helios/crypto/electionalgs.py @@ -389,9 +389,10 @@ def one_question_winner(question, result, num_cast_votes): class Election(HeliosObject): FIELDS = ['uuid', 'questions', 'name', 'short_name', 'description', 'voters_hash', 'openreg', - 'frozen_at', 'public_key', 'private_key', 'cast_url', 'result', 'result_proof', 'use_voter_aliases', 'voting_starts_at', 'voting_ends_at'] + 'frozen_at', 'public_key', 'private_key', 'cast_url', 'result', 'result_proof', 'use_voter_aliases', 'voting_starts_at', 'voting_ends_at', 'election_type'] + JSON_FIELDS = ['uuid', 'questions', 'name', 'short_name', 'description', 'voters_hash', 'openreg', - 'frozen_at', 'public_key', 'cast_url', 'use_voter_aliases', 'voting_starts_at', 'voting_ends_at'] + 'frozen_at', 'public_key', 'cast_url', 'use_voter_aliases', 'voting_starts_at', 'voting_ends_at', 'election_type'] def init_tally(self): return Tally(election=self) diff --git a/helios/forms.py b/helios/forms.py index c15e5e0ed61d5184ee5b453bce4843c86ad2f4c6..5204f8e10e10b52cf569d035fac3d8e0eff85b1e 100644 --- a/helios/forms.py +++ b/helios/forms.py @@ -11,6 +11,7 @@ class ElectionForm(forms.Form): short_name = forms.SlugField(max_length=25, help_text='no spaces, will be part of the URL for your election, e.g. my-club-2010') name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'size':60}), help_text='the pretty name for your election, e.g. My Club 2010 Election') description = forms.CharField(max_length=2000, widget=forms.Textarea(attrs={'cols': 70, 'wrap': 'soft'})) + election_type = forms.ChoiceField(label="type", choices = Election.ELECTION_TYPES) use_voter_aliases = forms.BooleanField(required=False, initial=False, help_text='if selected, voter identities will be replaced with aliases, e.g. "V12", in the ballot tracking center') diff --git a/helios/models.py b/helios/models.py index 5135118421f21a0bf065a18baa3d45d6bbee1685..a925c0c1d3683ee5bcd3880801bea79a3995e870 100644 --- a/helios/models.py +++ b/helios/models.py @@ -35,6 +35,14 @@ class Election(models.Model, electionalgs.Election): short_name = models.CharField(max_length=100) name = models.CharField(max_length=250) + ELECTION_TYPES = ( + ('election', 'Election'), + ('referendum', 'Referendum') + ) + + election_type = models.CharField(max_length=250, null=False, default='election', choices = ELECTION_TYPES) + advanced_audit_features = models.BooleanField(default=True, null=False) + description = models.TextField() public_key = JSONField(algs.EGPublicKey, null=True) private_key = JSONField(algs.EGSecretKey, null=True) @@ -93,7 +101,11 @@ class Election(models.Model, electionalgs.Election): # decryption proof, a JSON object result_proof = JSONField(null=True) - + + @property + def pretty_type(self): + return dict(self.ELECTION_TYPES)[self.election_type] + @property def num_cast_votes(self): return self.voter_set.exclude(vote=None).count() @@ -654,6 +666,9 @@ class CastVote(models.Model, electionalgs.CastVote): # cache the hash of the vote vote_hash = models.CharField(max_length=100) + # a tiny version of the hash to enable short URLs + vote_tinyhash = models.CharField(max_length=50, null=True, unique=True) + cast_at = models.DateTimeField(auto_now_add=True) # when is the vote verified? diff --git a/helios/templates/election_view.html b/helios/templates/election_view.html index 6434fe65d14ca1fd48f68d9c68d9cecb59c354cb..1a007f479b2753cbd05642696856b597b5dc91c0 100644 --- a/helios/templates/election_view.html +++ b/helios/templates/election_view.html @@ -24,7 +24,7 @@ if (!navigator.javaEnabled()) { {% endif %} {% endif %}</h2> <p style="padding-top:0px; margin-top:0px"> -an election created by <u><b>{{election.admin.display_html_small|safe}}</b></u> +{{ election.election_type }} created by <u><b>{{election.admin.display_html_small|safe}}</b></u> {% if election.is_archived %} [archived] {% endif %} @@ -34,12 +34,12 @@ an election created by <u><b>{{election.admin.display_html_small|safe}}</b></u> <br /> {% if admin_p %} {% if election.featured_p %} -this election is featured on the front page. +this {{election.election_type}} is featured on the front page. {% if can_feature_p %} [<a href="{% url helios.views.one_election_set_featured election.uuid %}?featured_p=0">unfeature it</a>] {% endif %} {% else %} -this election is <u>not</u> featured on the front page. +this {{election.election_type}} is <u>not</u> featured on the front page. {% if can_feature_p %} [<a href="{% url helios.views.one_election_set_featured election.uuid %}?featured_p=1">feature it</a>] {% endif %} @@ -156,7 +156,7 @@ all voters will be notified that the tally is ready. {% if election.voting_has_started %} <span class="highlight-box round" style="font-size: 1.6em; margin-right: 10px;" id="votelink"> -<a href="{{test_cookie_url}}">Vote in this election </a> +<a href="{{test_cookie_url}}">Vote in this {{election.election_type}} </a> </span><br /> {% if not user %} <br /> @@ -165,15 +165,15 @@ For your privacy, you'll be asked to log in only once your ballot is encrypted. {% endif %} {% if election.voting_extended_until %} <br /> -This election was initially scheduled to end at {{election.voting_ends_at}} (UTC),<br /> +This {{election.election_type}} was initially scheduled to end at {{election.voting_ends_at}} (UTC),<br /> but has been extended until {{ election.voting_extended_until }} (UTC). {% else %} {% if election.voting_ends_at %} <br /> -This election is scheduled to end at {{election.voting_ends_at}} (UTC). +This {{election.election_type}} is scheduled to end at {{election.voting_ends_at}} (UTC). {% else %} <br /> -This election ends at the administrator's discretion. +This {{election.election_type}} ends at the administrator's discretion. {% endif %} <br /> {% endif %} @@ -192,7 +192,7 @@ This election ends at the administrator's discretion. {% if user %} {% if voter %} <p style="padding-top:1px;"> - You are registered to vote in this election. + You are registered to vote in this {{election.election_type}}. {% if election.use_voter_aliases %} Your voter alias is {{voter.alias}}. {% endif %} @@ -204,19 +204,19 @@ Your voter alias is {{voter.alias}}. {% if election.openreg %} {% if eligible_p %} {% if election.voting_has_started %} -This election is open to anyone. +This {{election.election_type}} is open to anyone. {% else %} -You are <em>not</em> registered to vote in this election.<br /> +You are <em>not</em> registered to vote in this {{election.election_type}}.<br /> <form method="post" action="{% url helios.views.one_election_register election.uuid %}"> <input type="hidden" name="csrf_token" value="{{csrf_token}}" /> <input type="submit" value="register!" /> </form> {% endif %} {% else %} -Registration for this election is open, but You are <em>not eligible</em>. +Registration for this {{election.election_type}} is open, but You are <em>not eligible</em>. {% endif %} {% else %} -You are <em>not eligible</em> to vote in this election, because registration is closed and you are not registered.<br /> +You are <em>not eligible</em> to vote in this {{election.election_type}}, because registration is closed and you are not registered.<br /> {% endif %} {% endif %} {% endif %} diff --git a/helios/views.py b/helios/views.py index 6e2e5d3ea46cc622927c57c2cde7778ed0ae03ef..9571a5e6ba6113ce15a2ab51e833124721ebe976 100644 --- a/helios/views.py +++ b/helios/views.py @@ -145,8 +145,7 @@ def election_new(request): user = get_user(request) election_params['admin'] = user - # election_params['api_client'] = get_api_client(request) - + election, created_p = Election.get_or_create(**election_params) if created_p: @@ -162,7 +161,7 @@ def election_new(request): def one_election_edit(request, election): error = None - RELEVANT_FIELDS = ['short_name', 'name', 'description', 'use_voter_aliases'] + RELEVANT_FIELDS = ['short_name', 'name', 'description', 'use_voter_aliases', 'election_type'] if request.method == "GET": values = {}