Loading api/urls.py +5 −2 Changes for api/urls.py: 5 added lines, 2 removed lines. Original line number Diff line number Diff line from django.urls import path from api.views import ElectionListView, ElectionView, VoterView, VoteAPIView from api.views import ElectionListView, ElectionView, VoterView, VoteAPIView, ResultsView app_name = "api" urlpatterns = [ path("elections/", ElectionListView.as_view(), name="election-list-api"), path("election/<str:alias>/", ElectionView.as_view(), name="election-api"), path("voter/<uuid:token>/", VoterView.as_view(), name="voter-api"), path("vote/<str:alias>/<str:option_id>", VoteAPIView.as_view(), name="vote-api") path("vote/<str:alias>/<str:option_id>", VoteAPIView.as_view(), name="vote-api"), path("results/<int:election_id>/", ResultsView.as_view(), name="results-api") ] No newline at end of file api/views.py +23 −0 Changes for api/views.py: 23 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ from rest_framework.views import APIView from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework import status from rest_framework.response import Response from rest_framework.permissions import BasePermission from django.utils import timezone from django.db.models import Q, OuterRef, Exists from django.shortcuts import get_object_or_404 Loading Loading @@ -120,3 +122,24 @@ class VoteAPIView(APIView): {"detail": "Głos pomyślnie zapisany."}, status = status.HTTP_201_CREATED ) class ResultsViewPermission(BasePermission): def has_permission(self, request, view): return request.user and request.user.is_authenticated and request.user.is_active class ResultsView(APIView): permission_classes = [ResultsViewPermission] def get(self, request, election_id): election = get_object_or_404(Election, pk=election_id) options = list(election.options.values('name', 'votes')) if election.allow_invalid: options.append({'name' : 'GŁOS NIEWAŻNY', 'votes' : election.invalid_votes}) rsp = { 'name' : election.name, 'options' : options } return Response(rsp) No newline at end of file elections/migrations/0003_alter_option_unique_together.py 0 → 100644 +17 −0 Changes for elections/migrations/0003_alter_option_unique_together.py: 17 added lines, 0 removed lines. Original line number Diff line number Diff line # Generated by Django 6.0.3 on 2026-05-31 13:03 from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('elections', '0002_alter_option_election'), ] operations = [ migrations.AlterUniqueTogether( name='option', unique_together={('name', 'election')}, ), ] stats/templates/admin/live_results.html +1 −1 Changes for stats/templates/admin/live_results.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ </div> <script> const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'vote:api_internal_results' %}?election_id={{ election_id }}"; const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'api:results-api' election_id %}"; </script> <script src="{% static 'js/live_results.js' %}"></script> {% endblock %} No newline at end of file stats/templates/admin/statistics.html +1 −1 Changes for stats/templates/admin/statistics.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ {{ stats_by_class|json_script:"attendance-data-json" }} <script> const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'vote:api_internal_results' %}?election_id={{ election_id }}"; const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'api:results-api' election_id %}"; </script> <script src="{% static 'js/statistics.js' %}"></script> Loading Loading
api/urls.py +5 −2 Changes for api/urls.py: 5 added lines, 2 removed lines. Original line number Diff line number Diff line from django.urls import path from api.views import ElectionListView, ElectionView, VoterView, VoteAPIView from api.views import ElectionListView, ElectionView, VoterView, VoteAPIView, ResultsView app_name = "api" urlpatterns = [ path("elections/", ElectionListView.as_view(), name="election-list-api"), path("election/<str:alias>/", ElectionView.as_view(), name="election-api"), path("voter/<uuid:token>/", VoterView.as_view(), name="voter-api"), path("vote/<str:alias>/<str:option_id>", VoteAPIView.as_view(), name="vote-api") path("vote/<str:alias>/<str:option_id>", VoteAPIView.as_view(), name="vote-api"), path("results/<int:election_id>/", ResultsView.as_view(), name="results-api") ] No newline at end of file
api/views.py +23 −0 Changes for api/views.py: 23 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ from rest_framework.views import APIView from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework import status from rest_framework.response import Response from rest_framework.permissions import BasePermission from django.utils import timezone from django.db.models import Q, OuterRef, Exists from django.shortcuts import get_object_or_404 Loading Loading @@ -120,3 +122,24 @@ class VoteAPIView(APIView): {"detail": "Głos pomyślnie zapisany."}, status = status.HTTP_201_CREATED ) class ResultsViewPermission(BasePermission): def has_permission(self, request, view): return request.user and request.user.is_authenticated and request.user.is_active class ResultsView(APIView): permission_classes = [ResultsViewPermission] def get(self, request, election_id): election = get_object_or_404(Election, pk=election_id) options = list(election.options.values('name', 'votes')) if election.allow_invalid: options.append({'name' : 'GŁOS NIEWAŻNY', 'votes' : election.invalid_votes}) rsp = { 'name' : election.name, 'options' : options } return Response(rsp) No newline at end of file
elections/migrations/0003_alter_option_unique_together.py 0 → 100644 +17 −0 Changes for elections/migrations/0003_alter_option_unique_together.py: 17 added lines, 0 removed lines. Original line number Diff line number Diff line # Generated by Django 6.0.3 on 2026-05-31 13:03 from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('elections', '0002_alter_option_election'), ] operations = [ migrations.AlterUniqueTogether( name='option', unique_together={('name', 'election')}, ), ]
stats/templates/admin/live_results.html +1 −1 Changes for stats/templates/admin/live_results.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ </div> <script> const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'vote:api_internal_results' %}?election_id={{ election_id }}"; const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'api:results-api' election_id %}"; </script> <script src="{% static 'js/live_results.js' %}"></script> {% endblock %} No newline at end of file
stats/templates/admin/statistics.html +1 −1 Changes for stats/templates/admin/statistics.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ {{ stats_by_class|json_script:"attendance-data-json" }} <script> const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'vote:api_internal_results' %}?election_id={{ election_id }}"; const apiUrl = "{{ request.scheme }}://{{ request.get_host }}{% url 'api:results-api' election_id %}"; </script> <script src="{% static 'js/statistics.js' %}"></script> Loading