diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml new file mode 100644 index 0000000000..8675b06b04 --- /dev/null +++ b/.github/workflows/django.yml @@ -0,0 +1,54 @@ +name: Python application + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + pyversion: ['3.8', '3.5'] + pgversion: ['10.8', '12'] + + services: + postgres: + image: postgres:${{matrix.pgversion}} + env: + POSTGRES_USER: decide + POSTGRES_PASSWORD: decide + POSTGRES_DB: decide + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{matrix.pyversion}} + uses: actions/setup-python@v2 + with: + python-version: ${{matrix.pyversion}} + - name: psycopg2 prerequisites + run: sudo apt-get install libpq-dev + - name: Install dependencies and config + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install codacy-coverage + cp decide/local_settings.gactions.py decide/local_settings.py + - name: Run migrations (unnecessary) + run: | + cd decide + python manage.py migrate + - name: Run tests + run: | + cd decide + coverage run --branch --source=. ./manage.py test --keepdb + coverage xml + - name: Codacy Coverage Reporter + uses: codacy/codacy-coverage-reporter-action@v1 + with: + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + coverage-reports: decide/coverage.xml diff --git a/.github/workflows/simpleWF.yml b/.github/workflows/simpleWF.yml new file mode 100644 index 0000000000..f045431d14 --- /dev/null +++ b/.github/workflows/simpleWF.yml @@ -0,0 +1,19 @@ +name: GitHub Actions Demo +on: [push] +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v1 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - run: echo "🍏 This job's status is ${{ job.status }}." + - name: Contains expresion in a step + run: echo "Is this branch master or develop? ${{ contains('refs/heads/master refs/heads/develop',github.ref)}}" diff --git a/decide/authentication/tests_auth.py b/decide/authentication/tests_auth.py new file mode 100644 index 0000000000..b92f7f7f09 --- /dev/null +++ b/decide/authentication/tests_auth.py @@ -0,0 +1,65 @@ +from pyexpat import model +from django.test import TestCase +from django.contrib.staticfiles.testing import StaticLiveServerTestCase + +from selenium import webdriver +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.keys import Keys + +from base.tests import BaseTestCase +from voting.models import Question, Voting + +class AdminTestCase(StaticLiveServerTestCase): + + + def setUp(self): + #Load base test functionality for decide + self.base = BaseTestCase() + self.base.setUp() + + options = webdriver.ChromeOptions() + options.headless = False + self.driver = webdriver.Chrome(options=options) + + super().setUp() + + def tearDown(self): + super().tearDown() + self.driver.quit() + + self.base.tearDown() + + def test_simpleVisualizer(self): + q = Question(desc='test question') + q.save() + v = Voting(name='test voting', question=q) + v.save() + response =self.driver.get(f'{self.live_server_url}/visualizer/{v.pk}/') + vState= self.driver.find_element(By.TAG_NAME,"h2").text + self.assertTrue(vState, "Votación no comenzada") + + def test_simpleCorrectLogin(self): + self.driver.get(f'{self.live_server_url}/admin/') + self.driver.find_element(By.ID,'id_username').send_keys("admin") + self.driver.find_element(By.ID,'id_password').send_keys("qwerty",Keys.ENTER) + + print(self.driver.current_url) + #In case of a correct loging, a element with id 'user-tools' is shown in the upper right part + self.assertTrue(len(self.driver.find_elements(By.ID,'user-tools'))==1) + + def test_Admin_Login_fail(self): + self.driver.get(f'{self.live_server_url}/admin/') + data = {'id_username': 'voter1', 'id_password': '321'} + response = self.client.post('/authentication/login/', data, format='json') + + self.assertEqual(response.status_code, 400) + + +class SimpleTest(TestCase): + def test_basic_addition(self): + self.assertEqual(1 + 1, 2) + + + \ No newline at end of file diff --git a/decide/booth/templates/booth/booth.html b/decide/booth/templates/booth/booth.html index 164f547a31..27a80e51c6 100644 --- a/decide/booth/templates/booth/booth.html +++ b/decide/booth/templates/booth/booth.html @@ -81,7 +81,7 @@

[[ voting.question.desc ]]

