diff --git a/decide/census/export/README.md b/decide/census/export/README.md new file mode 100644 index 0000000000..ed4bee0cb4 --- /dev/null +++ b/decide/census/export/README.md @@ -0,0 +1,4 @@ +Export Folder +================================ + +Este directorio incluirá todos los censos que exportes. diff --git a/decide/census/templates/census_export.html b/decide/census/templates/census_export.html new file mode 100644 index 0000000000..6fe6cb45af --- /dev/null +++ b/decide/census/templates/census_export.html @@ -0,0 +1,62 @@ +{% extends "base.html" %} +{% load i18n static %} + +{% block extrahead %} + + + + +{% endblock %} + + +{% block content %} +
+

Export Census

+
+ +
+
+

In this view you can manage the census by exporting the users participating in a voting

+
+
+ +
+ +
+ +
+ {% csrf_token %} +
+
+ + + +
+
+
+
+ +
+
+
+ +{% if messages %} + + +{% endif %} + + +{% endblock %} \ No newline at end of file diff --git a/decide/census/templates/census_import.html b/decide/census/templates/census_import.html new file mode 100644 index 0000000000..0d0aec11a4 --- /dev/null +++ b/decide/census/templates/census_import.html @@ -0,0 +1,69 @@ +{% extends "base.html" %} +{% load i18n static %} + +{% block extrahead %} + + + + +{% endblock %} + + +{% block content %} +
+

Import Census

+
+ +
+
+

In this view you can manage the census by importing users participating in a voting

