From a2a1330e64271cc0d3d364ebcabc4d3359a6d1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= <michael.loipfuehrer@stusta.de> Date: Wed, 11 Nov 2020 15:09:13 +0100 Subject: [PATCH] #18 add option to disable abstentions for elections --- management/forms.py | 4 +- .../templates/management/add_election.html | 3 +- .../templates/management/add_tokens.html | 3 +- management/templates/management/results.html | 40 ++++++++++--------- vote/forms.py | 12 +++--- .../0023_election_disable_abstention.py | 18 +++++++++ vote/models.py | 6 +++ vote/templates/vote/vote.html | 12 +++--- 8 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 vote/migrations/0023_election_disable_abstention.py diff --git a/management/forms.py b/management/forms.py index e9e6925..2a1f354 100644 --- a/management/forms.py +++ b/management/forms.py @@ -139,7 +139,7 @@ class AddElectionForm(TemplateStringForm): model = Election fields = ( 'title', 'start_date', 'end_date', 'session', 'max_votes_yes', 'voters_self_apply', 'send_emails_on_start', - 'remind_text') + 'remind_text', 'disable_abstention') labels = { 'title': 'Election Name', @@ -148,6 +148,8 @@ class AddElectionForm(TemplateStringForm): 'voters_self_apply': 'Voters can apply for the election', 'send_emails_on_start': 'Voters receive an e-mail when the election starts<br>' '(useful for elections that last several days)', + 'disable_abstention': 'Disable the option to abstain in this election<br>' + '(only YES and NO votes will be allowed)', 'remind_text': '', } diff --git a/management/templates/management/add_election.html b/management/templates/management/add_election.html index 6a426e6..d93f215 100644 --- a/management/templates/management/add_election.html +++ b/management/templates/management/add_election.html @@ -13,7 +13,7 @@ {{ form|as_crispy_errors }} {% for field in form %} - {% if field.html_name != "remind_text" and field.html_name != "send_emails_on_start" and field.html_name != "voters_self_apply" and field.html_name != "email" %} + {% if field.html_name != "remind_text" and field.html_name != "send_emails_on_start" and field.html_name != "voters_self_apply" and field.html_name != "email" and field.html_name != 'disable_abstention' %} {{ field|as_crispy_field }} {% endif %} {% endfor %} @@ -28,6 +28,7 @@ </a> </div> <div id="collapseOne" class="card-body collapse{% if form.remind_text.value %} show{% endif %}"> + {{ form.disable_abstention|as_crispy_field }} {{ form.voters_self_apply|as_crispy_field }} {{ form.send_emails_on_start|as_crispy_field }} <h5>Remind email template text</h5> diff --git a/management/templates/management/add_tokens.html b/management/templates/management/add_tokens.html index 6650ae9..21e0ba4 100644 --- a/management/templates/management/add_tokens.html +++ b/management/templates/management/add_tokens.html @@ -11,8 +11,7 @@ <span>Enter the amount of tokens that you want to generate and click "Submit". Tokens can then be downloaded in form of a PDF file in the session view.<br> Caution: The voters generated purely by token are anonymous. Also note that new tokens will be generated every time you download the PDF file, - invalidation any previously generated PDF. - This due to the nature that we never save any raw tokens in our database. + invalidating any previously generated PDF. </span> <hr> <form class="user" action="{% url 'management:add_tokens' session.pk %}" method="post"> diff --git a/management/templates/management/results.html b/management/templates/management/results.html index ea9c7d5..d5fad3d 100644 --- a/management/templates/management/results.html +++ b/management/templates/management/results.html @@ -1,23 +1,27 @@ {% load static %} <table class="table table-striped"> - <thead> + <thead> + <tr> + <th scope="col">#</th> + <th scope="col">Applicant</th> + <th scope="col">Yes</th> + <th scope="col">No</th> + {% if not election.disable_abstention %} + <th scope="col">Abstention</th> + {% endif %} + </tr> + </thead> + <tbody> + {% for application in election.election_summary %} <tr> - <th scope="col">#</th> - <th scope="col">Applicant</th> - <th scope="col">Yes</th> - <th scope="col">No</th> - <th scope="col">Abstention</th> + <th scope="row">{{ forloop.counter }}</th> + <td>{{ application.get_display_name }}</td> + <td>{{ application.votes_accept }}</td> + <td>{{ application.votes_reject }}</td> + {% if not election.disable_abstention %} + <td>{{ application.votes_abstention }}</td> + {% endif %} </tr> - </thead> - <tbody> - {% for application in election.election_summary %} - <tr> - <th scope="row">{{ forloop.counter }}</th> - <td>{{ application.get_display_name }}</td> - <td>{{ application.votes_accept }}</td> - <td>{{ application.votes_reject }}</td> - <td>{{ application.votes_abstention }}</td> - </tr> - {% endfor %} - </tbody> + {% endfor %} + </tbody> </table> diff --git a/vote/forms.py b/vote/forms.py index e0f8344..501548c 100644 --- a/vote/forms.py +++ b/vote/forms.py @@ -4,7 +4,8 @@ from django.db import transaction from django.utils.translation import gettext_lazy as _ from management.forms import ApplicationUploadForm -from vote.models import Application, Voter, OpenVote, VOTE_CHOICES, Vote, VOTE_ABSTENTION, VOTE_ACCEPT +from vote.models import Application, Voter, OpenVote, VOTE_CHOICES, Vote, VOTE_ABSTENTION, VOTE_ACCEPT, \ + VOTE_CHOICES_NO_ABSTENTION class AccessCodeAuthenticationForm(forms.Form): @@ -58,12 +59,12 @@ class VoteBoundField(forms.BoundField): class VoteField(forms.ChoiceField): - def __init__(self, *, application, **kwargs): + def __init__(self, *, application, disable_abstention=False, **kwargs): super().__init__( label=application.get_display_name(), - choices=VOTE_CHOICES, + choices=VOTE_CHOICES_NO_ABSTENTION if disable_abstention else VOTE_CHOICES, widget=forms.RadioSelect(), - initial=VOTE_ABSTENTION, + initial=None if disable_abstention else VOTE_ABSTENTION, **kwargs ) self.application = application @@ -85,7 +86,8 @@ class VoteForm(forms.Form): # dynamically construct form fields for application in self.election.applications: - self.fields[f'{application.pk}'] = VoteField(application=application) + self.fields[f'{application.pk}'] = VoteField(application=application, + disable_abstention=self.election.disable_abstention) self.num_applications = len(self.election.applications) diff --git a/vote/migrations/0023_election_disable_abstention.py b/vote/migrations/0023_election_disable_abstention.py new file mode 100644 index 0000000..709cf5c --- /dev/null +++ b/vote/migrations/0023_election_disable_abstention.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.2 on 2020-11-11 13:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('vote', '0022_auto_20201104_1438'), + ] + + operations = [ + migrations.AddField( + model_name='election', + name='disable_abstention', + field=models.BooleanField(default=False), + ), + ] diff --git a/vote/models.py b/vote/models.py index 96fceb5..5b3621d 100644 --- a/vote/models.py +++ b/vote/models.py @@ -30,6 +30,11 @@ VOTE_CHOICES = [ (VOTE_REJECT, 'No'), ] +VOTE_CHOICES_NO_ABSTENTION = [ + (VOTE_ACCEPT, 'Yes'), + (VOTE_REJECT, 'No'), +] + class Enc32: alphabet = "0123456789abcdefghjknpqrstuvwxyz" @@ -79,6 +84,7 @@ class Election(models.Model): session = models.ForeignKey(Session, related_name='elections', on_delete=CASCADE) result_published = models.CharField(max_length=1, choices=[('0', 'unpublished'), ('1', 'fully published')], default='0') + disable_abstention = models.BooleanField(default=False) voters_self_apply = models.BooleanField(default=False) send_emails_on_start = models.BooleanField(default=False) remind_text = models.TextField(max_length=8000, blank=True, null=True) diff --git a/vote/templates/vote/vote.html b/vote/templates/vote/vote.html index 15f6981..82a60e8 100644 --- a/vote/templates/vote/vote.html +++ b/vote/templates/vote/vote.html @@ -47,7 +47,9 @@ <thead class="thead-light"> <tr> <th>Applicant</th> - <th class="choice text-center">Abstention</th> + {% if not election.disable_abstention %} + <th class="choice text-center">Abstention</th> + {% endif %} <th class="choice text-center text-success">YES</th> <th class="choice text-center text-muted" title="NO should only be selected if you want to vote EXPLICITLY AGAINST this applicant">NO* @@ -60,13 +62,9 @@ <td class="applicant"> <div class="row no-gutters"> {% if field.application.avatar %} - <div class="col-3"> - {#{% if field.application.avatar %}#} + <div class="col-3"> <img src="{{ field.application.avatar.url }}" class="card-img" alt="applicant-picture"> - {#{% else %}#} - {# <img src="{% static 'img/blank_avatar.png' %}" class="card-img" alt="applicant-picture">#} - {#{% endif %}#} - </div> + </div> {% endif %} <div class="col-9"> <div class="card-body"> -- GitLab