- + diff --git a/decide/census/admin.py b/decide/census/admin.py index 8fa7f6762b..90d69bdbe5 100644 --- a/decide/census/admin.py +++ b/decide/census/admin.py @@ -4,9 +4,11 @@ class CensusAdmin(admin.ModelAdmin): + #list_display = ('voting_id', 'voter_id','adscripcion_id') list_display = ('voting_id', 'voter_id') list_filter = ('voting_id', ) + #search_fields = ('voter_id','adscripcion_id', ) search_fields = ('voter_id', ) diff --git a/decide/census/models.py b/decide/census/models.py index e51a5b44e4..409c9f2b32 100644 --- a/decide/census/models.py +++ b/decide/census/models.py @@ -4,6 +4,7 @@ class Census(models.Model): voting_id = models.PositiveIntegerField() voter_id = models.PositiveIntegerField() - + #adscripcion_id = models.PositiveIntegerField() class Meta: + #unique_together = (('voting_id', 'voter_id','adscripcion_id'),) unique_together = (('voting_id', 'voter_id'),) diff --git a/decide/census/views.py b/decide/census/views.py index 26dcf92f19..fb775e87e8 100644 --- a/decide/census/views.py +++ b/decide/census/views.py @@ -20,8 +20,10 @@ class CensusCreate(generics.ListCreateAPIView): def create(self, request, *args, **kwargs): voting_id = request.data.get('voting_id') voters = request.data.get('voters') + #adscripcion_id = request.data.get('adscripcion_id') try: for voter in voters: + #census = Census(voting_id=voting_id, voter_id=voter, adscripcion_id=adscripcion_id) census = Census(voting_id=voting_id, voter_id=voter) census.save() except IntegrityError: @@ -30,6 +32,7 @@ def create(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): voting_id = request.GET.get('voting_id') + #adscripcion_id = request.GET.get('adscripcion_id') voters = Census.objects.filter(voting_id=voting_id).values_list('voter_id', flat=True) return Response({'voters': voters}) diff --git a/decide/decide/settings.py b/decide/decide/settings.py index 1d22b67324..3611fc6916 100644 --- a/decide/decide/settings.py +++ b/decide/decide/settings.py @@ -75,6 +75,7 @@ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -151,6 +152,9 @@ USE_TZ = True + + + TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' # Static files (CSS, JavaScript, Images) @@ -180,3 +184,12 @@ INSTALLED_APPS = INSTALLED_APPS + MODULES +from django.utils.translation import ugettext_lazy as _ +LANGUAGES = [ + ('es', _('Español')), + ('en-us', _('English')), + ('de', _('German')) +] +LOCALE_PATHS = [ + os.path.join(BASE_DIR, 'locale') +] \ No newline at end of file diff --git a/decide/local_settings.py b/decide/local_settings.py new file mode 100644 index 0000000000..becbb60fca --- /dev/null +++ b/decide/local_settings.py @@ -0,0 +1,42 @@ +ALLOWED_HOSTS = ["*"] + +# Modules in use, commented modules that you won't use +MODULES = [ + 'authentication', + 'base', + 'booth', + 'census', + 'mixnet', + 'postproc', + 'store', + 'visualizer', + 'voting', +] + +APIS = { + 'authentication': 'http://localhost:8000', + 'base': 'http://localhost:8000', + 'booth': 'http://localhost:8000', + 'census': 'http://localhost:8000', + 'mixnet': 'http://localhost:8000', + 'postproc': 'http://localhost:8000', + 'store': 'http://localhost:8000', + 'visualizer': 'http://localhost:8000', + 'voting': 'http://localhost:8000', +} + +BASEURL = 'http://localhost:8000' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'postgres', + 'USER': 'decide', + 'PASSWORD': 'complexpassword', + 'HOST': 'localhost', + 'PORT': '5432', + } +} + +# number of bits for the key, all auths should use the same number of bits +KEYBITS = 256 diff --git a/decide/locale/es/LC_MESSAGES/django.po b/decide/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000..167cd0fbd0 --- /dev/null +++ b/decide/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,64 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-11-17 19:27+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: booth/templates/booth/booth.html:19 +msgid "logout" +msgstr "" + +#: booth/templates/booth/booth.html:33 +msgid "Username" +msgstr "Que" + +#: booth/templates/booth/booth.html:41 +msgid "Password" +msgstr "Pasa" + +#: booth/templates/booth/booth.html:49 +msgid "Login" +msgstr "Perro" + +#: booth/templates/booth/booth.html:64 +msgid "Vote" +msgstr "" + +#: booth/templates/booth/booth.html:160 booth/templates/booth/booth.html:170 +#: booth/templates/booth/booth.html:201 +msgid "Error: " +msgstr "" + +#: booth/templates/booth/booth.html:198 +msgid "Conglatulations. Your vote has been sent" +msgstr "" + +#: decide/settings.py:189 +msgid "Español" +msgstr "" + +#: decide/settings.py:190 +msgid "English" +msgstr "" + +#: decide/settings.py:191 +msgid "German" +msgstr "" + +#: visualizer/templates/visualizer/visualizer.html:25 +msgid "result" +msgstr "Resultado de la votación" diff --git a/decide/visualizer/templates/visualizer/visualizer.html b/decide/visualizer/templates/visualizer/visualizer.html index 0faed6bac3..89a761b747 100644 --- a/decide/visualizer/templates/visualizer/visualizer.html +++ b/decide/visualizer/templates/visualizer/visualizer.html @@ -22,7 +22,7 @@