+
+
+ +
+ +
+ +
+ {% csrf_token %} +
+
+ + + +
+
+
+
+ + + +
+
+
+
+ +
+
+
+ +{% if messages %} + + +{% endif %} + + +{% endblock %} \ No newline at end of file diff --git a/decide/census/templates/result_page.html b/decide/census/templates/result_page.html index 6e68087d7a..40e5e85eec 100644 --- a/decide/census/templates/result_page.html +++ b/decide/census/templates/result_page.html @@ -27,6 +27,10 @@
{% if remove %} + {% elif export %} + + {% elif import %} + {% else %} {% endif %} diff --git a/decide/census/tests.py b/decide/census/tests.py index 097b4fda89..6332a5e4b4 100644 --- a/decide/census/tests.py +++ b/decide/census/tests.py @@ -1,16 +1,26 @@ import random + +#Added AnonymousUser from django.contrib.auth.models import User, AnonymousUser + +#Added RequestFactory to handle the request.user.is_staff check in the views from django.test import RequestFactory +#Added these Middleware to simulate the messages, since RequestFactory doesn't do it +from django.contrib.messages.middleware import MessageMiddleware +from django.contrib.sessions.middleware import SessionMiddleware + from rest_framework.test import APIClient from .models import Census +#Added the necessary models from voting.models import Voting, Question, QuestionOption from base import mods from base.tests import BaseTestCase -from .views import add_to_census, remove_from_census +import os + +from .views import exporting_census, importing_census, add_to_census, remove_from_census +import csv -from django.contrib.messages.middleware import MessageMiddleware -from django.contrib.sessions.middleware import SessionMiddleware class CensusTestCase(BaseTestCase): @@ -187,4 +197,119 @@ def test_delete_census_from_gui(self): request.user = self.user response = remove_from_census(request) self.assertEqual(response.status_code, 200) - self.assertEqual(existing_censuss, Census.objects.count()) \ No newline at end of file + self.assertEqual(existing_censuss, Census.objects.count()) + +class CensusExportImport(BaseTestCase): + def setUp(self): + super().setUp() + + self.q = Question(desc='test question') + self.q.save() + for i in range(5): + self.opt = QuestionOption(question=self.q, option='option {}'.format(i+1)) + self.opt.save() + self.v = Voting(name='test voting', question=self.q) + self.v.save() + + self.voter = User(username='test_user') + self.voter.save() + + self.census = Census(voting_id=self.v.id, voter_id=self.voter.id) + self.census.save() + + self.factory = RequestFactory() + self.sm = SessionMiddleware() + self.mm = MessageMiddleware() + + def tearDown(self): + super().tearDown() + self.census = None + + self.q = None + self.opt = None + + if os.path.exists('./census/export/export_' + self.v.name + '.csv'): + os.remove('./census/export/export_' + self.v.name + '.csv') + + if os.path.exists('./census/export/import_test.csv'): + os.remove('./census/export/import_test.csv') + + self.v = None + self.voter = None + self.factory = None + self.sm = None + self.mm = None + + self.file = None + + def test_export_census(self): + self.user = AnonymousUser() + data = {'voting-select': self.v.id} + request = self.factory.post('/census/export/exporting_census/', data, format='json') + self.sm.process_request(request) + self.mm.process_request(request) + request.user = self.user + response = exporting_census(request) + self.assertEqual(response.status_code, 401) + self.assertFalse(os.path.exists('./census/export/export_' + self.v.name + '.csv')) + + user_admin = User.objects.get(username="admin") + self.user = user_admin + data = {'voting-select': self.v.id} + request = self.factory.post('/census/export/exporting_census/', data, format='json') + self.sm.process_request(request) + self.mm.process_request(request) + request.user = self.user + response = exporting_census(request) + self.assertEqual(response.status_code, 302) + self.assertTrue(os.path.exists('./census/export/export_' + self.v.name + '.csv')) + with open('./census/export/export_' + self.v.name + '.csv', 'r') as csvfile: + self.assertEqual(2, len(csvfile.readlines())) + + + def generate_import_csv(self): + #Creates a csv file with a row containing the user admin + try: + user_admin = User.objects.get(username="admin") + self.file = open('./census/export/import_test.csv', 'w', encoding='UTF8') + wr = csv.writer(self.file) + header = ['username', 'first_name', 'last_name', 'email'] + wr.writerow(header) + row = [user_admin.username,'','',''] + wr.writerow(row) + finally: + self.file.close() + + return self.file + + def test_import_census(self): + #Gets the csv file with the user admin to import it into the census created in the set up method + import_csv = self.generate_import_csv() + file_path = import_csv.name + + f = open(file_path, "r") + + self.user = AnonymousUser() + data = {'voting-select': self.v.id, 'csv-file': f} + request = self.factory.post('/census/import/importing_census/', data, format='json') + self.sm.process_request(request) + self.mm.process_request(request) + request.user = self.user + response = importing_census(request) + self.assertEqual(response.status_code, 401) + + f.close() + f = open(file_path, "r") + + user_admin = User.objects.get(username="admin") + self.user = user_admin + data = {'voting-select': self.v.id, 'csv-file': f} + request = self.factory.post('/census/import/importing_census/', data, format='json') + self.sm.process_request(request) + self.mm.process_request(request) + request.user = self.user + response = importing_census(request) + self.assertEqual(response.status_code, 302) + self.assertTrue(Census.objects.all().filter(voting_id=self.v.id,voter_id=user_admin.id).exists()) + + f.close() diff --git a/decide/census/urls.py b/decide/census/urls.py index 41cc26e1d7..4c016b195a 100644 --- a/decide/census/urls.py +++ b/decide/census/urls.py @@ -8,5 +8,9 @@ path('add/', views.census_add, name='census_add'), path('add/add_to_census', views.add_to_census), path('remove/', views.census_remove, name='census_remove'), - path('remove/remove_from_census', views.remove_from_census) + path('remove/remove_from_census', views.remove_from_census), + path('export/', views.export_census), + path('export/exporting_census/', views.exporting_census), + path('import/', views.import_census), + path('import/importing_census/', views.importing_census) ] diff --git a/decide/census/views.py b/decide/census/views.py index d8b5cff366..60125c3578 100644 --- a/decide/census/views.py +++ b/decide/census/views.py @@ -10,6 +10,7 @@ HTTP_409_CONFLICT as ST_409 ) from django.http import HttpResponse +from django.http import HttpResponseRedirect from django.template import loader from voting.models import Voting from django.contrib.auth.models import User @@ -17,7 +18,7 @@ from base.perms import UserIsStaff from .models import Census - +import csv class CensusCreate(generics.ListCreateAPIView): permission_classes = (UserIsStaff,) @@ -71,7 +72,7 @@ def census_add(request): template = loader.get_template("result_page.html") messages.error(request, "You must be a staff member to access this page") return HttpResponse(template.render({}, request), status=ST_401) - + def add_to_census(request): template = loader.get_template("result_page.html") @@ -99,6 +100,7 @@ def add_to_census(request): return HttpResponse(template.render({}, request), status=ST_401) + def census_remove(request): if request.user.is_staff: template = loader.get_template("census_remove.html") @@ -139,5 +141,91 @@ def remove_from_census(request): else: messages.error(request, "You must be a staff member to access this page") return HttpResponse(template.render({'remove': True}, request), status=ST_401) + + + +def export_census(request): + if request.user.is_staff: + template = loader.get_template("census_export.html") + votings = Voting.objects.all() + context = { + 'votings': votings, + } + return HttpResponse(template.render(context, request)) + else: + template = loader.get_template("result_page.html") + messages.error(request, "You must be a staff member to access this page") + return HttpResponse(template.render({'export': True}, request), status=ST_401) + + + +def exporting_census(request): + if request.user.is_staff: + voting_id = request.POST['voting-select'] + censuss_to_export = Census.objects.all().filter(voting_id=voting_id) + voting = Voting.objects.get(id=voting_id) + + with open('./census/export/export_' + voting.name + '.csv', 'w', encoding='UTF8', newline='') as csvfile: + exportwriter = csv.writer(csvfile, delimiter=',') + header = ['username', 'first_name', 'last_name', 'email'] + exportwriter.writerow(header) + + for census in censuss_to_export: + voter = User.objects.get(id=census.voter_id) + row = [voter.username, voter.first_name, voter.last_name, voter.email] + exportwriter.writerow(row) + + + + messages.success(request, "Census was exported correctly") + return HttpResponseRedirect('/census/export/') + + else: + template = loader.get_template("result_page.html") + messages.error(request, "You must be a staff member to access this page") + return HttpResponse(template.render({'export': True}, request), status=ST_401) + + +def import_census(request): + if request.user.is_staff: + template = loader.get_template("census_import.html") + votings = Voting.objects.all() + context = { + 'votings': votings, + } + return HttpResponse(template.render(context, request)) + else: + template = loader.get_template("result_page.html") + messages.error(request, "You must be a staff member to access this page") + return HttpResponse(template.render({'export': True}, request), status=ST_401) + + + +def importing_census(request): + if request.user.is_staff: + voting_id = request.POST['voting-select'] + csvfile = request.FILES['csv-file'] + + csvfile.readline() + lines = csvfile.readlines() + + for line in lines: + fields = line.decode("utf-8").split(',') + voter_exists = User.objects.all().filter(username=fields[0].strip()).exists() + if voter_exists: + voter = User.objects.get(username=fields[0].strip()) + already_exists = Census.objects.all().filter(voting_id=voting_id, voter_id=voter.id).exists() + if not already_exists: + census = Census(voting_id=voting_id,voter_id=voter.id) + census.save() + + + messages.success(request, "Census was imported correctly") + return HttpResponseRedirect('/census/import/') + + else: + template = loader.get_template("result_page.html") + messages.error(request, "You must be a staff member to access this page") + return HttpResponse(template.render({'import': True}, request), status=ST_401)