diff --git a/management/forms.py b/management/forms.py index 5495341b9b0d96934d5ef6173c9dcb3201665c51..351cfbfe46a43f78c914c6a19729c7faa9e97cab 100644 --- a/management/forms.py +++ b/management/forms.py @@ -81,8 +81,6 @@ class AddSessionForm(forms.ModelForm): class AddElectionForm(forms.ModelForm): - max_votes_yes = forms.IntegerField(min_value=1, required=False, label='Maximum number of YES votes (optional)') - def __init__(self, user, session, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['session'].disabled = True @@ -91,12 +89,14 @@ class AddElectionForm(forms.ModelForm): self.fields['start_date'].widget = forms.TextInput(attrs={'placeholder': 'e.g.: 2020-05-12 13:00:00'}) self.fields['end_date'].widget = forms.TextInput(attrs={'placeholder': 'e.g.: 2020-05-12 13:00:00'}) # self.fields['start_date'].initial = timezone.now() + self.fields['max_votes_yes'] = forms.IntegerField(min_value=1, required=False, + label='Maximum number of YES votes (optional)') self.user = user self.session = session class Meta: model = Election - fields = ('title', 'voters_self_apply', 'start_date', 'end_date', 'session') + fields = ('title', 'voters_self_apply', 'start_date', 'end_date', 'max_votes_yes', 'session') labels = { 'title': 'Election Name', diff --git a/management/templates/management/election.html b/management/templates/management/election.html index 88e11c48063b222f5df320df65a860b4028ac145..fed03b0f37d8089a33fadc67b1c86f7b1e827526 100644 --- a/management/templates/management/election.html +++ b/management/templates/management/election.html @@ -112,6 +112,10 @@ {{ election_upload_application_form |crispy }} <button type="submit" class="btn btn-info">Apply</button> </form> + <hr> + <h5>Export result</h5> + <a href="{% url 'management:export_csv' election.pk %}" class="btn btn-primary mr-2">CSV</a> + <a href="{% url 'management:export_json' election.pk %}" class="btn btn-primary">JSON</a> {% endif %} </div> </div> diff --git a/management/urls.py b/management/urls.py index cc7ba836e83f8b8bf76da21adf06909b3bc8b0ff..0cea2f70541f54519cbbff8e624e16d75d7c0bd0 100644 --- a/management/urls.py +++ b/management/urls.py @@ -18,6 +18,8 @@ urlpatterns = [ path('election/<int:pk>', views.election_detail, name='election'), path('election/<int:pk>/delete_voter', views.delete_voter, name='delete_voter'), path('election/<int:pk>/delete_election', views.delete_election, name='delete_election'), + path('election/<int:pk>/export_csv', views.export_csv, name='export_csv'), + path('election/<int:pk>/export_json', views.export_json, name='export_json'), path('meeting/<int:pk>/delete_session', views.delete_session, name='delete_session'), path('meeting/<int:pk>/print_token', views.print_token, name='print_token'), path('meeting/<int:pk>/import_csv', views.import_csv, name='import_csv'), diff --git a/management/views.py b/management/views.py index bfb7844475a114343df19157101874d8acc15f64..41d68e26a1ec9c7e48d47720d14f914afff9e5f3 100644 --- a/management/views.py +++ b/management/views.py @@ -4,6 +4,8 @@ from pathlib import Path from typing import Dict import qrcode +import csv +import json from django.conf import settings from django.contrib import messages from django.contrib.auth import views as auth_views @@ -301,3 +303,58 @@ def import_csv(request, pk): else: form = CSVUploaderForm(session) return render(request, 'management/import_csv.html', {'form': form, 'session': session}) + + +@management_login_required +def export_csv(request, pk): + e = Election.objects.filter(session__in=request.user.sessions.all(), pk=pk) + if not e.exists(): + raise Http404('Election does not exist') + e = e.first() + + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="results.csv"' + + writer = csv.writer(response) + header = ['#', 'applicant', 'email', 'yes', 'no', 'abstention'] + print(e.max_votes_yes) + if e.max_votes_yes is not None: + header.append('elected') + writer.writerow(header) + for i in range(len(e.election_summary)): + a = e.election_summary[i] + row = [i+1, a.get_display_name(), a.email, a.votes_accept, a.votes_reject, a.votes_abstention] + if e.max_votes_yes is not None: + row.append(True if i < e.max_votes_yes else False) + writer.writerow(row) + + return response + + +@management_login_required +def export_json(request, pk): + e = Election.objects.filter(session__in=request.user.sessions.all(), pk=pk) + if not e.exists(): + raise Http404('Election does not exist') + e = e.first() + + json_data = [] + for i in range(len(e.election_summary)): + a = e.election_summary[i] + appl_data = { + "applicant": a.get_display_name(), + "email": a.email, + "yes": a.votes_accept, + "no": a.votes_reject, + "abstention": a.votes_abstention + } + if e.max_votes_yes is not None: + appl_data["elected"] = True if i < e.max_votes_yes else False + json_data.append(appl_data) + + json_str = json.dumps(json_data) + + response = HttpResponse(json_str, content_type='application/json') + response['Content-Disposition'] = 'attachment; filename=result.json' + + return response diff --git a/vote/templates/vote/tex/invitation.tex b/vote/templates/vote/tex/invitation.tex index 81bd431cbddfc930096f741f18994192d1faf59a..86cd0628a5665e34db363fea99d3cf548fe77631 100644 --- a/vote/templates/vote/tex/invitation.tex +++ b/vote/templates/vote/tex/invitation.tex @@ -11,7 +11,6 @@ \usepackage{natbib} \usepackage{graphicx} \usepackage{pifont} -\usepackage{lipsum} \usepackage[a4paper, left=3cm, right=3cm, bottom=2.5cm, top=3cm]{geometry} \pagenumbering{gobble} @@ -32,11 +31,11 @@ \section*{Invitation to Participate in an Online Election} \noindent You have been in invited to attend the following online election session:\\\\ Title: {{session.title}}\\ - {% if session.meeting_link %} - Meeting room link: {{ session.meeting_link}}\\ + {% if session.meeting_link %}% + Meeting room: {{ session.meeting_link}}\\ {% endif %}% - {% if session.start_date %} - Start date: {{session.start_date}}\\ + {% if session.start_date %}% + Start date: {{session.start_date}}\\ {% endif %}% Access token: {{token.token}}\\