[[ voting.id ]] - [[ voting.name ]]

Votación no comenzada

Votación en curso

-

Resultados:

+

{% trans "result" %}

@@ -48,7 +48,7 @@

Resultados:

{% block extrabody %} - + diff --git a/decide/voting/models.py b/decide/voting/models.py index a10ab2bcb6..156d5a8a5c 100644 --- a/decide/voting/models.py +++ b/decide/voting/models.py @@ -121,3 +121,5 @@ def do_postproc(self): def __str__(self): return self.name + + diff --git a/decide/voting/tests.py b/decide/voting/tests.py index 063c52e1cc..2e0263fdb8 100644 --- a/decide/voting/tests.py +++ b/decide/voting/tests.py @@ -106,6 +106,21 @@ def test_complete_voting(self): for q in v.postproc: self.assertEqual(tally.get(q["number"], 0), q["votes"]) + def testCreateVotinAPI(self): + self.login() + data = { + 'name': 'Example', + 'desc': 'Description example', + 'question': 'I want a ', + 'question_opt': ['cat', 'dog', 'horse'] + } + + response = self.client.post('/voting/', data, format='json') + self.assertEqual(response.status_code, 201) + + voting = Voting.objects.get(name='Example') + self.assertEqual(voting.desc, 'Description example') + def test_create_voting_from_api(self): data = {'name': 'Example'} response = self.client.post('/voting/', data, format='json') @@ -208,3 +223,26 @@ def test_update_voting(self): response = self.client.put('/voting/{}/'.format(voting.pk), data, format='json') self.assertEqual(response.status_code, 400) self.assertEqual(response.json(), 'Voting already tallied') + +class VotingModelTestCase(BaseTestCase): + def setUp(self): + + q = Question(desc='Descripcion') + q.save() + + opt1 = QuestionOption(question=q, option='opcion 1') + opt1.save() + opt1 = QuestionOption(question=q, option='opcion 2') + opt1.save() + + self.v = Voting(name='Votacion', question=q) + self.v.save() + super().setUp() + + def tearDown(self): + super().tearDown() + self.v = None + + def testExist(self): + v=Voting.objects.get(name='Votacion') + self.assertEquals(v.question.options.all()[0].option, "opcion 1") \ No newline at end of file diff --git a/decide/voting/tests_admin.py b/decide/voting/tests_admin.py new file mode 100644 index 0000000000..89cbf57bfa --- /dev/null +++ b/decide/voting/tests_admin.py @@ -0,0 +1,50 @@ +from pyexpat import model +from django.test import TestCase +from django.contrib.staticfiles.testing import StaticLiveServerTestCase + +from selenium import webdriver +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.keys import Keys + +from base.tests import BaseTestCase +from voting.models import Question, Voting + +class AdminTestCase(StaticLiveServerTestCase): + + + def setUp(self): + #Load base test functionality for decide + self.base = BaseTestCase() + self.base.setUp() + + options = webdriver.ChromeOptions() + options.headless = False + self.driver = webdriver.Chrome(options=options) + + super().setUp() + + def tearDown(self): + super().tearDown() + self.driver.quit() + + self.base.tearDown() + + def test_simpleVisualizer(self): + q = Question(desc='test question') + q.save() + v = Voting(name='test voting', question=q) + v.save() + response =self.driver.get(f'{self.live_server_url}/visualizer/{v.pk}/') + vState= self.driver.find_element(By.TAG_NAME,"h2").text + self.assertTrue(vState, "Votación no comenzada") + + def test_simpleCorrectLogin(self): + self.driver.get(f'{self.live_server_url}/admin/') + self.driver.find_element(By.ID,'id_username').send_keys("admin") + self.driver.find_element(By.ID,'id_password').send_keys("qwerty",Keys.ENTER) + + print(self.driver.current_url) + #In case of a correct loging, a element with id 'user-tools' is shown in the upper right part + self.assertTrue(len(self.driver.find_elements(By.ID,'user-tools'))==1) \ No newline at end of file diff --git a/loadtest/gen_census.py b/loadtest/gen_census.py index 64f5705604..b30c92b95d 100644 --- a/loadtest/gen_census.py +++ b/loadtest/gen_census.py @@ -4,7 +4,7 @@ HOST = "http://localhost:8000" USER = "admin" -PASS = "admin" +PASS = "MisPapis55" VOTING = 1 diff --git a/requirements.txt b/requirements.txt index d5860a1eb4..73e5855f29 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ djangorestframework==3.7.7 django-cors-headers==2.1.0 requests==2.18.4 django-filter==1.1.0 -psycopg2==2.7.4 +psycopg2==2.8.4 django-rest-swagger==2.2.0 coverage==4.5.2 django-nose==1.4.6